LeetCode33-搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
一、思路
(一)从两边的指针考虑
原来已经排好序的数组可以使用二分查找,使得时间复杂度为 O ( l o g ( n ) ) O(log(n)) O(log(n)),现在在未知处发生了旋转,这个数组可以看成两个升序的数组,假设旋转之前的数组为A,旋转后的数组为B,可以视为两个有序数组C和D的组合。
根据旋转的性质,很明的一点是:
C
[
0
]
>
D
[
l
e
n
[
D
]
]
C[0]>D[len[D]]
C[0]>D[len[D]],即
B
[
0
]
>
B
[
l
e
n
[
B
]
]
B[0]>B[len[B]]
B[0]>B[len[B]]
可以看成是在两个有序无重复的数组中查找val,据此分为以下六类情况:
C++代码:
class Solution {
public:
int search(vector<int>& nums, int target) {
if (nums.empty())
return -1;
int i = 0, j = nums.size() - 1, m, n;
int middle0 = nums[i], middlen = nums[j];
if (target > nums[j] && target < nums[i])
return -1;
if (target == nums[i])
return i;
if (target == nums[j])
return j;
if (target > nums[i]) // 确定可能在数组C
{
while (i < j) {
m = (i + j) / 2;
if(m == i)
break;
if (nums[m] == target)
return m;
if (nums[m] > target) // target可能在i,m之间
j = m;
else {
if (nums[m] > nums[i])
i = m;
else
j = m;
}
}
}
else { // 确定可能在数组D
while (i < j) {
m = (i + j) / 2;
if(m == i)
break;
if (nums[m] == target)
return m;
if (nums[m] < target) // target可能在m,j之间
i = m;
else {
if (nums[m] < nums[j])
j = m;
else
i = m;
}
}
}
return -1;
}
};
执行效率:
(二)从target的位置开始考虑
我们知道target一定在两个数组中的一个,那么可以通过确定target的位置,来决定两边指针的移动方向。
设两个指针为lo与hi,中间的指针为mid
将数组划分为两个前一个大的数组为nums1,后一个小的数组为nums2
(1)假设target在nums1中
那么必然有: n u m s [ h i ] < t a r g e t nums[hi]<target nums[hi]<target
(2)假设target在nums2中
那么必然有: n u m s [ l o ] > t a r g e t nums[lo]>target nums[lo]>target
C++代码:
class Solution {
public:
int search(vector<int>& nums, int target) {
if (nums.empty())
return -1;
int lo = 0, hi = nums.size() - 1;
int mid;
while (lo <= hi) {
mid = lo + ((hi - lo) >> 1);
if (nums[mid] == target)
return mid;
if (nums[lo] == target)
return lo;
if (nums[hi] == target)
return hi;
// 在前一个数组的情况
if (target >= nums[lo] && target < nums[mid])
hi = mid - 1;
else if (target > nums[lo] && target > nums[mid] && nums[mid] >= nums[lo])
lo = mid + 1;
else if (target > nums[lo] && target > nums[mid] && nums[mid] <= nums[lo])
hi = mid - 1;
// 在后一个数组的情况
else if (target < nums[hi] && nums[mid] >= nums[lo])
lo = mid + 1;
else if (target < nums[hi] && nums[mid] <= nums[lo] && nums[mid] > target)
hi = mid - 1;
else if (target < nums[hi] && nums[mid] <= nums[lo] && nums[mid] < target)
lo = mid + 1;
else
return -1;
}
return -1;
}
};
执行效率: