题目来源:LC35

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


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

https://leetcode-cn.com/problems/search-insert-position/

LeetCode 每日一题 | 搜索插入位置 - 什么是二分查找_java


暴力解法

最简单的想法就是直接暴力搜索。


由于数组已经排好序了,我们只需要从小到大遍历一遍。如果目标值存在,则输出位置。如果不存在,返回比目标值大的第一个数字的位置即可。


这里就不详细写代码啦,相信大家都可以自己写出来。


时间复杂度分析:

我们将数组遍历了一遍,因此时间复杂度为 O(n)


二分查找

实际上,遍历数组并没有很好地利用它有序的性质。


如果它是无序的,我们也可以通过遍历一遍数组来判断目标值是否在数组中。


对于一个有序数组,经常刷题的小伙伴首先想到的就是二分查找。它可以很好地利用数组有序的性质来进行查找。


如果你早就会二分查找,那后面的内容就不用看啦~


下面我会用递归来实现二分查找。


实际上递归的效率(主要是空间效率)并不高,但可以帮大家更好的理解算法的思想。

下面是具体步骤:

  • 将目标值和数组的中间值进行对比

    • 如果目标值和中间值相等,找到目标

    • 如果目标值更小,意味着目标值在数组的左半区域,搜索左半数组

    • 如果目标值更大,意味着目标值在数组的右半区域,搜索右半数组

  • 搜索左/右半数组的时候依然采取二分查找的方式,即重复第一个步骤


如果你觉得这个过程有点抽象,那么看一下我写的代码吧~

def searchInsert(self, nums: List[int], target: int) -> int:

  n = len(nums)
  mid = n//2

  # 边界条件
  if n == 0:
    return 0
  if nums[mid] == target:
    return mid

  # 二分查找

  # 如果目标值更大,意味着目标值在数组的右半区域,搜索右半数组
  if nums[mid] < target:
    return mid + 1 + self.searchInsert(nums[mid+1:],target)

  # 如果目标值更小,意味着目标值在数组的左半区域,搜索左半数组
  if nums[mid] > target:
    return self.searchInsert(nums[:mid],target)

SearchInsert 是一个利用二分查找来搜索目标值的函数,搜索子数组的过程用递归来实现。


是不是和步骤中说的一模一样呢。


一般来说,大家会用 while 循环来实现二分查找,但思想和上面的递归是完全一样的。


时间复杂度分析的证明需要花点时间,所以这里就直接说结论。


二分查找的时间复杂度是 O(logn)