LeetCode 二分法在旋轉陣列應用系列

2021-10-22 12:23:38 字數 3170 閱讀 6686

這個系列整理一下旋轉陣列,就是原始單調不減陣列,在預先未知的某個下標 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。假設陣列中不存在重複項。陣列有序首選二分,但是題目中陣列並非完全有序,而是因為旋轉的原因導致...