leetcode不按期刷題---33. 搜索旋轉排序數組

來源:力扣(LeetCode) 連接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array算法

題目概述

假設按照升序排序的數組在預先未知的某個點上進行了旋轉。
( 例如,數組 [0,1,2,4,5,6,7] 可能變爲 [4,5,6,7,0,1,2] )。
搜索一個給定的目標值,若是數組中存在這個目標值,則返回它的索引,不然返回 -1 。
你能夠假設數組中不存在重複的元素。
你的算法時間複雜度必須是 O(log n) 級別。
示例 1:數組

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

示例 2:code

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

題解:

在讀完一遍題目以後呢,大致的感受是從數組中找到指定值的位置返回,沒有的話就返回-1。
而後我就直接寫下了排序

var search = function(nums, target) {
     return nums.indexOf(target);
};

運行以後通了,提交以後也通了,執行時間68ms,內存消耗33.7MB。
完美的開始,不過在仔細審題以後,發現一個問題,題目要求複雜度必須是 O(log n)級別,那意思就是必須得使用二分法來作。那麼上面的答案就沒有意義了。
那麼從新開始思考。二分法很簡單,就是每次都二分數組,而後在符合條件的數組中進行下一步的二分查找。
將數組一分爲二以後,存在兩種可能,一邊是順序的,一邊是旋轉的,那麼就須要將target值與左右中間作間隔的值以及兩個數組的兩端值進行比較。從而判斷出要繼續在哪一個數組中繼續尋找。遞歸

實例
nums = [4,5,6,7,8,9,0,1,2], target = 0

第一步:取數組中間值,將數組一分爲二。

//設置初試下標值:
left=0;
right = nums.length;
mid = ~~((left + right)/2)
//二分數組那麼這個時候mid=4
[4,5,6,7] 
8 
[9,0,1,2]

第二步:mid值跟兩邊數組的首尾進行比較

存在如下幾種狀況索引

  • nums[mid] === target

中間值等於目標值,此時能夠直接返回mid內存

  • nums[mid]>target && nums[left] <= target

中間值比目標值target大而且左邊數組第一個值小於target,那麼說明左邊數組是存在旋轉的,而且目標值就在這個數組中,這個時候須要繼續在左邊數組中查找,這個時候left不變,right變成了mid-1;leetcode

  • nums[mid]<target && nums[right]>=target

中間值比目標值target小而且右邊數組最後一個值大於等於target,說明target值在右邊數組中,因此須要在右邊的數組中繼續查找。此時left變成了mid+1,right不變。get

  • nums[mid]<target && nums[right]<target
  • nums[mid]>target && nums[left] > target

這兩種狀況下,都是沒有肯定值在哪邊,因此講left+1或者right-1進行進一步的查找。
就這樣一步一步查找知道最終找到值。用遞歸能夠解決這個問題。io

因此代碼以下:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number}
 */
var search = function(nums, target) {
   var bs = (left,right)=>{
          const mid = ~~((left + right)/2);
          if(left > right)return - 1;
          if(nums[mid] === target){
              return mid;
          }else if(nums[mid]>target && nums[left] <= target){
              return bs(left,mid-1);
          }else if(nums[mid]>target && nums[left] > target){
              return bs(left+1,right);
          }else if(nums[mid]<target && nums[right]>=target){
              return bs(mid+1,right);
          }else if(nums[mid]<target && nums[right]<target){
              return bs(left,right-1);
          }
      };
      return bs(0,nums.length-1);
};
運行結果:
執行時間:68ms
內存消耗:33.9MB
相關文章
相關標籤/搜索