[剑指offer]面试题8:旋转数组的最小数字
面試題8:旋轉數組的最小數字
題目:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該數組的最小值為1。
在數組{3,4,5,1,2}中查找最小值的過程:
前面我們提到在旋轉數組中,由于是把遞增排序數組前面的若干個數字搬到數組的后面,因此第一個數字總是大于或者等于最后一個數字。
但按照定義還有一個特例:如果把排序數組的前面的 0 個元素搬到最后面,即排序數組本身,這仍然是數組的一個旋轉,我們的代碼需要支持這種情況。
此時,數組中的第一個數字就是最小的數字,可以直接返回。
這就是在上面的代碼中,把indexMid初始化為index1的原因。
一旦發現數組中第一個數字小于最后一個數字,表明該數組是排序的,就可以直接返回第一個數字了。
上述代碼是否就完美了呢?面試官會告訴我們其實不然。
他將提示我們再仔細分析下標為index1和index2(index1和index2分別和圖中P1和P2相對應)的兩個數相同的情況。
在前面的代碼中,當這兩個數相同,并且它們中間的數字(即indexMid指向的數字)也相同時,我們把indexMid賦值給了 index1,也就是認為此時最小的數字位于中間數字的后面。
是不是一定這樣?
我們再來看一個例子。
數組{1,0,1,1,1}和數組{1,1,1,0,1}都可以看成是遞增排序數組{0,1,1,1,1}的旋轉,圖2.11分別畫出它們由最小數字分隔開的兩個子數組。
圖2.11 數組{0,1,1,1,1}的兩個旋轉{1,0,1,1,1}和{1,1,1,0,1}
注:在這兩個數組中,第一個數字、最后一個數字和中間數字都是1,我們無法確定中間的數字 1 屬于第一個遞增子數組還是屬于第二個遞增子數組。
第二個子數組用灰色背景表示。
在這兩種情況中,第一個指針和第二個指針指向的數字都是1,并且兩個指針中間的數字也是1,這3個數字相同。
在第一種情況中,中間數字(下標為2)位于后面的子數組;
在第二種情況中,中間數字(下標為2)位于前面的子數組中。
因此,當兩個指針指向的數字及它們中間的數字三者相同的時候,我們無法判斷中間的數字是位于前面的子數組中還是后面的子數組中,也就無法移動兩個指針來縮小查找的范圍。
此時,我們不得不采用順序查找的方法。
在把問題分析清楚形成清晰的思路之后,我們就可以把前面的代碼修改為:
#include <iostream> using namespace std;int Min(int *numbers, int length) {if (numbers == nullptr || length <= 0) throw new exception("Invalid parameters");int idx1 = 0;int idx2 = length - 1;int idxmin = idx1;while (numbers[idx1] >= numbers[idx2]){if (idx2 - idx1 == 1){idxmin = idx2;break;}idxmin = (idx1 + idx2) / 2;if (numbers[idx1] == numbers[idx2] && numbers[idxmin] == numbers[idx1]) return MinInOrder(numbers, idx1, idx2);if (numbers[idxmin] >= numbers[idx1]) idx1 = idxmin;else if (numbers[idxmin] <= numbers[idx2]) idx2 = idxmin;}return numbers[idxmin]; }int MinInOrder(int *numbers, int idx1, int idx2) {int res = numbers[idx1];for (int i = idx1 + 1; i <= idx2; i++){if (res > numbers[i]) res = numbers[i];}return res; }測試用例:
● 功能測試(輸入的數組是升序排序數組的一個旋轉,數組中有重復數字或者沒有重復數字)。
● 邊界值測試(輸入的數組是一個升序排序的數組、只包含一個數字的數組)。
● 特殊輸入測試(輸入NULL指針)。
本題考點:
● 考查對二分查找的理解。本題變換了二分查找的條件,輸入的數組不是排序的,而是排序數組的一個旋轉。這要求我們對二分查找的過程有深刻的理解。
● 考查溝通學習能力。本題面試官提出了一個新的概念:數組的旋轉。我們要在很短時間內學習理解這個新概念。在面試過程中如果面試官提出新的概念,我們可以主動和面試官溝通,多問幾個問題把概念弄清楚。
● 考查思維的全面性。排序數組本身是數組旋轉的一個特例。另外,我們要考慮到數組中有相同數字的特例。如果不能很好地處理這些特例,就很難寫出讓面試官滿意的完美代碼。
總結
以上是生活随笔為你收集整理的[剑指offer]面试题8:旋转数组的最小数字的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 发票作废应该怎么操作发票作废后怎么操作
- 下一篇: [剑指offer]面试题9:斐波那契数列