您的位置:首页 > 其它

leetcode-33 Search in Rotated Sorted Array

2015-09-19 21:17 441 查看
问题描述:

Supposea 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 arrayreturn its index, otherwise return -1.

You may assume no duplicate exists in the array.



问题分析:

问题表示有一个原来有序,后来在某一位置反转的数组,查找某个值;

该题很容易想到《剑指offer》中的求旋转数组的最小值的问题,这里要更简单一点,因为不用考虑重复值问题;

原题可以转化为先求取旋转数组的旋转位置,然后将旋转后的数组想象成一个循环右移一定位数的有序数组,进行二分查找即可;



代码:

public class Solution {
// 其实可以看做两个问题的组合,先找到反转位置,再进行二分查找
public intsearch(int[] nums, int target) {
if (nums.length == 0)
return -1;
return binarySearch(nums, 0, nums.length - 1, target,getRotateIndex(nums, 0, nums.length - 1));
}

// 找到反转的位置,即整个反转数组中的最小值
private int getRotateIndex(int[] nums, int start, int end) {
int mid = start;
while (start < end) {
mid = start + (end - start) / 2;
// 由于每个值都不同,中间值大于末尾值,则表示中间值位于前面的递增序列,则最小值一定在右半段中
if (nums[mid] > nums[end])
start = mid + 1;
else // 注意如果[mid]值小于[end],可能[mid]就是最小值,故end = mid;而不是mid - 1
end = mid;
}
return start;
}

// 二分查找
private intbinarySearch(int[] nums, int start, int end, int target, int index) {
int mid, read_mid;
while (start <= end) {
mid = start + (end -start) / 2;
// 这里涉及到一个技巧,将反转的数组想象成一个循环数组,则相当于把0-n位循环左移了index位(0移动到了index);
read_mid = (mid + index) % nums.length;
if (target == nums[read_mid])
return read_mid;
if (nums[read_mid] < target)
start = mid + 1;
else
end = mid - 1;
}
return -1;
}
}


运行结果:


 

 

拓展:

剑指Offer》 旋转数组的最小数字:

题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减序列的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
 
解题思路:
遍历的时间复杂度为O(n),性能较差;由于旋转数组是由两个递增数组(当旋转元素个数为0时,只有一个递增数组,要特殊处理此特殊情况)组成。
采用二分查找(双指针法)可以有效地优化时间复杂度;
情况一:
对于{3,4,5,1,2},采用双指针法,中间元素[mid]的值如果在前面的递增序列,则[mid]一定不小于[start];故可以缩小查找的范围:将start挪至mid处,因为最小值即为两个递增数组的分界点;
情况二:
对于{4,5,1,2,3},[mid]处于后面的递增序列,则[mid]一定不大于[end];此时可以缩小查找范围:将end挪至mid处
情况三:
此为特殊情况需要考虑:{2,2,2,2,1,2},此时[mid],[start],[end]值相同,无法判断是向左还是向右缩小窗口;故只能采取遍历的方法找到最小值;
情况四:
特殊情况:即0个元素反转时,此时应当满足[start]<[end](等于的情况可以认为已经做了反转),直接输出首元素即可;
 
代码

public class Solution {
public int minNumberInRotateArray(int [] array){
if (array.length == 0)
return 0;
int result = 0;

int start = 0, end = array.length - 1;
int mid = start;
while (array[start] >= array[end]) {
// 处理start = 2,end = 3,这种特殊情况

if (end - start <= 1) {
mid= end;
break;
}

mid= start + (end - start) / 2;
// 如果出现头指针和尾指针,以及中间指针三个数字相同的情况,则需要顺序遍历
if ((array[start] ==array[mid])&&(array[end] == array[mid])){
result= array[start];
for (int i = start + 1; i <= end; i++) {
if (array[i] < result) {
result= array[i];
}
}
return result;
}

// 中间元素在左边递增序列中的情况
if (array[mid] >= array[start])
start= mid;
if (array[mid] <= array[end])
end= mid;
}
return array[mid];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: