旋轉數組的最小數字-Java實現

12. 旋轉數組的最小數字

問題描述

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

很容易我們想到的是,從頭到尾遍歷一次數據,我們就找出了最小值,時間複雜度是O(n),但是我們一點都沒有用到旋轉數組的特性.

分析

  1. 旋轉數組,其實可以劃分爲兩個排序的子數組,而且前面的子數組的元素都大於後面子數組的元素
  2. 最小值剛好就是這兩個子數組的分界線
  3. 我們可以嘗試用二分查找來實現(時間複雜度 O(logn))

代碼如下:

/**
 * Class day12 ...
 *
 * @author LiJun
 * Created on 2018/12/28
 */
public class day12 {
    public static int Min(int[] numbers) {
        // 參數有效性驗證
        if (numbers == null || numbers.length <= 0) {
            return Integer.MIN_VALUE;
        }
        // 二分法的基本實現就是一個指向頭 一個指向尾
        int start = 0;
        int end = numbers.length - 1;
        // 設置medium的原因是一旦數組中的第一個數字 小於最後一個數字,說明這個數組是排序的
        // 直接返回第一個數字就行
        int medium = start;
        while (numbers[start] >= numbers[end]) {
            // 如果start 和 end 執行相鄰的數字
            // 則 start 執行第一個遞增數列的最後一個數字
            // end 指向第二個遞增數列的第一個數字
            if (end - start == 1) {
                medium = end;
                break;
            }
            medium = (start + end) / 2;
            // 這裏是特殊情況 如果這三者相等的話,就只能老老實實的順序查找了
            if(numbers[start] == numbers[medium] && numbers[medium]  == numbers[end]){
                return GetMinInOrder(numbers, start, end);
            }
            if(numbers[medium] >= numbers[end]){
                start = medium;
            }else if(numbers[medium] <= numbers[end]){
                end = medium;
            }
        }
        return numbers[medium];
    }

    public static int GetMinInOrder(int[] numbers, int start, int end) {
        int min = numbers[start];
        for(int i = start+1; i <= end; i++){
            if(numbers[i] < min){
                min = numbers[i];
            }
        }
        return min;
    }

    public static void main(String[] args) {
        // 基礎測試
        int[] numbers = {3,4,5,1,2};
        System.out.println(Min(numbers));
        numbers = new int[]{1, 0, 1, 1, 1};
        System.out.println(Min(numbers));
    }
}

在這我需要解釋下,如果numbers[start] < numbers[end] 這就說明,這區間已經是排序好了的,無須查找了。

其次,有種情況,那就是 根據旋轉數組的特性,第一個數字總是大於或者等於最後一個數字,那麼我們現在想想,如果我們把 0 個數據搬到後面去 這時候第一個數據就是最小的,這也就是我們爲什麼把 medium 初始爲 start 的值的原因。

但是我們也有種情沒考慮到,當 numbers[start] = numbers[end] =numbers[medium] 的時候, 這個時候,我們應該怎麼辦呢。 例如: {1, 0, 1, 1, 1} 之類的,我們可以得到 numbers[medium] = 1 這三個值都相等的時候,我們怎樣二分。我們只能老老實實的順序遍歷找出答案了。

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