【二分查詢】力扣81:搜尋旋轉排序陣列 II
已知存在一個按非降序排列的整數陣列 nums ,陣列中的值不必互不相同。
在傳遞給函式之前,nums 在預先未知的某個下標 k(0 <= k < nums.length)上進行了 旋轉 ,使陣列變為 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下標 從 0 開始 計數)。例如, [0,1,2,4,4,4,5,6,6,7] 在下標 5 處經旋轉後可能變為 [4,5,6,6,7,0,1,2,4,4] 。
給你 旋轉後 的陣列 nums 和一個整數 target ,請你編寫一個函式來判斷給定的目標值是否存在於陣列中。如果 nums 中存在這個目標值 target ,則返回 true ,否則返回 false 。
你必須儘可能減少整個操作步驟。
進階:這是 搜尋旋轉排序陣列 的延伸題目,本題中的 nums 可能包含重複元素。這會影響到程式的時間複雜度嗎?會有怎樣的影響,為什麼?
示例:
輸入:nums = [2,5,6,0,0,1,2], target = 0
輸出:true
將陣列一分為二,其中一定有一個是有序的,另一個可能是有序,也能是部分有序。此時有序部分用二分法查詢。無序部分再一分為二,其中一個一定有序,另一個可能有序,可能無序。就這樣迴圈.
即使陣列被旋轉過,我們仍然可以利用這個陣列的遞增性,使用二分查詢。對於當前的中點,如果它指向的值小於等於右端,那麼說明右區間是排好序的;反之,那麼說明左區間是排好序的。如果目標值位於排好序的區間內,我們可以對這個區間繼續二分查詢;反之,我們對於另一半區間繼續二分查詢。
注意:
class Solution: def search(self, nums: List[int], target: int) -> bool: n = len(nums) low, high = 0, n - 1 while low <= high: mid = (low + high) // 2 if nums[mid] == target: # 只有此時才True return True # 如果中點和左端的數字相同,則不能確定是左區間全部相同,還是右區間完全相同。在這種情況下,可以簡單地將左端點右移一位,然後繼續進行二分查詢 elif nums[mid] == nums[low]: low += 1 elif nums[mid] <= nums[high]: # 右區間是升序 if nums[mid] < target and nums[high] >= target: # 如果在右區間範圍內就在右區間繼續二分查詢 low = mid + 1 else: # 如果不在就去左區間繼續找 high = mid - 1 else: # 左區間升序 if nums[mid] > target and nums[low] <= target: high = mid - 1 else: low = mid + 1 return False
力扣81基於力扣33 [搜尋旋轉排序陣列]。
整數陣列 nums 按升序排列,陣列中的值 互不相同 。
在傳遞給函式之前,nums 在預先未知的某個下標 k(0 <= k < nums.length)上進行了 旋轉,使陣列變為 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下標 從 0 開始 計數)。例如, [0,1,2,4,5,6,7] 在下標 3 處經旋轉後可能變為 [4,5,6,7,0,1,2] 。
給你 旋轉後 的陣列 nums 和一個整數 target ,如果 nums 中存在這個目標值 target ,則返回它的下標,否則返回 -1 。
示例:
輸入:nums = [4,5,6,7,0,1,2], target = 0
輸出:4
法1:
有了前面的思路,其實只需要把 return True
改為return mid
返回target的下標,False
改為-1
,即可。
法2比較有意思:
對於旋轉陣列 nums = [4,5,6,7,0,1,2]
首先根據 nums[0] 與 target 的關係判斷 target 是在左段還是右段。
例如 target = 5, 目標值在左半段,因此在 [4, 5, 6, 7, inf, inf, inf] 這個有序數組裡找就行了;
例如 target = 1, 目標值在右半段,因此在 [-inf, -inf, -inf, -inf, 0, 1, 2] 這個有序數組裡找就行了。
如此,我們又雙叒叕將「旋轉陣列中找目標值」 轉化成了「有序陣列中找目標值」
Java 程式碼
class Solution {
public int search(int[] nums, int target) {
int lo = 0, hi = nums.length - 1;
while (lo <= hi) {
int mid = lo + (hi - lo) / 2;
if (nums[mid] == target) {
return mid;
}
// 先根據 nums[0] 與 target 的關係判斷目標值是在左半段還是右半段
if (target >= nums[0]) {
// 目標值在左半段時,若 mid 在右半段,則將 mid 索引的值改成 inf
if (nums[mid] < nums[0]) {
nums[mid] = Integer.MAX_VALUE;
}
} else {
// 目標值在右半段時,若 mid 在左半段,則將 mid 索引的值改成 -inf
if (nums[mid] >= nums[0]) {
nums[mid] = Integer.MIN_VALUE;
}
}
if (nums[mid] < target) {
lo = mid + 1;
} else {
hi = mid - 1;
}
}
return -1;
}
}
作者:sweetiee
連結:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/duo-si-lu-wan-quan-gong-lue-bi-xu-miao-dong-by-swe/
法3:(暴力解法)一行程式碼
參透本質,可以看出如果target不在nums裡肯定返回的是-1。在的話返回的就是它的下標(而且nums裡的值是互不相同的)。Python說:返回下標我熟呀,所以有nums.index(target)。結束。
作者:NfEOaSTGYy
連結:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/by-nfeoastgyy-kagi/
class Solution:
def search(self, nums: List[int], target: int) -> int:
return nums.index(target) if target in nums else -1
作者:zhsama
連結:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/pythonyi-xing-jie-jue-by-zhsama-c98f/