class Solution:
def getMoneyAmount(self, n: int) -> int:
dp = [[0] * (n + 2) for _ in range(n + 2)]
for length in range(2, n + 1):
for start in range(1, n - length + 2):
end = start + length - 1
dp[start][end] = float('inf')
for piv in range(start, end):
cost = piv + max(dp[start][piv - 1], dp[piv + 1][end])
dp[start][end] = min(dp[start][end], cost)
return dp[1][n]
class Solution {
public:
int getMoneyAmount(int n) {
vector<vector<int>> dp(n + 2, vector<int>(n + 2, 0));
for (int len = 2; len <= n; ++len) {
for (int start = 1; start <= n - len + 1; ++start) {
int end = start + len - 1;
dp[start][end] = INT_MAX;
for (int piv = start; piv < end; ++piv) {
int cost = piv + max(dp[start][piv - 1], dp[piv + 1][end]);
dp[start][end] = min(dp[start][end], cost);
}
}
}
return dp[1][n];
}
};
class Solution {
public int getMoneyAmount(int n) {
int[][] dp = new int[n + 2][n + 2];
for (int len = 2; len <= n; ++len) {
for (int start = 1; start <= n - len + 1; ++start) {
int end = start + len - 1;
dp[start][end] = Integer.MAX_VALUE;
for (int piv = start; piv < end; ++piv) {
int cost = piv + Math.max(dp[start][piv - 1], dp[piv + 1][end]);
dp[start][end] = Math.min(dp[start][end], cost);
}
}
}
return dp[1][n];
}
}
var getMoneyAmount = function(n) {
const dp = Array.from({length: n + 2}, () => Array(n + 2).fill(0));
for (let len = 2; len <= n; ++len) {
for (let start = 1; start <= n - len + 1; ++start) {
let end = start + len - 1;
dp[start][end] = Infinity;
for (let piv = start; piv < end; ++piv) {
let cost = piv + Math.max(dp[start][piv - 1], dp[piv + 1][end]);
dp[start][end] = Math.min(dp[start][end], cost);
}
}
}
return dp[1][n];
};
The "Guess Number Higher or Lower II" problem asks you to play a number guessing game with a twist: you must minimize the worst-case amount of money you could lose. Given an integer n
, you must guess a number between 1 and n
. Each time you guess a number x
and it is incorrect, you pay x
dollars. The game then continues with either the range 1
to x-1
or x+1
to n
, depending on whether the target number is lower or higher. Your goal is to find the minimum amount of money required to guarantee a win, no matter what the target number is.
1
to n
.At first glance, this problem seems similar to binary search, where you try to minimize the number of guesses. However, the twist is that each guess has a different "cost" (equal to the guessed number), and you need to minimize the maximum cost you could possibly pay, not the number of guesses. If you always guess the middle, you might not always minimize the worst-case cost, because the cost of a wrong guess can be high.
A brute-force approach would be to try every possible sequence of guesses for every possible range, but this quickly becomes infeasible as n
grows. The key insight is to use dynamic programming: for each possible range of numbers, calculate the minimum cost required to guarantee a win, and build up solutions for larger ranges using solutions for smaller ranges. This way, we avoid redundant calculations and efficiently find the optimal strategy.
We solve the problem using dynamic programming. Here's the step-by-step method:
dp[start][end]
be the minimum cost to guarantee a win for the range [start, end]
.start >= end
, then no guesses are needed, so dp[start][end] = 0
.piv
in [start, end]
, the cost is piv
(the cost of guessing) plus the maximum cost of the two resulting subranges: dp[start][piv-1]
and dp[piv+1][end]
.dp[start][end] = min_{piv in [start, end]} [piv + max(dp[start][piv-1], dp[piv+1][end])]
dp[start][end]
for all start
and end
where start < end
.dp[1][n]
, the minimum cost to guarantee a win in the full range.We use a 2D array for memoization because we need to store the minimum cost for every possible subrange. By always considering the worst-case cost at each guess and minimizing over all possible first guesses, we ensure the strategy is optimal.
Let's walk through the problem for n = 4
:
So, for n = 4
, the minimum amount of money needed to guarantee a win is 4.
O(2^n)
or worse.
O(n^2)
subproblems (one for each possible [start, end]
range).
O(n)
possible pivots (guesses).
O(n^3)
.
O(n^2)
for the DP table.
The dynamic programming solution is efficient enough for the constraints given in the problem.
The "Guess Number Higher or Lower II" problem is a classic example of dynamic programming applied to minimax optimization. Instead of simply guessing the middle number, we carefully analyze each possible guess to minimize the worst-case cost, using a DP table to store subproblem solutions. This approach guarantees that, no matter what the target number is, we will never pay more than the computed minimum amount. The elegance of the solution lies in breaking the problem into manageable subproblems and always considering the worst-case scenario at each step.