问题描述
题目要求: 给定一个有序的数组,已知这个数组在某个位置进行了扭转,(即[0,1,2,3,4,5] --> [3,4,5,0,1,2]类似操作),要求在logn时间内,找到给定的target对应的位置index
解题思路
首先找到pivot的位置,即找到数组中发生扭转的位置(即例子中0的位置index 3),有序题目要求是logn时间内完成,所以这个查找肯定是要用binary search的,然而不能用原版的binary search,每次确定midpoint的值后,判读那midpoint和right的值的大小,如果midpoint对应的值大于right对应的值,说明扭转点在midpoint的右侧,反之则说明在midpoint的左侧。最后跳出循环后left和right对应的位置就是pivot的位置了。
找到了pivot之后操作就变得简单了很多,由于pivot两边对应的数组都是有序的,所以首先判断target在哪边之后用binarysearch即可。
代码实现
public int search(int[] nums, int target) {
//首先排除特殊案例
if(nums == null || nums.length == 0) return -1;
//找到pivot的位置,即找到数组中最小元素的Index
int left = 0, right = nums.length - 1;
while(left < right) {
int midpoint = (left+right) / 2;
//如果中点的值比右侧的值小说明pivot在右半部分
if(nums[midpoint] > nums[right])
left = midpoint + 1;
else
//反之说明pivot在左半部分
right = midpoint;
}
//System.out.println(left);
//此时找到了pivot的位置即是left(跟right同一个位置)
int pivot = left;
left = 0;
right = nums.length - 1;
if(pivot >= 1 && target >= nums[left] && target <= nums[pivot - 1])
right = pivot - 1;
else
left = pivot;
while(left <= right) {
int midpoint = (left + right) / 2;
if(nums[midpoint] == target)
return midpoint;
else if(nums[midpoint] > target)
right = midpoint - 1;
else
left = midpoint + 1;
}
return -1;
}
复杂度分析:
时间复杂度:O(logn)
空间复杂度:O(1)
后记
这题考虑的是bianry Search的变种,一开始没什么思路,总想着一遍就找出结果。后来才发现可以先找到pivot的位置进行操作。