1. 程式人生 > 實用技巧 >leetcode hot 100-33. 搜尋旋轉排序陣列

leetcode hot 100-33. 搜尋旋轉排序陣列

33. 搜尋旋轉排序陣列

給你一個升序排列的整數陣列 nums ,和一個整數 target 。

假設按照升序排序的陣列在預先未知的某個點上進行了旋轉。(例如,陣列[0,1,2,4,5,6,7]可能變為[4,5,6,7,0,1,2] )。

請你在陣列中搜索target ,如果陣列中存在這個目標值,則返回它的索引,否則返回-1。

示例 1:

輸入:nums = [4,5,6,7,0,1,2], target = 0
輸出:4

示例2:

輸入:nums = [4,5,6,7,0,1,2], target = 3
輸出:-1

示例 3:

輸入:nums = [1], target = 0
輸出:-1

提示:

1 <= nums.length <= 5000
-10^4 <= nums[i] <= 10^4
nums 中的每個值都 獨一無二
nums 肯定會在某個點上旋轉
-10^4 <= target <= 10^4

思路一:暴力法

遍歷陣列,分別判斷每個元素是否等於target

複雜度分析:

時間複雜度:O(n)。沒有利用陣列部分有序的特點,遍歷了整個陣列,所以時間複雜度為O(n)。 空間複雜度:O(1)。

思路二:三次二分查詢

二分法找到旋轉點,實現思路可以參考:劍指offer 6.旋轉陣列的最小數字 & 劍指 Offer 11. 旋轉陣列的最小數字

接下來二分法在前半段有序陣列區間中找target;

如果在前半段區間沒找到,則二分法在後半段有序陣列區間中找target;

都沒找到, 返回-1

 1 class Solution {
 2     public int search(int[] nums, int target) {
 3 
 4         int len = nums.length;
 5         // 二分法找到旋轉點
 6         int rotate = 0;
 7         int left = 0, right = len - 1, mid;
 8         while(left < right){
 9             mid = (left + right) / 2
; 10 if(nums[mid] > nums[right]){ // 說明mid在前半段區間中 11 left = mid + 1; 12 }else if(nums[mid] < nums[right]){ // 說明mid在後半段區間中 13 right = mid; 14 }else{ 15 right--; // 無法確定mid在哪個區間,right-- 16 } 17 } 18 rotate = left; 19 System.out.println(rotate); 20 // 二分法在前半段有序陣列區間中找target 21 left = 0; 22 right = rotate - 1; 23 while(left <= right){ 24 mid = (left + right) / 2; 25 if(target > nums[mid]){ 26 left = mid + 1; 27 }else if(target < nums[mid]){ 28 right = mid - 1; 29 }else{ 30 return mid; 31 } 32 } 33 // 二分法在後半段有序陣列區間中找target 34 left = rotate; 35 right = len - 1; 36 while(left <= right){ 37 mid = (left + right) / 2; 38 if(target > nums[mid]){ 39 left = mid + 1; 40 }else if(target < nums[mid]){ 41 right = mid - 1; 42 }else{ 43 return mid; 44 } 45 } 46 47 // 都沒找到, 返回-1 48 return -1; 49 } 50 }
leetcode 執行用時:4 ms > 15.28%, 記憶體消耗:37.8 MB > 92.01%

複雜度分析:

時間複雜度:O(logn)。三個迴圈,都是二分查詢,所以時間複雜度為O(3logn), 在陣列重複元素很多時,第一個迴圈查詢旋轉點因為無法判斷當前元素屬於前後哪個區間,使用rigiht-1來處理,所以可能退化成O(n)的複雜度,但是因為題目說明了陣列元素不重複,所以這個演算法的複雜度並不會退化成O(n)。 空間複雜度:O(1)。

思路二:只需一次二分查詢

思路參考:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/duo-si-lu-wan-quan-gong-lue-bi-xu-miao-dong-by-swe/

 1 class Solution {
 2     public int search(int[] nums, int target) {
 3 
 4         int len = nums.length;
 5         // 二分法找到旋轉點
 6         // int rotate = 0;
 7         int left = 0, right = len - 1, mid;
 8         while(left <= right){
 9             mid = (left + right) / 2;
10             if(nums[mid] == target){
11                 return mid;
12             }
13             if(nums[mid] > nums[right]){ // 說明mid在前半段區間中
14                 // 判斷target在[left, mid)之間還是在[mid, right]之間
15                 if(target >= nums[left] && target < nums[mid]){
16                     right = mid - 1;
17                 }else{
18                     left = mid + 1;
19                 }
20             }else if(nums[mid] < nums[right]){  // 說明mid在後半段區間中
21                 // 判斷target在[mid, right],之間還是在[left, mid]之間
22                 if(target > nums[mid] && target <= nums[right]){
23                     left = mid + 1;
24                 }else{
25                     right = mid;
26                 }
27             }else{
28                 right--;
29             }
30         }
31         // 都沒找到, 返回-1
32         return -1;
33     }
34 }
leetcode 執行用時:0 ms > 100.00%, 記憶體消耗:37.8 MB > 90.36%

複雜度分析:

時間複雜度:O(logn)。只有一個二分查詢的迴圈,所以時間複雜度為O(logn), 在陣列重複元素很多時,查詢旋轉點因為無法判斷當前元素屬於前後哪個區間,使用rigiht-1來處理,所以可能退化成O(n)的複雜度,但是因為題目說明了陣列元素不重複,所以這個演算法的複雜度並不會退化成O(n)。 空間複雜度:O(1)。