leetcode hot100 之 搜索旋转排序数组

题目

给定一个旋转过的升序数组,如 [1, 2, 3, 4, 5] 经过旋转后变成 [3, 4, 5, 1, 2],数组中每个数字都不重复。并给定一个 target 数字,请找出其在数组当中相应的下标,如果没有则返回 -1.

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

原题链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/

思路

升序数组的查找,可以通过二分法。只不过这道题里是旋转过的升序数组,需要特殊处理一下。首先,可以把旋转的升序数组看成两段:左半段升序数组和右半段升序数组,数组中的数字都不重复,保证了单调性。且左半段的左端点(记为 left)大于右半段的右端点(记为 right)。通过判断数字和左右端点的大小关系,可以知道某个数字在左半段还是右半段。
二分过程中,我们又可以把数组重新分成两段,一段是单调递增的,另一段是非单调或单调的。
如果 mid 在左半段,则 [left, mid) 是单调递增区间,(mid, right] 是非单调或单调的。
如果 mid 在右半段,则 (mid, right] 是单调递增区间,[left, mid) 是非单调或单调的。
利用单调性,我们进一步判断 target 和 nums[mid] 的关系,如果 mid 在左半段,且 target 在 [left, mid) 区间,则在 [left, mid) 中进一步搜索,反之则在 (mid, right] 搜索。
同理,如果 mid 在右半段,且 target 在 (mid, right] 区间,则在 (mid, right]中进一步搜索,反之则在 [left, mid) 搜索。

当数组整体变成单调递增的一段时,二分时,依然满足把数组重新分成两段,一段是单调递增的,另一段是非单调或单调的条件。所以无需特殊处理。

  • 复杂度分析
    • 时间复杂度 O(logn)
    • 空间复杂度 O(1)

代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int result = -1;
        if (nums.size() == 1) {
            if (target == nums[0]) {
                result = 0;
            }
            return result;
        }
        int left = 0;
        int right = nums.size() - 1;
        while (left <= right) {
            int mid = (right - left) * 0.5 + left;
            if (target == nums[mid]) {
                result = mid;
                break;
            }
            else if (nums[mid] >= nums[left]) {
                if (target >= nums[left] && target < nums[mid]) {
                    right = mid - 1;
                }
                else {
                    left = mid + 1;
                }
            }
            else {
                if (target <= nums[right] && target > nums[mid]) {
                    left = mid + 1;
                }
                else {
                    right = mid - 1;
                }
            }
        }
        return result;
    }
};

你可能感兴趣的:(LeetCode,leetcode,算法,排序算法)