80岁老爷爷学算法之过情人节
第三天上午
爷爷今天像往常一样,打开力扣准备做每日一题(其实是想和力扣续个火花),看到今天的每日一题799. 香槟塔,他年轻时不懂浪漫,一辈子没送过几回花,老了老了,倒被一道题勾得心里软乎乎的。题里说,香槟从顶端往下倒,一层层漫溢,匀匀地流进下一层的杯子。爷爷盯着那示意图看,忽然就想起了他和老伴的一辈子。 哪是什么惊天动地的浪漫,就是像这香槟塔似的,一年一年,一勺一勺,日子慢慢淌,从年轻时候的粗茶淡饭,淌到中年的柴米油盐,再淌到如今鬓角全白,杯杯都满,杯杯都暖。
首先要明确这道题的核心是模拟香槟的流动过程,先抓住两个关键规则:
1.每个香槟杯的容量固定为 1 单位,超过 1 的部分会等分成两份,分别流到下一层左右相邻的两个杯子中;
2.最终只需要求第 query_row 行第 query_glass 列的杯子中香槟的填充比例(最多为 1)。
二维数组的空间复杂度是 O(n²)(n 为目标行数),观察到一个关键规律:计算第 i+1 行的香槟量时,只需要用到第 i 行的数据,因此可以用一维数组优化,爷爷就用滚动数组完成这道题:
class Solution {
public:
double champagneTower(int poured, int query_row, int query_glass) {
vector<double> f(query_row + 1); // 1. 初始化滚动数组,存储当前层香槟量
f[0] = poured; // 2. 初始时所有香槟都在第0行第0个杯子
// 3. 外层循环:从第0层开始,逐层处理溢出,直到第query_row-1层
for (int i = 0; i < query_row; i++) {
// 4. 内层循环:倒序遍历当前层的每个杯子,避免覆盖未处理的值
for (int j = i; j >= 0; j--) {
double x = f[j] - 1; // 5. 计算溢出的香槟量(超过1的部分)
if (x > 0) { // 6. 如果有溢出
f[j + 1] += x / 2; // 7. 溢出的一半流到下一层的j+1位置
f[j] = x / 2; // 8. 溢出的另一半流到下一层的j位置(暂存到当前位置)
} else {
f[j] = 0; // 9. 没有溢出,下一层j位置不会得到来自这个杯子的香槟
}
}
}
return min(f[query_glass], 1.0); // 10. 杯子容量最大为1,返回占比
}
};
下午
爷爷过情人节去了,只能明天再学了。