Skip to content

Commit fa38c56

Browse files
authored
feat: add solutions to lc problem: No.3343 (doocs#3710)
No.3343.Count Number of Balanced Permutations
1 parent 7f9a026 commit fa38c56

File tree

11 files changed

+860
-12
lines changed

11 files changed

+860
-12
lines changed

solution/3300-3399/3341.Find Minimum Time to Reach Last Room I/README.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,15 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3341.Fi
8484

8585
<!-- solution:start -->
8686

87-
### 方法一
87+
### 方法一:Dijkstra 算法
88+
89+
我们定义一个二维数组 $\textit{dist}$,其中 $\textit{dist}[i][j]$ 表示从起点到达房间 $(i, j)$ 所需的最少时间。初始时,我们将 $\textit{dist}$ 数组中的所有元素设为无穷大,然后将起点 $(0, 0)$ 的 $\textit{dist}$ 值设为 $0$。
90+
91+
我们使用优先队列 $\textit{pq}$ 存储每一个状态,其中每个状态由三个值 $(d, i, j)$ 组成,表示从起点到达房间 $(i, j)$ 所需的时间为 $d$。初始时,我们将起点 $(0, 0, 0)$ 加入到 $\textit{pq}$ 中。
92+
93+
在每一次迭代中,我们取出 $\textit{pq}$ 中的队首元素 $(d, i, j)$,如果 $(i, j)$ 是终点,那么我们返回 $d$。如果 $d$ 大于 $\textit{dist}[i][j]$,那么我们跳过这个状态。否则,我们枚举 $(i, j)$ 的四个相邻位置 $(x, y)$,如果 $(x, y)$ 在地图内,那么我们计算从 $(i, j)$ 到 $(x, y)$ 的最终时间 $t = \max(\textit{moveTime}[x][y], \textit{dist}[i][j]) + 1$,如果 $t$ 小于 $\textit{dist}[x][y]$,那么我们更新 $\textit{dist}[x][y]$ 的值,并将 $(t, x, y)$ 加入到 $\textit{pq}$ 中。
94+
95+
时间复杂度 $O(n \times m \times \log (n \times m))$,空间复杂度 $O(n \times m)$。其中 $n$ 和 $m$ 分别是地图的行数和列数。
8896

8997
<!-- tabs:start -->
9098

solution/3300-3399/3341.Find Minimum Time to Reach Last Room I/README_EN.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,15 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3341.Fi
8181

8282
<!-- solution:start -->
8383

84-
### Solution 1
84+
### Solution 1: Dijkstra's Algorithm
85+
86+
We define a two-dimensional array $\textit{dist}$, where $\textit{dist}[i][j]$ represents the minimum time required to reach room $(i, j)$ from the starting point. Initially, we set all elements in the $\textit{dist}$ array to infinity, and then set the $\textit{dist}$ value of the starting point $(0, 0)$ to $0$.
87+
88+
We use a priority queue $\textit{pq}$ to store each state, where each state consists of three values $(d, i, j)$, representing the time $d$ required to reach room $(i, j)$ from the starting point. Initially, we add the starting point $(0, 0, 0)$ to $\textit{pq}$.
89+
90+
In each iteration, we take the front element $(d, i, j)$ from $\textit{pq}$. If $(i, j)$ is the endpoint, we return $d$. If $d$ is greater than $\textit{dist}[i][j]$, we skip this state. Otherwise, we enumerate the four adjacent positions $(x, y)$ of $(i, j)$. If $(x, y)$ is within the map, we calculate the final time $t$ from $(i, j)$ to $(x, y)$ as $t = \max(\textit{moveTime}[x][y], \textit{dist}[i][j]) + 1$. If $t$ is less than $\textit{dist}[x][y]$, we update the value of $\textit{dist}[x][y]$ and add $(t, x, y)$ to $\textit{pq}$.
91+
92+
The time complexity is $O(n \times m \times \log (n \times m))$, and the space complexity is $O(n \times m)$. Here, $n$ and $m$ are the number of rows and columns of the map, respectively.
8593

8694
<!-- tabs:start -->
8795

solution/3300-3399/3342.Find Minimum Time to Reach Last Room II/README.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,15 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3342.Fi
8585

8686
<!-- solution:start -->
8787

88-
### 方法一
88+
### 方法一:Dijkstra 算法
89+
90+
我们定义一个二维数组 $\textit{dist}$,其中 $\textit{dist}[i][j]$ 表示从起点到达房间 $(i, j)$ 所需的最少时间。初始时,我们将 $\textit{dist}$ 数组中的所有元素设为无穷大,然后将起点 $(0, 0)$ 的 $\textit{dist}$ 值设为 $0$。
91+
92+
我们使用优先队列 $\textit{pq}$ 存储每一个状态,其中每个状态由三个值 $(d, i, j)$ 组成,表示从起点到达房间 $(i, j)$ 所需的时间为 $d$。初始时,我们将起点 $(0, 0, 0)$ 加入到 $\textit{pq}$ 中。
93+
94+
在每一次迭代中,我们取出 $\textit{pq}$ 中的队首元素 $(d, i, j)$,如果 $(i, j)$ 是终点,那么我们返回 $d$。如果 $d$ 大于 $\textit{dist}[i][j]$,那么我们跳过这个状态。否则,我们枚举 $(i, j)$ 的四个相邻位置 $(x, y)$,如果 $(x, y)$ 在地图内,那么我们计算从 $(i, j)$ 到 $(x, y)$ 的最终时间 $t = \max(\textit{moveTime}[x][y], \textit{dist}[i][j]) + (i + 2) \bmod 2 + 1$,如果 $t$ 小于 $\textit{dist}[x][y]$,那么我们更新 $\textit{dist}[x][y]$ 的值,并将 $(t, x, y)$ 加入到 $\textit{pq}$ 中。
95+
96+
时间复杂度 $O(n \times m \times \log (n \times m))$,空间复杂度 $O(n \times m)$。其中 $n$ 和 $m$ 分别是地图的行数和列数。
8997

9098
<!-- tabs:start -->
9199

solution/3300-3399/3342.Find Minimum Time to Reach Last Room II/README_EN.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,15 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3342.Fi
8282

8383
<!-- solution:start -->
8484

85-
### Solution 1
85+
### Solution 1: Dijkstra's Algorithm
86+
87+
We define a two-dimensional array $\textit{dist}$, where $\textit{dist}[i][j]$ represents the minimum time required to reach room $(i, j)$ from the starting point. Initially, we set all elements in the $\textit{dist}$ array to infinity, and then set the $\textit{dist}$ value of the starting point $(0, 0)$ to $0$.
88+
89+
We use a priority queue $\textit{pq}$ to store each state, where each state consists of three values $(d, i, j)$, representing the time $d$ required to reach room $(i, j)$ from the starting point. Initially, we add the starting point $(0, 0, 0)$ to $\textit{pq}$.
90+
91+
In each iteration, we take the front element $(d, i, j)$ from $\textit{pq}$. If $(i, j)$ is the endpoint, we return $d$. If $d$ is greater than $\textit{dist}[i][j]$, we skip this state. Otherwise, we enumerate the four adjacent positions $(x, y)$ of $(i, j)$. If $(x, y)$ is within the map, we calculate the final time $t$ from $(i, j)$ to $(x, y)$ as $t = \max(\textit{moveTime}[x][y], \textit{dist}[i][j]) + (i + j) \bmod 2 + 1$. If $t$ is less than $\textit{dist}[x][y]$, we update the value of $\textit{dist}[x][y]$ and add $(t, x, y)$ to $\textit{pq}$.
92+
93+
The time complexity is $O(n \times m \times \log (n \times m))$, and the space complexity is $O(n \times m)$. Here, $n$ and $m$ are the number of rows and columns of the map, respectively.
8694

8795
<!-- tabs:start -->
8896

solution/3300-3399/3343.Count Number of Balanced Permutations/README.md

+281-4
Original file line numberDiff line numberDiff line change
@@ -85,32 +85,309 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3343.Co
8585

8686
<!-- solution:start -->
8787

88-
### 方法一
88+
### 方法一:记忆化搜索 + 组合数学
89+
90+
我们首先统计出字符串 $\textit{num}$ 中每个数字出现的次数,记录在数组 $\textit{cnt}$ 中,然后计算出字符串 $\textit{num}$ 的总和 $\textit{s}$。
91+
92+
如果 $\textit{s}$ 是奇数,那么 $\textit{num}$ 一定不是平衡的,直接返回 $0$。
93+
94+
接下来,我们定义记忆化搜索函数 $\text{dfs}(i, j, a, b)$,其中 $i$ 表示当前要从数字 $i$ 开始填充,而 $j$ 表示奇数位剩余待填的数字之和,而 $a$ 和 $b$ 分别表示奇数位和偶数位剩余待填的数字个数。我们记字符串 $\textit{num}$ 的长度为 $n$,那么答案就是 $\text{dfs}(0, s / 2, n / 2, (n + 1) / 2)$。
95+
96+
在 $\text{dfs}(i, j, a, b)$ 函数中,我们首先判断是否已经填充完了所有的数字,如果是的话,此时需要满足 $j = 0$ 且 $a = 0$ 且 $b = 0$,若满足这个条件,说明当前的排列是平衡的,返回 $1$,否则返回 $0$。
97+
98+
接下来,我们判断当前奇数位剩余待填的数字个数 $a$ 是否为 $0$ 且 $j > 0$,如果是的话,说明当前的排列不是平衡的,提前返回 $0$。
99+
100+
否则,我们可以枚举当前数字分配给奇数位的数字个数 $l$,那么偶数位的数字个数就是 $r = \textit{cnt}[i] - l$,我们需要满足 $0 \leq r \leq b$ 且 $l \times i \leq j$,然后我们计算出当前的方案数 $t = C_a^l \times C_b^r \times \text{dfs}(i + 1, j - l \times i, a - l, b - r)$,最后答案就是所有方案数之和。
101+
102+
时间复杂度 $O(|\Sigma| \times n^2 \times (n + |\Sigma|))$,其中 $|\Sigma|$ 表示数字的种类数,本题中 $|\Sigma| = 10$。空间复杂度 $O(n^2 \times |\Sigma|^2)$。
89103

90104
<!-- tabs:start -->
91105

92106
#### Python3
93107

94108
```python
95-
109+
class Solution:
110+
def countBalancedPermutations(self, num: str) -> int:
111+
@cache
112+
def dfs(i: int, j: int, a: int, b: int) -> int:
113+
if i > 9:
114+
return (j | a | b) == 0
115+
if a == 0 and j:
116+
return 0
117+
ans = 0
118+
for l in range(min(cnt[i], a) + 1):
119+
r = cnt[i] - l
120+
if 0 <= r <= b and l * i <= j:
121+
t = comb(a, l) * comb(b, r) * dfs(i + 1, j - l * i, a - l, b - r)
122+
ans = (ans + t) % mod
123+
return ans
124+
125+
nums = list(map(int, num))
126+
s = sum(nums)
127+
if s % 2:
128+
return 0
129+
n = len(nums)
130+
mod = 10**9 + 7
131+
cnt = Counter(nums)
132+
return dfs(0, s // 2, n // 2, (n + 1) // 2)
96133
```
97134

98135
#### Java
99136

100137
```java
101-
138+
class Solution {
139+
private final int[] cnt = new int[10];
140+
private final int mod = (int) 1e9 + 7;
141+
private Integer[][][][] f;
142+
private long[][] c;
143+
144+
public int countBalancedPermutations(String num) {
145+
int s = 0;
146+
for (char c : num.toCharArray()) {
147+
cnt[c - '0']++;
148+
s += c - '0';
149+
}
150+
if (s % 2 == 1) {
151+
return 0;
152+
}
153+
int n = num.length();
154+
int m = n / 2 + 1;
155+
f = new Integer[10][s / 2 + 1][m][m + 1];
156+
c = new long[m + 1][m + 1];
157+
c[0][0] = 1;
158+
for (int i = 1; i <= m; i++) {
159+
c[i][0] = 1;
160+
for (int j = 1; j <= i; j++) {
161+
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
162+
}
163+
}
164+
return dfs(0, s / 2, n / 2, (n + 1) / 2);
165+
}
166+
167+
private int dfs(int i, int j, int a, int b) {
168+
if (i > 9) {
169+
return ((j | a | b) == 0) ? 1 : 0;
170+
}
171+
if (a == 0 && j != 0) {
172+
return 0;
173+
}
174+
if (f[i][j][a][b] != null) {
175+
return f[i][j][a][b];
176+
}
177+
int ans = 0;
178+
for (int l = 0; l <= Math.min(cnt[i], a); ++l) {
179+
int r = cnt[i] - l;
180+
if (r >= 0 && r <= b && l * i <= j) {
181+
int t = (int) (c[a][l] * c[b][r] % mod * dfs(i + 1, j - l * i, a - l, b - r) % mod);
182+
ans = (ans + t) % mod;
183+
}
184+
}
185+
return f[i][j][a][b] = ans;
186+
}
187+
}
102188
```
103189

104190
#### C++
105191

106192
```cpp
107-
193+
using ll = long long;
194+
const int MX = 80;
195+
const int MOD = 1e9 + 7;
196+
ll c[MX][MX];
197+
198+
auto init = [] {
199+
c[0][0] = 1;
200+
for (int i = 1; i < MX; ++i) {
201+
c[i][0] = 1;
202+
for (int j = 1; j <= i; ++j) {
203+
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
204+
}
205+
}
206+
return 0;
207+
}();
208+
209+
class Solution {
210+
public:
211+
int countBalancedPermutations(string num) {
212+
int cnt[10]{};
213+
int s = 0;
214+
for (char& c : num) {
215+
++cnt[c - '0'];
216+
s += c - '0';
217+
}
218+
if (s % 2) {
219+
return 0;
220+
}
221+
int n = num.size();
222+
int m = n / 2 + 1;
223+
int f[10][s / 2 + 1][m][m + 1];
224+
memset(f, -1, sizeof(f));
225+
auto dfs = [&](auto&& dfs, int i, int j, int a, int b) -> int {
226+
if (i > 9) {
227+
return ((j | a | b) == 0 ? 1 : 0);
228+
}
229+
if (a == 0 && j) {
230+
return 0;
231+
}
232+
if (f[i][j][a][b] != -1) {
233+
return f[i][j][a][b];
234+
}
235+
int ans = 0;
236+
for (int l = 0; l <= min(cnt[i], a); ++l) {
237+
int r = cnt[i] - l;
238+
if (r >= 0 && r <= b && l * i <= j) {
239+
int t = c[a][l] * c[b][r] % MOD * dfs(dfs, i + 1, j - l * i, a - l, b - r) % MOD;
240+
ans = (ans + t) % MOD;
241+
}
242+
}
243+
return f[i][j][a][b] = ans;
244+
};
245+
return dfs(dfs, 0, s / 2, n / 2, (n + 1) / 2);
246+
}
247+
};
108248
```
109249
110250
#### Go
111251
112252
```go
253+
const (
254+
MX = 80
255+
MOD = 1_000_000_007
256+
)
257+
258+
var c [MX][MX]int
259+
260+
func init() {
261+
c[0][0] = 1
262+
for i := 1; i < MX; i++ {
263+
c[i][0] = 1
264+
for j := 1; j <= i; j++ {
265+
c[i][j] = (c[i-1][j] + c[i-1][j-1]) % MOD
266+
}
267+
}
268+
}
269+
270+
func countBalancedPermutations(num string) int {
271+
var cnt [10]int
272+
s := 0
273+
for _, ch := range num {
274+
cnt[ch-'0']++
275+
s += int(ch - '0')
276+
}
277+
278+
if s%2 != 0 {
279+
return 0
280+
}
281+
282+
n := len(num)
283+
m := n/2 + 1
284+
f := make([][][][]int, 10)
285+
for i := range f {
286+
f[i] = make([][][]int, s/2+1)
287+
for j := range f[i] {
288+
f[i][j] = make([][]int, m)
289+
for k := range f[i][j] {
290+
f[i][j][k] = make([]int, m+1)
291+
for l := range f[i][j][k] {
292+
f[i][j][k][l] = -1
293+
}
294+
}
295+
}
296+
}
297+
298+
var dfs func(i, j, a, b int) int
299+
dfs = func(i, j, a, b int) int {
300+
if i > 9 {
301+
if j == 0 && a == 0 && b == 0 {
302+
return 1
303+
}
304+
return 0
305+
}
306+
if a == 0 && j > 0 {
307+
return 0
308+
}
309+
if f[i][j][a][b] != -1 {
310+
return f[i][j][a][b]
311+
}
312+
ans := 0
313+
for l := 0; l <= min(cnt[i], a); l++ {
314+
r := cnt[i] - l
315+
if r >= 0 && r <= b && l*i <= j {
316+
t := c[a][l] * c[b][r] % MOD * dfs(i+1, j-l*i, a-l, b-r) % MOD
317+
ans = (ans + t) % MOD
318+
}
319+
}
320+
f[i][j][a][b] = ans
321+
return ans
322+
}
323+
324+
return dfs(0, s/2, n/2, (n+1)/2)
325+
}
326+
```
113327

328+
#### TypeScript
329+
330+
```ts
331+
const MX = 80;
332+
const MOD = 10 ** 9 + 7;
333+
const c: number[][] = Array.from({ length: MX }, () => Array(MX).fill(0));
334+
(function init() {
335+
c[0][0] = 1;
336+
for (let i = 1; i < MX; i++) {
337+
c[i][0] = 1;
338+
for (let j = 1; j <= i; j++) {
339+
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % MOD;
340+
}
341+
}
342+
})();
343+
344+
function countBalancedPermutations(num: string): number {
345+
const cnt = Array(10).fill(0);
346+
let s = 0;
347+
for (const ch of num) {
348+
cnt[+ch]++;
349+
s += +ch;
350+
}
351+
352+
if (s % 2 !== 0) {
353+
return 0;
354+
}
355+
356+
const n = num.length;
357+
const m = Math.floor(n / 2) + 1;
358+
const f: Record<string, number> = {};
359+
360+
const dfs = (i: number, j: number, a: number, b: number): number => {
361+
if (i > 9) {
362+
return (j | a | b) === 0 ? 1 : 0;
363+
}
364+
if (a === 0 && j > 0) {
365+
return 0;
366+
}
367+
368+
const key = `${i},${j},${a},${b}`;
369+
if (key in f) {
370+
return f[key];
371+
}
372+
373+
let ans = 0;
374+
for (let l = 0; l <= Math.min(cnt[i], a); l++) {
375+
const r = cnt[i] - l;
376+
if (r >= 0 && r <= b && l * i <= j) {
377+
const t = Number(
378+
(((BigInt(c[a][l]) * BigInt(c[b][r])) % BigInt(MOD)) *
379+
BigInt(dfs(i + 1, j - l * i, a - l, b - r))) %
380+
BigInt(MOD),
381+
);
382+
ans = (ans + t) % MOD;
383+
}
384+
}
385+
f[key] = ans;
386+
return ans;
387+
};
388+
389+
return dfs(0, s / 2, Math.floor(n / 2), Math.floor((n + 1) / 2));
390+
}
114391
```
115392

116393
<!-- tabs:end -->

0 commit comments

Comments
 (0)