Leetcode的完美广场
Perfect Square in Leetcode
我很难理解Leetcode问题。
给定一个正整数n,求和为n的完美平方数的最小数(例如,1、4、9、16…(。
例如,给定n=12,返回3,因为12=4+4+4;给定n=13,则返回2,因为13=4+9。
解决方案:
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];
}
我真的不明白min(squares,dp[m-i*i]+1)
是怎么回事。你能解释一下吗?
thx。
我也遇到了困难。让我们举一个n=13的例子。
- 首先要观察的是:1^2=1,2^2=4,3^2=9,4^2=16
- 所以13不可能由大于3^2。一般来说,n只能由数字1到sqrt(n(组成
- 因此,我们只剩下以下数字的平方的组合:1、2或3
- 接下来我们要做的是提出递归公式。我花了很长时间才明白。但我们基本上想缩小到使用较小的n(这就是递归的全部意义(。我们通过从n中减去我们的候选完美平方来做到这一点。例如:
- 如果我们尝试3,那么dp(13(=dp(13-3^2(+1=dp(4(+1。+1是将计数增加1,这是因为我们已经从13减去了一个完美的正方形,也就是3^2。每个+1都是一个完美的正方形
- 如果我们尝试2,那么dp(13(=13-2^2=dp(9(+1
- 如果我们尝试1,那么dp(13(=13-1^2=dp(12(+1
因此,我们只需要比较dp(4(、dp(9(和dp(12(中哪一个最小。因此,最小
您提到的解决方案是自下而上版本的算法。为了更好地理解算法,我建议查看自上而下的解决方案。
让我们更仔细地研究包含在数字N
中的完美平方的最小数量的计算的递推关系。对于给定的N
和任意数x
(它是被认为是最短数列成员的候选者,其平方和为N
(:
f(N, x) = 0 , if N = 0 ;
f(N, x) = min( f(N, x + 1), f(N - x^2, 1) ) , if N >= x^2 ;
f(N, x) = +infinity , otherwise ;
solution(N) = f(N, 1)
现在,考虑到所考虑的递归,我们可以构建自上而下的解决方案(我将在Java中实现它(:
int solve(int n) {
return solve(n, 1);
}
int solve(int n, int curr) {
if (n == 0) {
return 0;
}
if ((curr * curr) > n) {
return POSITIVE_INFINITY;
}
// if curr belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
int inclusive = solve(n - (curr * curr), 1) + 1;
// otherwise:
int exclusive = solve(n, curr + 1);
return Math.min(exclusive, inclusive);
}
给定解决方案的运行时复杂性是指数级的。
然而,我们可以注意到,n
的[1..n]
可能值和curr
的[1..sqrt(n)]
可能值。这意味着函数solve
的自变量的不同值只有n * sqrt(n)
的组合。因此,我们可以创建记忆表,并降低自上而下解决方案的复杂性:
int solve(int n) {
// initialization of the memoization table
int[][] memoized = new int[n + 1][(int) (Math.sqrt(n) + 1)];
for (int[] row : memoized) {
Arrays.fill(row, NOT_INITIALIZED);
}
return solve(n, 1, memoized);
}
int solve(int n, int curr, int[][] memoized) {
if (n == 0) {
return 0;
}
if ((curr * curr) > n) {
return POSITIVE_INFINITY;
}
if (memoized[n][curr] != NOT_INITIALIZED) {
// the sub-problem has been already solved
return memoized[n][curr];
}
int exclusive = solve(n, curr + 1, memoized);
int inclusive = solve(n - (curr * curr), 1, memoized) + 1;
memoized[n][curr] = Math.min(exclusive, inclusive);
return memoized[n][curr];
}
给定的解决方案具有运行时复杂性O(N * sqrt(N))
。
然而,可以将运行时复杂性降低到O(N)
。
就f(N, x)
的递推关系仅依赖于f(N, x + 1)
和f(N - x^2, 1)
而言,这意味着该关系可以等价地转换为循环形式:
f(0) = 0
f(N) = min( f(N - x^2) + 1 ) , across the all x, such that x^2 <= N
在这种情况下,我们必须仅为其参数的N
的不同值存储f(N)
。因此,下面介绍了O(N)
自上而下的解决方案:
int solve_top_down_2(int n) {
int[] memoized = new int[n + 1];
Arrays.fill(memoized, NOT_INITIALIZED);
return solve_top_down_2(n, memoized);
}
int solve_top_down_2(int n, int[] memoized) {
if (n == 0) {
return 0;
}
if (memoized[n] != NOT_INITIALIZED) {
return memoized[n];
}
// if 1 belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
int result = solve_top_down_2(n - (1 * 1)) + 1;
for (int curr = 2; (curr * curr) <= n; curr++) {
// check, whether some other number belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
result = Math.min(result, solve_top_down_2(n - (curr * curr)) + 1);
}
memoized[n] = result;
return result;
}
最后,所提出的自上而下的解决方案可以很容易地转换为自下而上的解决方案:
int solve_bottom_up(int n) {
int[] memoized = new int[n + 1];
for (int i = 1; i <= n; i++) {
memoized[i] = memoized[i - (1 * 1)] + 1;
for (int curr = 2; (curr * curr) <= i; curr++) {
memoized[i] = Math.min(memoized[i], memoized[i - (curr * curr)] + 1);
}
}
return memoized[n];
}
澄清您的困惑在于问题本身。结构CCD_ 20保持最小平方数,其总和为CCD_ 21的索引位置。
例如,squares
将在n=9
时返回3
,但最不可能的是1
,这是dp[m- i*i] + 1
将返回的。
- 试试完美的正方形,你能给点小费吗
- 为什么我在leetcode上收到AddressSanitizer:地址0x602000000058上的堆缓冲区溢出错误
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 不计算一个范围内的完美数
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 完美前进使用 std::forward vs RefRefCast
- LeetCode 1:两和 - 地址清理器:堆缓冲区溢出地址
- 如何编写一个完美的缩写函数模板?
- LeetCode 1011.Binary Search,C++和Python的想法相同,但输出不同
- 将函数参数完美转发到函数指针:按值传递呢?
- 返回 str vs. str.substr(0,str.size()) 在 leetcode 中给了我不同的输出
- 尝试从头开始实现Leetcode的FizzBuzz多线程问题。收到"libc++abi.dylib: terminating"错误
- 二叉树级别顺序遍历在leetcode中
- C++20理念:要求表达和完美转发
- LeetCode 删除 c++ 中的重复项
- 完美的转发和构造函数
- Leetcode 1366:堆缓冲区溢出
- 我可以列表初始化 std::vector 并完美转发元素吗?
- 完美的广场与位明智和
- Leetcode的完美广场