首页 > 其他分享 >LeetCode | 35. 搜索插入位置

LeetCode | 35. 搜索插入位置

时间:2023-01-30 11:23:27浏览次数:53  
标签:right target middle int nums 35 插入 LeetCode left

 题:力扣

35. 搜索插入位置

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

请必须使用时间复杂度为 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
 

提示:

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

我的原始思路:

由于数组大小排列好了,因此小于数组0位置的数,直接插入,位置0;

大于数组最后一个数的,直接插入,插入位置nums.size();
大小在数组中间,进行二分查找,找到的话输出位置;
没有找到,比大小,夹在中间的输出i+1,即插入的位置。

class Solution {
public:
    int searchInsert(std::vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1;
        int middle = (left + right) / 2;       
        // 大于数组
        if (target < nums[left]) {
            return 0;
        }
        //小于数组
        else if (target > nums[right]) {
            return right + 1;
        }
        //在数组之间进行二分查找
        else {
            while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
                              
                if (nums[middle] == target) {
                    return middle;
                }
                else if (nums[middle] > target) {
                    right = middle - 1; // target 在左区间,所以[left, middle - 1]
                }
                else {
                    left = middle + 1; // target 在右区间,所以[middle + 1, right]
                }
                middle = (left + right) / 2;

            }
            // 未找到目标值,插入位置
            
            for (int i = 0; i < nums.size() - 1; i++) {
                if (nums[i] < target && target  < nums[i + 1]) {
                    return i + 1;
                }

            }
        }
        return -1;
    }
};

​编辑

答案:

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  left=0 or right + 1=0
        // 目标值等于数组中某一个元素  return middle;二分法中返回
        // 目标值插入数组中的位置 [left, right],return  left or right + 1
        // 目标值在数组所有元素之后的情况 [left, right], 因为是右闭区间,所以 return left or  right + 1
        return right + 1;  //or return left
    }
};
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

解析:

 (1)目标值在数组所有元素之前,二分法会使得区间的right一直左移,直到越过了left才停止,最终变为 [0, -1],right=-1跳出循环。返回值0,可用left或者right+1代替。 (我是直接返回了0,后来发现一个巧妙的共同输出。)且left>right,left-right=1。

​编辑

 

(2)目标值等于数组中某一个元素,在二分法中返回 middle,与外围的right+1无关。

 

(3)目标值插入数组中的位置,target不是数组中的一个,二分法最后是[left, right],且left>right,left-right=1。返回left或者right + 1。

left等于比target大的第一个数的位置,这个位置就是要插入的位置,right等于比target小的第一个数的位置。

因为总是会归于这么一个情况,即比这个target小,再循环一次,跳到比这个target大的数。

或者比这个target大,再循环一次,跳到比这个target小的数。不管哪种情况,left=x>right=x-1。

(更本质的是因为在倒数第二次的循环中,不是在左边就是在右边,且middle不是等于left就是等于right,然后继续循环一次,导致left+1或者right-1,由于target是两个数之间的一个数,因此跳过了也还没找到target,然后就跳出了循环,得出没找到的结论。)

​编辑

 

​编辑

 

 

(4)目标值在数组所有元素之后的情况,[left=right+1,right]。left一直右移,直到left+1越过right,跳出循环,即left=right+1,right=numas.size()-1。插入的位置就是left或者说right+1。

总结:

四种情况,除了数组内有和target一样的值的情况返回middle,其他三种情况均可用一个left或者right+1表示。

 

其他解法:

非二分法,暴力解法。

时间复杂度为O(n),时间复杂度不符合题目要求。

空间复杂度:O(1)

class Solution {
public:
    int searchInsert(std::vector<int>& nums, int target) {
        for(int i = 0; i < nums.size();i++) {
            // 大于或者等于target的num[i],那么i就是结果
            if(nums[i] >= target){
                return i;
            }
        }
        return nums.size(); //target是最大的
    }
};

 

python:

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums) - 1
        middle = (left + right) // 2
        while (left <= right):
            if nums[middle] == target:
                return middle
            elif nums[middle] > target:
                right = middle - 1
            else:
                left = middle + 1
            middle = (left + right) // 2

        return left


标签:right,target,middle,int,nums,35,插入,LeetCode,left
From: https://www.cnblogs.com/AIBigTruth/p/17074891.html

相关文章

  • 「解题报告」ARC135D Add to Square
    这种题的第一想法应当是找不变量。如果给原图黑白染色,那么每次操作都是操作两个黑格两个白格,那么黑格与白格的差不变。如果我们给黑格的数乘上\(-1\),那么就是所有格子的......
  • 【双指针】LeetCode 18. 四数之和
    题目链接18.四数之和思路与【双指针】LeetCode15.三数之和思路相似,但是要注意测试用例可能溢出,需要转换为long代码classSolution{publicList<List<Inte......
  • LeetCode:1669. 合并两个链表
    /***Definitionforsingly-linkedlist.*structListNode{*intval;*ListNode*next;*ListNode():val(0),next(nullptr){}*ListN......
  • Mysql数据库插入数据时出现Unknown column ‘admin‘ in ‘field list‘错误
    报错内容  报错原因字段和插入的值所用的引号不对 解决方案 insertintot_user(`username`,`password`,`email`)VALUES(`admin`,`admin`,`[email protected]......
  • leetcode简单(矩阵):[566, 766, 832, 867, 999, 1030, 1261, 1275, 1337, 1351]
    目录566.重塑矩阵766.托普利茨矩阵832.翻转图像867.转置矩阵999.可以被一步捕获的棋子数1030.距离顺序排列矩阵单元格1260.二维网格迁移1275.找出井字棋的获胜者13......
  • LeetCode-21.合并两个有序链表
    21.合并两个有序链表(MergeTwoSortedLists)将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。示例1:输入:l1=[1,2,4......
  • LeetCode_周赛_330
    6337.统计桌面上的不同数字代码后面出现的数字都是小于n的。n=1时,答案是1。n>1时:第一天,n%(n-1)==1,n-1会被加入第二天,(n-1)%(n-2)==1,n-......
  • 插入排序
    话不多少,直接上代码(Coding):/***插入排序对于少量元素来说选择排序是一种有效的最简单的排序算法*算法和冒泡排序有点像都是逐一比较插入一个元素然后取出元素......
  • leetcode 15. 三数之和
    想到了先排序然后再用双指针,可是没有想过往O(n^2)的时间复杂度上怼。哈哈哈。正确解法如下:classSolution{publicList<List<Integer>>threeSum(int[]nums){......
  • 【双指针】LeetCode 16. 最接近的三数之和
    题目链接16.最接近的三数之和思路借鉴【双指针】LeetCode15.三数之和的思路,只不过把0换成target代码classSolution{publicintthreeSumClosest(int[]n......