版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tc_To_Top/article/details/88803380
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...
) which sum to n.
Example 1:
Input: n = 12 Output: 3 Explanation: 12 = 4 + 4 + 4.
Example 2:
Input: n = 13 Output: 2 Explanation: 13 = 4 + 9.
题目链接:https://leetcode.com/problems/perfect-squares/
题目分析:先暴力BFS一发:101ms,时间击败20%
class Solution {
class Item {
int num, step;
Item(int num, int step) {
this.num = num;
this.step = step;
}
}
public int numSquares(int n) {
HashSet<Integer> st = new HashSet<>();
Queue<Item> q = new LinkedList<>();
q.offer(new Item(n, 0));
st.add(n);
while (!q.isEmpty()) {
Item cur = q.poll();
if (cur.num == 0) {
return cur.step;
}
int ma = (int)Math.sqrt(1.0 * cur.num);
for (int i = ma; i >= 1; i--) {
Item item = new Item(cur.num - i * i, cur.step + 1);
if (!st.contains(item.num)) {
st.add(item.num);
q.offer(item);
}
}
}
return n;
}
}
把HashSet改成数组:34ms,时间击败45%
class Solution {
class Item {
int num, step;
Item(int num, int step) {
this.num = num;
this.step = step;
}
}
public int numSquares(int n) {
boolean[] vis = new boolean[n + 1];
Queue<Item> q = new LinkedList<>();
q.offer(new Item(n, 0));
vis[n] = true;
while (!q.isEmpty()) {
Item cur = q.poll();
if (cur.num == 0) {
return cur.step;
}
int ma = (int)Math.sqrt(1.0 * cur.num);
for (int i = ma; i >= 1; i--) {
Item item = new Item(cur.num - i * i, cur.step + 1);
if (!vis[item.num]) {
vis[item.num] = true;
q.offer(item);
}
}
}
return n;
}
}
把class Item改成int[]:19ms,时间击败87.2%
BFS的时候如果正着搜是26ms,尽管sqrt是个比较耗时的函数,但是就本题而言,优先减大的可以更快得到解
class Solution {
public int numSquares(int n) {
boolean[] vis = new boolean[n + 1];
Queue<int[]> q = new LinkedList<>();
q.offer(new int[]{n, 0});
vis[n] = true;
while (!q.isEmpty()) {
int[] cur = q.poll();
if (cur[0] == 0) {
return cur[1];
}
int ma = (int)Math.sqrt(1.0 * cur[0]);
for (int i = ma; i >= 1; i--) {
int nxtVal = cur[0] - i * i;
if (nxtVal >= 0 && !vis[nxtVal]) {
vis[nxtVal] = true;
q.offer(new int[]{nxtVal, cur[1] + 1});
}
}
}
return n;
}
}
在offer之前判断nxtVal是否为0,减少一层搜索:7ms,时间击败97.9%
class Solution {
public int numSquares(int n) {
boolean[] vis = new boolean[n + 1];
Queue<int[]> q = new LinkedList<>();
q.offer(new int[]{n, 0});
vis[n] = true;
while (!q.isEmpty()) {
int[] cur = q.poll();
int ma = (int)Math.sqrt(1.0 * cur[0]);
for (int i = ma; i >= 1; i--) {
int nxtVal = cur[0] - i * i;
if (nxtVal == 0) {
return cur[1] + 1;
}
if (!vis[nxtVal]) {
vis[nxtVal] = true;
q.offer(new int[]{nxtVal, cur[1] + 1});
}
}
}
return n;
}
}
最优解是采用拉格朗日四平方和定理:0ms,时间击败100%
参考:https://en.wikipedia.org/wiki/Lagrange%27s_four-square_theorem
class Solution {
public int numSquares(int n) {
while (n % 4 == 0) {
n >>= 2;
}
if (n % 8 == 7) {
return 4;
}
for (int x = 0; x * x <= n; x++) {
int y = (int)Math.sqrt(n - x * x);
if (x * x + y * y == n) {
return 1 + (x == 0 ? 0 : 1);
}
}
return 3;
}
}