題目:
把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。
輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。
例如,數組 [3,4,5,1,2] 爲 [1,2,3,4,5] 的一個旋轉,該數組的最小值爲1。
示例 1:
輸入:[3,4,5,1,2]
輸出:1
示例 2:
輸入:[2,2,2,0,1]
輸出:0
思路:
方案一:簡單的知己遍歷查找:時間複雜度:O(n),空間O(1)
因爲題目中所提供的是一個排序的原始數組,因此我們只要循環一次,找到變小的那個元素,這個元素就是最小元素;如果如果沒有,那麼第一個元素就是我們要找的元素了;
從給這個方案中的思考中,我們知道代碼中要對 未經旋轉的數組進行處理,不妨設置一個測試用例爲
[1,2,3,4,5];
方案二:快排思想/ 二分思想 / 切分數組:時間複雜度:O(logn), 空間O(1)
對於[3,4,5,1,2], 他是兩段連續增長的數組拼接而成的
我們取 起始點、中點、 終止點三個點進行比較,3 > 5 && 5 > 2
可見第一段是遞增的,而第二段顯然並非遞增,因此最小值在第二段中;
我們重複這個過程,5 > 1 && 1 < 2,第一段不是遞增的,因此對第一段繼續;
而此時這兩個元素只相差1個下標,因此這段中的第二個值就是我們要的最小值;
據此不難實現如下代碼:
while(last - first >= 1){
if(last - first == 1)
return numbers[last];
int mid_index = (first + last)/2;
// 註釋一:
// if(numbers[first] == numbers[last] && numbers[first] == numbers[mid_index]){
// return find_byOrder(numbers);
// }
if(numbers[first] > numbers[mid_index]){
last = mid_index;
}
else if(numbers[last] < numbers[mid_index]){
first = mid_index;
}
}
return numbers[0]; // 註釋2
對於剛剛說的測試用例 [1,2,3,4,5],這並不能滿足,對於原地旋轉的情況我們沒有判斷,其實只需要在return的時候:註釋二;
對於小於等於3個元素的數組呢?while中的判斷條件也有問題:旋轉過後的數組的特點就是 first的數值要大於last,因此修改爲:numbers[first] >= numbers[last]
還有一點細節!如果最初的 first 、last、mid_index對應的數值都相等怎麼辦?
這將不會進行任何操作,一直循環
比如:【1,0,1,1,1,1】
這時可能有一些其他的辦法,這裏我直接調用方法一函數,遍歷查找;
方法二:代碼:
class Solution {
public:
int find_byOrder(vector<int>& numbers){
int index = 0;
for(int i = 1; i< numbers.size(); i++)
{
if(numbers[i] < numbers[i - 1]) {
index = i;
}
}
return numbers[index];
}
int minArray(vector<int>& numbers) {
if(numbers.size() == 0)
return -9999;
int first = 0, last = numbers.size()-1;
while(numbers[first] >= numbers[last]){
if(last - first == 1)
return numbers[last];
int mid_index = (first + last)/2;
if(numbers[first] == numbers[last] && numbers[first] == numbers[mid_index]){
return find_byOrder(numbers);
}
if(numbers[first] > numbers[mid_index]){
last = mid_index;
}
else if(numbers[last] < numbers[mid_index]){
first = mid_index;
}
}
return numbers[0];
}
};