文章目录
- 力扣33.搜索旋转排序数组
- 题目描述
- 方法1:二分查找
力扣33.搜索旋转排序数组
题目描述
整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -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
示例 3:
输入:nums = [1], target = 0
输出:-1
提示:
1 <= nums.length <= 5000
-104 <= nums[i] <= 104
nums 中的每个值都 独一无二
题目数据保证 nums 在预先未知的某个下标上进行了旋转
-104 <= target <= 104
方法1:二分查找
-
题目特别要求时间复杂度应限制在O(logn)以内,并且输入的数组可以分成两部分的有序数组,所以我们想到应该用二分查找去解本题。
-
关键需要解决的问题是,我们需要找到一个分界点,这个分界点可以将原数组分成两个升序数组,然后才能对两部分升序数组各自使用二分查找来解题
-
对于分解位置k的查找,我们也需要使用二分查找来进行:破坏升序性的位置k一定存在于这样一个区间,即任意一个位置i,如果k存在于i到right之间,则必有nums[i]>nums[right];若k存在于left到i之间,则必有nums[i]<nums[left];据此我们可以判断每一次递归查找结束之后,下一次递归查找的区间范围。
int k,result;
void locateK(int * nums,int left,int right)//找出分界位置k
{
if(left>=right) return;
int mid=(right+left)/2;
if(nums[mid]>nums[mid+1])
{
k=mid;
return;
}
if(mid>=1&&nums[mid]<nums[mid-1])
{
k=mid-1;
return;
}
if(nums[left]>nums[mid])locateK(nums,left,mid-1);
if(nums[right]<nums[mid])locateK(nums,mid+1,right);
}
void BinarySearch(int *nums,int left,int right,int target)//进行二分查找
{
if(left>right) return ;
int mid=(right+left)/2;
if(nums[mid]==target)
{
result=mid;
return;
}
if(nums[mid]>target)
BinarySearch(nums,left,mid-1,target);
else if(nums[mid]<target)
BinarySearch(nums,mid+1,right,target);
}
int search(int* nums, int numsSize, int target){
k=0,result=-1;
locateK(nums,0,numsSize-1);
if(nums[0]<=target&&nums[k]>=target) BinarySearch(nums,0,k,target);
else BinarySearch(nums,k+1,numsSize-1,target);
return result;
}