0033 搜索旋转排序数组
算法思路
考虑到题目要求要求以 \(O(\log n)\) 的时间复杂度在数组中找到特定元素。同时,题目给出的数组本质上是有序的,相当于一个不重复的递增数组,在某一位置进行了切割并重新拼起来。
根据以上信息,显然考虑使用二分查找。关键在于如何进行二分查找,这道题我想到的方法是查找两次:由于数组的特性,我们可以先通过第一次二分查找获得数组的最大值及其索引。 随后,根据最大值索引将数组视作两个不相交的递增数组,并进行第二次二分查找获得题目所求。
代码实现
search-in-rotated-sorted-array.c
int getMax(int* nums, int left, int right, int a) {
if (left == right) {
return left;
} else if (left + 1 == right) {
return nums[left] > nums[right] ? left : right;
}
int mid = nums[(left + right) / 2];
if (mid > a) {
return getMax(nums, (left + right) / 2, right, a);
} else {
return getMax(nums, left, (left + right) / 2, a);
}
}
int getIndex(int* nums, int left, int right, int target) {
if (left >= right && nums[right] != target) {
return -1;
}
int mid = nums[(left + right) / 2];
if (mid > target) {
return getIndex(nums, left, (left + right) / 2 - 1, target);
} else if (mid < target) {
return getIndex(nums, (left + right) / 2 + 1, right, target);
} else {
return (left + right) / 2;
}
}
int search(int* nums, int numsSize, int target) {
int a = nums[0];
if (target == a)
return 0;
int maxIndex = getMax(nums, 0, numsSize - 1, a);
if (target > a) {
return getIndex(nums, 1, maxIndex, target);
} else {
return getIndex(nums, maxIndex + 1, numsSize - 1, target);
}
}
- 易错:对于第二次二分查找
getIndex函数,由于target不一定存在,需要进行if (left >= right && nums[right] != target)判断。并且由于left >= right,应使用right作为数组下标避免越界。
UPDATE
阅读题解后,不免感叹自身实力欠缺,竟然绕了一个大弯去解决此题。可能是“将未知问题转化为已知问题”的想法过于强烈,以至于我采用了两次二分查找去解决此问题,试图将数组变成最令人舒适的简单递增数组。
但实际上,一次二分查找即可无痛解决问题。因为我们将数组拆分为两部分后,必然至少有一边是有序的。而在不断递归二分查找的过程中,必然存在一次拆分,使得我们的目标值出现在有序数组的取值区间中。以上,即说明了一次二分查找便可解决问题。
search-in-rotated-sorted-array.c
int search(int* nums, int numsSize, int target) {
int n = numsSize;
if (n == 0) {
return -1;
}
if (n == 1) {
return nums[0] == target ? 0 : -1;
}
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
if (nums[0] <= nums[mid]) {
if (nums[0] <= target && target < nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[n - 1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return -1;
}