解题思路
这道题在周赛的时候纯粹自己想多了,没有认真看题,还卡在了子序列连续或不连续上。
//错误代码
func minimumAddedInteger(nums1 []int, nums2 []int) int {
sort.Ints(nums2)
sort.Ints(nums1)
tmp := 2500
for i := 0; i < len(nums1)-len(nums2)+1;i++{
for j := 1; j < len(nums2); j++{
if nums2[j]-nums1[j+i] != nums2[j-1]-nums1[j+i-1]{ //默认子序列连续,其实这样不对
break
}
if j == len(nums2)-1{
tmp = min(tmp,nums2[j]-nums1[j+i])
}
}
}
return tmp
}
func minimumAddedInteger(nums1 []int, nums2 []int) int {
sort.Ints(nums1)
sort.Ints(nums2)
for i := 2; i > 0; i--{
diff := nums2[0] - nums1[i]
j := 0
for _,v := range nums1[i:]{
if nums2[j] == v+diff{
j++
}
if j == len(nums2){
return diff
}
}
}
return nums2[0]-nums1[0]
}
二分
对于二分而言重点在于分析循环不变量,即l
l,r
会停在哪
34. 在排序数组中查找元素的第一个和最后一个位置
对于这道题而言,如果我们要找第一个大于等于x的位置,那么我就假设L最终会停在第一个大于等于x的位置,R停在L的左边。
这样按照上面那句话,可以把循环不变式描述为“L的左边恒小于x,R的右边恒大于等于x”,这样一来,其他的各种条件就不言自明了。
比如循环条件肯定是L小于等于R,因为我假设R停在L的左边。
而L和R转移的时候,根据循环不变式,如果mid小于x,肯定要令L等于mid+1,如果大于等于x,就令R等于mid-1。
至于初始的时候L和R怎么选,也是看循环不变式,只需要保证初始L和R的选择满足“L的左边恒小于x,R的右边恒大于等于x”,并且不会出现越界的情况即可,L必为0,因为0左边可以看作负无穷,恒小于x,R取第一个一定满足条件的(防止mid取到非法值),例如n-1(n开始可以看作正无穷,恒大于等于x,如果保证x在数组里可以选择n-2,其实大于等于n也满足不变式,但是mid可能会取非法值)。取n-1是有条件的,一般来说是r取n,因为n位置默认是无穷大,一定符合大于等于x的条件,但是如果事先已知x一定在数组里,就可以取r为n-1,因为数组最大值至少是x。至于访问mid+1这种就属于变种的问题了,需要具体情况具体分析
解题思路
对于本题而言,l
可以定义为第一个大于等于target
的位置,r
可以定义为最后一个大于等于target
的位置,即第一个大于等于target+1
的位置。那么上图就是可以转换的
func searchRange(nums []int, target int) []int {
var s1 func(target int)int
s1 = func(target int)int{
l,r := 0,len(nums)
for l < r{
mid := l+(r-l)/2
if nums[mid] >= target{
r = mid
}else{
l = mid+1
}
}
return r
}
start := s1(target)
if start == len(nums) || nums[start] != target{
return []int{-1,-1}
}
end := s1(target+1)-1
return []int{start,end}
}