題目:把一個數組最開始的若幹個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該數組的最小值為1.
和二分查找法一樣,用兩個指針分别指向數組的第一個元素和最後一個元素。
我們注意到旋轉之後的數組實際上可以劃分為兩個排序的子數組,而且前面的子數組的元素都大于或者等于後面子數組的元素。我們還可以注意到最小的元素剛好是這兩個子數組的分界線。我們試着用二進制查找法的思路在尋找這個最小的元素。
首先我們用兩個指針,分别指向數組的第一個元素和最後一個元素。按照題目旋轉的規則,第一個元素應該是大于或者等于最後一個元素的(這其實不完全對,還有特例。後面再讨論特例)。
接着我們得到處在數組中間的元素。如果該中間元素位于前面的遞增子數組,那麼它應該大于或者等于第一個指針指向的元素。此時數組中最小的元素應該位于該中間 元素的後面。我們可以把第一指針指向該中間元素,這樣可以縮小尋找的範圍。同樣,如果中間元素位于後面的遞增子數組,那麼它應該小于或者等于第二個指針指 向的元素。此時該數組中最小的元素應該位于該中間元素的前面。我們可以把第二個指針指向該中間元素,這樣同樣可以縮小尋找的範圍。我們接着再用更新之後的 兩個指針,去得到和比較新的中間元素,循環下去。
按 照上述的思路,我們的第一個指針總是指向前面遞增數組的元素,而第二個指針總是指向後面遞增數組的元素。最後第一個指針将指向前面子數組的最後一個元素, 而第二個指針會指向後面子數組的第一個元素。也就是它們最終會指向兩個相鄰的元素,而第二個指針指向的剛好是最小的元素。這就是循環結束的條件。
核心實作代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<code>int</code> <code>Min(</code><code>int</code> <code>*numbers , </code><code>int</code> <code>length)</code>
<code>{</code>
<code> </code><code>if</code><code>(numbers == NULL || length <= 0)</code>
<code> </code><code>return</code><code>;</code>
<code> </code><code>int</code> <code>index1 = 0;</code>
<code> </code><code>int</code> <code>index2 = length - 1;</code>
<code> </code><code>int</code> <code>indexMid = index1;</code>
<code> </code><code>while</code><code>(numbers[index1] >= numbers[index2])</code>
<code> </code><code>{</code>
<code> </code><code>if</code><code>(index2 - index1 == 1)</code>
<code> </code><code>{</code>
<code> </code><code>indexMid = index2;</code>
<code> </code><code>break</code><code>;</code>
<code> </code><code>}</code>
<code> </code><code>indexMid = (index1 + index2) / 2;</code>
<code> </code><code>//如果下标為index1、index2和indexMid指向的三個數字相等,則隻能順序查找</code>
<code> </code><code>if</code><code>(numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1])</code>
<code> </code><code>return</code> <code>MinInOrder(numbers , index1 , index2);</code>
<code> </code><code>if</code><code>(numbers[indexMid] >= numbers[index1])</code>
<code> </code><code>index1 = indexMid;</code>
<code> </code><code>else</code> <code>if</code><code>(numbers[indexMid] <= numbers[index2])</code>
<code> </code><code>index2 = indexMid;</code>
<code> </code><code>}</code>
<code> </code><code>return</code> <code>numbers[indexMid];</code>
<code>}</code>
<code>//順序查找</code>
<code>int</code> <code>MinInOrder(</code><code>int</code> <code>*numbers , </code><code>int</code> <code>index1 , </code><code>int</code> <code>index2)</code>
<code> </code><code>int</code> <code>result = numbers[index1];</code>
<code> </code><code>for</code><code>(</code><code>int</code> <code>i = index1 + 1 ; i <= index2 ; ++i)</code>
<code> </code><code>if</code><code>(result > numbers[i])</code>
<code> </code><code>result = numbers[i];</code>
<code> </code><code>return</code> <code>result;</code>
注意:當兩個指針指向的數字及他們中間的數字三者相同的時候,我們無法判斷中間的數字是位于前面的字數組還是後面的子數組中,也就無法移動兩個指針來縮小查找的範圍。此時,我們不得不采用順序查找的方法。
本題考查了對二分查找的了解。
其中二分查找法的實作代碼如下:
<code>int</code> <code>binary_search(</code><code>int</code> <code>array[] , </code><code>int</code> <code>len , </code><code>int</code> <code>value)</code>
<code> </code><code>int</code> <code>left = 0;</code>
<code> </code><code>int</code> <code>right = len - 1;</code>
<code> </code><code>while</code><code>(left <= right){</code>
<code> </code><code>int</code> <code>middle = left + ((right - left) >> 1);</code>
<code> </code>
<code> </code><code>if</code><code>(array[middle] > value){</code>
<code> </code><code>right = middle - 1;</code>
<code> </code><code>else</code> <code>if</code><code>(array[middle] < value){</code>
<code> </code><code>left = middle + 1;</code>
<code> </code><code>else</code>
<code> </code><code>return</code> <code>middle;</code>
<code> </code>
<code> </code><code>return</code> <code>-1;</code>
這是一個經典的話題,如何計算二分查找中的中值?
算法一: mid = (low + high) / 2
算法二: mid = low + (high – low)/2
乍 看起來,算法一簡潔,算法二提取之後,跟算法一沒有什麼差別。但是實際上,差別是存在的。算法一的做法,在極端情況下,(low + high)存在着溢出的風險,進而得到錯誤的mid結果,導緻程式錯誤。而算法二能夠保證計算出來的mid,一定大于low,小于high,不存在溢出的 問題。
本文轉自夏雪冬日部落格園部落格,原文連結:http://www.cnblogs.com/heyonggang/p/3405041.html,如需轉載請自行聯系原作者