📅  最后修改于: 2023-12-03 15:29:43.103000             🧑  作者: Mango
在一个有序数组里面,我们可以通过二分查找(O(log n))来查找一个元素。但是如果这个数组旋转了k次,那么怎么样在O(log n)的时间复杂度内查找一个元素就是今天的主题。
我们假设原来有一个有序数组 a
,旋转之后变成了一个有序的循环数组 b
,如下图所示。通过观察很容易发现如果我们把循环数组拉成一条直线,那么和原来的有序数组是一样的。因此在这个问题中,我们可以把循环数组拉成一条直线来处理,最后得到在拉成直线后的有序数组中元素的索引。
我们要在这样的一个循环数组中查找某个元素。
由于我们不能简单地使用原来的二分查找,因为有了旋转的操作,因此我们可以先手动地模拟旋转的过程,得到旋转后的有序数组 b
。
接着我们可以使用二分查找(O(log n))的方法,在旋转数组 b
中找到元素。这个过程同一般的二分查找是类似的,由于数组是被旋转的,因此左右两个端点的位置可能会有变化。我们需要根据数组的情况来决定取左区间还是右区间进行递归查找。
具体实现方法可以查看下方的代码片段。
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = nums.size();
if (n == 0) return -1;
int lo = 0, hi = n - 1;
while (lo < hi) {
int mid = (lo + hi) / 2;
if (nums[mid] == target) return mid;
if (nums[lo] <= nums[mid]) {
if (nums[lo] <= target && target <= nums[mid])
hi = mid - 1;
else
lo = mid + 1;
}
else {
if (nums[mid] < target && target <= nums[hi])
lo = mid + 1;
else
hi = mid - 1;
}
}
return nums[lo] == target ? lo : -1;
}
};
在算法的实现过程中,由于有旋转的操作,因此我们需要判断每个递归的区间的情况,来决定我们应该是寻找左区间还是右区间。只有这样我们才能将时间复杂度降低至O(log n)。