題目鏈接:旋轉數組的最小數字
第一種:正確寫法(num[m]和nums[r]比較)
class Solution {
public:/*** 代碼中的類名、方法名、參數名已經指定,請勿修改,直接返回方法規定的值即可** * @param nums int整型vector * @return int整型*/int minNumberInRotateArray(vector<int>& nums) {// write code hereint l = 0, m = 0, r = nums.size() - 1;while (l < r) { // 將結果框在[l,r]的范圍內,因此當l==r時,代表就是結果m = (l + r) / 2; // 此處在l=r-1時要注意死循環,因為循環條件時l < r,如果在l根據m改變時,必須給l賦值m+1,因為直接賦值為m就會導致死循環。(此處只需要注意l=m+1,而r=m是可以的,這是因為(l+r)/2的結果可能等于l,但不可能等于r)if (nums[m] > nums[r]) {l = m + 1; // 說明m是在第一個上升數組中,且m不可能是最小值,所以m這個位置不需要保留,同時為了避免死循環,l=m+1而不是l=m} else if (nums[m] < nums[r]) {r = m; // 說明m是在第二個上升數組中,且m有可能是結果的位置,因此m必須要保留,r=m而不是r=m-1} else {r--; // 此處就是第一次沒想到的解法,當nums[m] == nums[r]時,沒法確定是第一個還是第二個上升數組,但能確定的是,r這個位置可以不要了,因為有m在保留著結果(m不可能等于r,因為如果m==r的話,說明l==r,那么循環就走不到這里了。為了縮小結果集范圍,直接r--就可以了)}}return nums[l];}
};
但是很神奇的是,上面的代碼都是和num[r]比較的,但如果像下面這么寫,有些用例就是失敗的
第二種錯誤寫法:nums[m]和num[l]比較
class Solution {
public:/*** 代碼中的類名、方法名、參數名已經指定,請勿修改,直接返回方法規定的值即可** * @param nums int整型vector * @return int整型*/int minNumberInRotateArray(vector<int>& nums) {// write code hereint l = 0, m = 0, r = nums.size() - 1;while (l < r) {m = (l + r) / 2;if (nums[m] > nums[l]) {l = m + 1;} else if (nums[m] < nums[l]) {r = m;} else {l++;}}return nums[l];}
};
上面的代碼表明看起來是對的,但這段代碼只能通過部分用例。
因為存在特殊情況,即在旋轉0個數字情況下,nums[m]是一定會大于num[l],此時按照上面的代碼,l=m+1,l會越加越多,離正確答案nums[0]越來越遠了。
因此這就是為什么要按照第一種寫法,nums[m]和num[r]進行比較。在旋轉0個數字這種特殊情況,nums[m]<num[r]是永遠成立的,此時的操作正好是r = m,就不會錯過正確答案。
例如[1,0,1,1,1]這個輸入,nums[m]和nums[l]比較這個上面的第二種代碼就是錯誤的。
第一輪l=0,r=4,m=2。此時nums[l]==nums[r],因此l++
第二輪l=1,r=4,m=2。此時[l,r]就是[0,1,1,1]這個升序的序列了,就是上面所說的特殊場景,nums[m] > nums[l],按照第二種代碼的邏輯,l = m+1,l=3。這樣直接就把正確答案跳過去了。