题目:LeetCode(33)
设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [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
题解:
题目的意思是让我们在旋转数组中搜索一个给定值,若存在则返回这个值对应坐标,若不存在,则直接返回-1。仔细思考后,我们会发现它其实是二分查找的变种题,考虑二分搜索法,但是这道题的难点在于我们不知道原数组在哪旋转了,我们还是用题目中给的例子来分析,对于数组[0 1 2 4 5 6 7] 共有下列七种旋转方法:
[0 1 2 4 5 6 7]
[7 0 1 2 4 5 6]
[6 7 0 1 2 4 5]
[5 6 7 0 1 2 4]
[4 5 6 7 0 1 2]
[2 4 5 6 7 0 1]
[1 2 4 5 6 7 0]
观察结果:发现中间值>最右值时,左边有序;当中间值<最右值时,右边有序。所以我们只要在有序的半段里用首尾两个数组来判断目标值是否在这一区域内,这样就可以确定保留哪半边了。
int rotatedBinarySearch(int[] arr, int target){
// 最左侧元素下标
int left = 0;
// 最右侧元素下标
int right = arr.length - 1;
while(left <= right){
// 中间元素下标
int mid = left + (right - left) / 2;
if(arr[mid] == target){
return mid;
}
// 情况1:如果中间元素在旋转点左侧
if(arr[mid] >= arr[left]){
//target 如果位于中间元素的左侧
if(arr[mid] > target && target >= arr[left]){
right = mid - 1;
}else{
left = mid + 1;
}
}
// 情况2:中间元素在旋转点的右侧
else{
// target 如果位于中间元素的右侧
if(arr[mid] < target && target <= arr[right]){
left = mid + 1;
}else{
right = mid - 1;
}
}
}
return -1;
}