Skip to content

Commit 3f772f3

Browse files
authored
feat: add solutions to lcci problem: No.08.08 (doocs#1659)
No.08.08.Permutation II
1 parent dc5512a commit 3f772f3

File tree

8 files changed

+514
-84
lines changed

8 files changed

+514
-84
lines changed

lcci/08.08.Permutation II/README.md

+184-28
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
## 题目描述
66

77
<!-- 这里写题目描述 -->
8+
89
<p>有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。</p>
910
<p><strong>示例1:</strong></p>
1011
<pre><strong> 输入</strong>:S = &quot;qqe&quot;
@@ -24,22 +25,182 @@
2425

2526
<!-- 这里可写通用的实现逻辑 -->
2627

28+
**方法一:排序 + 回溯**
29+
30+
我们可以先对字符串按照字符进行排序,这样就可以将重复的字符放在一起,方便我们进行去重。
31+
32+
然后,我们设计一个函数 $dfs(i)$,表示当前需要填写第 $i$ 个位置的字符。函数的具体实现如下:
33+
34+
- 如果 $i = n$,说明我们已经填写完毕,将当前排列加入答案数组中,然后返回。
35+
- 否则,我们枚举第 $i$ 个位置的字符 $s[j]$,其中 $j$ 的范围是 $[0, n - 1]$。我们需要保证 $s[j]$ 没有被使用过,并且与前面枚举的字符不同,这样才能保证当前排列不重复。如果满足条件,我们就可以填写 $s[j]$,并继续递归地填写下一个位置,即调用 $dfs(i + 1)$。在递归调用结束后,我们需要将 $s[j]$ 标记为未使用,以便于进行后面的枚举。
36+
37+
在主函数中,我们首先对字符串进行排序,然后调用 $dfs(0)$,即从第 $0$ 个位置开始填写,最终返回答案数组即可。
38+
39+
时间复杂度 $O(n \times n!)$,空间复杂度 $O(n)$。其中 $n$ 是字符串 $s$ 的长度。需要进行 $n!$ 次枚举,每次枚举需要 $O(n)$ 的时间来判断是否重复。另外,我们需要一个标记数组来标记每个位置是否被使用过,因此空间复杂度为 $O(n)$。
40+
2741
<!-- tabs:start -->
2842

2943
### **Python3**
3044

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

3347
```python
34-
48+
class Solution:
49+
def permutation(self, S: str) -> List[str]:
50+
def dfs(i: int):
51+
if i == n:
52+
ans.append("".join(t))
53+
return
54+
for j in range(n):
55+
if vis[j] or (j and cs[j] == cs[j - 1] and not vis[j - 1]):
56+
continue
57+
t[i] = cs[j]
58+
vis[j] = True
59+
dfs(i + 1)
60+
vis[j] = False
61+
62+
cs = sorted(S)
63+
n = len(cs)
64+
ans = []
65+
t = [None] * n
66+
vis = [False] * n
67+
dfs(0)
68+
return ans
3569
```
3670

3771
### **Java**
3872

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

4175
```java
76+
class Solution {
77+
private int n;
78+
private char[] cs;
79+
private List<String> ans = new ArrayList<>();
80+
private boolean[] vis;
81+
private StringBuilder t = new StringBuilder();
82+
83+
public String[] permutation(String S) {
84+
cs = S.toCharArray();
85+
n = cs.length;
86+
Arrays.sort(cs);
87+
vis = new boolean[n];
88+
dfs(0);
89+
return ans.toArray(new String[0]);
90+
}
91+
92+
private void dfs(int i) {
93+
if (i == n) {
94+
ans.add(t.toString());
95+
return;
96+
}
97+
for (int j = 0; j < n; ++j) {
98+
if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] == cs[j - 1])) {
99+
continue;
100+
}
101+
vis[j] = true;
102+
t.append(cs[j]);
103+
dfs(i + 1);
104+
t.deleteCharAt(t.length() - 1);
105+
vis[j] = false;
106+
}
107+
}
108+
}
109+
```
42110

111+
### **C++**
112+
113+
```cpp
114+
class Solution {
115+
public:
116+
vector<string> permutation(string S) {
117+
vector<char> cs(S.begin(), S.end());
118+
sort(cs.begin(), cs.end());
119+
int n = cs.size();
120+
vector<string> ans;
121+
vector<bool> vis(n);
122+
string t;
123+
function<void(int)> dfs = [&](int i) {
124+
if (i == n) {
125+
ans.push_back(t);
126+
return;
127+
}
128+
for (int j = 0; j < n; ++j) {
129+
if (vis[j] || (j && !vis[j - 1] && cs[j] == cs[j - 1])) {
130+
continue;
131+
}
132+
vis[j] = true;
133+
t.push_back(cs[j]);
134+
dfs(i + 1);
135+
t.pop_back();
136+
vis[j] = false;
137+
}
138+
};
139+
dfs(0);
140+
return ans;
141+
}
142+
};
143+
```
144+
145+
### **Go**
146+
147+
```go
148+
func permutation(S string) (ans []string) {
149+
cs := []byte(S)
150+
sort.Slice(cs, func(i, j int) bool { return cs[i] < cs[j] })
151+
t := []byte{}
152+
n := len(cs)
153+
vis := make([]bool, n)
154+
var dfs func(int)
155+
dfs = func(i int) {
156+
if i == n {
157+
ans = append(ans, string(t))
158+
return
159+
}
160+
for j := 0; j < n; j++ {
161+
if vis[j] || (j > 0 && !vis[j-1] && cs[j] == cs[j-1]) {
162+
continue
163+
}
164+
vis[j] = true
165+
t = append(t, cs[j])
166+
dfs(i + 1)
167+
t = t[:len(t)-1]
168+
vis[j] = false
169+
}
170+
}
171+
dfs(0)
172+
return
173+
}
174+
```
175+
176+
### **TypeScript**
177+
178+
```ts
179+
function permutation(S: string): string[] {
180+
const cs: string[] = S.split('').sort();
181+
const ans: string[] = [];
182+
const n = cs.length;
183+
const vis: boolean[] = Array(n).fill(false);
184+
const t: string[] = [];
185+
const dfs = (i: number) => {
186+
if (i === n) {
187+
ans.push(t.join(''));
188+
return;
189+
}
190+
for (let j = 0; j < n; ++j) {
191+
if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] === cs[j - 1])) {
192+
continue;
193+
}
194+
vis[j] = true;
195+
t.push(cs[j]);
196+
dfs(i + 1);
197+
t.pop();
198+
vis[j] = false;
199+
}
200+
};
201+
dfs(0);
202+
return ans;
203+
}
43204
```
44205

45206
### **JavaScript**
@@ -50,35 +211,30 @@
50211
* @return {string[]}
51212
*/
52213
var permutation = function (S) {
53-
let res = [];
54-
let arr = [...S];
55-
arr.sort();
56-
let prev = [];
57-
let record = new Array(S.length).fill(false);
58-
dfs(arr, 0, prev, record, res);
59-
return res;
60-
};
61-
function dfs(arr, depth, prev, record, res) {
62-
if (depth == arr.length) {
63-
res.push(prev.join(''));
64-
return;
65-
}
66-
for (let i = 0; i < arr.length; i++) {
67-
if (record[i]) {
68-
continue;
214+
const cs = S.split('').sort();
215+
const ans = [];
216+
const n = cs.length;
217+
const vis = Array(n).fill(false);
218+
const t = [];
219+
const dfs = i => {
220+
if (i === n) {
221+
ans.push(t.join(''));
222+
return;
69223
}
70-
// 剪枝
71-
if (i > 0 && arr[i] == arr[i - 1] && record[i - 1]) {
72-
continue;
224+
for (let j = 0; j < n; ++j) {
225+
if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] === cs[j - 1])) {
226+
continue;
227+
}
228+
vis[j] = true;
229+
t.push(cs[j]);
230+
dfs(i + 1);
231+
t.pop();
232+
vis[j] = false;
73233
}
74-
prev.push(arr[i]);
75-
record[i] = true;
76-
dfs(arr, depth + 1, prev, record, res);
77-
// 回溯
78-
prev.pop();
79-
record[i] = false;
80-
}
81-
}
234+
};
235+
dfs(0);
236+
return ans;
237+
};
82238
```
83239

84240
### **...**

0 commit comments

Comments
 (0)