38
38
39
39
<!-- 这里可写通用的实现逻辑 -->
40
40
41
- 动态规划,定义 ` dp[i] ` 表示和为 ` i ` 的完全平方数的最少数量。
41
+ ** 方法一:动态规划(完全背包)**
42
+
43
+ 我们定义 $f[ i] [ j ] $ 表示使用数字 $1, 2, \cdots, i$ 的完全平方数组成和为 $j$ 的最少数量。初始时 $f[ 0] [ 0 ] = 0$,其余位置的值均为正无穷。
44
+
45
+ 我们可以枚举使用的最后一个数字的数量 $k$,那么:
46
+
47
+ $$
48
+ f[i][j] = \min(f[i - 1][j], f[i - 1][j - i^2] + 1, \cdots, f[i - 1][j - k \times i^2] + k)
49
+ $$
50
+
51
+ 其中 $i^2$ 表示最后一个数字 $i$ 的完全平方数。
52
+
53
+ 不妨令 $j = j - i^2$,那么有:
54
+
55
+ $$
56
+ f[i][j - i^2] = \min(f[i - 1][j - i^2], f[i - 1][j - 2 \times i^2] + 1, \cdots, f[i - 1][j - k \times i^2] + k - 1)
57
+ $$
58
+
59
+ 将二式代入一式,我们可以得到以下状态转移方程:
60
+
61
+ $$
62
+ f[i][j] = \min(f[i - 1][j], f[i][j - i^2] + 1)
63
+ $$
64
+
65
+ 最后答案即为 $f[ m] [ n ] $。
66
+
67
+ 时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 为 $sqrt(n)$ 的整数部分。
68
+
69
+ 注意到 $f[ i] [ j ] $ 只与 $f[ i - 1] [ j ] $ 和 $f[ i] [ j - i^2 ] $ 有关,因此我们可以将二维数组优化为一维数组,空间复杂度降为 $O(n)$。
70
+
71
+ 相似题目:
72
+
73
+ - [ 322. 零钱兑换] ( /solution/0300-0399/0322.Coin%20Change/README.md )
42
74
43
75
<!-- tabs:start -->
44
76
49
81
``` python
50
82
class Solution :
51
83
def numSquares (self , n : int ) -> int :
52
- dp = [0 ] * (n + 1 )
53
- for i in range (1 , n + 1 ):
54
- j, mi = 1 , inf
55
- while j * j <= i:
56
- mi = min (mi, dp[i - j * j])
57
- j += 1
58
- dp[i] = mi + 1
59
- return dp[- 1 ]
84
+ m = int (sqrt(n))
85
+ f = [[inf] * (n + 1 ) for _ in range (m + 1 )]
86
+ f[0 ][0 ] = 0
87
+ for i in range (1 , m + 1 ):
88
+ for j in range (n + 1 ):
89
+ f[i][j] = f[i - 1 ][j]
90
+ if j >= i * i:
91
+ f[i][j] = min (f[i][j], f[i][j - i * i] + 1 )
92
+ return f[m][n]
93
+ ```
94
+
95
+ ``` python
96
+ class Solution :
97
+ def numSquares (self , n : int ) -> int :
98
+ m = int (sqrt(n))
99
+ f = [0 ] + [inf] * n
100
+ for i in range (1 , m + 1 ):
101
+ for j in range (i * i, n + 1 ):
102
+ f[j] = min (f[j], f[j - i * i] + 1 )
103
+ return f[n]
60
104
```
61
105
62
106
### ** Java**
@@ -66,15 +110,38 @@ class Solution:
66
110
``` java
67
111
class Solution {
68
112
public int numSquares (int n ) {
69
- int [] dp = new int [n + 1 ];
70
- for (int i = 1 ; i <= n; ++ i) {
71
- int mi = Integer . MAX_VALUE ;
72
- for (int j = 1 ; j * j <= i; ++ j) {
73
- mi = Math . min(mi, dp[i - j * j]);
113
+ int m = (int ) Math . sqrt(n);
114
+ int [][] f = new int [m + 1 ][n + 1 ];
115
+ for (var g : f) {
116
+ Arrays . fill(g, 1 << 30 );
117
+ }
118
+ f[0 ][0 ] = 0 ;
119
+ for (int i = 1 ; i <= m; ++ i) {
120
+ for (int j = 0 ; j <= n; ++ j) {
121
+ f[i][j] = f[i - 1 ][j];
122
+ if (j >= i * i) {
123
+ f[i][j] = Math . min(f[i][j], f[i][j - i * i] + 1 );
124
+ }
74
125
}
75
- dp[i] = mi + 1 ;
76
126
}
77
- return dp[n];
127
+ return f[m][n];
128
+ }
129
+ }
130
+ ```
131
+
132
+ ``` java
133
+ class Solution {
134
+ public int numSquares (int n ) {
135
+ int m = (int ) Math . sqrt(n);
136
+ int [] f = new int [n + 1 ];
137
+ Arrays . fill(f, 1 << 30 );
138
+ f[0 ] = 0 ;
139
+ for (int i = 1 ; i <= m; ++ i) {
140
+ for (int j = i * i; j <= n; ++ j) {
141
+ f[j] = Math . min(f[j], f[j - i * i] + 1 );
142
+ }
143
+ }
144
+ return f[n];
78
145
}
79
146
}
80
147
```
@@ -85,48 +152,88 @@ class Solution {
85
152
class Solution {
86
153
public:
87
154
int numSquares(int n) {
88
- vector<int > dp(n + 1);
89
- for (int i = 1; i <= n; ++i) {
90
- int mi = 100000;
91
- for (int j = 1; j * j <= i; ++j) {
92
- mi = min(mi, dp[ i - j * j] );
155
+ int m = sqrt(n);
156
+ int f[ m + 1] [ n + 1 ] ;
157
+ memset(f, 0x3f, sizeof(f));
158
+ f[ 0] [ 0 ] = 0;
159
+ for (int i = 1; i <= m; ++i) {
160
+ for (int j = 0; j <= n; ++j) {
161
+ f[ i] [ j ] = f[ i - 1] [ j ] ;
162
+ if (j >= i * i) {
163
+ f[ i] [ j ] = min(f[ i] [ j ] , f[ i] [ j - i * i ] + 1);
164
+ }
93
165
}
94
- dp[ i] = mi + 1;
95
166
}
96
- return dp [ n] ;
167
+ return f [ m ] [ n ] ;
97
168
}
98
169
};
99
170
```
100
171
101
- ### **TypeScript**
102
-
103
- ```ts
104
- function numSquares(n: number): number {
105
- let dp = new Array(n + 1).fill(0);
106
- for (let i = 1; i <= n; ++i) {
107
- let min = Infinity;
108
- for (let j = 1; j * j <= i; ++j) {
109
- min = Math.min(min, dp[i - j * j]);
172
+ ```cpp
173
+ class Solution {
174
+ public:
175
+ int numSquares(int n) {
176
+ int m = sqrt(n);
177
+ int f[n + 1];
178
+ memset(f, 0x3f, sizeof(f));
179
+ f[0] = 0;
180
+ for (int i = 1; i <= m; ++i) {
181
+ for (int j = i * i; j <= n; ++j) {
182
+ f[j] = min(f[j], f[j - i * i] + 1);
183
+ }
110
184
}
111
- dp[i] = min + 1 ;
185
+ return f[n] ;
112
186
}
113
- return dp.pop();
114
- }
187
+ };
115
188
```
116
189
117
190
### ** Go**
118
191
119
192
``` go
120
193
func numSquares (n int ) int {
121
- dp := make ([]int , n+1 )
122
- for i := 1 ; i <= n; i++ {
123
- mi := 100000
124
- for j := 1 ; j*j <= i; j++ {
125
- mi = min (mi, dp[i-j*j])
194
+ m := int (math.Sqrt (float64 (n)))
195
+ f := make ([][]int , m+1 )
196
+ const inf = 1 << 30
197
+ for i := range f {
198
+ f[i] = make ([]int , n+1 )
199
+ for j := range f[i] {
200
+ f[i][j] = inf
201
+ }
202
+ }
203
+ f[0 ][0 ] = 0
204
+ for i := 1 ; i <= m; i++ {
205
+ for j := 0 ; j <= n; j++ {
206
+ f[i][j] = f[i-1 ][j]
207
+ if j >= i*i {
208
+ f[i][j] = min (f[i][j], f[i][j-i*i]+1 )
209
+ }
210
+ }
211
+ }
212
+ return f[m][n]
213
+ }
214
+
215
+ func min (a , b int ) int {
216
+ if a < b {
217
+ return a
218
+ }
219
+ return b
220
+ }
221
+ ```
222
+
223
+ ``` go
224
+ func numSquares (n int ) int {
225
+ m := int (math.Sqrt (float64 (n)))
226
+ f := make ([]int , n+1 )
227
+ for i := range f {
228
+ f[i] = 1 << 30
229
+ }
230
+ f[0 ] = 0
231
+ for i := 1 ; i <= m; i++ {
232
+ for j := i * i; j <= n; j++ {
233
+ f[j] = min (f[j], f[j-i*i]+1 )
126
234
}
127
- dp[i] = mi + 1
128
235
}
129
- return dp [n]
236
+ return f [n]
130
237
}
131
238
132
239
func min (a , b int ) int {
@@ -137,6 +244,41 @@ func min(a, b int) int {
137
244
}
138
245
```
139
246
247
+ ### ** TypeScript**
248
+
249
+ ``` ts
250
+ function numSquares(n : number ): number {
251
+ const m = Math .floor (Math .sqrt (n ));
252
+ const f: number [][] = Array (m + 1 )
253
+ .fill (0 )
254
+ .map (() => Array (n + 1 ).fill (1 << 30 ));
255
+ f [0 ][0 ] = 0 ;
256
+ for (let i = 1 ; i <= m ; ++ i ) {
257
+ for (let j = 0 ; j <= n ; ++ j ) {
258
+ f [i ][j ] = f [i - 1 ][j ];
259
+ if (j >= i * i ) {
260
+ f [i ][j ] = Math .min (f [i ][j ], f [i ][j - i * i ] + 1 );
261
+ }
262
+ }
263
+ }
264
+ return f [m ][n ];
265
+ }
266
+ ```
267
+
268
+ ``` ts
269
+ function numSquares(n : number ): number {
270
+ const m = Math .floor (Math .sqrt (n ));
271
+ const f: number [] = Array (n + 1 ).fill (1 << 30 );
272
+ f [0 ] = 0 ;
273
+ for (let i = 1 ; i <= m ; ++ i ) {
274
+ for (let j = i * i ; j <= n ; ++ j ) {
275
+ f [j ] = Math .min (f [j ], f [j - i * i ] + 1 );
276
+ }
277
+ }
278
+ return f [n ];
279
+ }
280
+ ```
281
+
140
282
### ** ...**
141
283
142
284
```
0 commit comments