Skip to content

Commit 7993360

Browse files
committed
feat: add solutions to lc problem: No.0996
No.0996.Number of Squareful Arrays
1 parent d2808c0 commit 7993360

File tree

8 files changed

+464
-5
lines changed

8 files changed

+464
-5
lines changed

solution/0900-0999/0996.Number of Squareful Arrays/README.md

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,187 @@
3939

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

42+
**方法一:二进制状态压缩 + 动态规划**
43+
44+
注意到,数组 $nums$ 的长度 $n$ 不超过 $12$,因此我们可以用一个二进制数表示当前所选的数字的状态,若第 $i$ 位为 $1$,则表示当前选择了第 $i$ 个数字,否则表示当前没有选择第 $i$ 个数字。
45+
46+
我们定义 $f[i][j]$ 表示当前所选的数字的状态为 $i$,且最后一个数字为 $nums[j]$ 的方案数。那么答案就是 $\sum_{j=0}^{n-1} f[2^n-1][j]$。由于最后求解的是排列数,因此还需要除以每个数字出现的次数的阶乘。
47+
48+
接下来,我们考虑如何进行状态转移。
49+
50+
假设当前所选的数字的状态为 $i$,最后一个数字为 $nums[j]$,那么我们可以枚举 $i$ 的每一位为 $1$ 的数字作为倒数第二个数,不妨设为 $nums[k]$,那么我们只需要判断 $nums[j]+nums[k]$ 是否为完全平方数即可,若是,方案数 $f[i][j]$ 就可以加上 $f[i \oplus 2^j][k]$,其中 $i \oplus 2^j$ 表示将 $i$ 的第 $j$ 位取反,即表示将 $nums[j]$ 从当前所选的数字中去除。
51+
52+
最后,我们还需要除以每个数字出现的次数的阶乘,因为我们在枚举 $i$ 的每一位为 $1$ 的数字时,可能会重复计算某些排列,因此需要除以每个数字出现的次数的阶乘。
53+
54+
时间复杂度 $O(2^n \times n^2),空间复杂度 O(2^n \times n)$。其中 $n$ 为数组 $nums$ 的长度。
55+
4256
<!-- tabs:start -->
4357

4458
### **Python3**
4559

4660
<!-- 这里可写当前语言的特殊实现逻辑 -->
4761

4862
```python
49-
63+
class Solution:
64+
def numSquarefulPerms(self, nums: List[int]) -> int:
65+
n = len(nums)
66+
f = [[0] * n for _ in range(1 << n)]
67+
for j in range(n):
68+
f[1 << j][j] = 1
69+
for i in range(1 << n):
70+
for j in range(n):
71+
if i >> j & 1:
72+
for k in range(n):
73+
if (i >> k & 1) and k != j:
74+
s = nums[j] + nums[k]
75+
t = int(sqrt(s))
76+
if t * t == s:
77+
f[i][j] += f[i ^ (1 << j)][k]
78+
79+
ans = sum(f[(1 << n) - 1][j] for j in range(n))
80+
for v in Counter(nums).values():
81+
ans //= factorial(v)
82+
return ans
5083
```
5184

5285
### **Java**
5386

5487
<!-- 这里可写当前语言的特殊实现逻辑 -->
5588

5689
```java
90+
class Solution {
91+
public int numSquarefulPerms(int[] nums) {
92+
int n = nums.length;
93+
int[][] f = new int[1 << n][n];
94+
for (int j = 0; j < n; ++j) {
95+
f[1 << j][j] = 1;
96+
}
97+
for (int i = 0; i < 1 << n; ++i) {
98+
for (int j = 0; j < n; ++j) {
99+
if ((i >> j & 1) == 1) {
100+
for (int k = 0; k < n; ++k) {
101+
if ((i >> k & 1) == 1 && k != j) {
102+
int s = nums[j] + nums[k];
103+
int t = (int) Math.sqrt(s);
104+
if (t * t == s) {
105+
f[i][j] += f[i ^ (1 << j)][k];
106+
}
107+
}
108+
}
109+
}
110+
}
111+
}
112+
long ans = 0;
113+
for (int j = 0; j < n; ++j) {
114+
ans += f[(1 << n) - 1][j];
115+
}
116+
Map<Integer, Integer> cnt = new HashMap<>();
117+
for (int x : nums) {
118+
cnt.merge(x, 1, Integer::sum);
119+
}
120+
int[] g = new int[13];
121+
g[0] = 1;
122+
for (int i = 1; i < 13; ++i) {
123+
g[i] = g[i - 1] * i;
124+
}
125+
for (int v : cnt.values()) {
126+
ans /= g[v];
127+
}
128+
return (int) ans;
129+
}
130+
}
131+
```
132+
133+
### **C++**
134+
135+
```cpp
136+
class Solution {
137+
public:
138+
int numSquarefulPerms(vector<int>& nums) {
139+
int n = nums.size();
140+
int f[1 << n][n];
141+
memset(f, 0, sizeof(f));
142+
for (int j = 0; j < n; ++j) {
143+
f[1 << j][j] = 1;
144+
}
145+
for (int i = 0; i < 1 << n; ++i) {
146+
for (int j = 0; j < n; ++j) {
147+
if ((i >> j & 1) == 1) {
148+
for (int k = 0; k < n; ++k) {
149+
if ((i >> k & 1) == 1 && k != j) {
150+
int s = nums[j] + nums[k];
151+
int t = sqrt(s);
152+
if (t * t == s) {
153+
f[i][j] += f[i ^ (1 << j)][k];
154+
}
155+
}
156+
}
157+
}
158+
}
159+
}
160+
long long ans = 0;
161+
for (int j = 0; j < n; ++j) {
162+
ans += f[(1 << n) - 1][j];
163+
}
164+
unordered_map<int, int> cnt;
165+
for (int x : nums) {
166+
++cnt[x];
167+
}
168+
int g[13] = {1};
169+
for (int i = 1; i < 13; ++i) {
170+
g[i] = g[i - 1] * i;
171+
}
172+
for (auto& [_, v] : cnt) {
173+
ans /= g[v];
174+
}
175+
return ans;
176+
}
177+
};
178+
```
57179
180+
### **Go**
181+
182+
```go
183+
func numSquarefulPerms(nums []int) (ans int) {
184+
n := len(nums)
185+
f := make([][]int, 1<<n)
186+
for i := range f {
187+
f[i] = make([]int, n)
188+
}
189+
for j := range nums {
190+
f[1<<j][j] = 1
191+
}
192+
for i := 0; i < 1<<n; i++ {
193+
for j := 0; j < n; j++ {
194+
if i>>j&1 == 1 {
195+
for k := 0; k < n; k++ {
196+
if i>>k&1 == 1 && k != j {
197+
s := nums[j] + nums[k]
198+
t := int(math.Sqrt(float64(s)))
199+
if t*t == s {
200+
f[i][j] += f[i^(1<<j)][k]
201+
}
202+
}
203+
}
204+
}
205+
}
206+
}
207+
for j := 0; j < n; j++ {
208+
ans += f[(1<<n)-1][j]
209+
}
210+
g := [13]int{1}
211+
for i := 1; i < 13; i++ {
212+
g[i] = g[i-1] * i
213+
}
214+
cnt := map[int]int{}
215+
for _, x := range nums {
216+
cnt[x]++
217+
}
218+
for _, v := range cnt {
219+
ans /= g[v]
220+
}
221+
return
222+
}
58223
```
59224

60225
### **...**

solution/0900-0999/0996.Number of Squareful Arrays/README_EN.md

Lines changed: 152 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,164 @@
4141
### **Python3**
4242

4343
```python
44-
44+
class Solution:
45+
def numSquarefulPerms(self, nums: List[int]) -> int:
46+
n = len(nums)
47+
f = [[0] * n for _ in range(1 << n)]
48+
for j in range(n):
49+
f[1 << j][j] = 1
50+
for i in range(1 << n):
51+
for j in range(n):
52+
if i >> j & 1:
53+
for k in range(n):
54+
if (i >> k & 1) and k != j:
55+
s = nums[j] + nums[k]
56+
t = int(sqrt(s))
57+
if t * t == s:
58+
f[i][j] += f[i ^ (1 << j)][k]
59+
60+
ans = sum(f[(1 << n) - 1][j] for j in range(n))
61+
for v in Counter(nums).values():
62+
ans //= factorial(v)
63+
return ans
4564
```
4665

4766
### **Java**
4867

4968
```java
69+
class Solution {
70+
public int numSquarefulPerms(int[] nums) {
71+
int n = nums.length;
72+
int[][] f = new int[1 << n][n];
73+
for (int j = 0; j < n; ++j) {
74+
f[1 << j][j] = 1;
75+
}
76+
for (int i = 0; i < 1 << n; ++i) {
77+
for (int j = 0; j < n; ++j) {
78+
if ((i >> j & 1) == 1) {
79+
for (int k = 0; k < n; ++k) {
80+
if ((i >> k & 1) == 1 && k != j) {
81+
int s = nums[j] + nums[k];
82+
int t = (int) Math.sqrt(s);
83+
if (t * t == s) {
84+
f[i][j] += f[i ^ (1 << j)][k];
85+
}
86+
}
87+
}
88+
}
89+
}
90+
}
91+
long ans = 0;
92+
for (int j = 0; j < n; ++j) {
93+
ans += f[(1 << n) - 1][j];
94+
}
95+
Map<Integer, Integer> cnt = new HashMap<>();
96+
for (int x : nums) {
97+
cnt.merge(x, 1, Integer::sum);
98+
}
99+
int[] g = new int[13];
100+
g[0] = 1;
101+
for (int i = 1; i < 13; ++i) {
102+
g[i] = g[i - 1] * i;
103+
}
104+
for (int v : cnt.values()) {
105+
ans /= g[v];
106+
}
107+
return (int) ans;
108+
}
109+
}
110+
```
111+
112+
### **C++**
113+
114+
```cpp
115+
class Solution {
116+
public:
117+
int numSquarefulPerms(vector<int>& nums) {
118+
int n = nums.size();
119+
int f[1 << n][n];
120+
memset(f, 0, sizeof(f));
121+
for (int j = 0; j < n; ++j) {
122+
f[1 << j][j] = 1;
123+
}
124+
for (int i = 0; i < 1 << n; ++i) {
125+
for (int j = 0; j < n; ++j) {
126+
if ((i >> j & 1) == 1) {
127+
for (int k = 0; k < n; ++k) {
128+
if ((i >> k & 1) == 1 && k != j) {
129+
int s = nums[j] + nums[k];
130+
int t = sqrt(s);
131+
if (t * t == s) {
132+
f[i][j] += f[i ^ (1 << j)][k];
133+
}
134+
}
135+
}
136+
}
137+
}
138+
}
139+
long long ans = 0;
140+
for (int j = 0; j < n; ++j) {
141+
ans += f[(1 << n) - 1][j];
142+
}
143+
unordered_map<int, int> cnt;
144+
for (int x : nums) {
145+
++cnt[x];
146+
}
147+
int g[13] = {1};
148+
for (int i = 1; i < 13; ++i) {
149+
g[i] = g[i - 1] * i;
150+
}
151+
for (auto& [_, v] : cnt) {
152+
ans /= g[v];
153+
}
154+
return ans;
155+
}
156+
};
157+
```
50158
159+
### **Go**
160+
161+
```go
162+
func numSquarefulPerms(nums []int) (ans int) {
163+
n := len(nums)
164+
f := make([][]int, 1<<n)
165+
for i := range f {
166+
f[i] = make([]int, n)
167+
}
168+
for j := range nums {
169+
f[1<<j][j] = 1
170+
}
171+
for i := 0; i < 1<<n; i++ {
172+
for j := 0; j < n; j++ {
173+
if i>>j&1 == 1 {
174+
for k := 0; k < n; k++ {
175+
if i>>k&1 == 1 && k != j {
176+
s := nums[j] + nums[k]
177+
t := int(math.Sqrt(float64(s)))
178+
if t*t == s {
179+
f[i][j] += f[i^(1<<j)][k]
180+
}
181+
}
182+
}
183+
}
184+
}
185+
}
186+
for j := 0; j < n; j++ {
187+
ans += f[(1<<n)-1][j]
188+
}
189+
g := [13]int{1}
190+
for i := 1; i < 13; i++ {
191+
g[i] = g[i-1] * i
192+
}
193+
cnt := map[int]int{}
194+
for _, x := range nums {
195+
cnt[x]++
196+
}
197+
for _, v := range cnt {
198+
ans /= g[v]
199+
}
200+
return
201+
}
51202
```
52203

53204
### **...**
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
class Solution {
2+
public:
3+
int numSquarefulPerms(vector<int>& nums) {
4+
int n = nums.size();
5+
int f[1 << n][n];
6+
memset(f, 0, sizeof(f));
7+
for (int j = 0; j < n; ++j) {
8+
f[1 << j][j] = 1;
9+
}
10+
for (int i = 0; i < 1 << n; ++i) {
11+
for (int j = 0; j < n; ++j) {
12+
if ((i >> j & 1) == 1) {
13+
for (int k = 0; k < n; ++k) {
14+
if ((i >> k & 1) == 1 && k != j) {
15+
int s = nums[j] + nums[k];
16+
int t = sqrt(s);
17+
if (t * t == s) {
18+
f[i][j] += f[i ^ (1 << j)][k];
19+
}
20+
}
21+
}
22+
}
23+
}
24+
}
25+
long long ans = 0;
26+
for (int j = 0; j < n; ++j) {
27+
ans += f[(1 << n) - 1][j];
28+
}
29+
unordered_map<int, int> cnt;
30+
for (int x : nums) {
31+
++cnt[x];
32+
}
33+
int g[13] = {1};
34+
for (int i = 1; i < 13; ++i) {
35+
g[i] = g[i - 1] * i;
36+
}
37+
for (auto& [_, v] : cnt) {
38+
ans /= g[v];
39+
}
40+
return ans;
41+
}
42+
};

0 commit comments

Comments
 (0)