【每日一題】劍指 Offer 11. 旋轉數組的最小數字

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

示例 1:

輸入:[3,4,5,1,2]
輸出:1
示例 2:

輸入:[2,2,2,0,1]
輸出:0

我尋思這不就是找最小值嗎?
但是仔細看題還是也有一點點區別,這個數組是半有序,[3,4,5,1,2]這樣子,總體無序前後兩端都是有序的,所以有一些特殊的方法。

解法一:暴力求解

class Solution {
    public int minArray(int[] numbers) {
        for(int i=0;i<numbers.length-1;i++)
        {
            if(numbers[i]>numbers[i+1]) 
            	return numbers[i+1];
        }
        return numbers[0];
    }
}

在這裏插入圖片描述
解法二:二分法

  1. 循環二分: 設置 i, j 指針分別指向 numbers 數組左右兩端,m = (i + j) / 2 ,爲每次二分的中點( “//” 代表向下取整除法,因此恆有 i <=m <j ),可分爲以下三種情況:
  • 當 numbers[m] > numbers[j]時: m 一定在 左排序數組 中,即旋轉點 x 一定在 [m+1,j] 閉區間內,因此執行 i = m + 1;
  • 當 numbers[m] < numbers[j] 時: m 一定在 右排序數組 中,即旋轉點 x 一定在[i,m] 閉區間內,因此執行 j = m;
  • 當 numbers[m] == numbers[j] 時: 無法判斷 m 在哪個排序數組中,即無法判斷旋轉點 x 在 [i, m]還是 [m + 1, j]區間中。
  • 解決方案: 執行 j = j - 1 縮小判斷範圍 (分析見以下內容) 。
  1. 返回值: 當 i = j 時跳出二分循環,並返回 numbers[i] 即可。
圖1
圖2
圖3
圖4
圖5
class Solution {
    public int minArray(int[] numbers) {
        int i = 0, j = numbers.length - 1;
        while (i < j) {
            int m = (i + j) / 2;
            if (numbers[m] > numbers[j]) i = m + 1;
            else if (numbers[m] < numbers[j]) j = m;
            else j--;
        }
        return numbers[i];
    }
}

在這裏插入圖片描述

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