Leetcode OJ: Search in Rotated Sorted Array I/II

对于有序数组进行查找我们可以用二分查找,可以参考我之前写的 Search Insert Position

但如果把这个排序的数组当成一个环,然后做一个旋转操作后再截断,再进行查找又会是什么情况呢?且看下文分解。

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

分成了两部分,而且是分别排序的,我们是不是也可以用二分呢?怎么用?先看看以下分析:

如果二分查找中的mid是落在左侧,则有A[mid] > A[begin] > A[end-1],否则有A[mid] < A[end - 1] < A[begin]

在我们确定是在哪一侧之后,那问题就变得简单了。

在左侧时,只需要比较target与A[begin];在右侧时,只需要比较target与A[end]。

具体代码吧:

 1 class Solution {
 2 public:
 3     int search(int A[], int n, int target) {
 4         int begin = 0, end = n;
 5         int mid;
 6         while (begin < end) {
 7             mid = begin + ((end - begin) >> 1);
 8             if (A[mid] == target)
 9                 return mid;
10             if (A[mid] > A[begin]) {
11                 if (A[mid] < target) {
12                     begin = mid + 1;
13                 } else {
14                     if (A[begin] < target)
15                         end = mid;
16                     else if (A[begin] > target)
17                         begin = mid + 1;
18                     else 
19                         return begin;
20                 }
21             } else {
22                 if (A[mid] > target) {
23                     end = mid;
24                 } else {
25                     if (A[end - 1] < target)
26                         end = mid;
27                     else if (A[end-1] > target)
28                         begin = mid + 1;
29                     else
30                         return end - 1;
31                 }
32             }
33         }
34         return -1;
35     }
36 };

对于这道题算是完美解决了,细心的同学们可能会发现这题的说明里面特意提到no duplicate,那如果有duplicate又怎样了?于是有了这题的变型:

Follow up for "Search in Rotated Sorted Array":
What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

Write a function to determine if a given target is in the array.

有重复元素又会怎样?我们上面解法的关键在于我们能区分得出mid点是在左侧还是右侧,那如果存在重复的元素呢?且看下图

当mid上的点与begin与end-1上的点都相等时,你无法判断是左侧还是右侧!

那怎么解决这个问题呢?我们想想,合并重复元素不就回到之前的问题了?

不过这里我们不用遍历一遍数组然后把重复的元素合并,一方面这样会破坏数组,另一方面,我们还有更高明的办法。

利用好排序的特点,我们只需要begin重复的往后移,end重复的往前移即可。且看代码:

 1 class Solution {
 2 public:
 3     bool search(int A[], int n, int target) {
 4         int begin = 0, end = n, mid;
 5         while (begin < end) {
 6             // 检测首尾重复的并移动
 7             while (begin < end - 1 && A[begin] == A[begin + 1])
 8                 ++begin;
 9             while (end > begin + 1 && A[end - 1] == A[end - 2])
10                 --end;
11             mid = begin + ((end - begin) >> 1);
12             if (A[mid] == target)
13                 return true;
14             if (A[mid] > A[begin]) {
15                 if (A[mid] < target) {
16                     begin = mid + 1;
17                 } else {
18                     if (A[begin] > target) {
19                         begin = mid + 1;
20                     } else if (A[begin] < target) {
21                         end = mid;
22                     } else {
23                         return true;
24                     }
25                 }
26             } else {
27                 if (A[mid] > target) {
28                     end = mid;
29                 } else {
30                     if (A[end - 1] > target) {
31                         begin = mid + 1;
32                     } else if (A[end - 1] < target) {
33                         end = mid;
34                     } else {
35                         return true;
36                     }
37                 }
38             }
39         }
40         return false;
41     }
42 };

转载于:https://www.cnblogs.com/flowerkzj/p/3619335.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值