LeetCode简易题解--375

这道题涉及到了极大极小算法的知识。题目要求的是求出在最坏情况下(猜错的次数最多)的最小代价。
例如,n=5时,先后选择第二个和第四个数就一定能知道被选中的数,也就是说,最坏情况是猜错两次。最小代价就是这两次的选择的代价和的最小值。
解题的思路是使用动态规划法。

先确定动态规划的边界:
假设对[start, end]范围求解。当数组数字个数为:

  • 1个时,结果为0
  • 2个时,选择较小的那个值,最坏情况选择错了,那么下一次一定能选对,最小代价为较小的值
  • 3个时,选择中间的值,最坏情况选择错了,下一次也一定能选对。若是选择第一个或第三个,最坏情况下还会选错一个,那么代价就更大了。因此这种情况下要选择中间那个值。

接下来就基于以上三种,将这道题分解为最优子结构:
依旧假设对[start, end]范围求解。
假设选中了一个值k(start < k < end),[start, k-1]范围的最差最小代价记为dp[start][k-1],[k+1, end]范围的最差最小代价记为dp[k+1][end],那么[start, end]范围的最差最小代价就是min{ k + max(dp[start][k-1], dp[k+1][end]) }, start < k < end
得出以上结论的理由是:最差情况下,选中这个数一定会失败(在一定能确定被选中的数之前),那么下一次猜的数要么比k小要么比k大,而最坏的情况一定会导致代价更大的选择,因此你下一次选择一定在代价更大的区间中。而在所有k的取值导致的结果中,选中那个最小的值,这就是最差的最小代价。

代码如下:

class Solution {
public:
    int getMoneyAmount(int n) {
        vector<vector<int> > dp(n, vector<int>(n, 0));
        for (int j = 0; j < n; ++j) {
            dp[j][j] = 0;
            for (int i = j - 1; i >= 0; --i) {
                if (i == j - 1) {
                    dp[i][j] = i + 1;
                } else {
                    int sum = INT_MAX;
                    for (int k = j - 1; k > i; --k) {
                        int tmp = k + 1 + max(dp[i][k - 1], dp[k + 1][j]);
                        if (tmp < sum) sum = tmp;
                    }
                    dp[i][j] = sum;
                }
            }
        }
        return dp[0][n - 1];
    }
};

一点代码的解释:
最外层循环是对列数的循环,从左往右。接下来一层循环是对行数的循环,从下往上。这样做的理由是,求解每一个dp[i][j],都要依赖于动态规划表中该点左边以及下边的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值