题目

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]).

You are given a target value to search. If found in the array return true, otherwise return false.

Example 1:

  1. Input: nums = [2,5,6,0,0,1,2], target = 0
  2. Output: true

Example 2:

  1. Input: nums = [2,5,6,0,0,1,2], target = 3
  2. Output: false

Follow up:

  • This is a follow up problem to Search in Rotated Sorted Array, where nums may contain duplicates.
  • Would this affect the run-time complexity? How and why?

题意

将一非递减数列的随机后半部分与前半部分换位,得到新数组,在新数组中查找目标值。

思路

33. Search in Rotated Sorted Array 相比,允许数组中存在重复的值,这带来的问题是,很难根据一个元素与最左侧元素的大小关系来判断它是落在左区间还是右区间,如数组 [2, 2, 2, 3, 4, 5, 2, 2]。

因此在 33. Search in Rotated Sorted Array 解法的基础上做出改动:只有当nums[mid]与nums[left]存在严格的大于小于关系时,才能确定mid是落在左区间还是右区间,而当nums[mid]等于nums[left]时,因为无法有效判断区间归属,只能令left右移(或者right左移)。在最坏情况下(全元素一样),时间复杂度退化至$O(N)$。


代码实现

Java

  1. class Solution {
  2. public boolean search(int[] nums, int target) {
  3. if (nums.length == 0) {
  4. return false;
  5. }
  6. int left = 0, right = nums.length - 1;
  7. while (left <= right) {
  8. int mid = (left + right) / 2;
  9. if (nums[mid] == target) {
  10. return true;
  11. }
  12. // 只有严格的大于小于关系才能明确判断落在左区间还是右区间
  13. if (nums[mid] > nums[left]) {
  14. if (target >= nums[left] && target < nums[mid]) {
  15. right = mid - 1;
  16. } else {
  17. left = mid + 1;
  18. }
  19. } else if (nums[mid] < nums[left]) {
  20. if (target <= nums[right] && target > nums[mid]) {
  21. left = mid + 1;
  22. } else {
  23. right = mid - 1;
  24. }
  25. } else {
  26. left++;
  27. }
  28. }
  29. return false;
  30. }
  31. }

JavaScript

  1. /**
  2. * @param {number[]} nums
  3. * @param {number} target
  4. * @return {boolean}
  5. */
  6. var search = function (nums, target) {
  7. let left = 0, right = nums.length - 1
  8. while (left <= right) {
  9. let mid = Math.trunc((right - left) / 2) + left
  10. if (nums[mid] == target) {
  11. return true
  12. }
  13. if (nums[mid] > nums[left] && target >= nums[left] && target < nums[mid]) {
  14. right = mid - 1
  15. } else if (nums[mid] > nums[left]) {
  16. left = mid + 1
  17. } else if (nums[mid] < nums[left] && target <= nums[right] && target > nums[mid]) {
  18. left = mid + 1
  19. } else if (nums[mid] < nums[left]) {
  20. right = mid - 1
  21. } else {
  22. left++
  23. }
  24. }
  25. return false
  26. }