1. 程式人生 > 實用技巧 >【劍指offer第10題】旋轉陣列的最小數字

【劍指offer第10題】旋轉陣列的最小數字

【題目】

把一個數組最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。

輸入一個升序的陣列的一個旋轉,輸出旋轉陣列的最小元素。

例如陣列{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該陣列的最小值為1。

陣列可能包含重複項。

注意:陣列內所含元素非負,若陣列大小為0,請返回-1。

樣例
輸入:nums=[2,2,2,0,1]

輸出:0

【思路】

這個題目最直觀的解法並不難,從頭到尾遍歷陣列一次,就可以找出最小的元素。這種思路的時間複雜度顯然是O(n)。但是並沒有利用旋轉陣列的特性。應該不是最佳的解法。

我們注意到旋轉之後得到的兩個陣列都是有序的,而且前面的子陣列的元素要大於或者等於後面子陣列的元素。我們還注意到最小的元素剛好是這兩個子陣列的分界線,在排序的陣列中我們可以使用二分法實現O(logn)的查詢。

另外我們注意到使用O(n)的時間複雜度無法求解時,就應該想到是否能用O(logn)的時間複雜度來求解。

【通常情況】和二分查詢一樣,使用兩根指標分別指向陣列的第一個元素和最後一個元素,根據題目中的旋轉規則,第一個元素應該是大於或者等於最後一個的。接著我們可以找到陣列的中間元素,如果該中間元素位於前面遞增的子陣列,那麼他應該大於或者等於第一個指標指向的元素。此時分界點元素(最小值)應該在後一個子陣列。此時我們可以將頭指標指向該中間元素,縮小了查詢範圍。

同樣的道理,如果中間元素位於後面的遞增子陣列,那麼他應該小於或者等於第二個指標指向的元素,此時分界點元素(最小值)應該在前一個子陣列,此時我們可以將尾指標指向該中間元素,縮小了查詢範圍。

按著上面的思路:第一個指標總是指向前面遞增陣列的元素,第二個指標總是指向後面遞增陣列的元素也就是說他們最後會指向兩個相鄰的元素,而第二個指標剛好指向的是最小的元素。這也是迴圈結束的條件。

【特例】

如果將排序陣列的前面0個元素搬到最後面,即排序陣列的本身,這仍然是一個旋轉,我們上述程式碼思路是支援這種情況的。即陣列中的第一個元素即為最小的數字。特例:陣列{1,0,1,1,1}和陣列{1,1,1,0,1} 可以看成是遞增排序陣列{0,1,1,1,1}的旋轉。這兩種情況使用上述二分思路,第一個指標和第二個指標以及中間值都相等,則我們沒辦法判斷中間數字是位於前半部分的子陣列中還是後半部分的子陣列中,也就無法通過移動兩個指標來縮小查詢的範圍。此時我們不得不採用順序查詢的方法進行查詢。

【程式碼】