題目描述
假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。
( 例如,陣列[0,0,1,2,2,5,6]
可能變為[2,5,6,0,0,1,2]
)。
編寫乙個函式來判斷給定的目標值是否存在於陣列中。若存在返回true
,否則返回false
。
示例 1:
輸入: nums = [2,5,6,0,0,1,2], target = 0
輸出: true
示例 2:
輸入: nums = [2,5,6,0,0,1,2], target = 3
輸出: false
高階:題解:參考 搜尋旋轉排序陣列 一題,這題增加了乙個條件:可以有重複值,這個條件有點麻煩。。。
還是用二分來搞定。
注意:二分不一定必須要有單調性,二分的本質是尋找某種性質的分界點。只要找到某種性質,可以確定目標在區間的前半部分還是後半部分,就可以用二分找到這個分界點。
為了便於分析,將陣列中的元素畫在二維座標系中,橫軸代表下標,縱軸代表值。
水平的實線表示相同的元素。可以發現,除了黑色水平那段,其餘部分均滿足二分性質:豎直的虛線左邊的元素均滿足arr
[i]>=a
rr[0
]arr[i]>=arr[0]
arr[i]
>=a
rr[0
],而虛線右邊(除了黑色部分)元素均滿足arr[i]
r[0]
arr[i]ar
r[i]
r[0]
。首先,我們需要把黑色的水平段刪除,至於為什麼刪除呢?考慮一種情況:arr
[mid
]==a
[0]arr[mid] == a[0]
arr[mi
d]==
a[0]
,這種情況下,根本不知道往哪邊走,所以只能刪除。
還需要處理陣列未旋轉的情況,當刪除黑色水平段後,若剩下的最後乙個元素大於等於arr[0],說明陣列完全單調。
最壞情況:元素均相等情況下的時間複雜度為o(n
)o(n)
o(n)
。法一:兩次二分。參考 在有序旋轉陣列中找到最小值 一題,如果我們可以找到分界點,就可以確定target
在左右哪個區間,然後直接在該區間上進行二分查詢即可。
把複雜問題分解成簡單的子問題思想很重要。
class
solution
int l =
0, r = n, m;
if( nums[0]
> nums[n])if
( target <= nums[n]
) r = n;
else l =0,
--r;
}while
( l < r )
return nums[r]
== target;}}
;/*記憶體:13.6mb,擊敗:29.95%
*/法二:
在二分過程中,通過一些條件判斷target
在哪個區間也行:
class
solution
int l =
0, r = n, m;
while
( l < r )
else
}return nums[r]
== target;}}
;/*記憶體:13.6mb,擊敗:30.23%
*/
法三:
直接掃瞄一遍nums
。。。
class
solution};
/*記憶體:13.6mb,擊敗:22.29%
*/
三種方法記憶體消耗簡直離譜。。。 81 搜尋旋轉排序陣列 II
假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。例如,陣列 0,0,1,2,2,5,6 可能變為 2,5,6,0,0,1,2 編寫乙個函式來判斷給定的目標值是否存在於陣列中。若存在返回 true,否則返回 false。示例 1 輸入 nums 2,5,6,0,0,1,2 target 0 輸...
81 搜尋旋轉排序陣列 II
假設按照公升序排序的陣列在預先未知的某個點上進行了旋轉。例如,陣列 0,0,1,2,2,5,6 可能變為 2,5,6,0,0,1,2 編寫乙個函式來判斷給定的目標值是否存在於陣列中。若存在返回 true,否則返回 false。示例 1 輸入 nums 2,5,6,0,0,1,2 target 0 輸...
81 搜尋旋轉排序陣列 II
題目.middle 這是乙個二分查詢的公升級版,我們可以認為,經過旋轉後分成了兩部分,left half和right half,所以每次根據mid所在的位置,淘汰掉一半的資料。千萬不要去尋找旋轉點。這樣會搞得很麻煩 package main import fmt func search nums i...