题目描述
思路解析动画文字版
下面 15 步动画会按主解代码推进,而不是泛泛讲题型。
1. 看输入:示例 nums = [3,1,3,3,3]:升序数组旋转后还混入了重复值,目标是找出最小元素 1(在下标 1 处)。整段是当前搜索窗口。
2. 初始化双指针:左指针 l = 0、右指针 r = 4,搜索窗口覆盖整个数组 [0,4]。此时 nums[l]=3、nums[r]=3。
3. 为什么和 nums[r] 比:每轮取中点 mid,拿 nums[mid] 和右端 nums[r] 比:小于则最小值在左半(含 mid),大于则在右半,相等时方向不明、只能把右端去掉一个。
4. 第1轮·取中点:第 1 轮:l=0、r=4,mid = (0+4)//2 = 2。读出 nums[mid]=3、nums[r]=3。
5. 第1轮·比较:比较 nums[mid]=3 与 nums[r]=3:既不小于也不大于,正好相等,落到 else 分支。
6. 第1轮·相等收缩 r--:相等时无法判断最小值在哪边,但 nums[r] 这个重复值丢掉是安全的,所以 r 从 4 减到 3。下标 4 已排除,窗口收为 [0,3]。
7. 第2轮·取中点:第 2 轮:l=0、r=3,mid = (0+3)//2 = 1。读出 nums[mid]=1、nums[r]=3。
8. 第2轮·比较:比较 nums[mid]=1 与 nums[r]=3:1 小于 3,说明最小值落在左半段且可能就是 mid,走 r = mid 分支。
9. 第2轮·收缩 r=mid:把 r 收到 mid=1(mid 自身可能是最小值,所以不能 mid+1)。下标 2、3、4 排除,窗口收为 [0,1]。
10. 第3轮·取中点:第 3 轮:l=0、r=1,mid = (0+1)//2 = 0。读出 nums[mid]=3、nums[r]=1。
11. 第3轮·比较:比较 nums[mid]=3 与 nums[r]=1:3 大于 1,说明 mid 在旋转的左段高处,最小值在它右边,走 l = mid+1 分支。
12. 第3轮·收缩 l=mid+1:把 l 推到 mid+1=1(mid 比 nums[r] 大,肯定不是最小值,可丢)。下标 0 也排除,窗口收为 [1,1],l 与 r 重合。
13. 循环结束:l 和 r 同为 1,窗口只剩一个元素,循环条件 l 小于 r 不再成立,退出循环。
14. 返回答案:窗口收敛到下标 1,返回 nums[1] = 1,正是数组的最小元素。
15. 不变量回顾:整个过程的不变量:最小值始终落在窗口 [l,r] 内。和无重复版的唯一区别是相等分支用 r-=1 安全去重,正因这一步最坏退化到 O(n)。
记住这题的代码骨架:题意约束先落到状态变量,再用循环或递归维护它。
参考代码
class Solution: def findMin(self, nums): l = 0 r = len(nums) - 1 while l < r: mid = (l + r) // 2 if nums[mid] < nums[r]: r = mid elif nums[mid] > nums[r]: l = mid + 1 else: r -= 1 return nums[l]复杂度
- 时间复杂度:O(n) 最坏,平均 O(log n),大量重复时退化
- 空间复杂度:O(1),只用指针
易错点
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。再去主线里挑下一道练手。
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题