The first day of the code random recording algorithm training camp | LeetCode704. Binary search, LeetCode27. Remove elements

LeetCode704. Binary Search

topic link

https://leetcode.cn/problems/binary-search/

Video explanation

https://www.bilibili.com/video/BV1fA4y1o715

topic analysis

Given an ordered (ascending) integer array nums with n elements and a target value target, write a function to search the target in nums, and return the subscript if the target value exists, otherwise return -1.

The array given in this topic is an ordered array, and you need to search for the value in the array according to the given target value target and return the subscript value, or return -1 if there is no value. This type of question is a typical binary search question type, and everyone needs to be proficient in binary search.

Binary search code analysis

There are two mainstream ways of writing intervals for binary search:

  • Left closed right closed [left , right]

  • Left closed right open [left , right)

For the two different interval writing methods, the key distinguishing points are the following three points:

  • When initially setting the right boundary, set it to right = nums.size() - 1 or right = nums.size()

  • Should the judgment condition of the while loop be left < right or left <= right

  • When updating the right border, should you set right = middle - 1 or right = middle

  1. Key point one

For the left-closed right-closed interval [left , right],

The right boundary of right is desirable, indicating that the maximum range of the initial setting of right should be exactly at the maximum lower boundary of the array. At this time, it should be set to right = nums.size() - 1.

For the left-closed right-open interval [left , right),

The right boundary of right is not taken, indicating that the maximum range initially set by right should be exactly 1 larger than the maximum subscript boundary of the array, and it should be set to right = nums.size() at this time.

  1. Key point two

When judging the judgment condition of the while loop, you only need to substitute the left < right and left <= right into the set range to see if it is reasonable.

For the left-closed right-closed interval [left , right],

When left <= right, the interval still holds true, and the judgment condition at this time is left <= right.

For the left-closed right-open interval [left , right),

When left < right, the interval is still valid, and when left <= right, the interval is no longer valid, and the judgment condition at this time is left < right.

For left-closed intervals, when updating the left boundary, set left = middle + 1.

  1. Key point three

When updating the right border,

For the left-closed right-closed interval [left , right],

The corresponding conclusion has been drawn by comparing nums[middle] with target. At this time, if the right boundary is updated to right = middle, the comparison will be repeated again, which is unreasonable, so right = middle - 1 should be set at this time.

For the left-closed right-open interval [left , right),

The comparison between nums[middle] and target has drawn a corresponding conclusion. If you update the right boundary right = middle at this time, the range opened to the right will just block the compared middle item, so you should set right = middle at this time .

Binary Search Code Example

Close left and close right

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //左闭右闭写法
        int left = 0;
        int right = nums.size() - 1;
        while(left <= right) {
            int middle = left + (right - left) / 2;
            if(nums[middle] > target) {
                right = middle - 1;
            }
            else if(nums[middle] < target) {
                left = middle + 1;
            }
            else return middle; 
        }
        return -1;
    }
};

left closed right open

class Solution {
public:
    int search(vector<int>& nums, int target) {
        //左闭右开写法
        int left = 0;
        int right = nums.size();
        while(left < right) {
            int middle = left + (right - left) / 2;
            if(nums[middle] > target) {
                right = middle;
            }
            else if(nums[middle] < target) {
                left = middle + 1;
            }
            else return middle; 
        }
        return -1;
    }
};

additional supplement

When finding the middle value, the editor's action is

int middle = left + (right - left) / 2

instead of writing

int middle = (left + right) / 2

In fact, both of these two writing methods are correct, but the second writing method is thought to involve the problem of adding the left and right boundaries, which is easy to cause overflow, so it is more convenient and safe to use the first writing method here.

In addition, there is still room for improvement in the first way of writing, that is——

int middle = left + (right - left) >> 1

Here is the operation using bit operators. For details, please refer to related articles.

The decimal operation of >>1 is equivalent to a decimal operation of dividing by 2, and the bit operation of >>2 is equivalent to a decimal operation of dividing by 4... and so on.

This way of writing avoids the problem of floating-point number overflow, and it is also faster than direct use / calculation.

LeetCode27. Remove elements

topic link

https://leetcode.cn/problems/remove-element/

Video explanation

https://www.bilibili.com/video/BV12A4y1Z7LP

topic analysis

Given an array nums and a value val, you need to remove all elements whose value is equal to val in place, and return the new length of the removed array.
Don't use extra array space, you have to use only O(1) extra space and modify the input array in-place.
The order of elements can be changed. You don't need to consider elements in the array beyond the new length.

This topic involves the deletion and movement of elements. The focus of the investigation is how to move the retained elements to the original position of the deleted elements. Two solutions are shared as follows.

Solution one - violent solution

class Solution {
public:
    
    int removeElement(vector<int>& nums, int val) {
        //暴力解法
        int size = nums.size();
        for(int i = 0; i < size; i++) {
            if(nums[i] == val) {
                for(int j = i; j < size - 1; j++) {
                    nums[j] = nums[j + 1];
                }
                size--;
                i--;
            }
        }
        return size;
    }
};

This code mainly uses the movement of elements, and the time complexity reaches O(n2). The error-prone point is that when moving the latter part of the elements to the position of the deleted element, both the length size of the array and the pointer i need to be subtracted by one to re-match the length and Location.

Solution 2 - double pointer method

Only operate on the nums array with the help of fast and slow pointers

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

Use the temp array to match the nums array to perform fast and slow pointer operations

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        vector<int> temp(nums.size());
        for(int m = 0; m < nums.size(); m++) {
            temp[m] = nums[m];
        }
        int i, j = 0;
        while(i < nums.size()) {
            if(temp[i] == val) {
                i++;
            }
            else {
                nums[j] = temp[i];
                j++;
                i++;
            }
        }
        return j;

    }
};

There is no essential difference between the two operations, but pay attention to the copy operation when using the operation using the temp array.

Summarize

Today's algorithm topic is relatively simple, and there have been exercises before, but considering that these two topics are only the most basic operations of the two algorithms, further expansion exercises are needed to consolidate them.

There are still a few extended question types that have not been tried, mark them here, and continue to overcome them later.

Binary search type -

  • 35. Search insertion position(opens new window)

  • 34. Find the first and last position of an element in a sorted array(opens new window)

  • square root of 69.x

  • 367. Effective perfect square numbers

Remove element type -

  • 26. Remove duplicates in sorted array

  • 283. Moving Zero

  • 844. Compare strings with backspace

  • 977. Squaring an Ordered Array

Guess you like

Origin blog.csdn.net/wyr1849089774/article/details/128666156