同志们,大家好,我是阿良
今日,世界杯已经开始拉开帷幕,在这个程序员的人群中,我相信,应该有不少人会一起看球吧?毕竟,他比赛那个时间,你还没下班
那你看比赛,就盯着看啊,眼动嘴不动,他也难受是不是,不能上去踢球,我看着比赛,吃点喝点,不过分吧?
既然都喝上了,咱们就别对着瓶吹了,优雅永不过时,懂不?
那接下来,就迎接我们的主题!香槟塔!
题目描述:
我们把玻璃杯摆成金字塔的形状,其中 第一层 有 1 个玻璃杯, 第二层 有 2 个,依次类推到第 100 层,每个玻璃杯 (250ml) 将盛有香槟。
从顶层的第一个玻璃杯开始倾倒一些香槟,当顶层的杯子满了,任何溢出的香槟都会立刻等流量的流向左右两侧的玻璃杯。当左右两边的杯子也满了,就会等流量的流向它们左右两边的杯子,依次类推。(当最底层的玻璃杯满了,香槟会流到地板上)
例如,在倾倒一杯香槟后,最顶层的玻璃杯满了。倾倒了两杯香槟后,第二层的两个玻璃杯各自盛放一半的香槟。在倒三杯香槟后,第二层的香槟满了 - 此时总共有三个满的玻璃杯。在倒第四杯后,第三层中间的玻璃杯盛放了一半的香槟,他两边的玻璃杯各自盛放了四分之一的香槟,如下图所示。
示例 1:
输入: poured(倾倒香槟总杯数) = 1, query_glass(杯子的位置数) = 1, query_row(行数) = 1
输出: 0.00000
解释: 我们在顶层(下标是(0,0))倒了一杯香槟后,没有溢出,因此所有在顶层以下的玻璃杯都是空的。
示例 2:
输入: poured(倾倒香槟总杯数) = 2, query_glass(杯子的位置数) = 1, query_row(行数) = 1
输出: 0.50000
解释: 我们在顶层(下标是(0,0)倒了两杯香槟后,有一杯量的香槟将从顶层溢出,位于(1,0)的玻璃杯和(1,1)的玻璃杯平分了这一杯香槟,所以每个玻璃杯有一半的香槟。
示例 3:
输入: poured = 100000009, query_row = 33, query_glass = 17
输出: 1.00000
首先,我们需要分析一下题目,他现在是出于一个倒酒的状态,我们需要知道几个要素,
- 每层的酒杯递增
- 在没有倒满之前,每层的液体总数是对称的
- 处于中间的酒杯最先倒满
由于图片的原因,很多人可能在模拟倒酒得过程中可能会出现问题,本人小白,也没看过现场到香槟塔的,所以在第一次想这个模拟倒酒的过程中也是出现了问题
当上述的问题解决之后,我们就应该考虑怎么用代码去模拟我们倒酒的过程了,
怎么模拟?找杯水去到啊!
先从第一个杯子来看,我们倒水的过程就是,第一个杯子倒满了,之后水流向其他的杯子(这不是废话吗)
那我们流经我们第一个杯子的水量就是poured(倾倒香槟总杯数) 那我们有多少水流到下一个杯子呢?poured(倾倒香槟总杯数)-1
OK,我们知道这个道理以后,我们使用一个二维数组来模拟我们倒水的一个过程,
设置第一个杯子的位置为[0][0],这时候可能就会有疑问了,我们第一个杯子不是在中间吗,这要是[0][0]开始,我们向左的杯子怎么办?那么咱就是说,实际情况的确是,但是,这不是在用代码,模拟吗,在代码中,我们整个香槟塔的位置,都向左移动了,向下流的规则就变成了,正下方和正下方向右一位,就像我们最开始写的九九乘法表一样
class Solution {
public double champagneTower(int poured, int query_row, int query_glass) {
double[][] w = new double[query_row+2][query_row+2];
w[0][0]=poured;
for (int i=0;i<=query_row;i++){
for (int j=0;j<=i;j++){
if(w[i][j]<=1)continue;
w[i+1][j]+=(w[i][j]-1)/2;
w[i+1][j+1]+=(w[i][j]-1)/2;
}
}
return Math.min(w[query_row][query_glass],1);
}
}
在这个方法里面,使用的一个二维数组,便于我们理解,当然,我们也可以使用滚动数组的方式,这样的话会更加的节省空间,甚至,你可以只计算一般的的香槟塔,因为我们的整个香槟塔是对称的,我们寻找杯子的时候只需要进行一个折中的操作。
那最后,不管是因为什么进来的,点个赞再走呗!
别打作者就行!!!
本文正在参加「金石计划 . 瓜分6万现金大奖」