1. 程式人生 > 其它 >279.完全平方數

279.完全平方數

目錄

279.完全平方數

題目

給定正整數n,找到若干個完全平方數(比如1, 4, 9, 16, ...)使得它們的和等於 n。你需要讓組成和的完全平方數的個數最少。

給你一個整數 n ,返回和為 n 的完全平方數的 最少數量 。

完全平方數 是一個整數,其值等於另一個整數的平方;換句話說,其值等於一個整數自乘的積。例如,1、4、9 和 16 都是完全平方數,而 3 和 11 不是。

示例1:

輸入:n = 12
輸出:3 
解釋:12 = 4 + 4 + 4

示例 2:

輸入:n = 13
輸出:2
解釋:13 = 4 + 9
```
提示:

1 <= n <= 104

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/perfect-squares
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

## 題解
給定正整數n,找到若干個完全平方數(比如1, 4, 9, 16, ...)使得它們的和等於 n。
---> 從一個數組(一堆數)中按一定的選取方式得到目標target,嘗試將題目進行轉化為揹包問題。
揹包的容量是n,物品是從 1*1、2*2、3*3...、m*m中選擇,其中m*m<=,每個物品可以多次選擇,那麼這是一道完全揹包問題。

**1.確定dp[j]及下標的含義**
dp[j]:表示組成j的完全平方數個數最少為dp[j]。

**2.遞推公式**
dp[j]可以由兩種方式推出。
假設當前物品是num
- 組成j-num的完全平方數個數最少為dp[j-num],那麼此時num放入之後,組成j的完全平方數個數為dp[j-num]+1。
- 當前num不放入,之前的物品已經組成了j的揹包,個數為dp[j]
題目要求求最少的個數,那麼遞推式為`dp[j]=Math.min(dp[j],dp[j-num]+1)`

**3.dp陣列如何初始化**
n=0,dp[0]=0
n≠0,涉及到求最小值,那麼初始化應該為Integer.MAX_VALUE

**4.確定遍歷順序**
這是求最少的個數,不涉及什麼組合排序,所以都可以。
先從小到大遍歷物品,再從小到大遍歷揹包。

```java
for(int i=1;i*i<=n;i++){
  int num = i*i;
  for(int j=num;j<=n;j++){
   //if(dp[j-num]!=Integer.MAX_VALUE) 這個註釋掉是因為總會由辦法湊齊1+1+1+...
      dp[j]=Math.min(dp[j],dp[j-num]+1);
  
  }
}

5.舉例推導dp陣列
n=4

程式碼

class Solution {
    public int numSquares(int n) {
        int [] dp = new int [n+1];
        Arrays.fill(dp,Integer.MAX_VALUE);
        dp[0] = 0;
        for(int i=1;i*i<=n;i++){
            int num=i*i;
            for(int j=num;j<=n;j++){
                dp[j]=Math.min(dp[j],dp[j-num]+1); 
            }
        }
        return dp[n];
    }
}