力扣刷题-搜索插入位置(代码片段)

王六六的IT日常 王六六的IT日常     2022-12-31     265

关键词:

力扣题目链接

题目描述

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。
如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
使用时间复杂度为 O(log n) 的算法。

你可以假设数组中无重复元素。

示例 1: 输入: [1,3,5,6], 5 输出: 2

示例 2: 输入: [1,3,5,6], 2 输出: 1

示例 3: 输入: [1,3,5,6], 7 输出: 4

示例 4: 输入: [1,3,5,6], 0 输出: 0

提示:nums 为无重复元素的升序排列数组 - 最后一个值肯定是最大的

思路

有序数组中查找,可以使用「二分查找」。

  • 要在数组中插入目标值,无非是这四种情况:

    • 目标值在数组所有元素之前
    • 目标值等于数组中某一个元素
    • 目标值插入数组中的位置
    • 目标值在数组所有元素之后
  • 整体思路和普通的二分查找几乎没有区别,先设定左侧下标 left 和右侧下标 right,再计算中间下标 mid

  • 每次根据 nums[mid] 和 target 之间的大小进行判断,相等则直接返回下标,nums[mid] < target 则 left 右移,nums[mid] > target 则 right 左移

  • 查找结束如果没有相等值则返回 (left)第 1 个 大于等于(等于的情况可以看示例 1) 目标元素的下标,该值为插入位置

  • 如果当前mid值严格小于 target,那么 mid 以及 mid 左边的所有元素就一定不是题目要求的结果

  • 时间复杂度: O ( l o g n ) O(logn) O(logn)

参考代码一:

public class Solution 

    public int searchInsert(int[] nums, int target) 
        int len = nums.length; 
        // 特殊判断
        if (nums[len - 1] < target) 
            return len;
        

        // 程序走到这里一定有 nums[len - 1] >= target
        int left = 0;
        int right = len - 1; //【左闭右闭】
        // 在区间 nums[left..right] 里查找第 1 个大于等于 target 的元素的下标
        // while(left < right)
        //     int mid = (left + right) / 2;
        //     if(nums[mid] == target)
        //         return mid;
        //     else if(nums[mid] < target)
        //         left = mid +1;
        //     else if(nums[mid] > target)
        //         right = mid;
        //     
        // 
        while (left < right) 
            int mid = (right + left) / 2;
            if (nums[mid] < target)
                // 下一轮搜索的区间是 [mid + 1..right]
                left = mid + 1;
             else  //nums[mid] >= target
                // 下一轮搜索的区间是 [left..mid]
                right = mid;
            
        
        return left;
    


既然 len 也有可能是答案,可以在初始化的时候,把 right 设置成 len,此时就不需要特殊判断了。

参考代码二:

public class Solution 

    public int searchInsert(int[] nums, int target) 
        int len = nums.length;
        int left = 0;
        int right = len;
        // 在区间 nums[left..right] 里查找第 1 个大于等于 target 的元素的下标
        while (left < right) 
            int mid = left + (right - left) / 2;
            if (nums[mid] < target)
                // 下一轮搜索的区间是 [mid + 1..right]
                left = mid + 1;
             else 
                // 下一轮搜索的区间是 [left..mid]
                right = mid;
            
        
        return left;
    


注意点概括

  • 写成 while(left < right) ,退出循环的时候有 left == right 成立,好处是不用判断应该返回 left 还是 right;
  • 区间 [left…right] 划分只有以下两种情况:
    • 分成 [left…mid] 和 [mid + 1…right],分别对应 right = mid 和 left = mid + 1;int mid = (left + right) / 2
    • 分成 [left…mid - 1] 和 [mid…right],分别对应 right = mid - 1 和 left = mid,这种情况下。需要将 int mid = (left + right) / 2 改成 int mid = (left + right + 1) / 2,否则会出现死循环,这一点不用记,出现死循环的时候,把 left 和 right 的值打印出来看一下就很清楚了;
  • 退出循环 left == right,如果可以确定区间 [left…right] 一定有解,直接返回 left 就可以。否则还需要对 left 这个位置单独做一次判断;
  • 二分查找的循环不变量是:在区间 [left…right] 里查找目标元素。

2.leetcode刷题-搜索插入位置(代码片段)

这是我坚持力扣刷题打卡的第2/100题~ 一、题目描述给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为O(l... 查看详情

力扣刷题:单词搜索(java实现)(代码片段)

题目:给定一个mxn二维字符网格board和一个字符串单词word。如果word存在于网格中,返回true;否则,返回false。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相... 查看详情

力扣刷题每日打卡(代码片段)

​力扣刷题:重新排列数组:/***Note:Thereturnedarraymustbemalloced,assumecallercallsfree().*/int*shuffle(int*nums,intnumsSize,intn,int*returnSize)if(numsSize==1)*returnSize=1;returnnums;in 查看详情

力扣刷题每日打卡(代码片段)

​力扣刷题:重新排列数组:/***Note:Thereturnedarraymustbemalloced,assumecallercallsfree().*/int*shuffle(int*nums,intnumsSize,intn,int*returnSize)if(numsSize==1)*returnSize=1;returnnums;in 查看详情

力扣刷题:寻找峰值(java实现)(代码片段)

题目:峰值元素是指其值严格大于左右相邻值的元素。给你一个整数数组nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回任何一个峰值所在位置即可。你可以假设nums[-1]=nums[n]=... 查看详情

力扣刷题(代码片段)

两数之和给定一个整数数组nums和一个目标值target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。示例:给定nums=[2... 查看详情

力扣刷题之双指针(c++)(代码片段)

(学习参考书:LeetCode101)双指针双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延申多个数组的多个指针。若两个指针指向同一数组,遍历方向相同且不会相交,则... 查看详情

力扣刷题:快乐数(java实现)(代码片段)

题目描述:编写一个算法来判断一个数n是不是快乐数。「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为1,也可能是无限循环但始终变... 查看详情

力扣刷题:在排序数组中查找元素的第一个和最后一个位置(java实现)(代码片段)

题目:给定一个按照升序排列的整数数组nums,和一个目标值target。找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值target,返回[-1,-1]。进阶:你可以设计并实现时间复杂度为O(logn)的算法... 查看详情

力扣刷题详解(含代码动态展示)(代码片段)

(文章目录)一、448.找到所有数组中消失的数字1.完整过程动态展示2.代码实现int*findDisappearedNumbers(int*nums,intnumsSize,int*returnSize)int*ptr=(int*)malloc(sizeof(int)*numsSize);intindex=0;intnoindex=0;while(index<numsSize)if(num 查看详情

力扣刷题之双指针(c++&java)(代码片段)

(学习参考书:LeetCode101)双指针双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。也可以延申多个数组的多个指针。若两个指针指向同一数组,遍历方向相同且不会相交,则... 查看详情

力扣刷题:单词搜索(java实现)(代码片段)

题目:给定一个mxn二维字符网格board和一个字符串单词word。如果word存在于网格中,返回true;否则,返回false。单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相... 查看详情

力扣刷题:括号生成(java实现)(代码片段)

数字n代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且有效的括号组合。有效括号组合需满足:左括号必须以正确的顺序闭合。示例1:输入:n=3输出:["((()))","(()())",&... 查看详情

力扣刷题—两数之和(代码片段)

题目:给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重... 查看详情

力扣刷题:合并区间(java实现)(代码片段)

题目描述:以数组intervals表示若干个区间的集合,其中单个区间为intervals[i]=[starti,endi]。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。示例1:输入:in... 查看详情

力扣刷题:岛屿数量(java实现)(代码片段)

给你一个由'1'(陆地)和'0'(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以... 查看详情

力扣刷题:全排列(java实现)(代码片段)

题目:给定一个不含重复数字的数组nums,返回其所有可能的全排列。你可以按任意顺序返回答案。示例1:输入:nums=[1,2,3]输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]示例2:输入:nums=[0,1]输出&#x... 查看详情

力扣刷题:字母异位词分组(java实现)(代码片段)

题目:给你一个字符串数组,请你将字母异位词组合在一起。可以按任意顺序返回结果列表。字母异位词是由重新排列源单词的字母得到的一个新单词,所有源单词中的字母都恰好只用一次。示例1:输入:strs=["eat... 查看详情