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
题解
暴力法
乍一看就是暴力法 但是题目要求O(logn)的时间复杂度 暴力出来是O(n)
但是这题的测试用例有点少 暴力也能ac 并且用时击败80% 内存击败100%
class Solution {
public:
int search(vector<int>& nums, int target) {
for(int i = 0 ; i < nums.size() ; i ++){
if(nums[i] == target)
return i ;
}return -1;
}
};
在从暴力法优化时想到可以通过第一个数组的值进行取余直接算坐标 这样复杂度才O(1) 但是题目给的数据也看出来只有有序的规律 没有全排列所有数字都存在的规律
二分
题目要求的时间复杂度就是在提示用二分法
思路也相对好理解 把整体总是分成一半一半来判断 但要注意的是二分只在有序序列中使用 所以每次需要先判断哪一部分是有序的 在有序的中判断target是否属于 如果属于则继续二分 如果不属于 则再另一半暂时无序(其中必存在有序)的队列中划分出有序序列用同样的方法
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = (int)nums.size();
if (!n) return -1; // 特判 不存在时和下面就一个元素时
if (n == 1) return nums[0] == target ? 0 : -1; // 三目运算
int l = 0, r = n - 1; // l为左 r为右
while (l <= r) { // 跳出条件 左坐标 > 右坐标时
int mid = (l + r) / 2; // 取中位
if (nums[mid] == target) return mid; // 恰好中位就是target时
/* 下方if else来判断哪个区间有序 决定在哪个区间搜索 并抛弃另一边 */
if (nums[0] <= nums[mid]) { // 中位左边区间有序
if (nums[0] <= target && target < nums[mid]) {// target如果在此区间 则继续二分
r = mid - 1;
} else { // 不在左区间 则从右区间二分寻找
l = mid + 1;
}
} else { // 中位右边区间有序
if (nums[mid] < target && target <= nums[n - 1]) {
l = mid + 1; // 和上方左区间有序一样操作
} else {
r = mid - 1;
}
}
}
return -1;
}
};