|
5 | 5 | ## 题目描述
|
6 | 6 |
|
7 | 7 | <!-- 这里写题目描述 -->
|
| 8 | + |
8 | 9 | <p>有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。</p>
|
9 | 10 | <p><strong>示例1:</strong></p>
|
10 | 11 | <pre><strong> 输入</strong>:S = "qqe"
|
|
24 | 25 |
|
25 | 26 | <!-- 这里可写通用的实现逻辑 -->
|
26 | 27 |
|
| 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 | + |
27 | 41 | <!-- tabs:start -->
|
28 | 42 |
|
29 | 43 | ### **Python3**
|
30 | 44 |
|
31 | 45 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
32 | 46 |
|
33 | 47 | ```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 |
35 | 69 | ```
|
36 | 70 |
|
37 | 71 | ### **Java**
|
38 | 72 |
|
39 | 73 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
40 | 74 |
|
41 | 75 | ```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 | +``` |
42 | 110 |
|
| 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 | +} |
43 | 204 | ```
|
44 | 205 |
|
45 | 206 | ### **JavaScript**
|
|
50 | 211 | * @return {string[]}
|
51 | 212 | */
|
52 | 213 | 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; |
69 | 223 | }
|
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; |
73 | 233 | }
|
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 | +}; |
82 | 238 | ```
|
83 | 239 |
|
84 | 240 | ### **...**
|
|
0 commit comments