小技巧
计算中间值(防止溢出)
mid = low + (high - low) / 2
向上取整
10 / 5 = 2
12 / 5 = 3
res = (a - 1)/b + 1
dfs
适用于路径探索。
使用vis数组的条件是,存在不同路径汇聚的情况,避免一个节点被访问多次。
在调用dfs函数之前,重置路径,路径上加入起点。
bfs
适用于连通性测试。
代码模板(包含四个变量)
func bfs() {
// 首节点设置成已访问
var vis [110]bool
vis[1] = true
// 首节点入队列
var que [110]int
que[0] = 1
// 设置开始的下标和队列元素数量
beginIndex := 0
beginCount := 1
// 只要队列还有元素就一直迭代
for beginCount > 0 {
// 新添加的元素数量入队列的开始下标
nextIndex := beginIndex + beginCount
// 新添加的元素数量,即下一层元素数量
nextCount := 0
for i := 0; i < beginCount; i++ {
index := que[i + beginIndex]
...
if childCount == 0 {
...
} else {
for j := 0; j < childCount; j++ {
next := childList[index][j]
if !vis[next] {
vis[next] = true
// 新元素入队列
que[nextIndex] = next
nextIndex++
nextCount++
}
}
}
}
// 更新队列元素数量和开始的下标
beginIndex += beginCount
beginCount = nextCount
}
}
二分查找
函数binarySearch表示传统的二分查找,没有找到时返回-1。
函数lowerBound表示寻找第一个值>=目标值对应的下标,没有找到时返回长度。
函数upperBound表示寻找第一个值>目标值对应的下标,没有找到时返回长度。
package main
import "fmt"
func binarySearch(nums []int, goal int) int {
low := 0
high := len(nums) - 1
for low <= high {
mid := low + (high - low) / 2
if nums[mid] == goal {
return mid
} else if nums[mid] > goal {
high = mid - 1
} else {
low = mid + 1
}
}
return -1
}
func lowerBound(nums []int, goal int) int {
low := 0
high := len(nums)
for low < high {
mid := low + (high - low) / 2
if nums[mid] >= goal {
high = mid
} else {
low = mid + 1
}
}
return high
}
func upperBound(nums []int, goal int) int {
low := 0
high := len(nums)
for low < high {
mid := low + (high - low) / 2
if nums[mid] > goal {
high = mid
} else {
low = mid + 1
}
}
return high
}
func main() {
nums := []int{1, 3, 5, 7, 8, 9}
fmt.Println(binarySearch(nums, 8)) // 4
fmt.Println(lowerBound(nums, 1)) // 0
fmt.Println(upperBound(nums, 6)) // 3
}