1.1.1 数组——搜索插入位置(Leetcode 35)

1.题目

leetcode链接
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

请必须使用时间复杂度为 O(log n) 的算法。

示例 1:

输入: nums = [1,3,5,6], target = 5
输出: 2

示例 2:

输入: nums = [1,3,5,6], target = 2
输出: 1

示例 3:

输入: nums = [1,3,5,6], target = 7
输出: 4

示例 4:

输入: nums = [1,3,5,6], target = 0
输出: 0

示例 5:

输入: nums = [1], target = 0
输出: 0

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums 为无重复元素的升序排列数组
  • -104 <= target <= 104

2. 思路

题目提示使用二分法:

  • nums 为无重复元素的升序排列数组
  • 必须使用时间复杂度为 O(log n) 的算法

四种情况:

  • 目标值在数组所有元素之前
  • 目标值等于数组中某一个元素
  • 目标值插入数组中的位置
  • 目标值在数组所有元素之后

关键点:

  • 采用二分法结束遍历时,left和right所指向的位置

3. 代码实现

3.1 解法一:暴力求解

  • 不满足时间复杂度为 O(log n) 的条件
class Solution {
    
    
public:
    int searchInsert(vector<int>& nums, int target) {
    
    
        for(int i = 0; i < nums.size(); i++){
    
    
            // 对应于前三种情况
            if(nums[i] >= target){
    
    
                return i;
            }

        }
        // 对应于目标值在数组所有元素之后的情况
        return nums.size();

    }
};

3.2 解法二:二分法(左闭右闭)

class Solution {
    
    
public:
    int searchInsert(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){
    
    
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            }else if(nums[middle] > target){
    
    
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            }else{
    
    // nums[middle] == target
                return middle;
            }
        }

        // 数组中不存在target
        // 1. 插入到所有元素之前,所有的元素都比target大:right = -1(left = 0)
        // 2. 插入到数组中,nums[left] < target < nums[right]
        // 下一次循环,执行left = middle + 1;
        // 下一次循环,执行right = middle - 1, 结束循环;
        // 3. 插入到所有元素之后,所有的元素都比target大:right = nums.size() - 1(left = nums.size())
        return right + 1;

    }
};

3.3 解法三:二分法(左闭右开)

class Solution {
    
    
public:
    int searchInsert(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){
    
    
                left = middle + 1; // target 在右区间,所以[middle + 1, right)
            }else if(nums[middle] > target){
    
    
                right = middle; // target 在左区间,所以[left, middle)
            }else{
    
    // nums[middle] == target
                return middle;
            }
        }

        // 数组中不存在target
        // 1. 插入到所有元素之前,所有的元素都比target大:right = 0(left = 0)
        // 2. 插入到数组中,nums[left] < target < nums[right]
        // 下一次循环,执行left = middle + 1;
        // 下一次循环,执行right = middle, 结束循环;
        // 3. 插入到所有元素之后,所有的元素都比target大:right = nums.size()(left = nums.size())
        return right;

    }
};

4. 总结

  • 需要加深对二分法流程的理解,尤其是结束循环时,left和right的指向位置

猜你喜欢

转载自blog.csdn.net/weixin_46297585/article/details/123195584