Search in Rotated Sorted Array II

本文探讨在含有重复元素的旋转有序数组中搜索特定目标值的方法。文章分析了不同情况下数组的特性,并提出一种改进的二分查找算法实现高效搜索。

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.

分析:条件判断的前面两个部分与变化之前的版本是一样的。最后一行也可以改称递归的方法,对两边都进行查找,然后对其结果去或之后返回。


2014/07/29: 今天又重新做这两道题,在网上看到有人说如果是降序就不对了,觉得很有意思,就接着研究了一下该如何处理。

我觉得,如果不知道数组是生序还是降序的话,需要先判断一下,然后再用这道题的方法进行查找(当然,如果是降序的话,下面的判断条件需要改一下)。我想了一下,琢磨出了一种生降序的判断方法,不知道还有没有更好的,先写下来吧。

首先,无论是生序还是降序,是至少针对三个数来说的。1个数的情况不用多说,无生降序可言。如果是2个数,一次rotation就可以将生序变为降序,或者是将降序变为生序,所以对2个数的数组谈生降序也是毫无疑义的。所以,问题就扩展到了3个和3个以上数的情况。我的方法是,查看前三个数,然后共有下面若干种可能的情况:

1. 前3个数生序:答案显而易见,这个数组在rotated之前一定是生序。

2. 前3个数降序:同样,很容易判断,该数组rotated之前必然是降序。

3. 前3个数先降后生或先生后降:这里开始,情况变的有意思且复杂起来。

(1)首先,我们讨论先降后生的情况。如果画个图,这3个数组成的图像像一个“V”字形。问题的关键在于,这个降的数有啥特殊性?通过分析可以发现,这个数,即第2个数,必然是原数组,也就是被rotate之前的数组,中的最小值。于是,通过比较第1,3个数的关系,我们便可以得到数组的顺序是生还是降。如果第1个数大于第3个,那么数组一定是生序的。相反,如果第1个数小于第3个,那么数组为降序。

(2)基于(1)中的分析,先生后降的情况就不难理解了。这种情况对应的图像像是“^”。中间的第2个数是原数组中的最大值。所以,如果数1小于数3,则数组为降序。若数1大于数3,则数组为生序。

(3)通过观察(1)和(2)中的结果可以看出,对于这种3个数顺序不一致的情况,如果数1大于数3,则原数组为生序;如果数1小于数3,则原数组为降序。


还要说明一下,以上的分析只适用于没有重复的情况(即这道题的I)。如果数组中有重复的话,好像也只能从头到尾扫描来判断数组是生序还是降序了吧,反正目前我还没想到更好的办法。这样做的话,总体的时间复杂度还是O(N),不会发生变化。

public class Solution {
    public boolean search(int[] A, int target) {
        int low=0, high=A.length-1;
        
        while(low <= high) {
            int mid = (low+high)/2;
            if(target==A[mid]) return true;
            if(A[mid] > A[low]) {               // left in order
                if(target<A[mid] && target>=A[low]) high=mid-1;
                else low=mid+1;
            }
            else if(A[mid] < A[low]) {          // right in order
                if(target>A[mid] && target<=A[high]) low=mid+1;
                else high=mid-1;
            }
            else if(A[mid]==A[low]) low+=1;     // increase low by 1 and continue
        }
         
        return false;
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值