您的位置:首页 > 其它

LeetCode简易题解--375

2017-10-20 23:09 169 查看
这道题涉及到了极大极小算法的知识。题目要求的是求出在最坏情况下(猜错的次数最多)的最小代价。

例如,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]
,都要依赖于动态规划表中该点左边以及下边的值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: