问题:给定一个 n
个元素有序的(升序)整型数组 nums
和一个目标值 target
,写一个函数搜索 nums
中的 target
,如果目标值存在返回下标,否则返回 -1
求解:对于区间的选择有很多种,我习惯使用左闭右开的方式[left,right)
值得注意的是,这里mid的选取不要写成(left+right)/2!!!可能会出现数组越界的问题!!!
func lowerBound2(nums []int, target int) int {
left, right := 0, len(nums)
for left < right {
mid := left + (right-left)/2
if nums[mid] < target {
left = mid + 1
} else {
right = mid
}
}
return left
}
引申:二分查找基本思想可以用在多种场景下,他也是少数logn算法。实现二分查找必须满足单调性:题目中出现,在题目中出现mid越大或越小,则越容易满足条件要求,这种便满足单调性。另外,题目中出现最大化最小值或者最小化最大值时候,一般可用此法。
上述题目比较的是nums[mid]与target,引申中一般用check(...)函数来比较!!!
以leetcode中一道题为例1482. 制作 m 束花所需的最少天数 - 力扣(LeetCode)
求最少天数,由于天数越多,越容易达成制作m束花的条件,因此满足单调性。求出最少天数与最大天数,然后二分,对于不同的天数mid,在check中检测mid能否完成m束花制作?能的话即为true。答案可求。
答案:
func check(bloomDay []int,m int,mid int,k int) bool{
res:=0
cnt:=0
for _,v := range bloomDay{
if v<=mid{
cnt++
if cnt==k{
res++
cnt=0
}
}else{
cnt=0
}
}
return res>=m
}
func minDays(bloomDay []int, m int, k int) int {
if m > len(bloomDay)/k {
return -1
}
minDay, maxDay := math.MaxInt32, 0
for _, day := range bloomDay {
if day < minDay {
minDay = day
}
if day > maxDay {
maxDay = day
}
}
left,right:=minDay,maxDay
for left<right{
mid := left+(right-left)/2
if !check(bloomDay,m,mid,k){
left=mid+1
}else if check(bloomDay,m,mid,k){
right=mid
}
fmt.Println(left)
}
fmt.Println(left)
if check(bloomDay,m,left,k){
return left
}
return -1
}
补充,golang对于二分查找有专门实现,比如23478,查找6的位置,返回索引3。
//求nums中k的位置
sort.SearchInts(nums, 6)//整数
sort.Search(len(floats), func(i int) bool { return floats[i] >= 6.0 })//浮点数