程序员面试题精选100题(42)-旋转数组的最小元素[算法]
題目:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個排好序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3, 4, 5, 1, 2}為{1, 2, 3, 4, 5}的一個旋轉,該數組的最小值為1。
?????????分析:這道題最直觀的解法并不難。從頭到尾遍歷數組一次,就能找出最小的元素,時間復雜度顯然是O(N)。但這個思路沒有利用輸入數組的特性,我們應該能找到更好的解法。
?????????我們注意到旋轉之后的數組實際上可以劃分為兩個排序的子數組,而且前面的子數組的元素都大于或者等于后面子數組的元素。我們還可以注意到最小的元素剛好是這兩個子數組的分界線。我們試著用二元查找法的思路在尋找這個最小的元素。
?????????首先我們用兩個指針,分別指向數組的第一個元素和最后一個元素。按照題目旋轉的規則,第一個元素應該是大于或者等于最后一個元素的(這其實不完全對,還有特例。后面再討論特例)。
接著我們得到處在數組中間的元素。如果該中間元素位于前面的遞增子數組,那么它應該大于或者等于第一個指針指向的元素。此時數組中最小的元素應該位于該中間元素的后面。我們可以把第一指針指向該中間元素,這樣可以縮小尋找的范圍。同樣,如果中間元素位于后面的遞增子數組,那么它應該小于或者等于第二個指針指向的元素。此時該數組中最小的元素應該位于該中間元素的前面。我們可以把第二個指針指向該中間元素,這樣同樣可以縮小尋找的范圍。我們接著再用更新之后的兩個指針,去得到和比較新的中間元素,循環下去。
按照上述的思路,我們的第一個指針總是指向前面遞增數組的元素,而第二個指針總是指向后面遞增數組的元素。最后第一個指針將指向前面子數組的最后一個元素,而第二個指針會指向后面子數組的第一個元素。也就是它們最終會指向兩個相鄰的元素,而第二個指針指向的剛好是最小的元素。這就是循環結束的條件。
基于這個思路,我們可以寫出如下代碼:
// Get the minimum number of a roatation of a sorted array int 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/。整理出版物請和作者聯系。
總結
以上是生活随笔為你收集整理的程序员面试题精选100题(42)-旋转数组的最小元素[算法]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员面试题精选100题(44)-数值的
- 下一篇: 程序员面试题精选100题(45)-Sin