Minimax
极大极小:是一种原则,最小化最差情况下的损失. (minimizing the possible loss for a worst case (maximum loss) scenario)。
375. 猜数字大小 II
解法1:从上而下使用–递归
本解法参考递归的解法
其中dp[i][j]
状态表示依次以从i到j的数字作为分割点(猜的数),必定赢的游戏所用钱的最小值。
class Solution {
//方法1:自上而下 递归 + 记忆
public int getMoneyAmount(int n) {
int[][] tables = new int[n + 1][n + 1];
return dp(tables, 1, n);
}
/**
* @param tables 用于去除冗余计算的表格
* @param l 左边界
* @param r 右边界
* @return 依次以从i到j的数字作为分割点(猜的数),必定赢的游戏所用钱的最小值
*/
private int dp(int[][] tables, int l, int r) {
//截止条件
if (l >= r) {
return 0;
}
//记忆
if (tables[l][r] != 0) {
return tables[l][r];
}
int res = Integer.MAX_VALUE;
for (int x = l; x <= r; x++) {
int tmp = x + Math.max(dp(tables, l, x - 1), dp(tables, x + 1, r));
res = Math.min(res, tmp);
}
tables[l][r] = res;
return res;
}
}
解法2:从下到上, 使用动态规划
本解答参考动态规划, 动态规划处理,边界条件处理是难点。在参考答案中,使用了
for(int k=i+1; k<j; k++){
int localMax = k + Math.max(table[i][k-1], table[k+1][j]);
globalMin = Math.min(globalMin, localMax);
}
table[i][j] = i+1==j?i:globalMin;
当两个数值时,直接返回较小值,即为i。
class Solution {
//方法2: 使用从下到上--动态规划的方法
//状态:dp[i][j]表示依次以从i到j的数字作为分割点(猜的数),必定赢的游戏所用钱的最小值。
//转换方程:
// dp[i][j] = min(x + max(dp[i][x - 1], dp[x + 1][j])) , x in [i~j]
public int getMoneyAmount(int n) {
int[][] dp = new int[n + 1][n + 1];
for (int i = n - 1; i >= 1; i--) {
for (int j = i + 1; j <= n; j++) {
dp[i][j] = Integer.MAX_VALUE;
//处理(i, j)区间的情况,不包含两端
for (int x = i + 1; x < j; x++) {
int tmp = x + Math.max(dp[i][x - 1], dp[x + 1][j]);
dp[i][j] = Math.min(dp[i][j], tmp);
}
//左端点
dp[i][j] = Math.min(dp[i][j], i + dp[i + 1][j]);
//右端点
dp[i][j] = Math.min(dp[i][j], j + dp[i][j - 1]);
}
}
return dp[1][n];
}
}