I am having trouble understanding one of a Leetcode Problem.
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.
For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
Solution:
int numSquares(int n) {
static vector<int> dp {0};
while (dp.size() <= n) {
int m = dp.size(), squares = INT_MAX;
for (int i=1; i*i<=m; ++i)
squares = min(squares, dp[m-i*i] + 1);
dp.push_back(squares);
}
return dp[n];
}
I really dont understand what is going on with min(squares,dp[m-i*i]+1)
. Can you please explain?
thx.
The clarification to your confusion lies in the question itself. The structure
dp
holds the least number of squares that sum up to the index position ofdp
.E.g.,
squares
would return3
whenn=9
, but least possible is1
, which is whatdp[m- i*i] + 1
would return.I had a hard time with this too. Let's take the example number n=13.
So we are left with comparing which is the smallest out of dp(4), dp(9), and dp(12). Hence the min.
The solution, which you have mentioned, is the bottom-up version of the algorithm. In order to understand the algorithm better, I would advice to look at the top-down version of the solution.
Let's look closer at the recurrence relation for the calculation of the minimal amount of the perfect squares, contained inside the number
N
. For givenN
and any arbitrary numberx
(which is the candidate for being considered as the member of the shortest sequence of numbers, whose perfect squares sums-up toN
):Now, having in mind the considered recurrence, we can construct the top-down solution (I will implement it in Java):
The runtime complexity of the given solution is exponential.
However, we can notice that there are only
[1..n]
possible values ofn
and[1..sqrt(n)]
values ofcurr
. Which, implies, that there are onlyn * sqrt(n)
combinations of different values of arguments of the functionsolve
. Hence, we can create the memoization table and reduce the complexity of the top-down solution:Given solution has the runtime complexity
O(N * sqrt(N))
.However, it is possible to reduce the runtime complexity to
O(N)
.As far as the recurrence relation for
f(N, x)
depends only onf(N, x + 1)
andf(N - x^2, 1)
- it means, that the relation can be equivalently transformed to the loop form:In this case we have to memoize the
f(N)
only forN
different values of its argument. Hence, below presented theO(N)
top-down solution:Finally, the presented top-down solution can be easily transformed to the bottom-up solution: