外观
旋转数组找到目标值
⭐ 题目日期:
拼多多 - 2024/10/31
🌳 题目描述:
整数数组 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
🕵🏽 面试评估:
二分查找的变种,难度适中。
🧗难度系数:
⭐️ ⭐️ ⭐️
📝思路分析:
二分查找折半的规则为当中间的数小于目标值,查右边,如果大于,查左边。
旋转之后的数组,打破了这个规则,
如果 nums[mid] > target, 正常查左边,移动右边界 right = mid - 1; 但是有一种情况需要查右边,当 mid 落在旋转区域,并且左边界大于目标值。4, 5, 6, 7, 8, 0, 1, 2,3; 假设 target = 2, nums[mid] = 8, 此时需要移动左边界。
如果 nums[mid] < target, 正常查右边,移动左边界 left = mid + 1; 但是有一种情况需要查左边,当 mid 落在未旋转区域,并且右边界小于目标值,说明更大的数在旋转区域。5, 6, 7, 8, 0, 1, 2,3,4; 假设 target = 6, nums[mid] = 0, 此时需要移动右边界。
如何判断 mid 落在哪?
当 nums[mid] > nums[right], mid 落在旋转区域
当 nums[mid] < nums[left], mid 落在未旋转区域
💻代码(Java、Python、C++):
保留了原始二分查找的写法,只加了两个打破规则的判断:
中间值大于目标值:
if (nums[mid] > nums[right] && nums[left] > target) left = mid + 1;
中间值小于目标值:
if (nums[mid] < nums[left] && nums[right] < target) right = mid - 1;
Coding Tips: 记场景,不要记代码!
Java
public int search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int left = 0;
int right = nums.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > target) {
if (nums[mid] > nums[right] && nums[left] > target) {
left = mid + 1;
} else {
right = mid - 1;
}
} else {
if (nums[mid] < nums[left] && nums[right] < target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return -1;
}
Python
class Solution:
def search(self, nums: list[int], target: int) -> int:
if not nums:
return -1
left, right = 0, len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] == target:
return mid
elif nums[mid] > target:
if nums[mid] > nums[right] and nums[left] > target:
left = mid + 1
else:
right = mid - 1
else:
if nums[mid] < nums[left] and nums[right] < target:
right = mid - 1
else:
left = mid + 1
return -1
C++
class Solution {
public:
int search(vector<int>& nums, int target) {
if (nums.empty()) {
return -1;
}
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] > target) {
if (nums[mid] > nums[right] && nums[left] > target) {
left = mid + 1;
} else {
right = mid - 1;
}
} else {
if (nums[mid] < nums[left] && nums[right] < target) {
right = mid - 1;
} else {
left = mid + 1;
}
}
}
return -1;
}
};
🚵🏻复杂度分析:
时间复杂度:O(logn)
空间复杂度:O(1)