Search in Rotated Sorted Array

406 篇文章 0 订阅
406 篇文章 0 订阅

1,题目要求

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,1,2,4,5,6,7]might become [4,5,6,7,0,1,2]).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Your algorithm’s runtime complexity must be in the order ofO(log n).

Example 1:
Input: nums = [4,5,6,7,0,1,2],target = 0
Output: 4

Example 2:
Input:nums = [4,5,6,7,0,1,2], target = 3
Output: -1

假设按升序排序的数组在事先未知的某个枢轴处旋转。

您将获得要搜索的目标值。 如果在数组中找到则返回其索引,否则返回-1。

您可以假设数组中不存在重复。

算法的运行时复杂度必须是O(log n)的顺序。

2,题目思路

对于这道题,是找到一个经过旋转的有序数组内查找给定元素。

对于元素查找,一定可以在O(n)的时间内完成查找。但是题目要求在O(logn)的时间内完成,如果是二分查找,而自然是可以的。

但是,二分查找有要求,即数组一定是有序的

题目中给出的数组是经过旋转的数组,详见题目:
189. Rotate Array

对这种类型的数组而言,我们经过分析可以得到,它其实是由两个有序的数组所组成的。如果我们能够找到二者的分界位置,自然就可以使用二分查找的办法来查找元素了。

其中,对于这个分界位置的查找,因为都是部分有序的,基于时间复杂度的考量,我们还是会使用二分的策略来实现。

总体说来,问题的实现步骤为:

  • 利用二分查找找到数组中的最小的元素,即两个有序数组的分界位置。
  • 根据分界位置的下标,找到偏移量,基于偏移量再次使用二分查找,对target进行查找。

3,代码实现

int x = []() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    return 0;
}();


class Solution {
public:
    int search(vector<int>& nums, int target) {
        //利用二分策略,找到nums中最小的元素的下标
        //即两个有序序列的中间分界处
        //这里需要注意的是,之所以不是low<=high然后high=mid-1,
        //是因为我们需要找的是最小的那个,也就是后半部分的开头
        //最后搜索肯定会落在[max, min, min+1,...min+k]内,
        //且low = max.index, high = (min+k).index
        //而整数除法的特性是取整,因此,如果按照普通二分的策略
        //最后因为high-1和low<=high,肯定会落到max.index上,这不是我们想要的
        //使用下面的判断标准,我们最后会有:[max,min]的序列
        //之后,根据mid的计算,以及条件判断,可以得low = mid+1
        //即最后low所表示的下表就是我们想要求得下标
        int n = nums.size();
        if(n == 0)
            return -1;
        int low = 0, high = n-1;
        while(low < high){
            int mid = low + (high - low)/2;
            if(nums[mid] > nums[high])
                low = mid+1;
            else
                high = mid;
        }
        
        //利用取余的方法,获得原数组在有序状态下的真正中心点
        //省去对原数组分块查找或者重排的烦恼
        int rotateIndex = low;
        low = 0, high = n-1;
        while(low <= high){
            int mid = low + (high - low)/2;
            int realMid = (mid + rotateIndex)%n;
            if(nums[realMid] == target)
                return realMid;
            else if(nums[realMid] < target)
                low = mid+1;
            else
                high = mid-1;
        }
        return -1;       
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值