https://www.lingluan.vip
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
肯定是二分查找咯。那既二分查找,就需要通过不断变换左端点和右端点的值来进行求解。
这个题目其实在确定一个Mid后,我们会发现它总是会使得一半有序一半无序,那么我们就有依据nums[mid] >= nums[left]?来判断mid两边哪边是有序的,对于如果左半部分有序,则判断目标值是否介于nums[left]和nums[mid]之间 如果是的话,在这个区间上进行二分查找,否则他应介于右半部分区间内(如果存在),但是右半部分又是和大数组一样是不总是有序的,同上面的操作一样。 如果目标值nums[mid] < nums[left] ,说明mid右边有序,左边无序,接着判断target是否位于右边有序区间内,如果是则在右边有序区间内二分查找,否则在左边无序区间内查找。
一开始没有做出这道题的原因在于过分在意了二分查找的区间是否一定要有序,实际上即便不是真的完全有序,我们也可以做,普遍的做法是找中点-->中点将区间分为有序和无序区间-->判断目标值在哪一部分-->继续二分查找。
最终我们发现,只要能有分割条件,只要你的目标查找区间能够缩小,那么只是去类似递归的分割就好了,当最后只剩一个元素或者没有元素时,结果便有了。
package midlevel;
/**
*
*2020年8月24日下午3:37:11
*zms
*/
/**
* @author zms
*
*/
public class main33 {
/**
* @param args
*/
public static void main(String[] args) {
System.out.println(search(new int[]{4,5,6,7,0,1,2},3));
}
public static int search(int[] nums, int target) {
int len = nums.length;
int left = 0;
int right = len-1;
while(left < right){
//System.out.println(left+" "+right);
int mid = left + (right - left)/2;
if(nums[mid] == target) return mid;
if(nums[mid] >= nums[left]){
if(target <= nums[mid] && nums[left] <= target){
right = mid-1;
}else{
left = mid + 1 ;
}
}else{ //nums[mid] < nums[left]
if(target <=nums[right] && target >nums[mid]){
left = mid+1;
}else right = mid-1;
}
}
return nums[left] == target? left : -1;
}
}