LeetCode刷题记录----279.完全平方数(Medium)
2025/9/20
题目(Medium):
279.完全平方数
解题思路:
模式识别:对于每个数而言,我们可以感觉到它是由比它更小的数的相加,而每个数也有相应的最小完全平方数。因此子问题和当前问题有同样的结构,可以用动态规划的思路。
思路:
考虑动态转移数组 dp[i] 的含义:当前数字 i 最少需要多少个数的平方累加得到
而对于每个数字 i 而言,它一定可以找到比它更小的数字 j ∈ [1, 根号下i] 范围的数字的平方累加起来。 因此,我们可以枚举这个范围内的数字,找到其中累加数字中对应的dp[i - j*j]的最小值,作为当前数字的dp的一部分。
找到之后让 dp[i] = minDp + 1;(+1是因为至少还要加上这个数字本身)
具体代码如下:
public class Solution {public int NumSquares(int n) {int sqrtN = (int)Math.Sqrt(n);if(n == sqrtN * sqrtN)return 1;int[] dp = new int[n+1];//遍历到每一个数字for(int i = 1; i <= n; i++){int min = int.MaxValue;//枚举从[1,根号下i]这段位置的数值需要累加的平方数的数量for(int j = 1; j*j <= i; j++){min = Math.Min(min, dp[i - j*j]);}dp[i] = min + 1;}return dp[n];}
}
时间复杂度:
空间复杂度:O(n)
优化思路:
数学上严格证明了每个数都一定可以表示为四个数格子的平方之和。因此上界确定了是4。
同时也严格证明了
如果是两个正整数的:我们直接从1开始枚举到n,看看能不能找到另一个正整数
如果是一个正整数,那就直接说明它可以被开方为正整数
如果以上情况都不是,则为三个正整数
具体代码如下:(来自LeetCode官方题解,这里只做了搬运)
class Solution {
public:// 判断是否为完全平方数bool isPerfectSquare(int x) {int y = sqrt(x);return y * y == x;}// 判断是否能表示为 4^k*(8m+7)bool checkAnswer4(int x) {while (x % 4 == 0) {x /= 4;}return x % 8 == 7;}int numSquares(int n) {if (isPerfectSquare(n)) {return 1;}if (checkAnswer4(n)) {return 4;}for (int i = 1; i * i <= n; i++) {int j = n - i * i;if (isPerfectSquare(j)) {return 2;}}return 3;}
};
总结:
①对于数的相加,你永远可以相信枚举的作用。没有思路的时候就去往枚举考虑先
②理清思路后,我们可以通过枚举每个数字,直接计算其平方以作为目标数组的加数来进行相应调整。