0154. 寻找旋转排序数组中的最小值 II Find Minimum in Rotated Sorted Array II
这个问题是 0153 的扩展. 这个表面上看起来可以直用用二分查找法, 但因为可以有相同值的元素存在, 它把问题复杂化了.
暴力法 Brute force
遍历数组, 计算最小值:
#![allow(unused)] fn main() { // Brute force pub fn find_min1(nums: Vec<i32>) -> i32 { nums.iter().min().copied().unwrap_or_default() } }
时间复杂度是 O(n)
.
二分查找法
这个要对二分查找法的命中条件做一些改进. 因为有重复元素的存在, 我们在某些条件下无法确定元素的顺序, 但可以只对有明确顺序的情况使用二分查找:
- 如果
nums[middle] < nums[right]
则最小值不在右侧部分 - 如果
nums[middle] > nums[right]
则最小值在右侧部分 - 其它情况, 一次将
left
右移一步, 将right
左移一步, 渐渐靠近
#![allow(unused)] fn main() { // Binary Search #[allow(clippy::comparison_chain)] pub fn find_min2(nums: Vec<i32>) -> i32 { assert!(!nums.is_empty()); let mut left = 0; let mut right = nums.len() - 1; while left + 1 < right { let middle = left + (right - left) / 2; //println!("left: {left}, middle: {middle} right: {right}, nums: {nums:?}"); if nums[middle] < nums[right] { // (1, 2, 3) // 最小值位于左侧 right = middle; } else if nums[middle] > nums[right] { // (2, 3, 1) // 最小值位于右侧 left = middle + 1; } else { // 不容易确定, 一次移动一个位置, 考虑重复的元素. if right > left && nums[right - 1] <= nums[right] { right -= 1; } if left < right && nums[left + 1] <= nums[left] { left += 1; } } } nums[left].min(nums[right]) } }
该算法的时间复杂度是 O(log(n))
.