题目描述
给你一个 严格升序排列 的正整数数组 arr 和一个整数 k 。请你找到这个数组里第 k 个缺失的正整数。
样例:
输入:arr = [2,3,4,7,11], k = 5
输出:9
解释:缺失的正整数包括 [1,5,6,8,9,10,12,13,…] 。
第 5 个缺失的正整数为 9 。
参考代码:
def findKthPositive(arr, k) :
left=0
right=len(arr)
while left<right:
mid = (left+right)//2
if arr[mid]-mid-1>=k:
right=mid
else:
left=mid+1
return k+left
分析:
left:左边界
right:右边界
由样例可知数组arr是相对于整个正整数而言来计缺失的正整数,所以当数组arr确定时,它的最后一个数减去它的下标再减一(即arr[right]-right-1),就是到数组arr最后一个数一共缺失的整数的个数。
很容易想到该题可以使用二分查找的方法:
1、mid = (left+right)//2
2、当arr[mid]-mid-1>=k时,说明要找的第K个缺失的数在数组左边,所以right=mid(右边界替换)
3、当arr[mid]-mid-1<k时,说明要找的第K个缺失的数在数组右边,所以left=mid+1(左边界替换),这里的加一是因为要不满足 while left<right: 的循环条件退出,更重要的是保证第K个缺失的数在left最近的左边,所以往前加一。(补充:这里还要考虑一个特殊情况,要使mid等于arr下界,此时left=right,如果mid取下界时还是arr[mid]-mid-1<k,left+1越界,但循环不满足了,退出循环时正好保证第K个缺失的数在left最近的左边,虽然left是虚指了。)
4、当保证第K个缺失的数在left最近的左边时,要找的数就等于k加上left左边数的个数,正好是下标left的值,即k+left。
接下来我们来看一下阿里21年3月8号的面试题:
题目描述:
参考代码:
def findKthPositive(arr, k) :
left=0
right=len(arr)
while left<right:
mid = (left+right)//2
if (arr[mid]-arr[0]+1)-(mid+1)>=k:
right=mid
else:
left=mid+1
return k+left+(arr[0]-1)
分析:
理解题目后,分析发现与前一题的差别仅仅在于起始数字的不同,前题目是从一开始,后题目是从arr[0]开始,所以计算arr[mid]到arr[0]一共缺失数字的个数就是;(arr[mid]-arr[0]+1)-(mid+1).
之后的返回值第K个缺失的数,就等于k+left再加上arr[0]之前缺失的数的个数就行了,即k+left+(arr[0]-1)。(或者理解为加上起始点)
总结:
二分法的关键就在于何时更新上限,何时更新下限,即找出最简洁的条件判断式;
再一个就是返回的结果尽量找一个最精简的式子,在写代码之前多找规律,多写式子,然后尝试套用模板,找出关键点。