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、第一次先找到数组中最大值所在的位置:

(1)如果是单调递增区间,最大值就在右端点。

(2)如果是有旋转点的区间:中点值如果比左端点值小的话,说明最大值在左半部分,中点值如果比左端点的值大的话,说明最大值在右半部分。不断重复该过程,直至找到最大值位置。

2、第二次找目标值位置:如果目标值的大小处于左端点与旋转点值之间,那么就对旋转点左半部分的递增区间进行二分查找,找到目标值。如果目标值的大小在旋转点值与右端点值之间,那么就对旋转点右半部分的递增区间进行二分查找,直至找到目标值。如果找不到的话返回-1。

class Solution {
public:
int search(vector<int>& nums, int target) {
	if (nums.empty()) return -1;
	int l = 0, r = nums.size() - 1, l1, r1, flag = -1; //flag记录数组中最大值坐标
	while (l < r){
		if (nums[l] <= nums[r]) break;//单调递增区间,直接跳出循环,右端点r就是最大值索引
		else{                         //有旋转点的区间,一直等到循环结束,l是最大值索引
			int mid = l + (r - l) / 2;
			if (nums[mid] > nums[l])  
				l = mid;
			else  if (nums[mid] <= nums[l]) 
				r = mid-1;
		}
	}
	flag = (l < r ? r : l);  
	if (target >= nums[0]){ //目标值落在左半递增区间
		l1 = 0;
		r1 = flag;
	}
	if (target < nums[0]){//目标值落在右半递增区间
		l1 = flag + 1;
		r1 = nums.size() - 1;
	}
	while (l1 <= r1){//在递增区间内使用二分查找找到目标值
		int mid1 = l1 + (r1 - l1) / 2;
		if (nums[mid1] > target)
			r1 = mid1 - 1;
		if (nums[mid1] < target)
			l1 = mid1 + 1;
		if (nums[mid1] == target)
			return mid1;   
	}
	return -1;//如果找不到的话返回-1
}
};

猜你喜欢

转载自blog.csdn.net/Scarlett_Guan/article/details/80023207