返回
旋转排序数组中的最小值Ⅱ
闲谈
2024-01-18 12:07:43
旋转排序数组中的最小值Ⅱ
旋转排序数组中的最小值Ⅱ这道题是旋转排序数组中的最小值(153)的延伸题目。
在讲解本题之前,首先要对昨天的题目进行一个答疑。昨天有人问我为什么题目中讲的是与left进行比较,但是最后代码中写的时候变成了和right比较。这个确实是我讲的时候讲忘了,但是这其实是一个思维转化的问题:因为在旋转之前的数组中,左边的元素肯定小于右边的元素,所以与left进行比较;但是在旋转之后的数组中,左边的元素不一定是小于右边的元素,所以需要与right进行比较。
言归正传,我们来看本题。
本题与昨天那道题最大的区别在于,题目中说数组中可能包含重复的元素。这也就意味着,我们不能再用昨天那道题的解法了。因为昨天那道题的解法是基于这样一个事实:数组中不包含重复的元素。
那么,本题该怎么解呢?
我们还是从一个例子开始说起。假设我们有一个旋转排序数组nums = [4, 5, 6, 7, 0, 1, 2]。这个数组是按照递增顺序排序的,但是它被旋转了3次。
我们可以看到,这个数组中的最小值是0。但是,如果我们用昨天那道题的解法来解这道题,我们会得到最小值是4。这是因为昨天那道题的解法是基于这样一个事实:数组中不包含重复的元素。但是,在本题中,数组中包含重复的元素。
那么,我们该怎么解决这个问题呢?
我们可以使用一个二分查找的变种来解决这个问题。这个变种叫做“旋转二分查找”。
旋转二分查找的算法步骤如下:
- 初始化left和right分别为0和n-1。
- 计算中间位置mid。
- 如果nums[mid] < nums[right],那么最小值一定在[left, mid]之间。将right更新为mid-1。
- 如果nums[mid] > nums[right],那么最小值一定在[mid+1, right]之间。将left更新为mid+1。
- 如果nums[mid] == nums[right],那么我们需要继续查找最小值。将left更新为left+1,将right更新为right-1。
- 重复步骤2-5,直到left和right相等。
- 返回nums[left]。
这个算法的时间复杂度是O(logn)。
下面我们来看一个代码示例:
def find_min(nums):
"""
Finds the minimum value in a rotated sorted array.
Args:
nums: A rotated sorted array.
Returns:
The minimum value in the array.
"""
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right) // 2
if nums[mid] < nums[right]:
right = mid - 1
elif nums[mid] > nums[right]:
left = mid + 1
else:
left += 1
right -= 1
return nums[left]
if __name__ == "__main__":
nums = [4, 5, 6, 7, 0, 1, 2]
print(find_min(nums))
这个代码的时间复杂度是O(logn)。
总结
在这篇文章中,我们讨论了如何找出旋转排序数组中的最小值。我们介绍了旋转二分查找的算法,并提供了一些示例来帮助理解。