這個系列整理一下旋轉陣列,就是原始單調不減陣列,在預先未知的某個下標 k(0 <= k < nums.length)上進行了 旋轉,使陣列變為 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]]
針對這種陣列,兩個要求,乙個找到分界點k,另乙個是給乙個target,找到這個target的位置。然後針對原陣列是否有重複還需要考慮一下。這個系列用遍歷肯定是能解的,但是考察點肯定是二分~
無重複陣列,找target
傳統的公升序陣列上,只要確定了nums[mid]與target相比大小,就可以確定是調整left還是right。
但是旋轉陣列有個問題,我們無法確定邊界在哪兒 ,所以先確定邊界在左邊還是右邊(如果有的話), 在mid的左邊的話,有nums[mid] < nums[left]。在mid的右邊的話,有nums[mid] > nums[left]。
可以分為三種情況討論
(1)nums[left] < nums[mid] < nums[right]
整體公升序
(2)nums[left] < nums[mid] > nums[right]
左半部分公升序
(3)nums[left] > nums[mid] < nums[right]
右半部分公升序
換言之,對於乙個旋轉陣列,mid可以把陣列分成乙個公升序陣列和旋轉陣列
(1)對於nums[mid] >= nums[left]
那麼有mid的左邊肯定是個公升序陣列,判斷這個公升序陣列中有沒有target還是很容易的~在的話就調整右邊界。反之就在右邊的旋轉陣列。調整左邊界。
(2)對於nums[mid] < nums[left]
那麼有mid的右邊肯定是個公升序陣列,判斷這個公升序陣列中有沒有target還是很容易的~在的話就調整左邊界。反之就在左邊的旋轉陣列。調整右邊界。
總結一下,與普通的二分法的區別,我們先判斷一下,mid的左邊還是右邊是旋轉陣列,然後在判斷target在哪一邊的時候,是要去判斷公升序陣列的那一邊能不能包含target,這樣相對容易些。
class
solution
else
}return-1
;}};
有重複,找target
有重複的話,其他情況都不影響,主要影響的是nums[mid] 與nums[target]相等的時候,這個時候是沒法確定到底分界線在哪兒的。
上一題中nums[mid] 與nums[target]相等時,由於不重複,只會有一種情況,就是mid=target,此時把左部分看做是公升序序列一點問題沒有。
但這一題中我舉兩個例子
1,1, 4, 1
1, 3,1, 1, 1, 1
這兩種情況都是nums[mid] 與nums[target]相等,但是很明顯乙個分界線在左部分,乙個在右部分。
所以對於nums[mid] 與nums[target]相等的情況需要討論一下,遇到相等就把left前移一步。
class
solution
if(nums[left]
< nums[mid]
)else
}return
false;}
};
與上一種型別不同,這題找最小值
同理三種情況
(1)nums[left] < nums[mid] < nums[right]
最小值在左半部分
(2)nums[left] < nums[mid] > nums[right]
分界線在mid和right之間,最小值在右半部分
(3)nums[left] > nums[mid] < nums[right]
分界線在left和mid之間,最小值在左半部分(包括mid處)
不難發現最小值在左半部分的情況為(1)(3),我們只需要比較nums[mid]和nums[right]即可。
這個二分法用的是左閉右閉,但是在left與right相等的情況就跳出迴圈,收縮右邊界的時候,對於情況(3),mid本身可能就是最小值,所以收縮的時候只能right=mid,而不能right=mid-1。
class
solution
return nums[left];}
};
上一種不重複的情況,永遠不會有nums[mid]=num[right],因為mid永遠是偏向左邊的(除法影響),只有當left=right,才會有nums[mid]=num[right],而left=right就已經跳出迴圈了。
但是面對有重複元素,就會有nums[mid]=num[right],這裡我們的處理的方式與上一題一樣,將右邊界減一就可以~
class
solution
return nums[left];}
};
擴充套件一下,如果是最大值呢?先討論無重複的問題
還是3種情況
(1)nums[left] < nums[mid] < nums[right]
最大值在右半部分
(2)nums[left] < nums[mid] > nums[right]
分界線在mid和right之間,最大值在右半部分(包括mid處)
(3)nums[left] > nums[mid] < nums[right]
分界線在left和mid之間,最大值在左半部分
可以發現(1)(2)都在右半部分,縮小左邊界就可以,這兩種情況下比較nums[left]與nums[mid]。
但是這裡需要注意的一點是,為了避免無限迴圈,在left=right+1,此時肯定不能讓mid = left。那我們在選取mid的選取偏向右邊的就可以。
class
solution
return nums[left];}
};
那對於有重複的!
會有nums[mid]=num[left],這裡我們的處理的方式與上一題一樣,將左邊界加一就可以~
class
solution
return nums[left];}
};
二分法之旋轉陣列系列
給定乙個陣列,將陣列中的元素向右移動 k 個位置,其中 k 是非負數。要求使用空間複雜度為 o 1 的 原地 演算法。解法一 雙重迴圈class solution def rotate self,nums list int k int none do not return anything,modi...
二分法旋轉陣列找最小數
一 題目描述 把乙個陣列最開始的若干個元素搬到陣列的末尾,我們稱之為陣列的旋轉。輸入乙個非遞減排序的陣列的乙個旋轉,輸出旋轉陣列的最小元素。note 給出的所有元素都大於0,若陣列大小為0,請返回0。示例1輸入 3,4,5,1,2 返回值1 二 思路 這道題要求用二分法,一開始用的是遍歷的方法,時間...
二分法尋找旋轉陣列中的target
題目描述 給出乙個轉動過的有序陣列,你事先不知道該陣列轉動了多少 例如,0 1 2 4 5 6 7可能變為4 5 6 7 0 1 2 在陣列中搜尋給出的目標值,如果能在陣列中找到,返回它的索引,否則返回 1。假設陣列中不存在重複項。陣列有序首選二分,但是題目中陣列並非完全有序,而是因為旋轉的原因導致...