LeetCode 记录-808. 分汤
我的解法
思路
完全没有思路,笑死
官方解法 1: 动态规划
思路
采用动态规划的方式,具体思路就不详细写了。记录一点自己的疑问,就是在什么情况下应该使用动态规划?
做过一些动态规划类型的题目,每次要不是想不到用动态规划,要不就是不知道如何写一个合理的动态规划方程,感觉自己对动态规划这个思路蛮陌生的。我自己的思考是:当题目存在状态的概念,且当前状态的结果依赖于上一个状态,上一状态也参照同样的规则依赖于上上个状态,一直到最开始的几个可求出来的边界状态,而我们需要的答案就是其中的某一个状态时,就可以使用动态规划。
代码
/**
* @param {number} poured
* @param {number} query_row
* @param {number} query_glass
* @return {number}
*/
var soupServings = function (n) {
n = Math.ceil(n / 25);
if (n >= 179) {
return 1.0;
}
const dp = new Array(n + 1).fill(0).map(() => new Array(n + 1).fill(0));
dp[0][0] = 0.5;
for (let i = 1; i <= n; i++) {
dp[0][i] = 1.0;
}
for (let i = 1; i <= n; i++) {
for (let j = 1; j <= n; j++) {
dp[i][j] =
(dp[Math.max(0, i - 4)][j] +
dp[Math.max(0, i - 3)][Math.max(0, j - 1)] +
dp[Math.max(0, i - 2)][Math.max(0, j - 2)] +
dp[Math.max(0, i - 1)][Math.max(0, j - 3)]) /
4.0;
}
}
return dp[n][n];
};
复杂度分析
时间复杂度
,因为存在常数 C,在这里我们可以取,使得当时,所求的概率和 1 的误差在以内,我们可以直接返回,需要的时间为;当时,我们需要的时间复杂度为,因此总的时间复杂度为。
空间复杂度
,因为存在常数 C,在这里我们可以取,使得当时,所求的概率和 1 的误差在以内,我们可以直接返回,需要的空间为;当时,我们需要的空间为,因此总的空间复杂度为。
官方解法 2: 记忆化搜索
思路
同样动态规划的解题思路我们还可以采用自顶向下的记忆化搜索的方法来实现,与自底向上的动态规划相比记忆化搜索会减少许多无效状态的计算。
代码
/**
* @param {number} poured
* @param {number} query_row
* @param {number} query_glass
* @return {number}
*/
var soupServings = function (n) {
n = Math.ceil(n / 25);
if (n >= 179) {
return 1.0;
}
const memo = new Array(n + 1).fill(0).map(() => new Array(n + 1).fill(0));
const dfs = (i, j) => {
if (i <= 0 && j <= 0) {
return 0.5;
} else if (i <= 0) {
return 1;
} else if (j <= 0) {
return 0;
}
if (memo[i][j] === 0) {
memo[i][j] =
0.25 *
(dfs(i - 4, j) +
dfs(i - 3, j - 1) +
dfs(i - 2, j - 2) +
dfs(i - 1, j - 3));
}
return memo[i][j];
};
return dfs(n, n);
};
复杂度分析
时间复杂度
,因为存在常数 C,在这里我们可以取,使得当时,所求的概率和 1 的误差在以内,我们可以直接返回,需要的时间为;当时,我们需要的时间复杂度为,因此总的时间复杂度为。
空间复杂度
,因为存在常数 C,在这里我们可以取,使得当时,所求的概率和 1 的误差在以内,我们可以直接返回,需要的空间为;当时,我们需要的空间为,因此总的空间复杂度为。