33 搜索旋转排序数组-中等
题目:
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
解题思路
通过第一个元素来判断从前半段查找,还是从后半段查找;并且在查找过程中注意翻转的点,一旦到达直接终止查找。
这种算法可以达到O(N)的查找。
解法二
对于有序数组,我们可用二分查找来查找元素。如果数组是局部有序,就像题目中一样,那么还适用二分查找吗?答案,可以的。
对于一个前半部分和后半部分各自有序的一个数组,用二分查找从中间分开整个数组,那么一定有一部分是有序的。
如果[left, mid]
有序,与此同时,如果目标值在这个区间,那么继续二分查找;如果不在这个区间,说明目标值在另一半序列,也可以更新二分查找区间。
否则,就是[mid+1, right]
有序。
// date 2023/11/02
// 解法1 O(N)
func search(nums []int, target int) int {
res := -1
s := len(nums)
if s == 0 {
return res
}
if nums[0] <= target {
i := 0
for i < s {
if nums[i] == target {
res = i
break
}
if i + 1 < s && nums[i+1] < nums[i] {
break
}
i++
}
} else {
i := s-1
for i >= 0 {
if nums[i] == target {
res = i
break
}
if i > 0 && nums[i-1] > nums[i] {
break
}
i--
}
}
return res
}
// 解法2 二分查找
// O(logN)
func search(nums []int, target int) int {
res := -1
left, right := 0, len(nums)-1
// 每个都需要判断到,所以需要 =
for left <= right {
mid := left + (right-left)/2
if nums[mid] == target {
return mid
}
// 前半段有序
if nums[left] <= nums[mid] {
if nums[left] <= target && target < nums[mid] {
right = mid - 1 // search [left, mid-1]
} else {
left = mid + 1 // search [mid+1, right]
}
} else {
// 后半段有序
if nums[mid] < target && target <= nums[right] {
left = mid + 1 // search [mid+1, right]
} else {
right = mid - 1 // search [left, mid-1]
}
}
}
return res
}
最后更新于