Golang 二分查找 LEETCODE704 小记

二分查找 leetcode704

前面部分第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
}

你可能感兴趣的:(golang,开发语言,后端,leetcode,算法)