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