面試題11:旋轉數組的最小數字
題目:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如,數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。
解答:和二分查找一樣,我們用兩個指針分別指向數組的第一個元素和最後一個元素。接着找到數組中間的元素。如果該中間元素大於或者等於第一個指針指向的元素,說明此時數組中最小的元素應該位於該中間元素的後面,可以把第一個指針指向該中間元素,從而縮小查找範圍。
同樣,如果中間元素小於或者等於第二個指針指向的元素,則說明此時數組中最小的元素應該位於該中間元素的前面,可以把第二個指針指向該中間元素,從而縮小查找範圍。
以此循環下去,最終第一個指針將指向前面子數組的最後一個元素,而第二個指針會指向後面子數組的第一個元素。也就是它們最終會指向兩個相鄰的元素,而第二個指針指向的剛好是最小的元素。
還有一種特殊的情況,就是當兩個指針指向的數字及它們中間的數字三者相同的時候,我們無法判斷中間的數字是位於前面的子數組還是後面的子數組,也就無法移動兩個指針來縮小查找的範圍。此時不得不採用順序查找的辦法。實現代碼如下:
int MidInOrder(vector<int> rotateArray)
{
if(rotateArray.size() == 0)
{
throw new std::exception("Invalid parameters");
}
int len = rotateArray.size();
int result = rotateArray[0];
for(int i = 1;i < len;i++)
{
if(result > rotateArray[i])
{
result = rotateArray[i];
}
}
return result;
}
int minNumberInRotateArray(vector<int> rotateArray)
{
if(rotateArray.size() == 0)
{
throw new std::exception("Invalid parameters");
}
int left = 0;
int right = rotateArray.size() - 1;
int mid = left;//初始化爲第一個元素,若數組本身有序,可直接返回
while(rotateArray[left] >= rotateArray[right])//若用left<right作爲判斷條件則會陷入死循環
{
if(right - left == 1)
{
mid = right;
break;
}
mid = ((right - left) >> 1) + left;
//若三數相等只能遍歷
if(rotateArray[left] == rotateArray[mid]
&& rotateArray[mid] == rotateArray[right])
{
return MidInOrder(rotateArray);
}
if(rotateArray[mid] >= rotateArray[left])
{
left = mid;
}
else
{
right = mid;
}
}
return rotateArray[mid];
}