题目
题目描述
已知存在一个按非降序排列的整数数组 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,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4] 。
给你 旋转后 的数组 nums 和一个整数 target ,请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ,则返回 true ,否则返回 false 。
你必须尽可能减少整个操作步骤。
示例 1:
输入:nums = [2,5,6,0,0,1,2], target = 0
输出:true
示例 2:
输入:nums = [2,5,6,0,0,1,2], target = 3
输出:false
提示:
1 <= nums.length <= 5000
-
1
0
4
10^4
104 <= nums[i] <=
1
0
4
10^4
104
题目数据保证 nums 在预先未知的某个下标上进行了旋转
-
1
0
4
10^4
104 <= target <=
1
0
4
10^4
104
进阶:
此题与 搜索旋转排序数组 相似,但本题中的 nums 可能包含 重复 元素。这会影响到程序的时间复杂度吗?会有怎样的影响,为什么?
题解
这个问题可以通过修改二分查找算法来解决。由于数组是旋转排序的,并且可能包含重复元素,这增加了问题的复杂性。不过,我们仍然可以利用二分查找的思想来尽可能减少操作步骤。
解题思路
- 处理特殊情况:如果数组为空或长度为0,则直接返回
False。 - 二分查找:
- 初始化两个指针
left和right分别指向数组的起始和结束位置。 - 在每次迭代中,计算中间位置
mid,并检查nums[mid]是否等于target。 - 如果
nums[left] < nums[mid],说明左半部分是有序的;否则,右半部分是有序的(考虑到可能有重复元素,这里需要额外判断)。 - 根据目标值是否落在有序部分内调整
left或right指针的位置。
- 初始化两个指针
- 处理重复元素:当
nums[left] == nums[mid] == nums[right]时,无法确定哪一半是有序的,此时只能逐个排除重复元素。
代码实现
def search(nums, target):
if not nums:
return False
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return True
# 处理重复元素的情况
if nums[left] == nums[mid] == nums[right]:
left += 1
right -= 1
elif nums[left] <= nums[mid]: # 左半部分有序
if nums[left] <= target < nums[mid]:
right = mid - 1
else:
left = mid + 1
else: # 右半部分有序
if nums[mid] < target <= nums[right]:
left = mid + 1
else:
right = mid - 1
return False
进阶讨论
此题与“搜索旋转排序数组”的区别在于允许重复元素。
- 时间复杂度的影响:在原始的“搜索旋转排序数组”问题中,如果没有重复元素,我们可以保证每次迭代都能将搜索范围缩小一半,因此最坏情况下时间复杂度为 O(log n)。
- 重复元素的影响:引入重复元素后,在某些情况下(例如所有元素都相同),我们可能无法通过比较
nums[left]和nums[mid]来确定哪一半是有序的。这时,最坏情况下我们需要逐一排除重复元素,导致时间复杂度退化到 O(n),因为在这种极端情况下,实际上是在进行线性搜索。
因此,重复元素确实会影响程序的时间复杂度,使其在最坏情况下的性能不如没有重复元素时的表现。
提交结果

7634

被折叠的 条评论
为什么被折叠?



