题干: https://leetcode.com/problems/search-in-rotated-sorted-array/
这题要求搜索的时间复杂度在O(log(n)),很显然的一点是,如果做普通的排序数组的二分搜索,那么这个复杂度完全没问题,只不过现在有一点不同,就是那个pivot是从哪个index开始的是unknown的,这是题干所强调的。
假设这个pivot能在O(log(n))复杂度内找出来,那么剩下的就是二分搜索了,所以整体的时间复杂度就可以控制在O(log(n))内
这就是一个最直观的思路。
我这里人为定义一个pivot index如下:如果nums[k]<nums[k-1], 那么就称k为pivot index, 可以简单看出,这样的k在数组有翻转的情况下,有且仅有1个,在数组无翻转的情况下,不存在!
那么怎样在O(log(n))内找到k呢?
想想大概也知道,二分搜索嘛。不过这里面index的边界trick非常多,要十分注意,小心检查。
我这里隐约感觉我这个做法不是最直观的,应该有其他等价但看起来更优雅的代码,大家可以自己去找。
好了,上代码:
package com.example.demo.leetcode;
public class RotatedSorted {
public int search(int[] nums, int target) {
if(nums.length<1){
return -1;
}
if(nums.length==1){
return target==nums[0]?0:-1;
}
int pivot = findPivotIndex(nums, 0, nums.length-1);
System.out.println("pivot is: "+ pivot);
if(pivot==-1){
// already in order
return binarySearch(nums, 0, nums.length-1, target);
}
if(target<nums[0]){
// search int the right part, pivot~nums.length-1
return binarySearch(nums, pivot, nums.length-1, target);
}else{
// search in the left part 0~pivot-1
return binarySearch(nums, 0, pivot-1, target);
}
}
private int findPivotIndex(int[] nums, int startIndex, int endIndex){
if(endIndex<=startIndex){
//至少要有两个元素,才好做这种操作
return -1;
}
if(endIndex-startIndex==1){
if(nums[0]>nums[1]){
return 1;
}else{
return -1;
}
}
int leftIndex = startIndex;
int rightIndex = endIndex;
// find the index k that nums[k-1]>nums[k] and nums[k1+1]>nums[k]
int midIndex = (leftIndex+rightIndex)/2;
while(true){
if(leftIndex>rightIndex){
return -1;
}
if(midIndex>0 && nums[midIndex]<nums[midIndex-1]){
// matched
return midIndex;
}
if(nums[startIndex]<=nums[midIndex]){
//处于左连续段,往右侧去搜吧
leftIndex = midIndex+1;
midIndex = (leftIndex+rightIndex)/2;
}else{
//处于右连续段,往左侧去搜吧,包括自己
rightIndex = midIndex;
midIndex = (leftIndex+rightIndex)/2;
}
// System.out.println("left: "+ leftIndex+",mid:"+midIndex+",right:"+rightIndex);
}
}
private int binarySearch(int[] nums, int startIndex, int endIndex, int target){
if(startIndex>endIndex){
return -1;
}
if(startIndex==endIndex){
return nums[startIndex]==target?startIndex:-1;
}
int midIndex = (startIndex+endIndex)/2;
if(target==nums[midIndex]){
return midIndex;
}else if(target>nums[midIndex]){
return binarySearch(nums, midIndex+1, endIndex, target);
}else{
return binarySearch(nums, startIndex, midIndex-1, target);
}
}
public static void main(String[] args) {
//边界条件: nums为空
// int[] nums = {4,5,6,7,0,1,2};
// int[] nums = {4,5,6,7,0,1,2};
// int[] nums = {1,3};
int[] nums = {3,5,1};
int target = 1;
RotatedSorted demo = new RotatedSorted();
int ret = demo.search(nums, target);
System.out.println(ret);
}
}
反思:这题出的不怎么好,从leetcode的test case来看,是允许存在未经旋转的排序数组的,也允许出现空数组,但是题干中都没有提到,导致我出了一些边角条件的问题,shit~