Post

算法(九)--二分查找

算法(九)--二分查找

二分查找

重要重要!二分查找的前提是有序数组!并且元素不能重复,如果重复查找返回的下标可能不是唯一的。

循环不变量原则:根据定义不变量区间来判断while循环条件语句以及循环体内的操作。区间分为两种:左闭右闭区间和左闭右开区间。左闭右闭区间的循环条件是left<=right,左闭右开区间的循环条件是left<right。在循环中一定要根据区间的定义来确定边界条件,进行边界处理

二分查找的基本模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size()-1;
        while(left<=right) {
            int mid = (right+left)/2;
            if(nums[mid] == target) return mid;
            if(nums[mid] > target) {
                right = mid - 1;
            }
            else left = mid + 1;
        }
        return -1;
    }
};

找到第一个大于等于target的元素的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 找到第一个大于等于target的元素的位置
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int n = nums.size();
        int left = 0, right = n - 1, ans = n;
        while (left <= right) {
            int mid = (left+right)/2;
            if (nums[mid] >= target) {
                ans = mid;
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return ans;
    }
};

二段有序数组的查找

不能在通过target值与nums[mid]的大小关系来判断target在左段还是右段,因为这样会导致无法判断左段和右段的有序性。应该先判断mid左段和右段的有序性,在判断target在不在有序的一段中,根据这个来进行left和right的更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0, right = nums.size()-1;
        while(left<=right) {
            int mid = (right+left)/2;
            if(nums[mid] == target) return mid;
            if(nums[left] < nums[mid]) {
                // 左边为有序区间
                (target >= nums[left] && target < nums[mid]) ? right = mid-1 : left = mid + 1;
            }
            else {
           (target > nums[mid] && target <= nums[right]) ? left = mid + 1 : right = mid - 1;
            }
        }
        return -1;
    }
};
This post is licensed under CC BY 4.0 by the author.