The first day of code random recording algorithm training camp | 704. Binary search, 27. Remove elements

Links to Articles and Videos Learned Today

704 article link: link
704 video explanation link: link
27 article link: link
27 video explanation link: link

704 Binary Search

See the title first thought

Because the topic is an ordered array, and there are no repeated elements in the array, the first method that comes to mind when looking for the target value is the dichotomy

Thoughts after reading the code caprice

The dichotomy is also used in the code random thoughts

Conditions for using dichotomy

The premise of this topic is that the array is an ordered array . At the same time, the topic also emphasizes that there are no repeated elements in the array , because once there are repeated elements, the subscript of the element returned by the binary search method may not be unique. These are the prerequisites for using the binary method , when you see that the title description meets the above conditions, think about whether you can use the dichotomy.

The key to binary search

  1. Interval definition
    The main reason why the idea of ​​dichotomy is not clear is that the definition of the interval is not clear, and the definition of the interval is the invariant . In the process of binary search, the invariant must be maintained, that is, in the while search, each boundary processing must be operated according to the definition of the interval, which is the rule of loop invariance .

    There are two common definitions of intervals:

    • Left closed right closed [left, right]
    • Left close right open [left, right)
  2. Boundary conditions
    Binary search involves many boundary conditions, and you need to set the boundary conditions according to the interval definition you choose.
    For example:
    while(left < right)or while(left <= right)
    right = middleorright = middle - 1

Difficulties Encountered During Implementation

1. The first way of writing, define the interval [left, right]
How to set the boundary conditions after defining the interval?

  • while (left <= right) to use <=, because left == right makes sense, so use <=
  • if (nums[middle] > target) right should be assigned middle - 1, because the current nums[middle] must not be target, then the end subscript position of the left interval to be searched next is middle - 1

2. The second way of writing, define the interval [left, right)
How to set the boundary conditions after defining the interval?

  • while (left < right), use < here, because left == right is meaningless in the interval [left, right)
  • if (nums[middle] > target) right is updated to middle, because the current nums[middle] is not equal to target, go to the left interval to continue searching, and the search interval is a left-closed right-open interval, so right is updated to middle, that is: the next The query interval will not compare nums[middle]

the code

The first way of writing [left, right]

class Solution {
    
    
public:
    int search(vector<int>& nums, int target) {
    
    
        int left = 0;
        int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) {
    
     // 当left==right,区间[left, right]依然有效,所以用 <=
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
    
    
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
    
    
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else {
    
     // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

The second way of writing [left, right)

class Solution {
    
    
public:
    int search(vector<int>& nums, int target) {
    
    
        int left = 0;
        int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) {
    
     // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
    
    
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
    
    
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else {
    
     // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

27 Remove elements

See the title first thought

Seeing that this topic requires removing all elements whose value is equal to val in place, and returning the new length of the removed array, the solution that comes to mind is the double pointer method, which deletes the corresponding elements through the fast and slow pointers.

Thoughts after reading the code caprice

Code Caprice also recommends the double-pointer method.
Double pointer method (fast and slow pointer method): complete the work of two for loops under one for loop through a fast pointer and a slow pointer.

Define fast and slow pointers

  • Fast pointer: Find the elements of the new array, the new array is the array that does not contain the target element
  • Slow pointer: point to the location where the subscript of the new array is updated

The deletion process is as follows:
insert image description here

Difficulties Encountered During Implementation

The solution of the double pointer method (fast and slow pointer method) has been mastered, but the opposite double pointer method is a bit unclear.

/**
* 相向双指针方法,基于元素顺序可以改变的题目描述改变了元素相对位置,确保了移动最少元素
* 时间复杂度:O(n)
* 空间复杂度:O(1)
*/
class Solution {
    
    
public:
    int removeElement(vector<int>& nums, int val) {
    
    
        int leftIndex = 0;
        int rightIndex = nums.size() - 1;
        while (leftIndex <= rightIndex) {
    
    
            // 找左边等于val的元素
            while (leftIndex <= rightIndex && nums[leftIndex] != val){
    
    
                ++leftIndex;
            }
            // 找右边不等于val的元素
            while (leftIndex <= rightIndex && nums[rightIndex] == val) {
    
    
                -- rightIndex;
            }
            // 将右边不等于val的元素覆盖左边等于val的元素
            if (leftIndex < rightIndex) {
    
    
                nums[leftIndex++] = nums[rightIndex--];
            }
        }
        return leftIndex;   // leftIndex一定指向了最终数组末尾的下一个元素
    }
};

the code

Double pointer method (fast and slow pointer method)

class Solution {
    
    
public:
    int removeElement(vector<int>& nums, int val) {
    
    
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
    
    
            if (val != nums[fastIndex]) {
    
    
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        return slowIndex;
    }
};

Harvest today

1. To have a deeper understanding of the dichotomy, the key is to insist on doing boundary processing according to the definition of the search interval in the loop, that is, the loop invariant rule.
2. Deepened the understanding of the definition of fast and slow pointers in the double-pointer method.
I often study for 3 hours today.

Guess you like

Origin blog.csdn.net/m0_46555669/article/details/126970834