前面部分第4题,包括使用条件等感谢代码随想录:)
leetcode704
??二分查找用于在有序且不重复的元素列表中寻找需要的元素,返回其位置或错误
??当要求算法的时间复杂度在O(logn) 等带log的复杂度时,可以考虑二分查找法
??二分查找法中对于 区间 的定义
??二分查找涉及的很多的边界条件,逻辑比较简单,但就是写不好。例如到底是 while(left < right)
还是 while(left <= right)
,到底是right = middle
呢,还是要right = middle - 1
呢?
??对于二分法的区间定义,可以有闭区间、左闭右开、左开右闭等多种写法,他们的含义是我们寻找的target与左右指针的关系
与此相关的自然就会产生循环条件的判断 以及 每次循环的左右指针的偏移 的定义问题
以下为闭区间版本的写法:
// 学习版本二分查找
func search(nums []int, target int) int {
high := len(nums) - 1
low := 0
for low <= high { //在闭区间中如[1,1]是有意义的
mid := low + (high-low)/2 //这样定义防止数字太大溢出
if nums[mid] == target {
return mid
} else if nums[mid] > target { //缩小target所在的区间,由于为闭区间,可以舍弃上次的边界值
high = mid - 1
} else {
low = mid + 1
}
}
return -1
}
左闭右开区间版本:
// 左闭右开区间版本
func search(nums []int, target int) int {
high := len(nums) //由于右开,取不到最右边的数,所以这里不用-1也不会超限
low := 0
for low < high { //类似于[1,1)这样的区间是没有意义的
mid := low + (high-low)/2 //同样防止溢出
if nums[mid] == target {
return mid
} else if nums[mid] > target {
high = mid //右开,不需要舍弃右边值
} else {
low = mid + 1 //左开,当前值不符合,抛弃当前值
}
}
return -1
}
704 学习 完整代码如下:
package main
import (
"fmt"
)
func main() {
nums := []int{-1, 0, 3, 5, 9, 12}
n := search(nums, 8)
fmt.Println(n)
}
//赖子玩法,使用hashmap进行解决
/*func search(nums []int, target int) int {
Abook := map[int]int{}
for i, num := range nums {
Abook[num] = i
}
number, ok := Abook[target]
if ok {
return number
}
return -1
}
*/
// 使用二分查找进行查询 个人版本,对区间的定义理解不够
// 因此需要额外定义多种情况
/*func search(nums []int, target int) int {
left, right := 0, len(nums)-1
//如果该目标值直接大于或者小于nums中所有数,直接返回-1
if target > nums[right] || target < nums[left] {
return -1
}
//为了避免与后面查询不到的情况避开,我们这里直接设定两个值时的情况
if nums[0] == target {
return 0
}
if nums[right] == target {
return right
}
for {
mid := (left + right) / 2 //偶数为中间往前一个数 ; 奇数即为中间数
//如果寻找到目标值。返回
if nums[mid] == target {
return mid
}
//如果没有查询到目标值
if math.Abs(float64(left-right)) == 1 {
return -1
}
if nums[mid] < target { //目标大于中间值,往后查找
left = mid
} else { //nums[mid] > target//目标小于中间值,往前查询
right = mid
}
}
}*/
// 学习版本二分查找 闭区间
/*func search(nums []int, target int) int {
high := len(nums) - 1
low := 0
for low <= high { //在闭区间中如[1,1]是有意义的
mid := low + (high-low)/2 //这样定义防止数字太大溢出
if nums[mid] == target {
return mid
} else if nums[mid] > target { //缩小target所在的区间,由于为闭区间,可以舍弃上次的边界值
high = mid - 1
} else {
low = mid + 1
}
}
return -1
}*/
// 左闭右开区间版本
func search(nums []int, target int) int {
high := len(nums) //由于右开,取不到最右边的数,所以这里不用-1也不会超限
low := 0
for low < high { //类似于[1,1)这样的区间是没有意义的
mid := low + (high-low)/2 //同样防止溢出
if nums[mid] == target {
return mid
} else if nums[mid] > target {
high = mid //右开,不需要舍弃右边值
} else {
low = mid + 1 //左开,当前值不符合,抛弃当前值
}
}
return -1
}