diff --git a/lcci/08.08.Permutation II/README.md b/lcci/08.08.Permutation II/README.md index 9b158442934ad..976fee76c19f6 100644 --- a/lcci/08.08.Permutation II/README.md +++ b/lcci/08.08.Permutation II/README.md @@ -5,6 +5,7 @@ ## 题目描述 +
有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。
示例1:
输入:S = "qqe" @@ -24,6 +25,19 @@ +**方法一:排序 + 回溯** + +我们可以先对字符串按照字符进行排序,这样就可以将重复的字符放在一起,方便我们进行去重。 + +然后,我们设计一个函数 $dfs(i)$,表示当前需要填写第 $i$ 个位置的字符。函数的具体实现如下: + +- 如果 $i = n$,说明我们已经填写完毕,将当前排列加入答案数组中,然后返回。 +- 否则,我们枚举第 $i$ 个位置的字符 $s[j]$,其中 $j$ 的范围是 $[0, n - 1]$。我们需要保证 $s[j]$ 没有被使用过,并且与前面枚举的字符不同,这样才能保证当前排列不重复。如果满足条件,我们就可以填写 $s[j]$,并继续递归地填写下一个位置,即调用 $dfs(i + 1)$。在递归调用结束后,我们需要将 $s[j]$ 标记为未使用,以便于进行后面的枚举。 + +在主函数中,我们首先对字符串进行排序,然后调用 $dfs(0)$,即从第 $0$ 个位置开始填写,最终返回答案数组即可。 + +时间复杂度 $O(n \times n!)$,空间复杂度 $O(n)$。其中 $n$ 是字符串 $s$ 的长度。需要进行 $n!$ 次枚举,每次枚举需要 $O(n)$ 的时间来判断是否重复。另外,我们需要一个标记数组来标记每个位置是否被使用过,因此空间复杂度为 $O(n)$。 + ### **Python3** @@ -31,7 +45,27 @@ ```python - +class Solution: + def permutation(self, S: str) -> List[str]: + def dfs(i: int): + if i == n: + ans.append("".join(t)) + return + for j in range(n): + if vis[j] or (j and cs[j] == cs[j - 1] and not vis[j - 1]): + continue + t[i] = cs[j] + vis[j] = True + dfs(i + 1) + vis[j] = False + + cs = sorted(S) + n = len(cs) + ans = [] + t = [None] * n + vis = [False] * n + dfs(0) + return ans ``` ### **Java** @@ -39,7 +73,134 @@ ```java +class Solution { + private int n; + private char[] cs; + private Listans = new ArrayList<>(); + private boolean[] vis; + private StringBuilder t = new StringBuilder(); + + public String[] permutation(String S) { + cs = S.toCharArray(); + n = cs.length; + Arrays.sort(cs); + vis = new boolean[n]; + dfs(0); + return ans.toArray(new String[0]); + } + + private void dfs(int i) { + if (i == n) { + ans.add(t.toString()); + return; + } + for (int j = 0; j < n; ++j) { + if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] == cs[j - 1])) { + continue; + } + vis[j] = true; + t.append(cs[j]); + dfs(i + 1); + t.deleteCharAt(t.length() - 1); + vis[j] = false; + } + } +} +``` +### **C++** + +```cpp +class Solution { +public: + vector permutation(string S) { + vector cs(S.begin(), S.end()); + sort(cs.begin(), cs.end()); + int n = cs.size(); + vector ans; + vector vis(n); + string t; + function dfs = [&](int i) { + if (i == n) { + ans.push_back(t); + return; + } + for (int j = 0; j < n; ++j) { + if (vis[j] || (j && !vis[j - 1] && cs[j] == cs[j - 1])) { + continue; + } + vis[j] = true; + t.push_back(cs[j]); + dfs(i + 1); + t.pop_back(); + vis[j] = false; + } + }; + dfs(0); + return ans; + } +}; +``` + +### **Go** + +```go +func permutation(S string) (ans []string) { + cs := []byte(S) + sort.Slice(cs, func(i, j int) bool { return cs[i] < cs[j] }) + t := []byte{} + n := len(cs) + vis := make([]bool, n) + var dfs func(int) + dfs = func(i int) { + if i == n { + ans = append(ans, string(t)) + return + } + for j := 0; j < n; j++ { + if vis[j] || (j > 0 && !vis[j-1] && cs[j] == cs[j-1]) { + continue + } + vis[j] = true + t = append(t, cs[j]) + dfs(i + 1) + t = t[:len(t)-1] + vis[j] = false + } + } + dfs(0) + return +} +``` + +### **TypeScript** + +```ts +function permutation(S: string): string[] { + const cs: string[] = S.split('').sort(); + const ans: string[] = []; + const n = cs.length; + const vis: boolean[] = Array(n).fill(false); + const t: string[] = []; + const dfs = (i: number) => { + if (i === n) { + ans.push(t.join('')); + return; + } + for (let j = 0; j < n; ++j) { + if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] === cs[j - 1])) { + continue; + } + vis[j] = true; + t.push(cs[j]); + dfs(i + 1); + t.pop(); + vis[j] = false; + } + }; + dfs(0); + return ans; +} ``` ### **JavaScript** @@ -50,35 +211,30 @@ * @return {string[]} */ var permutation = function (S) { - let res = []; - let arr = [...S]; - arr.sort(); - let prev = []; - let record = new Array(S.length).fill(false); - dfs(arr, 0, prev, record, res); - return res; -}; -function dfs(arr, depth, prev, record, res) { - if (depth == arr.length) { - res.push(prev.join('')); - return; - } - for (let i = 0; i < arr.length; i++) { - if (record[i]) { - continue; + const cs = S.split('').sort(); + const ans = []; + const n = cs.length; + const vis = Array(n).fill(false); + const t = []; + const dfs = i => { + if (i === n) { + ans.push(t.join('')); + return; } - // 剪枝 - if (i > 0 && arr[i] == arr[i - 1] && record[i - 1]) { - continue; + for (let j = 0; j < n; ++j) { + if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] === cs[j - 1])) { + continue; + } + vis[j] = true; + t.push(cs[j]); + dfs(i + 1); + t.pop(); + vis[j] = false; } - prev.push(arr[i]); - record[i] = true; - dfs(arr, depth + 1, prev, record, res); - // 回溯 - prev.pop(); - record[i] = false; - } -} + }; + dfs(0); + return ans; +}; ``` ### **...** diff --git a/lcci/08.08.Permutation II/README_EN.md b/lcci/08.08.Permutation II/README_EN.md index 479e46d2943c0..b1bdcae45f228 100644 --- a/lcci/08.08.Permutation II/README_EN.md +++ b/lcci/08.08.Permutation II/README_EN.md @@ -34,13 +34,160 @@ ### **Python3** ```python - +class Solution: + def permutation(self, S: str) -> List[str]: + def dfs(i: int): + if i == n: + ans.append("".join(t)) + return + for j in range(n): + if vis[j] or (j and cs[j] == cs[j - 1] and not vis[j - 1]): + continue + t[i] = cs[j] + vis[j] = True + dfs(i + 1) + vis[j] = False + + cs = sorted(S) + n = len(cs) + ans = [] + t = [None] * n + vis = [False] * n + dfs(0) + return ans ``` ### **Java** ```java +class Solution { + private int n; + private char[] cs; + private List ans = new ArrayList<>(); + private boolean[] vis; + private StringBuilder t = new StringBuilder(); + + public String[] permutation(String S) { + cs = S.toCharArray(); + n = cs.length; + Arrays.sort(cs); + vis = new boolean[n]; + dfs(0); + return ans.toArray(new String[0]); + } + + private void dfs(int i) { + if (i == n) { + ans.add(t.toString()); + return; + } + for (int j = 0; j < n; ++j) { + if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] == cs[j - 1])) { + continue; + } + vis[j] = true; + t.append(cs[j]); + dfs(i + 1); + t.deleteCharAt(t.length() - 1); + vis[j] = false; + } + } +} +``` +### **C++** + +```cpp +class Solution { +public: + vector permutation(string S) { + vector cs(S.begin(), S.end()); + sort(cs.begin(), cs.end()); + int n = cs.size(); + vector ans; + vector vis(n); + string t; + function dfs = [&](int i) { + if (i == n) { + ans.push_back(t); + return; + } + for (int j = 0; j < n; ++j) { + if (vis[j] || (j && !vis[j - 1] && cs[j] == cs[j - 1])) { + continue; + } + vis[j] = true; + t.push_back(cs[j]); + dfs(i + 1); + t.pop_back(); + vis[j] = false; + } + }; + dfs(0); + return ans; + } +}; +``` + +### **Go** + +```go +func permutation(S string) (ans []string) { + cs := []byte(S) + sort.Slice(cs, func(i, j int) bool { return cs[i] < cs[j] }) + t := []byte{} + n := len(cs) + vis := make([]bool, n) + var dfs func(int) + dfs = func(i int) { + if i == n { + ans = append(ans, string(t)) + return + } + for j := 0; j < n; j++ { + if vis[j] || (j > 0 && !vis[j-1] && cs[j] == cs[j-1]) { + continue + } + vis[j] = true + t = append(t, cs[j]) + dfs(i + 1) + t = t[:len(t)-1] + vis[j] = false + } + } + dfs(0) + return +} +``` + +### **TypeScript** + +```ts +function permutation(S: string): string[] { + const cs: string[] = S.split('').sort(); + const ans: string[] = []; + const n = cs.length; + const vis: boolean[] = Array(n).fill(false); + const t: string[] = []; + const dfs = (i: number) => { + if (i === n) { + ans.push(t.join('')); + return; + } + for (let j = 0; j < n; ++j) { + if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] === cs[j - 1])) { + continue; + } + vis[j] = true; + t.push(cs[j]); + dfs(i + 1); + t.pop(); + vis[j] = false; + } + }; + dfs(0); + return ans; +} ``` ### **JavaScript** @@ -51,35 +198,30 @@ * @return {string[]} */ var permutation = function (S) { - let res = []; - let arr = [...S]; - arr.sort(); - let prev = []; - let record = new Array(S.length).fill(false); - dfs(arr, 0, prev, record, res); - return res; -}; -function dfs(arr, depth, prev, record, res) { - if (depth == arr.length) { - res.push(prev.join('')); - return; - } - for (let i = 0; i < arr.length; i++) { - if (record[i]) { - continue; + const cs = S.split('').sort(); + const ans = []; + const n = cs.length; + const vis = Array(n).fill(false); + const t = []; + const dfs = i => { + if (i === n) { + ans.push(t.join('')); + return; } - // 剪枝 - if (i > 0 && arr[i] == arr[i - 1] && record[i - 1]) { - continue; + for (let j = 0; j < n; ++j) { + if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] === cs[j - 1])) { + continue; + } + vis[j] = true; + t.push(cs[j]); + dfs(i + 1); + t.pop(); + vis[j] = false; } - prev.push(arr[i]); - record[i] = true; - dfs(arr, depth + 1, prev, record, res); - // 回溯 - prev.pop(); - record[i] = false; - } -} + }; + dfs(0); + return ans; +}; ``` ### **...** diff --git a/lcci/08.08.Permutation II/Solution.cpp b/lcci/08.08.Permutation II/Solution.cpp new file mode 100644 index 0000000000000..89418c7dd37e3 --- /dev/null +++ b/lcci/08.08.Permutation II/Solution.cpp @@ -0,0 +1,29 @@ +class Solution { +public: + vector permutation(string S) { + vector cs(S.begin(), S.end()); + sort(cs.begin(), cs.end()); + int n = cs.size(); + vector ans; + vector vis(n); + string t; + function dfs = [&](int i) { + if (i == n) { + ans.push_back(t); + return; + } + for (int j = 0; j < n; ++j) { + if (vis[j] || (j && !vis[j - 1] && cs[j] == cs[j - 1])) { + continue; + } + vis[j] = true; + t.push_back(cs[j]); + dfs(i + 1); + t.pop_back(); + vis[j] = false; + } + }; + dfs(0); + return ans; + } +}; \ No newline at end of file diff --git a/lcci/08.08.Permutation II/Solution.go b/lcci/08.08.Permutation II/Solution.go new file mode 100644 index 0000000000000..e53c94550e2fb --- /dev/null +++ b/lcci/08.08.Permutation II/Solution.go @@ -0,0 +1,26 @@ +func permutation(S string) (ans []string) { + cs := []byte(S) + sort.Slice(cs, func(i, j int) bool { return cs[i] < cs[j] }) + t := []byte{} + n := len(cs) + vis := make([]bool, n) + var dfs func(int) + dfs = func(i int) { + if i == n { + ans = append(ans, string(t)) + return + } + for j := 0; j < n; j++ { + if vis[j] || (j > 0 && !vis[j-1] && cs[j] == cs[j-1]) { + continue + } + vis[j] = true + t = append(t, cs[j]) + dfs(i + 1) + t = t[:len(t)-1] + vis[j] = false + } + } + dfs(0) + return +} \ No newline at end of file diff --git a/lcci/08.08.Permutation II/Solution.java b/lcci/08.08.Permutation II/Solution.java new file mode 100644 index 0000000000000..ca44d0d3d3023 --- /dev/null +++ b/lcci/08.08.Permutation II/Solution.java @@ -0,0 +1,33 @@ +class Solution { + private int n; + private char[] cs; + private List ans = new ArrayList<>(); + private boolean[] vis; + private StringBuilder t = new StringBuilder(); + + public String[] permutation(String S) { + cs = S.toCharArray(); + n = cs.length; + Arrays.sort(cs); + vis = new boolean[n]; + dfs(0); + return ans.toArray(new String[0]); + } + + private void dfs(int i) { + if (i == n) { + ans.add(t.toString()); + return; + } + for (int j = 0; j < n; ++j) { + if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] == cs[j - 1])) { + continue; + } + vis[j] = true; + t.append(cs[j]); + dfs(i + 1); + t.deleteCharAt(t.length() - 1); + vis[j] = false; + } + } +} \ No newline at end of file diff --git a/lcci/08.08.Permutation II/Solution.js b/lcci/08.08.Permutation II/Solution.js index d4df4efb9e28d..44aed97be109c 100644 --- a/lcci/08.08.Permutation II/Solution.js +++ b/lcci/08.08.Permutation II/Solution.js @@ -3,33 +3,27 @@ * @return {string[]} */ var permutation = function (S) { - let res = []; - let arr = [...S]; - arr.sort(); - let prev = []; - let record = new Array(S.length).fill(false); - dfs(arr, 0, prev, record, res); - return res; -}; - -function dfs(arr, depth, prev, record, res) { - if (depth == arr.length) { - res.push(prev.join('')); - return; - } - for (let i = 0; i < arr.length; i++) { - if (record[i]) { - continue; + const cs = S.split('').sort(); + const ans = []; + const n = cs.length; + const vis = Array(n).fill(false); + const t = []; + const dfs = i => { + if (i === n) { + ans.push(t.join('')); + return; } - // 剪枝 - if (i > 0 && arr[i] == arr[i - 1] && record[i - 1]) { - continue; + for (let j = 0; j < n; ++j) { + if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] === cs[j - 1])) { + continue; + } + vis[j] = true; + t.push(cs[j]); + dfs(i + 1); + t.pop(); + vis[j] = false; } - prev.push(arr[i]); - record[i] = true; - dfs(arr, depth + 1, prev, record, res); - // 回溯 - prev.pop(); - record[i] = false; - } -} + }; + dfs(0); + return ans; +}; diff --git a/lcci/08.08.Permutation II/Solution.py b/lcci/08.08.Permutation II/Solution.py new file mode 100644 index 0000000000000..5731468cfdea6 --- /dev/null +++ b/lcci/08.08.Permutation II/Solution.py @@ -0,0 +1,21 @@ +class Solution: + def permutation(self, S: str) -> List[str]: + def dfs(i: int): + if i == n: + ans.append("".join(t)) + return + for j in range(n): + if vis[j] or (j and cs[j] == cs[j - 1] and not vis[j - 1]): + continue + t[i] = cs[j] + vis[j] = True + dfs(i + 1) + vis[j] = False + + cs = sorted(S) + n = len(cs) + ans = [] + t = [None] * n + vis = [False] * n + dfs(0) + return ans diff --git a/lcci/08.08.Permutation II/Solution.ts b/lcci/08.08.Permutation II/Solution.ts new file mode 100644 index 0000000000000..44aed97be109c --- /dev/null +++ b/lcci/08.08.Permutation II/Solution.ts @@ -0,0 +1,29 @@ +/** + * @param {string} S + * @return {string[]} + */ +var permutation = function (S) { + const cs = S.split('').sort(); + const ans = []; + const n = cs.length; + const vis = Array(n).fill(false); + const t = []; + const dfs = i => { + if (i === n) { + ans.push(t.join('')); + return; + } + for (let j = 0; j < n; ++j) { + if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] === cs[j - 1])) { + continue; + } + vis[j] = true; + t.push(cs[j]); + dfs(i + 1); + t.pop(); + vis[j] = false; + } + }; + dfs(0); + return ans; +};