原题链接:https://leetcode-cn.com/problems/guess-number-higher-or-lower-ii/
这题难点在于不能直接使用二分法,举个例子:如果n=5,则1、2、3、4、5,那么先选4,再选2,和为6是最小的,而不是传统二分法的先选3,再选4,和为7。并且这题求的是最好的最坏,也就是min(max())。
1、递归+二分法(超时)
int getMoneyAmount(int n) {
return func(1,n);
}
int func(int low,int high){
if(low>=high) return 0;
int cost=INT_MAX;
for(int i=low;i<=high;i++){
cost=min(cost,i+max(func(low,i-1),func(i+1,high)));//如果选了i的花费
}
return cost;
}
2、递归+二分法优化(超时)
先找最坏情况,因为右边比较大,所以只要每次选择右边代价更高。
int getMoneyAmount(int n) {
return func(1,n);
}
int func(int low,int high){
if(low>=high) return 0;
int cost=INT_MAX;
for(int i=(low+high)/2;i<=high;i++){
cost=min(cost,i+max(func(low,i-1),func(i+1,high)));
}
return cost;
}
3、动态规划
还是得动态规划
dp[i][j] 代表在(i,j)中最坏情况的最小开销
状态转移
//i<=j<=i+len,每次选择j的最坏代价,并且从中取最小值
dp[i][i+len]=min(j+max(dp[i][j-1],dp[j+1][i+len])
所以是三层循环
int getMoneyAmount(int n) {
vector<vector<int>> dp(n+1,vector<int>(n+1,0));
for(int len=1;len<n;len++){
for(int i=1;i<=n-len;i++){
int count=INT_MAX;
for(int j=i;j<i+len;j++){
count=min(count,j+max(dp[i][j-1],dp[j+1][i+len]));
}
dp[i][i+len]=count;
}
}
return dp[1][n];
}
如图,帮助理解
如(1,3)区间取2是最小结果;(1,4)区间取3、1,3+1=4是最小结果;(1,5)区间取4、2,4+2=6是最小结果。