数组:二分法一看就会,一写就废

数组:二分法一看就会,一写就废

35. 搜索插入位置
思路:

数组有序,且不含重复元素,这就是使用二分查找的重要前提,因为一旦有重复元素,使用二分查找返回的元素下标并不是唯一的。

二分查找涉及的很多的边界条件,是 while(left < right) 还是 while(left <= right),到底是right = middle呢,还是要right = middle - 1呢?

第一种写法:[left,right]

class Solution {
    
    
public:
    int searchInsert(vector<int>& nums, int target) {
    
    
        int n = nums.size();
        int left = 0;
        int right = n - 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;
            }
        }
        // 分别处理如下四种情况
        // 目标值在数组所有元素之前  [0, -1]
        // 目标值等于数组中某一个元素  return middle;
        // 目标值插入数组中的位置 [left, right],return  right + 1
        // 目标值在数组所有元素之后的情况 [left, right], return right + 1
        return right + 1;
    }
};

时间复杂度:O(logn)
空间复杂度:O(1)

第二种写法[left,right)

class Solution {
    
    
public:
    int searchInsert(vector<int>& nums, int target) {
    
    
        int n = nums.size();
        int left = 0;
        int right = n; // 定义target在左闭右开的区间里,[left, right)  target
        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; // 数组中找到目标值的情况,直接返回下标
            }
        }
        // 分别处理如下四种情况
        // 目标值在数组所有元素之前 [0,0)
        // 目标值等于数组中某一个元素 return middle
        // 目标值插入数组中的位置 [left, right) ,return right 即可
        // 目标值在数组所有元素之后的情况 [left, right),return right 即可
        return right;
    }
};

总结:
在二分查找中,坚持循环不变量的原则,弄不清楚主要是因为对区间的定义没有想清楚。

猜你喜欢

转载自blog.csdn.net/cckluv/article/details/111152285
今日推荐