Skip to content

Commit fed16e8

Browse files
committed
feat: add solutions to lc problem: No.0279
No.0279.Perfect Squares
1 parent 12d93b3 commit fed16e8

File tree

10 files changed

+423
-133
lines changed

10 files changed

+423
-133
lines changed

lcof/面试题66. 构建乘积数组/README.md

+18
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,24 @@ func constructArr(a []int) []int {
121121
}
122122
```
123123

124+
### **TypeScript**
125+
126+
```ts
127+
function constructArr(a: number[]): number[] {
128+
const n = a.length;
129+
const ans: number[] = Array(n);
130+
for (let i = 0, left = 1; i < n; ++i) {
131+
ans[i] = left;
132+
left *= a[i];
133+
}
134+
for (let i = n - 1, right = 1; i >= 0; --i) {
135+
ans[i] *= right;
136+
right *= a[i];
137+
}
138+
return ans;
139+
}
140+
```
141+
124142
### **JavaScript**
125143

126144
```js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
function constructArr(a: number[]): number[] {
2+
const n = a.length;
3+
const ans: number[] = Array(n);
4+
for (let i = 0, left = 1; i < n; ++i) {
5+
ans[i] = left;
6+
left *= a[i];
7+
}
8+
for (let i = n - 1, right = 1; i >= 0; --i) {
9+
ans[i] *= right;
10+
right *= a[i];
11+
}
12+
return ans;
13+
}

solution/0200-0299/0279.Perfect Squares/README.md

+184-42
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,39 @@
3838

3939
<!-- 这里可写通用的实现逻辑 -->
4040

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)
4274

4375
<!-- tabs:start -->
4476

@@ -49,14 +81,26 @@
4981
```python
5082
class Solution:
5183
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]
60104
```
61105

62106
### **Java**
@@ -66,15 +110,38 @@ class Solution:
66110
```java
67111
class Solution {
68112
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+
}
74125
}
75-
dp[i] = mi + 1;
76126
}
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];
78145
}
79146
}
80147
```
@@ -85,48 +152,88 @@ class Solution {
85152
class Solution {
86153
public:
87154
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+
}
93165
}
94-
dp[i] = mi + 1;
95166
}
96-
return dp[n];
167+
return f[m][n];
97168
}
98169
};
99170
```
100171
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+
}
110184
}
111-
dp[i] = min + 1;
185+
return f[n];
112186
}
113-
return dp.pop();
114-
}
187+
};
115188
```
116189

117190
### **Go**
118191

119192
```go
120193
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)
126234
}
127-
dp[i] = mi + 1
128235
}
129-
return dp[n]
236+
return f[n]
130237
}
131238

132239
func min(a, b int) int {
@@ -137,6 +244,41 @@ func min(a, b int) int {
137244
}
138245
```
139246

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+
140282
### **...**
141283

142284
```

0 commit comments

Comments
 (0)