Array| 704. Binary Search

reference:

1. Detailed Explanation of Binary Search - labuladong - 博客园

2. Dichotomy of seven different requirements (c++) bzdww

Table of contents

Topic: 704. Binary search (power button)

zero.description

1. The most commonly used binary search scenario

2. Dichotomous framework 

Difference: left closed right closed or left closed right open

3. Left closed right closed [left, right]

3. Left closed right open [left,right)

1. Seven situations (see reference 2 for the original text)

Summarize:

1. Find the number equal to key in the array

2. Find the first number equal to key in the array

3. Find the last number equal to key in the array

4. Find the first number greater than or equal to key in the array

5. Find the last number in the array that is less than or equal to key

6. Find the first number in the array that is greater than key

7. Find the last number in the array that is less than key


Topic: 704. Binary search ( power button )

zero.description

The idea is not difficult, but the details are difficult

1. The most commonly used binary search scenario

Find a number, find left bound, find right bound.
 

Details: whether while ( unequal sign) should have an equal sign; whether mid should be plus one

2. Dichotomous framework 

int binarySearch(int[] nums, int target) {
    int left = 0, right = ...;                       //注意1: right
    while(...) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) { ...} 
        else if (nums[mid] < target) { left = ...}   //注意2: 下一次left取值
        else if (nums[mid] > target) { right = ...}
   } 
    return ...;
}

Difference: left closed right closed or left closed right open

3. Left closed right closed [left, right]

Key: when the left ==right interval is left closed and right closed, it is still valid, so while( <= ) is required

Example: {1, 3, 4} looks for 4, if it is missing equals, it will not find

L=0,R=2,M=1 ,nums[M]=3<4

L=2, R=2, lack of equal, do not enter the while loop, error output -1

//搜索一个数,如果存在,返回其索引,否则返回 -1。
int Search(int[] nums, int target) {
    int left = 0;
    int right = nums.length - 1;                         // 注意[l,r]
    while(left <= right) {                               // 注意while(l<=r)  "<="
    // 当left==right,区间[left, right]依然有效,所以用 <=

        int mid = left + (right - left) / 2;
        if(nums[mid] == target)     return mid;
        else if (nums[mid] < target)    left = mid + 1;  // 注意
                                        // target 在右区间,所以[middle + 1, right]

        else if (nums[mid] > target)    right = mid - 1; // 注意
                                        // target 在左区间,所以[left, middle - 1]
    } 
    return -1;
}

// 同理
int Search(vector<int>& nums, int target) {
    int left = 0;
    int right = nums.size() - 1; 
    while (left <= right) { 
    // 当left==right,区间[left, right]依然有效,所以用 <=

        int middle = left + ((right - left) / 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{
            return middle;               // nums[middle] == target
        }                                // 数组中找到目标值,直接返回下标
    }
        // 未找到目标值
        return -1;
}

3. Left closed right open [left,right)

Key: Because when left == right, [left, right) is an invalid space, so use <

Example: {1, 3, 4} finds 4

L=0,R=3,M=1 ,nums[M]=3<4

L=2, R=3, M=2, nums[M]=4 correct output

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;
}

1. Seven situations (see reference 2 for the original text)

Summarize:

  1. Find the number equal to key in the array
    Basic template, commonly used [left, right]
  2. Find the first number equal to key in the array
    Difference: go to arr[mid]==key branch, change arr[mid]>key to >=
               plus judgment​​​​​​​​if(L < arr.size() && arr[L] == key)
               output L
  3. Find the last number equal to key in the array.
    Difference: go to arr[mid]== key branch, change arr[mid]<key to <=
               plus judge​​​​​​​​​if(R >= 0 && arr[R ] == key)
               outputs R
  4. Find the first number in the array that is greater than or equal to key
    Difference: go to the arr[mid]==key branch, change arr[mid]>key to >=
               plus judgment​​​​​​​​if(L < arr.size( ))
               output L
  5. Find the last number in the array that is less than or equal to key
    Difference: Go to the arr[mid]== key branch, change arr[mid]<key to <=
               don’t add judgment​​​​​​​​if(R >= 0) don’t return -1
               outputs R
  6. Find the first number in the array that is greater than key
    Difference: go to arr[mid]==key branch, still arr[mid]>key 
               do not add judgment​​​​​​​​​​if(L < arr.size())  do not return -1
               outputs L
  7. Find the last number in the array that is less than key
    Difference: go to arr[mid]==key branch, still arr[mid]<key 
               do not add judgment​​​​​​​​if (R >= 0) do not return -1
               output R

1. Find the number equal to key in the array

As mentioned above.


2. Find the first number equal to key in the array

Question: There may be duplicate keys in the array. What you need to find is the position
analysis of the first key: find a number equal to the key, and still continue to find whether there is a number equal to the key in front of it.

  • Modify the previous arr[mid]>key to arr[mid]>=key, and remove the branch arr[mid]==key, so that even if you
    encounter an answer equal to key, it will still not return
  • The program continues to look for other values ​​equal to key
  • Finally, after jumping out of the loop, if L satisfies L<arr.size()&&arr[L]==key, return the value of L as the result,
  • Otherwise, output -1, which means not found.

code:

/**查找第一个与key相等的元素的下标, 如果不存在返回-1 */
int erfenfirstEqual(vector<int> arr, int key){
    int L = 0, R = arr.size() - 1;          //在[L,R]查找第一个>=key的
    int mid;

    while( L <= R){
    // 采用[left,right]

        mid = L + ((R - L) >> 1);

        if(arr[mid] >= key)//第一次key出现在[L,mid]中
            R = mid - 1;   //下一次搜索范围[L,mid-1]
                           //意义:想使得arr[R+1]==key,即,R是key索引之前的倒数第一个数
        else
            L = mid + 1;   //下一次搜索范围[mid+1,R]
                           //意义:上面固定了arr[R+1]==key,再使得L不断递增,使得L=R+1跳出
    } 

    //此时,L>R
    if(L < arr.size() && arr[L] == key) //
        return L;

    return -1;
}

Example:

  • Find a number equal to key, and there is no number equal to key before it
    1, 2, 3, 5, 6, 6, 6, 6, 6, 6 (key=6) [correct solution is 4]
    L=0 , R=9, M=4, arr[M]=key but remove the arr[mid]==key branch, so continue to loop
    L=0, R=4-1=3, M=1, arr[M]< key L=mid+1
    L=2, R=3, M=2, arr[M]<key L=mid+1
    L=3, R=3, M=3, arr[M]<key L=mid +1
    L=4, jump out of the loop, judge arr[L]==key 
  • Find a number equal to key, but there is a number equal to key before it.
    1, 2, 3, 5, 6, 6, 6, 6, 6, 6, 6 (key=6) [the correct solution is 4]
    L=0, R=10, M=5, arr[M]=key But remove the arr[mid]==key branch, so continue to loop
    L=0, R=5-1=4, M=2, arr[M]<key L=mid+1
    L=3, R=4, M =3, arr[M]<key L=mid+1
    L=4, R=4, M=4, arr[M]=key but remove the arr[mid]==key branch, so continue to loop
    L=4, R=4-1=3, M=3, arr[M]<key L=mid+1
    L=M+1=4, at this time because L>R, jump out of the loop
  • If there is no key in the array, then the output condition arr[L] == key will not be satisfied, and
    the output is still -1;

memory:

        Modify the previous arr[mid]>key to arr[mid]>=key, and remove the branch arr[mid]==key. The idea is to make
        R the last number smaller than key, and then keep increasing L, so that L>R, jump out of while

3. Find the last number equal to key in the array

Question: There may be duplicate keys in the array. What you want to find is the position
analysis of the last key: find a number equal to the key, and still continue to find whether there is a number equal to the key behind it.

  • Modify the previous arr[mid]>=key to arr[mid]<=key
  • Change R=mid-1 to L=mid+1, which means moving backward

code:

/**查找第一个大于等于key的元素的下标*/
int erfenlasteuual(vector<int> arr,int key){
    int L = 0, R = arr.size() - 1;
    int mid;

    while( L <= R){
        mid = L + ((R - L) >> 1);

        if(arr[mid] <= key)      //注意:区别1
            L = mid + 1;
        else
            R = mid - 1;
        } 

    if(R >= 0 && arr[R] == key)  //注意:区别2
        return R;

    return -1;
}

Memory:
        Similar to finding the first one equal to the key, the difference is: the first if is arr[mid]<=key
        output R


  •  

4. Find the first number greater than or equal to key in the array

Question: Return the first number equal to key, if there is no number equal to key, return the first number greater than key,
           if there is no number greater than key, then return -1

analyze:

  • Modify the code in the second case, modify if(L < arr.size()&& arr[L]== key) to if(L <arr.size()), because if there is no
    number equal to key, then Just return L directly
  • L has several situations:
  • The first one is that L does not exceed the range of the array, then the correct result is returned.
    If L>=arr.size(), it means that the entire array is smaller than the key, and returns -1 directly.
    If there is a key in the array , then finally according to the idea of ​​finding the first key, the correct answer will be returned
  • If there is no key
    1. All elements are greater than key​​​​​​:
          L will not change, because it will not run to the L=mid+1 branch, and finally return 0 , the answer is correct
    2. All elements are less than The key
          R will not change all the time, because it will not run until R=mid-1. The last cycle must be when L is equal to R and
          still go to a branch of L=mid+1, and the mid at this time is arr. size()-1,
          because R will not change, R is arr.size()-1 at the beginning, and finally L=R+1=mid+1=arr.size() .
          Return arr.size( ) . The answer is correct.
    3. There is no key, but some array elements are larger than the key, and             some             are smaller than the       key
          . determined by the nature of the method), it is impossible to point forward or backward, but the condition for jumping out of the loop at the end must be that L is equal to R , then if pointing to a number smaller than key, do L=mid+1 before jumping out of the loop, or point to If it is greater than key,   do R=mid-1 before jumping out of the loop, and the results are all correct.



code:

/*在[L,R]查找第一个>=key的数字*/
int erfenfirstlargeEqual(vector<int> arr,int key){
    int L = 0, R = arr.size() - 1;      
    int mid;


    while( L <= R){
        mid = L + ((R - L) >> 1);
        if(arr[mid] >= key)
            R = mid - 1;
        else
            L = mid + 1;
    } 

    if(L < arr.size())       // 与寻找第一个等于key问题 区别if条件 不需要 arr[L] == key
        return L;

    return -1;
}

Memory:
        Similar to finding the first one equal to key, the difference is: when the final output judgment is made, the if condition does not need arr[L]==key


5. Find the last number in the array that is less than or equal to key

Because R is only equal to -1 and exceeds the range of the array, and the premise of this situation is that there is indeed no number less than or equal to key in the array, so just output R directly.
 

code:

int erfenlastSmallEqual(vector<int> arr,int key){
    int L = 0, R = arr.size() - 1;
    int mid;

    while( L <= R){
        mid = L + ((R - L) >> 1);
        if(arr[mid] <= key)
            L = mid + 1;
        else
            R = mid - 1;
    } 
    //if(R >= 0 && arr[R] == key)  //注意:区别于找第最后一个等于key的值
    return R;
    //也不需要return -1
}


6. Find the first number in the array that is greater than key

question:

The difference from the second and fourth cases is: if(arr[mid] >= key) is changed to if(arr[mid] > key), because it is not to find the key; but to find the key greater than the key Yes,
but because it is looking for the first one greater than, it still cannot return directly after finding it. It is a bit like the ordinary dichotomy, but it is not equal to the key and jumps out of this branch, and finally returns L

analyze:

  • All are smaller than key, then R will not change until the end,
    so the last returned L=mid+1= R+1= arr.size()-1+1 = arr.size()
  • All are greater than key, then L will not change, and finally return L, L=0
  • Greater than, and less than
    because when it is equal to the key, L=mid-1 is chosen, so the minimum R can only point to the last value equal to the key or the last value smaller than the key (in the case of no key), then the final result It returns L=R+1, and it still returns the first number greater than key

code:

/**查找第一个大于key的元素的下标 */
int erfenfirstLarge(vector<int> arr,int key){
    int L = 0,R = arr.size() - 1;
    int mid;
    while(L <= R){
        mid = L + ((R - L) >> 1);

        if(arr[mid] > key)
            R = mid - 1;
        else
            L = mid + 1;
    } 
    return L;               //区别在此,不需要判断
}

​​​​​​​​7.
Find the last number in the array that is less than key


int erfenlastSmall(vector<int> arr,int key){
    int L = 0, R = arr.size() - 1;
    int mid;

    while(L <= R){
        mid = L + ((R - L) >> 1);
        if(arr[mid] < key)
            L = mid + 1;
        else
            R = mid - 1;
    }

    return R;
}

Guess you like

Origin blog.csdn.net/weifengomg/article/details/128210184