2026年2月21日
滑动窗口是如何降低心智负担的
Best Time to Buy and Sell Stock
给一个数组表示每天的股价,你只能买一次、卖一次(必须先买后卖),求能获得的最大利润(卖不出去或没有利润就返回 0)。
两种做法整理
做法一:维护最小值(贪心 / 状态压缩)
class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) return 0;
int profit = 0;
int minPrice = prices[0];
for (int price : prices) {
minPrice = Math.min(minPrice, price);
profit = Math.max(profit, price - minPrice);
}
return profit;
}
}心智模型:我随身带着两个"数字标签"——minPrice(历史最低价是多少)和 profit(目前最优利润是多少)。每走一步,我要在脑子里做一次抽象判断:"这个数字要不要更新?"
做法二:双指针 / 滑动窗口
class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length < 2) return 0;
int left = 0;
int right = 1;
int maxProfit = 0;
while (right < prices.length) {
if (prices[left] < prices[right]) {
maxProfit = Math.max(maxProfit, prices[right] - prices[left]);
} else {
left = right;
}
right++;
}
return maxProfit;
}
}心智模型:我盯着一个"窗口" [left, right],它代表"我现在持有这枚币的时间段"。每走一步,我只需要问一句话:"这个窗口现在还划算吗?"
滑动窗口为什么心智负担更低
1. 把"要不要更新变量"变成了"窗口还成不成立"
做法一里,每一步你要做的判断其实是两个独立的、抽象的问题:
- "这个数比 minPrice 小吗?要不要更新 minPrice?"
- "这个数减 minPrice 是不是比 profit 大?要不要更新 profit?"
这两个问题之间的联系,需要你主动在脑子里搭桥——你得记住"minPrice 之所以要维护,是为了让 profit 的计算总是最优的",这层因果关系是隐藏的,得靠你自己脑补。
做法二里,这两个问题合并成了一个具体的、有画面感的问题:"我现在拿着这枚币([left, right])还赚不赚?" 如果不赚了,就直接说"这笔交易不划算,重新开一笔"(left = right)。判断逻辑和更新逻辑是同一个动作,不需要你额外去想"这两者之间的关系是什么"。
2. 数值和位置绑在一起,少一层"翻译"
minPrice 是一个脱离上下文的数字,你必须自己记住它"代表什么意思"。而 prices[left] 天然自带位置信息——它就是"窗口左边这一天的价格",不需要你额外解释。
也就是说,做法一需要你在脑子里维护一张"变量含义对照表"(minPrice = 历史最低价,profit = 当前最优解),做法二不需要这张表,因为区间本身就是含义。
3. 窗口给了你一个"整体画面",而不是碎片状态
做法一里,你是在逐帧观察两个数字如何跳变,很像看一堆散落的日志输出,需要自己在脑子里拼出一条时间线。
做法二里,[left, right] 这个区间在你脑子里是连续移动的——你能直接"看到"一个窗口在数组上向右滑,时不时收缩起点重新开始。这种连续、可视化的动态过程,比追踪两个跳变的数字更符合大脑处理空间信息的方式,所以感觉更轻松。
一句话总结
做法一是用"数值的因果关系"驱动决策,做法二是用"区间的可视化状态"驱动决策——当问题变得更复杂(比如窗口需要真正的收缩,而不只是跳跃式重置),这种"看着区间做决策"的方式会比"追踪一堆变量的因果链"更容易扩展,也更不容易出 bug。