昨天没能完成 34,今天来补上。恰好第 35 题也是二分查找算法的应用,放到一起来记录。
首先看下二分查找算法的概念:
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
百度百科:二分查找
使用的题目中,一般会提到要求时间复杂度为 O(log n) 级别,以及涉及到的列表、数组是有序排列的。结合今天要记的三道题,我们来练习下这种解法的应用。在难度上,第 35 题简单,33、34 是中等难度,我们先看简单的。
题目一
第 35 题:搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
你可以假设数组中无重复元素。
示例 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
#来源:力扣(LeetCode)
#链接:https://leetcode-cn.com/problems/search-insert-position
题目分析
要在排序数组中找目标值的位置,很典型的二分查找的应用场景。当目标不存在时,返回目标应该被插入的位置。这个我们先把特殊情况择出来:列表长度不到 2 的情况,目标值大小超出列表值范围情况。正常二分查找的操作类似双指针法,定义一前一后两个索引,每次取其中间位置的值来进行判断,直到最终定位出结果。
比如示例 1,我们分别先取第一位 1 和最后一位 6 作为前后位置,此时中间位置为第 2 位 3,3 小于目标值,所以我们把范围缩小到右半部;缩小范围后,第 2 位 3 成了左侧边界,最后一位 6 仍是右边界,此时中间位置为 第 3 位 恰好为 5 目标值,所以返回第 3 位的坐标 2,任务完成。
这题要注意的点是,若存在目标值,返回其坐标;若不存在,要返回目标应该插入的位置。
代码实现
看二分法,通常都会纠结于比较完中点值后,对之后左右边界如何划分,究竟取 mid、mid-1 还是 mid+1 作为新的坐标,这个要具体来分析。
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
# 空列表情况
if nums==[]:
return 0
length = len(nums)
# 只有一个数的列表情况
if length<2:
if nums[0]>=target:
return 0
else:
return 1
# 目标值不在列表值范围内情况
if target<=nums[0]:
return 0
if target> nums[-1]:
return length
# 二分查找法开始
# 定义左右边界位置,最左端和最右端索引
l,r = 0,length-1
# while 循环控制 l 和 r 来缩小范围
while l<r:
# 取中点,这里的取值会偏左,比如第 1、2 位取的中点是第 1 位
mid = (l