33. 搜索旋转排序数组

题目描述

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。

搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。

你可以假设数组中不存在重复的元素。你的算法时间复杂度必须是 O(logn) 级别。

示例 1:

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

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

思路

由题目要求的时间复杂度为o(logn),我们可以想到二分查找,但题目中的数组,不是传统的二分查找数组递增类型,所以,在设计二分查找跳转策略的时候,需要根据数组的特点,进行设计,至于这种跳转的合理性,可以根据实例进行观察,以及反证法进行证明

第一种方法

首先对要查找的区间分情况对待(已经有序了,还是包含两个局部有序的子片段).

代码

class Solution {
public:
    int search(int A[], int n, int target) {

    	int l = 0;
    	int r = n-1;
    	while(l <= r)
    	{
    		int mid = l+(r-l)/2;
    		if(A[mid] == target)
    			return mid;
            //这个条件判断说明要查找的区间已经是一段单独的递增区间了
            //可以直接使用传统的二分查找
            if(A[l] <= A[r])
            {
            	if(A[mid]>target)
            		r=mid-1;
            	else if(A[mid]<target)
            		l=mid+1;
            }
            else
            {//到这一步骤时说明要查找的范围包括两段递增的区间
                //这个条件判断说明mid在第一段递增区间
            	if(A[mid]>=A[l])
            	{
            		if(A[l]<=target && target<A[mid])
            			r = mid-1;
            		else
            			l=mid+1;//排除掉

            	}
                else//说明mid在第二段递增区间
                {
                	if(A[mid]<target && target<=A[r])
                		l = mid+1;
                	else
                		r=mid-1;//排除掉
                }


            }

    	}

    	return -1;
        
    }
};

第二种方法

如果查找的范围包含两段递增区间,mid会将之分为一半递增,一半没有单调性,如果查找的范围已经为一段递增区间,mid会将之分为两半都是递增的,故不管哪种情况,mid会将之分成的两半中至少一半是递增的,如果我们能排除目标值不在这一半递增区间中,那我们就可以转换到另一半中查找了
要点:由实例观察总结出规律,进而落实到代码实现上
其实这种方法还是先判断mid落在两个有序子序列的哪一个上,落在第一个上,则[l,mid]有序递增;落在第二个上,则[mid,r]单调递增;

代码

class Solution {
public:
    int search(vector<int>& nums, int target) {
        
        int n = nums.size();
        int l = 0;
        int r = n-1;
        while(l <= r)
        {
            int mid = l+(r-l)/2;
            if(nums[mid] == target)
                return mid;
            //首先判断前半段是否是单调的,如果前半段不单调,那么后半段一定单调
            if(nums[l] <= nums[mid])
            {
                if(nums[l] <= target && target < nums[mid])
                    r = mid - 1;
                else//排除掉
                    l = mid + 1;
            }
            else
            {
                if(nums[mid] < target && target <= nums[r])
                    l = mid + 1;
                else//排除掉
                    r = mid - 1;
            }
        }
        return -1;
    }
};

posted on 2021-05-01 15:35  朴素贝叶斯  阅读(35)  评论(0编辑  收藏  举报

导航