題目:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個排好序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3, 4, 5, 1, 2}為{1, 2, 3, 4, 5}的一個旋轉,該數組的最小值為1。
分析:這道題最直觀的解法並不難。從頭到尾遍曆數組一次,就能找出最小的元素,時間複雜度顯然是O(N)。但這個思路沒有利用輸入數組的特性,我們應該能找到更好的解法。
我們注意到旋轉之後的數組實際上可以劃分為兩個排序的子數組,而且前面的子數組的元素都大於或者等於後面子數組的元素。我們還可以注意到最小的元素剛好是這兩個子數組的分界線。我們試著用二元尋找法的思路在尋找這個最小的元素。
首先我們用兩個指標,分別指向數組的第一個元素和最後一個元素。按照題目旋轉的規則,第一個元素應該是大於或者等於最後一個元素的(這其實不完全對,還有特例。後面再討論特例)。
接著我們得到處在數組中間的元素。如果該中間元素位於前面的遞增子數組,那麼它應該大於或者等於第一個指標指向的元素。此時數組中最小的元素應該位於該中間元素的後面。我們可以把第一指標指向該中間元素,這樣可以縮小尋找的範圍。同樣,如果中間元素位於後面的遞增子數組,那麼它應該小於或者等於第二個指標指向的元素。此時該數組中最小的元素應該位於該中間元素的前面。我們可以把第二個指標指向該中間元素,這樣同樣可以縮小尋找的範圍。我們接著再用更新之後的兩個指標,去得到和比較新的中間元素,迴圈下去。
按照上述的思路,我們的第一個指標總是指向前面遞增數組的元素,而第二個指標總是指向後面遞增數組的元素。最後第一個指標將指向前面子數組的最後一個元素,而第二個指標會指向後面子數組的第一個元素。也就是它們最終會指向兩個相鄰的元素,而第二個指標指向的剛好是最小的元素。這就是迴圈結束的條件。
基於這個思路,我們可以寫出如下代碼:
// Get the minimum number of a roatation of a sorted arrayint Min(int *numbers, int length){ if(numbers == 0 || length <= 0) throw new std::exception("Invalid parameters"); int index1 = 0; int index2 = length - 1; int indexMid = index1; while(numbers[index1] >= numbers[index2]) { if(index2 - index1 == 1) { indexMid = index2; break; } indexMid = (index1 + index2) / 2; if(numbers[indexMid] >= numbers[index1]) index1 = indexMid; else if(numbers[indexMid] <= numbers[index2]) index2 = indexMid; } return numbers[indexMid];}
由於我們每次都把尋找的範圍縮小一半,該演算法的時間複雜度是O(logN)
值得注意的是,如果在面試現場寫代碼,通常我們需要用一些測試案例來驗證代碼是不是正確的,我們在驗證的時候盡量能考慮全面些。像這道題,我們出來最簡單測試案例之外,我們至少還需要考慮如下的情況:
1. 把數組前面的0個元素從最前面搬到最後面,也就是原數組不做改動,根據題目的規則這也是一個旋轉,此時數組的第一個元素是大於小於或者等於最後一個元素的;
2. 排好序的數組中有可能有相等的元素,我們特別需要注意兩種情況。一是旋轉之後的數組中,第一個元素和最後一個元素是相等的;另外一種情況是最小的元素在數組中重複出現
3. 在前面的代碼中,如果輸入的數組不是一個排序數組的旋轉,那將陷入死迴圈。因此我們需要跟面試官討論是不是需要判斷數組的有效性。在面試的時候,面試官討論如何驗證輸入的有效性,能顯示我們思維的嚴密性。本文假設在調用函數Min之前,已經驗證過輸入的有效性了。
最後需要指出的是,如果輸入的數組指標是非法指標,我們是用異常來做錯誤處理。這是因為在這種情況下,如果我們用return來結束該函數,返回任何數字都不是正確的。關於無效輸入時的函數如何返回錯誤資訊並結束,本部落格第17題有更詳細的討論,可以參考。
本文已經收錄到《劍指Offer——名企面試官精講典型編程題》一書中,有改動,書中的分析講解更加詳細。歡迎關注。
本題已被九度Online Judge系統收錄,歡迎讀者移步到http://ac.jobdu.com/hhtproblems.php線上測試自己的代碼。
博主何海濤對本部落格文章享有著作權。網路轉載請註明出處http://zhedahht.blog.163.com/。整理出版物請和作者聯絡。