您的位置:首页 > 其它

leetcode 33. Search in Rotated Sorted Array

2017-10-27 23:31 387 查看

原题描述

Suppose an array sorted in ascending order 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.


翻译

假定一个数组在一个我们预先不知道的轴点旋转。
例如,0 1 2 4 5 6 7可能会变为4 5 6 7 0 1 2。
给你一个目标值去搜索,如果找到了则返回它的索引,否则返回-1。
你可以假定没有重复的元素存在于数组中。


分析思路

这个题看起来就是个二分查找的变形,所以思考下能否使用二分查找。

首先可以确定这个旋转点pivot会有三种情况:

在mid处

在mid左侧

在mid右侧

[b]旋转点在mid左侧[/b]

情况1可以不考虑,因为target如果就是等于mid,二分查找肯定能找到了。情况2和3的分布和各部分对应大小关系可以见图1和图2。



先看看情况1,这是pivot位于mid左侧的情况,这时考虑target落在mid右边比较简单。而target要想落在mid右侧,则必须满足以下条件:

nums[mid]<target<=nums[rear]

再看看如果target不幸落入mid左边怎么办,落入左边,pivot其实仍然是三种情况:

在mid处

在mid左侧

在mid右侧

又重复了以上分析,所以没什么问题,再看看情况3.

[b]旋转点在mid右侧[/b]

很明显,如果pivot在mid右侧,那么pivot及其后面所有元素都要比nums[head]小,另外pivot及其后面所有元素也要比nums[mid]小。这个时候和旋转点在mid左侧一样,我们考虑target落在mid左侧更简单,需要满足的条件是:

nums[head]<=target<nums[mid]

所以,分析到这里使用二分查找完全可行,以下是代码。

代码

class Solution {
public int search(int[] nums, int target) {
int head = 0;
int rear = nums.length - 1;

while(head <= rear){
int mid = (head+rear)/2;
if(target == nums[mid]){
return mid;
} else if(nums[mid] < nums[rear]){  //根据以上分析,满足该条件则说明pivot在mid左侧
//target在右侧
if(nums[mid]<target && target<=nums[rear])
head = mid + 1;
else
rear = mid - 1;
} else {    //pivot在mid右侧
//target在左侧
if(nums[head]<=target && target<nums[mid])
rear = mid - 1;
else
head = mid + 1;
}
}
return -1;
}
}


扩展

该题我们一直在避开pivot,但还可以扩展一下:如何找到该旋转点的位置pivot?

这个题也是类似上面的分析,稍微有点区别的地方在于,通过什么样的标准来判断这个pivot。其实我们可以从图1图2看出,pivot需要满足的条件:

{nums[pivot−1]<nums[pivot]} && {nums[pivot]<nums[pivot+1]}

也就是说pivot的左右都比它大。

[b]代码[/b]

public static int search(int[] arr) {
int head = 0;
int rear = arr.length - 1;

while (head <= rear) {
int mid = (head + rear) / 2;

boolean isPivot = false;
//考虑两个边界条件
if (mid == 0)
isPivot = arr[mid] > arr[mid + 1];
else if (mid == arr.length - 1)
isPivot = arr[mid - 1] > arr[mid];
else
isPivot = arr[mid - 1] > arr[mid] && arr[mid] < arr[mid + 1];

if (isPivot) {
return mid;
} else if (arr[mid] < arr[rear]) {//pivot在mid左侧
rear = mid - 1;
} else {//pivot在mid右侧
head = mid + 1;
}
}
return 0;
}


这个扩展题当然直接通过遍历是最简单的,但是事件复杂度是O(n),而使用二分查找的思想,则时间复杂度是O(lgn)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode 算法