参考文章:
1 . LeetCode 中级 - 搜索旋转排序数组
https://blog.csdn.net/whdAlive/article/details/80432797
https://www.cnblogs.com/ariel-dreamland/p/9138064.html
题目描述:
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [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
对于旋转排序,我们写出更多的样例,来帮助我们查找规律。
对于数组[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
由于数组是旋转排序的,本质上还是 一个有序数组有序数组搜索 或者 两个分别有序数组的排序,另外由于对时间查找上的效率有了一定的限制 O(log n) ,这里我们考虑二分法 + 分治法的 实现。
由于是分段有序的,我们对二分后的数组进行分类,分为
1.单调递增的序列
2.2个递增的序列
等2种情况。
对于单调递增的序列,首元素一定小于末尾元素 (容易判断)。
对于2个单调递增的序列,首元素一定大于末尾元素 ,再对中间值 与之后的查找划分 做一定的规律规划 ,有2种情况
情况1 : 突变点在前面, 情况2 :突变点在后面, 然后再对每种情况分别归纳。
最终代码如下:
package leetcode.medium;
/*
搜索旋转排序数组
假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [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
*/
/**
* Created by szh on 2019/2/26.
*
* @author szh
*/
public class NO33_Search_in_Rotated_Sorted_Array {
public int search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int start = 0;
int end = nums.length - 1;
int mid;
//TODO :
int ct = 0;
while (start <= end) {
mid = (start + end) / 2;
//TODO :
ct++;
System.out.println("ct : " + ct + ", start : " + start + ", end : " + end + ", middle : " + mid);
// if (nums[start] == target) {
// return start;
// }
// if (nums[end] == target) {
// return end;
// }
if (nums[mid] == target) {
return mid;
}
//有突变点 , 思路: 分治法
if (nums[start] > nums[end]) {
//相当于两个有两个递增序列
//情况1 : 突变点在前半部
if (nums[start] > nums[mid]) {
//前半部分搜索
// [5, 6, 7, 0, 1, 2, 4] find 7
if (target > nums[mid] && target > nums[end]) {
end = mid - 1;
}
// [5, 1, 2, 3, 4] find 1
else if (target < nums[mid] && target < nums[end]) {
end = mid - 1;
}
//后半部分搜索
else {
start = mid + 1;
}
}
//情况2 : 突变点在后半部
else {
//前半部分搜索 , 因为一定是单调递增的,转换为单调递增求解的问题
// [2, 4, 5, 6, 7, 0, 1] find 4
if (target < nums[mid] && target > nums[end]) {
end = mid - 1;
}
//后半部分搜索 两种情况,因为不是单调递增的
// [2, 4, 5, 6, 7, 0, 1] find 7
// target > nums[mid] && target > nums[start]
// [2, 4, 5, 6, 7, 0, 1] find 0
// target < nums[mid] && target < nums[start]
else {
start = mid + 1;
}
}
}
//无突变点,单调递增
else {
if (nums[mid] > target) {
end = mid - 1;
} else {
start = mid + 1;
}
}
}
return -1;
}
public static void main(String[] args) {
{
NO33_Search_in_Rotated_Sorted_Array tmpObj = new NO33_Search_in_Rotated_Sorted_Array();
int loc = tmpObj.search(new int[]{4, 5, 6, 7, 0, 1, 2}, 0);
System.out.println(loc);
}
{
NO33_Search_in_Rotated_Sorted_Array tmpObj = new NO33_Search_in_Rotated_Sorted_Array();
int loc = tmpObj.search(new int[]{5, 1, 2, 3, 4}, 1);
System.out.println(loc);
}
}
}