题目:
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7]
might become [4,5,6,7,0,1,2]
).
You are given a target value to search. If found in the array return its index, otherwise return -1
.
You may assume no duplicate exists in the array.
Your algorithm's runtime complexity must be in the order of O(log n).
Example 1:
Input: nums = [4,5,6,7,0,1,2]
, target = 0
Output: 4
Example 2:
Input: nums = [4,5,6,7,0,1,2]
, target = 3
Output: -1
描述:
在一个由升序数组循环左移未知单位所形成的数组中查找目标值,要求算法的复杂度为log ( n )
分析:
如果没有循环移动的操作,那么只需要使用二分搜索既能解决问题,
但是目前的数组并非整体有序,而是部分有序,而题目给出的复杂度,不难想象出,还是要采用二分的方法,但是需要对原始的二分进行修改,具体的策略见下面分析:
由于所给的数组是经过翻转之后的结果,可知,有序段最多有两个,而且关键是,某个段的所有值均大于另一个段的所有值,不妨命名为较大段和较小段,具体步骤如下:
若中间值等于目标值,则返回查找成功的下标
如果中间值小于目标值,则分两种情况:
1,中间值所在的有序段是较大段,则只需要在右半侧寻找
2,中间值所在的有序段是较小段,则需要再分情况讨论
1)若目标值小于较小段的最大值,则只需要在右半侧寻找
2)若目标值大于较小段的最大值,则只需要在左半侧寻找
如果中间值大于目标值,也分两种情况:
1,中间值所在的有序段是较大段,则需要分两种情况:
1)如果目标值不大于较大段的最小值,则只需要在左半段寻找
2)如果目标值大于较大段的最小值,则只需要在右半段寻找
2,中间值所在的有序段是较小段,则只需要在左半段寻找
对于以上情况不够清楚的,可以尝试画图理解。
提供一部分样例,边界比较难控制
[3,1]
1
[3,1]
3
[4,5,6,7,8,1,2,3]
8
[5,1,3]
5
[5,1,3]
1
[5,1,3]
3
[4,5,6,7,0,1,2]
4
[]
1
[1]
1
[1]
2
[4,5,6,7,0,1,2]
4
[4,5,6,7,0,1,2]
5
[4,5,6,7,0,1,2]
6
[4,5,6,7,0,1,2]
7
[4,5,6,7,0,1,2]
0
[4,5,6,7,0,1,2]
1
[4,5,6,7,0,1,2]
2
[4,5,6,7,0,1,2]
3
[4,5,6,7,0,1,2]
8
代码:
class Solution {
public:
int search(vector<int>& nums, int target) {
if (!nums.size()) {
return -1;
}
int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = (left + right) >> 1;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
if (nums[left] <= nums[mid]) {
left = mid + 1;
} else {
if (target == nums[right]) {
return right;
} else if (target < nums[right]) {
left = mid +1;
} else {
right = mid - 1;
}
}
} else {
if (nums[left] <= nums[mid]) {
if (target == nums[left]) {
return left;
} else if (nums[left] < target) {
right = mid - 1;
} else {
left = mid + 1;
}
} else {
right = mid - 1;
}
}
}
return -1;
}
};