概述
我们有一个已排序的输入数组,但在某一索引处被枢轴化。例如,考虑以下数组
[1, 3, 5, 7, 9]
它在索引3处被旋转和枢轴化了。
[5, 7, 9, 1, 3]
给定一个目标元素,目标是在**O(logn)**时间内找到该排序和旋转的数组中目标元素的索引。如果目标元素在给定的数组中不存在,它应该返回-1。
例如
Input: [5, 7, 9, 1, 3]
Target Element: 7
Output: 2
Input: [5, 7, 9, 1, 3]
Target Element: 8
Output: -1
以下是策略
-
在给定的输入数组中使用二进制搜索,并进行一些修改,找到枢纽索引
-
如果目标元素小于数组的起始元素,那么从枢轴端到数组的末端进行二进制搜索
-
如果目标元素大于数组的起始元素,则从起始点到支点-1索引进行二进制搜索。
以下是寻找支点索引的策略
-
做一个二进制搜索。对于每一个mid元素,检查mid或mid+1 是否是支点
-
如果mid的值小于输入数组开始时的值,则在mid的左边进行搜索
-
如果mid的值大于输入数组的起始值,则在mid的右边搜索。
程序
以下是相同的程序。
package main
import "fmt"
func main() {
output := search([]int{4, 5, 6, 7, 0, 1, 2}, 0)
fmt.Println(output)
output = search([]int{4, 5, 6, 7, 0, 1, 2}, 1)
fmt.Println(output)
output = search([]int{4, 5, 6, 7, 0, 1, 2}, 2)
fmt.Println(output)
output = search([]int{4, 5, 6, 7, 0, 1, 2}, 4)
fmt.Println(output)
output = search([]int{4, 5, 6, 7, 0, 1, 2}, 5)
fmt.Println(output)
output = search([]int{4, 5, 6, 7, 0, 1, 2}, 6)
fmt.Println(output)
output = search([]int{4, 5, 6, 7, 0, 1, 2}, 7)
fmt.Println(output)
output = search([]int{4, 5, 6, 7, 0, 1, 2}, 3)
fmt.Println(output)
output = search([]int{1, 2}, 3)
fmt.Println(output)
}
func search(nums []int, target int) int {
pivot := findPivot(nums)
if pivot == -1 {
return binarySearch(nums, 0, len(nums)-1, target)
}
if target < nums[0] {
return binarySearch(nums, pivot, len(nums)-1, target)
}
return binarySearch(nums, 0, pivot-1, target)
}
func findPivot(nums []int) int {
return findPivotUtil(nums, 0, len(nums)-1)
}
func findPivotUtil(nums []int, start, end int) int {
if start > end {
return -1
}
mid := (start + end) / 2
if mid+1 <= end && nums[mid] > nums[mid+1] {
return mid + 1
}
if mid-1 >= start && nums[mid] < nums[mid-1] {
return mid
}
if nums[mid] < nums[start] {
return findPivotUtil(nums, start, mid-1)
}
return findPivotUtil(nums, mid+1, end)
}
func binarySearch(nums []int, start, end, target int) int {
if start > end {
return -1
}
mid := (start + end) / 2
if nums[mid] == target {
return mid
}
if target < nums[mid] {
return binarySearch(nums, start, mid-1, target)
} else {
return binarySearch(nums, mid+1, end, target)
}
}
输出
4
5
6
0
1
2
3
-1
-1