劍指Offer08:數組旋轉問題

數組旋轉問題

題目描述

把一個數組最開始的若干個元素搬到數組末尾,我們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出數組最小的元素。例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。

解題思路

採用二分法的思路,設定兩個指針分別指向數組的第一個元素和最後一個元素。(第一個元素應該是大於或者等於最後一個元素的,存在特例)找到數組中間的元素(mid=(head+tail)/2),如果中間的元素位於前面的遞增子數組,那麼它應該大於或者等於第一個指針指向的元素。此時數組中最小的元素應該位於該中間元素的後面。我們可以把第一個指針指向該中間元素,這樣可以縮小尋找的範圍。移動之後的第一個指針仍然位於前面的遞增數組中。
如果中間元素位於後面的遞增子數組,那麼它應該小於或者等於第二個指針指向的元素。此時該數組中最小的元素應該位於該中間元素的前面。我們可以把第二個指針指向該中間元素,這樣也可以縮小尋找的範圍。移動之後的第二個指針仍然位於後面的遞增子數組之中。
因此,第一個指針總是指向前面遞增的數字元素,而第二個指針總是指向後面遞增的數組的元素。最終第一個指針將指向前面子數組的最後一個元素,而第二個指針將指向後面子數組的第一個元素。也就是他們最終會指向兩個相鄰的元素,而第二個指針指向的剛好是最小的元素。這就是循環結束的條件。

注意兩種特殊情況:
{1,0,1,1,1}和數組{1,1,1,0,1}都可以看成是遞增數組{0,1,1,1,1}的旋轉。在這兩個數組中,第一個數字、最後一個數字和中間數字都是1,我們無法確定中間數字1屬於第一個遞增子數組還是屬於第二個遞增子數組。(實際上,第一種情況下,中間數字位於後面的子數組;第二種情況中,中間數字位於前面的子數組中)

public class Code008 {
    public static void main(String[] args){
        Scanner sc=new Scanner(System.in);
        String[] inLine=sc.nextLine().split(" ");
        int len=inLine.length;
        int[] arr=new int[len];
        for(int i=0;i<len;i++){
            arr[i]=Integer.parseInt(inLine[i]);
        }
        int result=solution(arr,len);
        System.out.println(result);
    }
    private static int solution(int[] arr,int len){
        if(arr == null || len<0){
            return -1;
        }
        int index1=0;
        int index2=len-1;
        int indexMid=index1;
        while (arr[index1]>=arr[index2]){
            if(index2-index1==1){
                indexMid=index2;
                break;
            }
            //兩指針正中間的數字對應的下標
            indexMid=(index1+index2)/2;
            //如果下標爲index1和index2和indexMid的三個數字相等,那麼只能順序查找了
            if(arr[index1]==arr[index2] && arr[indexMid]==arr[index1]){
                return minIndexOrder(arr,index1,index2);
            }
            //如果左指針指向的數字小於中間的數字,那麼目標數字位於中間數與尾指針之間
            if(arr[indexMid]>=arr[index1]){
                index1=indexMid;
            }
            //如果尾指針指向數字大於中間數字,那麼目標數字位於左指針與中間數字之間
            if(arr[indexMid]<=arr[index2]){
                index2=indexMid;
            }
        }
        return arr[indexMid];
    }

    private static int minIndexOrder(int[] arr, int index1, int index2) {
        int result=arr[index1];
        for(int i=index1+1;i<=index2;i++){
            if(result>arr[i]){
                result=arr[i];
            }
        }
        return result;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章