LeetCode 33 Search in Rotated Sorted Array 题解

题意简述:给定一个按升序排序的数组,这个数组进行了数次旋转(例如数组[0,1,2,4,5,6,7]在2和4之间执行一次旋转就会变成[4,5,6,7,0,1,2]。需要搜索某个数是否在这个数组里面。数组里面没有重复元素。
输入:数组nums,要搜索的值target
输出:如果target在nums里面,那么返回它在数组里面的位置下标;否则返回-1。
示例:对于nums=[4,5,6,7,0,1,2],target=5,应该返回5在nums中的下标1。


题解:
首先无论进行多少次旋转,数组最后只可能是两种状态:

  1. 跟原升序数组一致。
  2. 数组有一个断点,被划分为两段升序。

这是因为进行当前的旋转时,如果选择的断点跟上一次不一样,因上一次旋转而产生的两段升序又会连在一起变成一段升序。举个例子:对于数组[1,2,3,4,5],在2、3之间旋转会变成[3,4,5,1,2],断开的2和3在数组的首尾,下次在4、5之间旋转时,首尾的2和3又连在一起了([5,1,2,3,4])。如果选择的断点跟上一次一样,那就相当于撤销了上一次的旋转。

既然只有两种情况,那么我们只需加入分类讨论,就可以像排序数组一样使用二分搜索。存在断点的情况下,数更大的一段必定在数更小的一段的前面,所以考虑首尾两个值以及中间的值nums[low]、nums[up]、nums[mid](mid=(low+up)/2):

  1. 如果nums[low] < nums[mid],则数组的前半段就是升序的,直接在该段调用二分搜索;
  2. 如果nums[low] > nums[mid],则数组的前半段存在断点,无法直接调用二分搜索,因此递归调用函数在这半段继续以上的判断。
  3. 对数组的后半段的讨论跟以上两点类似。
  4. 只有在前半和后半都找不到target时才返回-1。

算法实现如下:

class Solution {
private:
    int binarySearch(vector<int>& nums,int low, int up, int target) {
        int mid, tempup = up;
        low--;up++;

        while(low + 1 != up) {
            mid = low + (up - low) / 2;

            if(nums[mid] < target) low = mid;
            else up = mid;
        }

        if(up > tempup || nums[up] != target) return -1;
        else return up;
    }

    int recur(vector<int>& nums,int low, int up, int target) {
        if(low == up) {
            if(nums[low] == target) return low;
            else return -1;
        } 

        int mid = low + (up - low) / 2;
        int resl, resr;

        if(nums[low] < nums[mid]) resl = binarySearch(nums, low, mid, target);
        else resl = recur(nums, low, mid, target);
        if(nums[up] > nums[mid]) resr = binarySearch(nums, mid+1, up, target);
        else resr = recur(nums, mid+1, up, target);

        if(resl != -1) return resl;
        else return resr;
    }
public:
    int search(vector<int>& nums, int target) {
        if(nums.size() == 0) return -1;
        return recur(nums, 0, nums.size()-1, target);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值