There is an integer array nums sorted in ascending order (with distinct values).

Prior to being passed to your function, nums is rotated at an unknown pivot index k (0 <= k < nums.length) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]] (0-indexed). For example, [0,1,2,4,5,6,7] might be rotated at pivot index 3 and become [4,5,6,7,0,1,2].

Given the array nums after the rotation and an integer target, return the index of target if it is in nums, or -1 if it is not in nums.

Example 1:

Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

Example 2:

Input: nums = [4,5,6,7,0,1,2], target = 3
Output: -1

Example 3:

Input: nums = [1], target = 0
Output: -1

Constraints:

  • 1 <= nums.length <= 5000
  • -104 <= nums[i] <= 104
  • All values of nums are unique.
  • nums is guaranteed to be rotated at some pivot.
  • -104 <= target <= 104

Follow up: Can you achieve this in O(log n) time complexity?

在旋转有序数组中搜索。

整数数组 nums 按升序排列,数组中的值 互不相同 。

在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。

给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这题grandyang大神的解释我直接搬过来了,非常详细。注意二分找到mid的位置之后,其实左半边和右半边是有可能都是有序的,所以需要额外判断到底是动 start 还是动 end。跳出 while 循环之后,因为 while的条件是 start + 1 < end 所以跟 153,154 题类似,跳出 while 的时候满足 start < end。所以需要再判断 target 是否在 start 或者在 end。

时间O(logn)

空间O(1)

JavaScript实现

 1 /**
 2  * @param {number[]} nums
 3  * @param {number} target
 4  * @return {number}
 5  */
 6 var search = function(nums, target) {
 7     // corner case
 8     if (nums === null || nums.length === 0) return -1;
 9 
10     // normal case
11     let start = 0;
12     let end = nums.length - 1;
13     while (start + 1 < end) {
14         let mid = Math.floor(start + (end - start) / 2);
15         if (nums[mid] === target) {
16             return mid;
17         }
18         // if target is on the left side
19         if (nums[start] < nums[mid]) {
20             if (nums[start] <= target && target <= nums[mid]) {
21                 end = mid;
22             } else {
23                 start = mid;
24             }
25         }
26         // if target is on the right side
27         else {
28             if (nums[mid] <= target && target <= nums[end]) {
29                 start = mid;
30             } else {
31                 end = mid;
32             }
33         }
34     }
35     if (nums[start] === target) return start;
36     if (nums[end] === target) return end;
37     return -1;
38 };

 

Java实现一,while (start + 1 < end)

 1 class Solution {
 2     public int search(int[] nums, int target) {
 3         int start = 0;
 4         int end = nums.length - 1;
 5         // start + 1 < end
 6         // 举例,start - 0, end = 3
 7         // 中间隔了起码有start + 1和start + 2两个下标
 8         // 这样跳出while循环的时候,end < start
 9         // 才有了最后的两个特判
10         while (start + 1 < end) {
11             int mid = start + (end - start) / 2;
12             if (nums[mid] == target) {
13                 return mid;
14             }
15             // left half is increasing
16             if (nums[start] < nums[mid]) {
17                 if (nums[start] <= target && target <= nums[mid]) {
18                     end = mid;
19                 } else {
20                     start = mid;
21                 }
22             }
23             // right half is increasing
24             else {
25                 if (nums[mid] <= target && target <= nums[end]) {
26                     start = mid;
27                 } else {
28                     end = mid;
29                 }
30             }
31         }
32         if (nums[start] == target) {
33             return start;
34         }
35         if (nums[end] == target) {
36             return end;
37         }
38         return -1;
39     }
40 }

 

Java实现二,while (start <= end)

如果是 <= 则说明二分法的两端是闭区间 [start, end] ;如果写成start + 1 < end,其实是在start和end之间预留了两个空格,在跳出while循环后要额外判断。

 1 class Solution {
 2     public int search(int[] nums, int target) {
 3         int start = 0;
 4         int end = nums.length - 1;
 5         // start <= end最后跳出while循环的时候end < start
 6         // end和start是邻近的两个index,所以无需特判
 7         while (start <= end) {
 8             int mid = start + (end - start) / 2;
 9             if (target == nums[mid]) {
10                 return mid;
11             }
12             // 左半段是有序的
13             if (nums[start] <= nums[mid]) {
14                 // target 在这段里
15                 if (target >= nums[start] && target < nums[mid]) {
16                     end = mid - 1;
17                 } else {
18                     start = mid + 1;
19                 }
20                 // 右半段是有序的
21             } else {
22                 if (target > nums[mid] && target <= nums[end]) {
23                     start = mid + 1;
24                 } else {
25                     end = mid - 1;
26                 }
27             }
28         }
29         return -1;
30     }
31 }

 

LeetCode 题目总结