📌  相关文章
📜  C ++程序在经过多次旋转后在给定索引处查找元素(1)

📅  最后修改于: 2023-12-03 15:29:43.103000             🧑  作者: Mango

C++程序在经过多次旋转后在给定索引处查找元素

在一个有序数组里面,我们可以通过二分查找(O(log n))来查找一个元素。但是如果这个数组旋转了k次,那么怎么样在O(log n)的时间复杂度内查找一个元素就是今天的主题。

问题分析

我们假设原来有一个有序数组 a,旋转之后变成了一个有序的循环数组 b,如下图所示。通过观察很容易发现如果我们把循环数组拉成一条直线,那么和原来的有序数组是一样的。因此在这个问题中,我们可以把循环数组拉成一条直线来处理,最后得到在拉成直线后的有序数组中元素的索引。

rotation

我们要在这样的一个循环数组中查找某个元素。

算法分析

由于我们不能简单地使用原来的二分查找,因为有了旋转的操作,因此我们可以先手动地模拟旋转的过程,得到旋转后的有序数组 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)。