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 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**
@@ -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;
+};