假设按照升序排序的数组在预先未知的某个点上进行了旋转。
( 例如,数组 [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
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
这个题需要用到递归,对于一个旋转过后的排序数组,从中间分开,至少有一半是有序的,对于左右两个序列,通过判断左端点和右端点值的关系,可以确定其是否有序
- 对有序的部分,如果目标在上下界之间,二分搜索目标
- 如果不在范围内,表示值在无序的那边,对无序序列递归,继续将无序部分划分为有序+无序,继续搜索
递归思路
对于旋转过的排序数组,我们将他一分为三:
左边一坨,中间元素,右边一坨
-
判断中间元素是否等于目标,如果等于,就返回
-
如果左边有序,右边无序:
如果目标位于
左序列
上下界之间,对该序列二分搜索
如果没搜到,返回-1,因为在确定范围内未找到元素扫描二维码关注公众号,回复: 9529236 查看本文章如果目标不在上下界之间,对
右边
无序序列递归地划分为 有序+无序,转1 -
如果左边无序,右边有序:(执行2中的镜像操作)
如果目标位于
右序列
上下界之间,对该序列二分搜索
如果没搜到,返回-1,因为在确定范围内未找到元素如果目标不在上下界之间,对
左边
无序序列递归地划分为 有序+无序,转1
代码
class Solution {
public:
int bisearch(int l, int r, vector<int>& nums, int target)
{
if(l <= r)
{
int mid = l + (r-l)/2;
if(nums[mid] == target)
{
return mid;
}
// 左边有序
if(l<=mid-1 && nums[l]<=nums[mid-1])
{
// 目标在范围内
if(nums[l]<=target && target<=nums[mid-1])
{
// 直接二分
int res = lower_bound(nums.begin()+l, nums.begin()+mid-1, target) - nums.begin();
if(0<=res && res<nums.size() && nums[res]==target)
{
return res;
}
return -1;
}
else
{
// 目标不在范围内,递归划分,再搜索
return bisearch(mid+1, r, nums, target);
}
}
// 右边有序
else if(mid+1<=r && nums[mid+1]<=nums[r])
{
// 目标在范围内
if(nums[mid+1]<=target && target<=nums[r])
{
// 直接二分
int res = lower_bound(nums.begin()+mid+1, nums.begin()+r, target) - nums.begin();
if(0<=res && res<nums.size() && nums[res]==target)
{
return res;
}
return -1;
}
else
{
// 目标不在范围内,递归划分,再搜索
return bisearch(l, mid-1, nums, target);
}
}
}
return -1;
}
int search(vector<int>& nums, int target)
{
if(nums.size() < 1)
{
return -1;
}
return bisearch(0, nums.size()-1, nums, target);
}
};