279. 完全平方数
题目:
思路:
【1】动态规划的方式
【2】数学公式的方式(依据 四平方和定理 )
同时四平方和定理包含了一个更强的结论:
当且仅当 n≠4^k×(8m+7) 时,n 可以被表示为至多三个正整数的平方和。
因此,当 n=4^k×(8m+7) 时,n 只能被表示为四个正整数的平方和。此时我们可以直接返回 4。
当 n≠4^k×(8m+7) 时,我们需要判断到底多少个完全平方数能够表示 n,我们知道答案只会是 1,2,3 中的一个:
答案为 1 时,则必有 n 为完全平方数,这很好判断;
答案为 2 时,则有 n=a^2+b^2,我们只需要枚举所有的 a(1≤a≤√n),判断 n-a^2 是否为完全平方数即可;
答案为 3 时,我们很难在一个优秀的时间复杂度内解决它,故只需要检查答案为 1 或 2 的两种情况,即可利用排除法确定答案。
代码展示:
【1】动态规划的方式
//时间21 ms 击败 91.34% //内存40.2 MB 击败 86.21% //时间复杂度:O(n * √n),其中 n 为给定的正整数。 //状态转移方程的时间复杂度为 O(√n)[n的平方根],共需要计算 n 个状态, //因此总时间复杂度为 O(n * √n)。 //空间复杂度:O(n)。我们需要 O(n) 的空间保存状态。 class Solution { public int numSquares(int n) { // 动态规划的方式列出从 1 - n 完全平方数的最少数量 int[] f = new int[n+1]; for (int i = 1; i <= n; i++){ int minn = Integer.MAX_VALUE; for (int j = 1; j * j <= i; j++) { minn = Math.min(minn, f[i - j * j]); } f[i] = minn + 1; } return f[n]; } }
【2】数学公式的方式
//时间0 ms 击败 100% //内存38.1 MB 击败 99.90% class Solution { public 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; } // 判断是否为完全平方数 public boolean isPerfectSquare(int x) { int y = (int) Math.sqrt(x); return y * y == x; } // 判断是否能表示为 4^k*(8m+7) public boolean checkAnswer4(int x) { while (x % 4 == 0) { x /= 4; } return x % 8 == 7; } }