二分查找变种
查找第一个等于给定值的元素。 查找最后一个等于给定值的元素。 查找第一个大于等于给定值的元素。 查找最后一个小于等于给定制的元素。
代码实现
package main
import "fmt"
// 递归实现
func BinarySearchRecursive(arr []int, item int) int {
n := len(arr)
if n < 1 {
return -1
}
return BinarySearchCore(arr, 0, n-1, item)
}
func BinarySearchCore(arr []int, start, end, item int) int {
if start > end {
return -1
}
mid := (start + end) / 2
if item < arr[mid] {
end = mid - 1
} else if item > arr[mid] {
start = mid + 1
} else {
return mid
}
return BinarySearchCore(arr, start, end, item)
}
// 非递归实现
func BinarySearch(arr []int, item int) int {
n := len(arr)
if n < 1 {
return -1
}
start := 0
end := n - 1
for start <= end {
mid := (start + end) / 2
if item < arr[mid] {
end = mid - 1
} else if item > arr[mid] {
start = mid + 1
} else {
return mid
}
}
return -1
}
// 查找等于指定值的最后个数
func BinarySearchLast(arr []int, item int) int {
n := len(arr)
if n < 1 {
return -1
}
start := 0
end := n - 1
for start <= end {
mid := (start + end) / 2
if item < arr[mid] {
end = mid - 1
} else if item > arr[mid] {
start = mid + 1
} else {
if mid == n-1 || arr[mid+1] != item {
return mid
} else {
start = mid + 1
}
}
}
return -1
}
// 查找等于指定值的第一个数
func BinarySearchFirst(arr []int, item int) int {
n := len(arr)
if n < 1 {
return -1
}
start := 0
end := n - 1
for start <= end {
mid := start + ((end - start) >> 2)
if item < arr[mid] {
end = mid - 1
} else if item > arr[mid] {
start = mid + 1
} else {
if mid == 0 || arr[mid-1] != item {
return mid
} else {
end = mid - 1
}
}
}
return -1
}
// 查找第一个大于等于给定值元素
func BinarySearchGtFirst(arr []int, item int) int {
n := len(arr)
if n < 1 {
return -1
}
start := 0
end := n - 1
for start <= end {
mid := start + ((end - start) >> 2)
if arr[mid] >= item {
if mid == 0 || arr[mid-1] < item {
return mid
} else {
end = mid - 1
}
} else if arr[mid] < item {
start = mid + 1
}
}
return -1
}
// 查找最后一个小于等于给定值元素
func BinarySearchLtLast(arr []int, item int) int {
n := len(arr)
if n < 1 {
return -1
}
start := 0
end := n - 1
for start <= end {
mid := start + ((end - start) >> 2)
if arr[mid] > item {
end = mid - 1
} else if arr[mid] <= item {
if mid == n-1 || arr[mid+1] > item {
return mid
} else {
start = mid + 1
}
}
}
return -1
}
func main() {
//arr := []int{0,1,2,3,4,5,7,8,9}
//m := BinarySearchRecursive(arr, 3)
//fmt.Println(m)
//i := BinarySearch(arr, 3)
//fmt.Println(i)
arr := []int{0, 1, 3, 3, 3, 4, 5, 7, 8, 9}
first := BinarySearchFirst(arr, 3)
fmt.Println(first)
last := BinarySearchLast(arr, 3)
fmt.Println(last)
gtFirst := BinarySearchGtFirst(arr, 6)
fmt.Println(gtFirst)
ltLast := BinarySearchLtLast(arr, 6)
fmt.Println(ltLast)
}
说明
凡是用二分查找能解决的,我们更倾向于散列表或者二分查找树来解决,即使二分查找在内存使用上更加节省。 实际开发中,二分查找“类似”的问题,更加便捷,如本篇的四种变形问题。