leetcode hot 100-33. 搜尋旋轉排序陣列
阿新 • • 發佈:2020-11-02
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) / 2leetcode 執行用時:4 ms > 15.28%, 記憶體消耗:37.8 MB > 92.01%; 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 }
複雜度分析:
時間複雜度:O(logn)。三個迴圈,都是二分查詢,所以時間複雜度為O(3logn), 在陣列重複元素很多時,第一個迴圈查詢旋轉點因為無法判斷當前元素屬於前後哪個區間,使用rigiht-1來處理,所以可能退化成O(n)的複雜度,但是因為題目說明了陣列元素不重複,所以這個演算法的複雜度並不會退化成O(n)。 空間複雜度:O(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] == 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%