前言
歡迎關注我的 Github 倉庫 https://github.com/bigrotor187/awesome-java-notes ,如果覺得有幫助,請點個 star
喲,目前主要在更 leetcode題解(Java版)
和 劍指offer題解(Java版)
,可以點個star
。
文本已收錄至我的GitHub倉庫,歡迎Star:awesome-java-notes
33. Search in Rotated Sorted Array
Description
假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。
搜索一個給定的目標值,如果數組中存在這個目標值,則返回它的索引,否則返回 -1 。
你可以假設數組中不存在重複的元素。
你的算法時間複雜度必須是 O(log n) 級別。
Example 1:
輸入: nums = [4,5,6,7,0,1,2],
target = 0
輸出: 4
Example 2:
輸入: nums = [4,5,6,7,0,1,2],
target = 3
輸出: -1
Example 3:
輸入:head = [1], pos = -1
輸出:no cycle
解釋:鏈表中沒有環。
Tags: Array, Binary Search
思路 0
參考這裏
循環鏈表中存在這樣一個性質(事實):將數組從中間點劈開,會將數組分成兩部分,分別是循環有序數組
部分和有序數組
部分。
爲了找到目標元素 target
,我們可以先找到數組的有序部分,然後再判斷目標元素是否在有序數組部分中。
- 如果首元素小於中間元素
mid
,那麼前半部分是有序的,後半部分是循環有序數組(如 4 5 6 7 8 1 2 3); - 如果首元素大於中間元素
mid
,那麼後半部分是有序的,前半部分是循環有序數組(如 5 6 1 2 3 4); - 如果
target
在有序數組部分中,則對有序部分使用二分查找; - 如果目標元素在循環有序數組中,則重新設定數組邊界後,重複上述步驟。
注 上述中,將數組 4 5 6 7 8 1 2 3 從中間元素 7(mid = 3) 劈開後分成了 4 5 6 的有序數組部分以及 8 1 2 3 的循環有序數組部分。
時間複雜度: O(logn)
空間複雜度: O(1)
public int search(int[] nums, int target) {
int start = 0;
int end = nums.length - 1;
while (start <= end) {
int mid = start + ((end - start) >> 2);
if (target == nums[mid]) {
return mid;
}
// 前面部分有序
// 千萬要注意這裏的條件是 `nums[start] <= nums[mid]`,而不是 `nums[start] < nums[mid]`
if (nums[start] <= nums[mid]) {
if (target >= nums[start] && target < nums[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
// 後半部分有序
} else {
if (target > nums[mid] && target <= nums[end]) {
start = mid + 1;
} else {
end = mid - 1;
}
}
}
return -1;
}
結語
如果你同我一樣想要征服數據結構與算法、想要刷 LeetCode,歡迎關注我 GitHub 上的 LeetCode 題解:awesome-java-notes