题目及测试
package pid033;
/*搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。
搜索一个给定的目标值,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
你可以假设数组中不存在重复的元素。
你的算法时间复杂度必须是 O(log n) 级别。
示例 1:
输入: nums = [4,5,6,7,0,1,2], target = 0
输出: 4
示例 2:
输入: nums = [4,5,6,7,0,1,2], target = 3
输出: -1
*/
public class main {
public static void main(String[] args) {
int[][] testTable1=new int[][]{{4,5,6,7,0,1,2},{5,1,3}};
int[] testTable2=new int[]{0,4};
for(int i=0;i<testTable1.length;i++){
test(testTable1[i],testTable2[i]);
}
}
private static void test(int[] ito1, int ito2) {
Solution solution = new Solution();
int rtn;
long begin = System.currentTimeMillis();
rtn = solution.search(ito1,ito2);//执行程序
long end = System.currentTimeMillis();
System.out.print(rtn);
System.out.println();
System.out.println("耗时:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
解法1(成功,26ms,超慢)
同样使用二分查找法,只是每次的判断的结果start还是end变成mid+-1的条件不同
如果startvalue<endvalue说明处于上升序列,类似于二分查找即可
如果>= ,则中间有一个下降的悬崖,然后根据各个value的大小,确定target在左边还是右边,
注意如果target<startvalue但是大于endvalue说明target不存在
package pid033;
import java.util.HashMap;
public class Solution {
public int search(int[] nums, int target) {
int length=nums.length;
if(length<=0){
return -1;
}
int start=0;
int end=length-1;
while(start<=end){
int mid=(start+end)/2;
int startValue=nums[start];
int endValue=nums[end];
int midValue=nums[mid];
if(midValue==target){
return mid;
}
//头尾处于一条上升的线,按普通的二分查找
if(startValue<=endValue){
if(midValue>target){
end=mid-1;
continue;
}
else{
start=mid+1;
continue;
}
}
//头尾中间包含下降的那部分
else{
//前半部分长
if(midValue>=startValue){
//target 处于mid 和中间的max之间,或者target处于max和end之间
if(midValue<target||endValue>=target){
start=mid+1;
continue;
}
//target处于start和mid之间
if(startValue<=target&&target<midValue){
end=mid-1;
continue;
}
return -1;
}
//后半部分长
else{
if(midValue>target||startValue<=target){
end=mid-1;
continue;
}
if(midValue<target&&endValue>=target){
start=mid+1;
continue;
}
return -1;
}
}
}
return -1;
}
}
解法2(成功,0ms,极快)
先将target与nums[0]进行比较,得到target在前半段还是后半段,然后进行二分查找,将now与nums[0]进行判断,判断now在前半段还是后半段,如果不是target对应的波段,直接缩小范围,如果是target对应的波段,直接安装二分查找的方法进行查找。
public int search(int[] nums, int target) {
int length=nums.length;
if(length==0){
return -1;
}
if(nums[0]==target){
return 0;
}
// 第一个元素的值,分割线
int first=nums[0];
int begin=0;
int end=length-1;
if(nums[0]<target){
// target一定在前半段
while(begin<=end){
int mid=(begin+end)/2;
int now=nums[mid];
if(now<first){
// now在后半段
end=mid-1;
continue;
}
// 现在now在前半段,进入二分查找的逻辑
if(now==target){
return mid;
}else if(now>target){
end=mid-1;
}else{
begin=mid+1;
}
}
}else{
// target一定在后半段
while(begin<=end){
int mid=(begin+end)/2;
int now=nums[mid];
if(now>=first){
// now在前半段
begin=mid+1;
continue;
}
// 现在now在后半段,进入二分查找的逻辑
if(now==target){
return mid;
}else if(now>target){
end=mid-1;
}else{
begin=mid+1;
}
}
}
return -1;
}