Follow up for "Search in Rotated Sorted Array":
What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

Write a function to determine if a given target is in the array.


解法

本题可以依照 Search in Rotated Sorted Array方法来,不过需要注意nums[left]==nums[right]不在代表两者指向同一元素这一种情况,而且包含是nums[left]==nums[mid],如121111,导致无法判断mid哪边是排好序的,即无法知道转折点在哪里


这时,如果nums[right]也等于nums[mid],仅仅需要将left+=1,right-=1即可,因为target肯定还在left和right内,

其他情况按照Search in Rotated Sorted Array方法来;

left=0,right=size-1;mid=left+(right-left)/2   这里最好这样写,right+left 可能溢出

  1. nums[mid]==target  return mid

  2. 如果nums[left]==nums[mid]==nums[right]   left++,right--;

  3. nums[left]<=nums[mid]  这里存在等于号是因为left和mid 可能是同一个下标,这种情况,转折点在mid右边,可能包含mid

    a)如果nums[left]<=target&&target<nums[mid]  则right=mid-1  ,这种情况,说明target在A中,

    b)不满足a,则说明target在mid的右边,left=mid+1

  4. nums[left]>nums[mid]  这种情况下,转折点在mid的左边,

    a)如果nums[mid]<target&&nums[right]>=target  则left=mid+1;这种情况,说明target在B中或者,B为空,A为升序,(mid,right]里,

    b)不满足a,则说明target在mid的左边,自然right=mid-1


步骤3能这样处理,是因为,如果nums[left]<=nums[mid],且nums[right]!=nums[mid],假设转折点不是在mid右边,则说明mid左边有个转折点,left和mid直接的Pos指向的元素为最大值,left-》pos递增,pos+1->right 递增,则right指向元素需大于mid指向,而且,小于left指向,即指向元素大小,rigt《mid《left,而由nums[left]<=nums[mid]知,这矛盾,则3成立,同理,4成立。

 int size=nums.size();

        if(size==0)

            return false;

            

        int left=0,right=size-1;

        

        while(left<=right){

            int mid=left+(right-left)/2;//right+left may be overflow;

            if(nums[mid]==target)

                return true;

            if(nums[left] == nums[mid] && nums[mid] == nums[right])

            {

               ++left;

               --right;

            }

            else if(nums[left]<=nums[mid]){//这里包含等于,因为left和mid可能指向同一个元素,

                if(nums[left]<=target&&target<nums[mid]){

                    right=mid-1;

                }

                else

                    left=mid+1;

            }

            else{

                if(nums[mid]<target&&target<=nums[right])

                    left=mid+1;

                else

                    right=mid-1;

            }

        }

        return false;

    }



解法二:

这个更好理解点,

To explain why, consider this sorted array 1111115, which is rotated to 1151111.

Assume left = 0 and mid = 3, and the target we want to search for is 5. Therefore, the condition A[left] == A[mid] holds true, which leaves us with only two possibilities:

  1. All numbers between A[left] and A[right] are all 1's.

  2. Different numbers (including our target) may exist between A[left] and A[right].

As we cannot determine which of the above is true, the best we can do is to move left one step to the right and repeat the process again. Therefore, we are able to construct a worst case input which runs in O(n), for example: the input 11111111...115.

Below is a pretty concise code (thanks to bridger) for your reference which I found from the old discuss.

 bool search(vector<int>& nums, int target) {

        int size=nums.size();

        if(size==0)

            return false;

            

        int left=0,right=size-1;

        

        while(left<=right){

            int mid=left+(right-left)/2;//right+left may be overflow;

            if(nums[mid]==target)

                return true;

            else if(nums[left]<nums[mid]){//这里包含等于,[left,mid]有序,

                if(nums[left]<=target&&target<nums[mid]){

                    right=mid-1;

                }

                else

                    left=mid+1;

            }

            else if(nums[left]>nums[mid]){//[mid,right]有序

                if(nums[mid]<target&&target<=nums[right])

                    left=mid+1;

                else

                    right=mid-1;

            }

            else

                left++;

        }

        return false;