近在做力扣学习学习数据结构与算法,评论区看到解决方案在此记录下。
1,BFS解决
这题让求的是若干个平方数的和等于n,并且平方数的个数最少。首先我们可以把它想象成为一颗m叉树,树的每一个节点的值都是平方数的和,如下图所示。
每一个节点的值都是从根节点到当前节点的累加。而平方数的个数其实就是遍历到第几层的时候累加和等于target。我们只需要一层一层的遍历,也就是常说的BFS,当遇到累加的和等于target的时候直接返回当前的层数即可。
我们知道二叉树的BFS遍历像下面这样
public void levelOrder(TreeNode tree) {
Queue<TreeNode> queue = new LinkedList<>();
queue.add(tree);
int level = 0;//统计有多少层
while (!queue.isEmpty()) {
//每一层的节点数
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
//打印节点
System.out.println(node.val);
if (node.left != null)
queue.add(node.left);
if (node.right != null)
queue.add(node.right);
}
level++;
//打印第几层
System.out.println(level);
}
}
最终代码:
//BFS
public int numSquares(int n) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(0);
//记录访问过的节点值
Set<Integer> visited = new HashSet<>();
visited.add(0);
//树的第几层
int min = 0;
while(!queue.isEmpty()){
min++;
int size = queue.size();
//遍历当前层的所有节点
for(int i=0;i<size;i++){
int value = queue.poll();
// 开始枚举所有满足条件的j,使j*j<=n.
// 类比二叉树的left/right节点或者二维网格的上下左右四个方向
//访问当前节点的子节点,类比于二叉树的左右子节点
for(int j=1;j*j<=n;j++){
int nValue = value + j*j;
// 如果新值大于目标值,则停止内层循环
if(nValue > n){
break;
}
// 如果新值已经遍历过,则跳到下一个循环继续
if(visited.contains(nValue)){
continue;
}
// 如果新值等于目标值,则直接返回当前层数
if(nValue == n){
return min;
}
// 否则,将新值加入到队列中并标记已遍历,为下一层的遍历做准备
queue.offer(nValue);
visited.add(nValue);
}
}
}
return min;
}
作者:数据结构和算法
链接:https://leetcode-cn.com/leetbook/read/queue-stack/kfgtt/?discussion=xgcYsh
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2,动态规划解决
这题除了使用BFS以外,还可以使用动态规划解决。
定义数组dp[],其中dp[i]表示的是当n等于i的时候完全平方数的最少数量。比如dp[12]表示当n等于12的时候完全平方数的最少数量。
比如当n等于60的时候,他的值是dp[60],但是60还可以由11加上7的平方组成,我们还可以改为dp[11]+1,取最小的即可,即
dp[60]=min(dp[60],dp[11]+1)
实际上60还可以由24加上6的平方组成……我们只需要找出所有的可能组合并记录最小的值即可。
所以递推公式我们很容易找出来
dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
那么初始条件是什么呢,我们默认任何正整数都是由1的平方组成,即dp[i]=i,也就是最大值,然后再通过递推公式找出最小值即可。
最后我们再来看下代码
//动态规划
public int numSquares2(int n) {
// 定义dp,dp[i]代表输入为i时,返回和为 i 的完全平方数的 最少数量
int[] dp = new int[n+1];
dp[0] = 0;
for(int i=1;i<=n;i++){
//最坏的情况都是由1的平方组成 dp[12] =12个数字
dp[i] = i;
for(int j=1;j*j<=i;j++){
//动态规划公式
//exp dp[60]=min(dp[60],dp[11]+1) 60=11+7*7
dp[i] = Math.min(dp[i],dp[i-j*j]+1);
}
}
return dp[n];
}