题目描述:
假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路:
这个题目要求算法时间复杂度必须是 O(log n) 级别,其实就是间接地要求使用二分法解题。
首先来复习一下二分法:
设定一个低序坐标low指向有序数组的第一个元素,一个高序坐标high指向有序数组的最后一个元素,middle指向low和high的中间位置,即middle=low+(low+high)/2,如果middle位置的数大于target的数,说明target的数在low和middle之间的位置,把(middle-1)设为新的high;如果middle位置的数小于target的数,说明target的数在middle和high之间的位置,把(middle+1)设为新的low。通过这样的一步就能把长度缩短一半,重复这一步,如果找到middle位置的数就是target,就直接返回middle;如果当high<low时仍未找到target,说明数组中不存在target。
代码(Java):
public static int binarySearch(int[] nums, int target) {
int ans = -1;
int low = 0;
int high = nums.length-1;
int middle = 0;
while(high>=low) {
middle = low + (high - low)/2;
if(nums[middle]==target) {
ans = middle;
}
if(nums[middle]>=target) {
high = middle - 1;
}else if (nums[middle]<=target) {
low = middle + 1;
}
}
return ans;
}
再看这个题目,其实很容易被旋转之后的数组迷惑。同样地,可以设置low,high,middle来将数组分成两个部分,其中一个部分必然是有序的,另一个部分是无序的,target在不在无序的部分不好判断,但是在不在有序的部分里面还是好判断的(假设数组里面有target),只要target大于有序部分的第一个数,而且小于有序部分的最后一个数,就说明target在有序的部分里面,否则,target就是在无序的部分,再根据现实情况,执行high = middle-1或者low = middle+1;执行第二次循环的时候,再次根据middle分割数组,同样是分为有序和无序的两个部分,和前面的操作一样。这样就和普通的二分法联系起来了。
代码(Java):
public class doingmyself {
public static void main(String[] args) {
int[] nums = new int[] {4,5,6,7,0,1,2};
System.out.println(search(nums, 3));
}
public static int search(int[] nums, int target) {
int low = 0; //low表示二分法里面目标值所在范围的头坐标
int high = nums.length-1; //high表示二分法里面目标所在范围的尾坐标
int middle = 0; //用mid表示数组中间那个数的坐标
while(low<=high) {
middle = low + (high-low)/2; //同样第二次执行循环的时候,也是将剩下的范围劈成两部分,一部分是有序的,另一部分是无序的
if(target == nums[middle]) {
return middle;
}
if(nums[low]<=nums[middle]) { //表示第一部分是有序的
if(target<=nums[middle] && target>=nums[low]) { //表示目标值在有序的这部分
high = middle-1;
}else { //表示目标在另一部分
low = middle+1;
}
}else { //第二部分是有序的
if(target>=nums[middle] && target<=nums[high]) { //表示目标值在有序的这部分
low = middle+1;
}else { //表示目标在另一部分
high = middle-1;
}
}
}
return -1;
}
}