80岁老爷爷学算法之过情人节

12 阅读2分钟

80岁老爷爷学算法之过情人节

第三天上午

爷爷今天像往常一样,打开力扣准备做每日一题(其实是想和力扣续个火花),看到今天的每日一题799. 香槟塔,他年轻时不懂浪漫,一辈子没送过几回花,老了老了,倒被一道题勾得心里软乎乎的。题里说,香槟从顶端往下倒,一层层漫溢,匀匀地流进下一层的杯子。爷爷盯着那示意图看,忽然就想起了他和老伴的一辈子。 哪是什么惊天动地的浪漫,就是像这香槟塔似的,一年一年,一勺一勺,日子慢慢淌,从年轻时候的粗茶淡饭,淌到中年的柴米油盐,再淌到如今鬓角全白,杯杯都满,杯杯都暖。

image.png 首先要明确这道题的核心是模拟香槟的流动过程,先抓住两个关键规则:

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,返回占比
    }
};

下午

爷爷过情人节去了,只能明天再学了。