From d46715134c9ff859fbb82d1626257d377e31ad4e Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Sat, 15 Feb 2025 17:31:11 +0800 Subject: [PATCH] feat: add solutions to lcci problems: No.08.06~08.09 (#4068) --- lcci/08.06.Hanota/README.md | 2 +- lcci/08.06.Hanota/README_EN.md | 2 +- lcci/08.06.Hanota/Solution.cpp | 4 +- lcci/08.07.Permutation I/README.md | 138 +++++++-------- lcci/08.07.Permutation I/README_EN.md | 137 +++++++-------- lcci/08.07.Permutation I/Solution.cpp | 20 +-- lcci/08.07.Permutation I/Solution.go | 21 ++- lcci/08.07.Permutation I/Solution.java | 27 +-- lcci/08.07.Permutation I/Solution.js | 5 +- lcci/08.07.Permutation I/Solution.py | 18 +- lcci/08.07.Permutation I/Solution.swift | 45 +++-- lcci/08.07.Permutation I/Solution.ts | 5 +- lcci/08.08.Permutation II/README.md | 203 ++++++++++------------ lcci/08.08.Permutation II/README_EN.md | 209 +++++++++++------------ lcci/08.08.Permutation II/Solution.cpp | 29 ++-- lcci/08.08.Permutation II/Solution.go | 27 ++- lcci/08.08.Permutation II/Solution.java | 34 ++-- lcci/08.08.Permutation II/Solution.js | 22 ++- lcci/08.08.Permutation II/Solution.py | 21 ++- lcci/08.08.Permutation II/Solution.swift | 48 +++--- lcci/08.08.Permutation II/Solution.ts | 22 ++- lcci/08.09.Bracket/README.md | 3 +- lcci/08.09.Bracket/README_EN.md | 3 +- lcci/08.09.Bracket/Solution.cpp | 5 +- 24 files changed, 482 insertions(+), 568 deletions(-) diff --git a/lcci/08.06.Hanota/README.md b/lcci/08.06.Hanota/README.md index 04efe8940d..b5dc3d3966 100644 --- a/lcci/08.06.Hanota/README.md +++ b/lcci/08.06.Hanota/README.md @@ -91,7 +91,7 @@ class Solution { class Solution { public: void hanota(vector& A, vector& B, vector& C) { - function&, vector&, vector&)> dfs = [&](int n, vector& a, vector& b, vector& c) { + auto dfs = [&](this auto&& dfs, int n, vector& a, vector& b, vector& c) { if (n == 1) { c.push_back(a.back()); a.pop_back(); diff --git a/lcci/08.06.Hanota/README_EN.md b/lcci/08.06.Hanota/README_EN.md index 6d4243950e..3f52664c58 100644 --- a/lcci/08.06.Hanota/README_EN.md +++ b/lcci/08.06.Hanota/README_EN.md @@ -98,7 +98,7 @@ class Solution { class Solution { public: void hanota(vector& A, vector& B, vector& C) { - function&, vector&, vector&)> dfs = [&](int n, vector& a, vector& b, vector& c) { + auto dfs = [&](this auto&& dfs, int n, vector& a, vector& b, vector& c) { if (n == 1) { c.push_back(a.back()); a.pop_back(); diff --git a/lcci/08.06.Hanota/Solution.cpp b/lcci/08.06.Hanota/Solution.cpp index 7cf7ad9647..3b5b8d483c 100644 --- a/lcci/08.06.Hanota/Solution.cpp +++ b/lcci/08.06.Hanota/Solution.cpp @@ -1,7 +1,7 @@ class Solution { public: void hanota(vector& A, vector& B, vector& C) { - function&, vector&, vector&)> dfs = [&](int n, vector& a, vector& b, vector& c) { + auto dfs = [&](this auto&& dfs, int n, vector& a, vector& b, vector& c) { if (n == 1) { c.push_back(a.back()); a.pop_back(); @@ -14,4 +14,4 @@ public: }; dfs(A.size(), A, B, C); } -}; \ No newline at end of file +}; diff --git a/lcci/08.07.Permutation I/README.md b/lcci/08.07.Permutation I/README.md index 34a783fde5..9d3e78c2da 100644 --- a/lcci/08.07.Permutation I/README.md +++ b/lcci/08.07.Permutation I/README.md @@ -45,7 +45,7 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcci/08.07.Permutation%20I ### 方法一:DFS(回溯) -我们设计一个函数 $dfs(i)$ 表示已经填完了前 $i$ 个位置,现在需要填第 $i+1$ 个位置。枚举所有可能的字符,如果这个字符没有被填过,就填入这个字符,然后继续填下一个位置,直到填完所有的位置。 +我们设计一个函数 $\textit{dfs}(i)$ 表示已经填完了前 $i$ 个位置,现在需要填第 $i+1$ 个位置。枚举所有可能的字符,如果这个字符没有被填过,就填入这个字符,然后继续填下一个位置,直到填完所有的位置。 时间复杂度 $O(n \times n!)$,其中 $n$ 是字符串的长度。一共有 $n!$ 个排列,每个排列需要 $O(n)$ 的时间来构造。 @@ -57,22 +57,20 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcci/08.07.Permutation%20I class Solution: def permutation(self, S: str) -> List[str]: def dfs(i: int): - if i == n: + if i >= n: ans.append("".join(t)) return for j, c in enumerate(S): - if vis[j]: - continue - vis[j] = True - t.append(c) - dfs(i + 1) - t.pop() - vis[j] = False + if not vis[j]: + vis[j] = True + t[i] = c + dfs(i + 1) + vis[j] = False + ans = [] n = len(S) vis = [False] * n - ans = [] - t = [] + t = list(S) dfs(0) return ans ``` @@ -82,30 +80,31 @@ class Solution: ```java class Solution { private char[] s; - private boolean[] vis = new boolean['z' + 1]; + private char[] t; + private boolean[] vis; private List ans = new ArrayList<>(); - private StringBuilder t = new StringBuilder(); public String[] permutation(String S) { s = S.toCharArray(); + int n = s.length; + vis = new boolean[n]; + t = new char[n]; dfs(0); return ans.toArray(new String[0]); } private void dfs(int i) { - if (i == s.length) { - ans.add(t.toString()); + if (i >= s.length) { + ans.add(new String(t)); return; } - for (char c : s) { - if (vis[c]) { - continue; + for (int j = 0; j < s.length; ++j) { + if (!vis[j]) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[c] = true; - t.append(c); - dfs(i + 1); - t.deleteCharAt(t.length() - 1); - vis[c] = false; } } } @@ -119,51 +118,49 @@ public: vector permutation(string S) { int n = S.size(); vector vis(n); + string t = S; vector ans; - string t; - function dfs = [&](int i) { + auto dfs = [&](this auto&& dfs, int i) { if (i >= n) { - ans.push_back(t); + ans.emplace_back(t); return; } for (int j = 0; j < n; ++j) { - if (vis[j]) { - continue; + if (!vis[j]) { + vis[j] = true; + t[i] = S[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push_back(S[j]); - dfs(i + 1); - t.pop_back(); - vis[j] = false; } }; dfs(0); return ans; } }; + ``` #### Go ```go func permutation(S string) (ans []string) { - t := []byte{} - vis := make([]bool, len(S)) + t := []byte(S) + n := len(t) + vis := make([]bool, n) var dfs func(int) dfs = func(i int) { - if i >= len(S) { + if i >= n { ans = append(ans, string(t)) return } for j := range S { - if vis[j] { - continue + if !vis[j] { + vis[j] = true + t[i] = S[j] + dfs(i + 1) + vis[j] = false } - vis[j] = true - t = append(t, S[j]) - dfs(i + 1) - t = t[:len(t)-1] - vis[j] = false } } dfs(0) @@ -178,7 +175,7 @@ function permutation(S: string): string[] { const n = S.length; const vis: boolean[] = Array(n).fill(false); const ans: string[] = []; - const t: string[] = []; + const t: string[] = Array(n).fill(''); const dfs = (i: number) => { if (i >= n) { ans.push(t.join('')); @@ -189,9 +186,8 @@ function permutation(S: string): string[] { continue; } vis[j] = true; - t.push(S[j]); + t[i] = S[j]; dfs(i + 1); - t.pop(); vis[j] = false; } }; @@ -211,7 +207,7 @@ var permutation = function (S) { const n = S.length; const vis = Array(n).fill(false); const ans = []; - const t = []; + const t = Array(n).fill(''); const dfs = i => { if (i >= n) { ans.push(t.join('')); @@ -222,9 +218,8 @@ var permutation = function (S) { continue; } vis[j] = true; - t.push(S[j]); + t[i] = S[j]; dfs(i + 1); - t.pop(); vis[j] = false; } }; @@ -237,34 +232,31 @@ var permutation = function (S) { ```swift class Solution { - private var s: [Character] = [] - private var vis: [Bool] = Array(repeating: false, count: 128) - private var ans: [String] = [] - private var t: String = "" - func permutation(_ S: String) -> [String] { - s = Array(S) + var ans: [String] = [] + let s = Array(S) + var t = s + var vis = Array(repeating: false, count: s.count) + let n = s.count + + func dfs(_ i: Int) { + if i >= n { + ans.append(String(t)) + return + } + for j in 0.. List[str]: def dfs(i: int): - if i == n: + if i >= n: ans.append("".join(t)) return for j, c in enumerate(S): - if vis[j]: - continue - vis[j] = True - t.append(c) - dfs(i + 1) - t.pop() - vis[j] = False + if not vis[j]: + vis[j] = True + t[i] = c + dfs(i + 1) + vis[j] = False + ans = [] n = len(S) vis = [False] * n - ans = [] - t = [] + t = list(S) dfs(0) return ans ``` @@ -88,30 +86,31 @@ class Solution: ```java class Solution { private char[] s; - private boolean[] vis = new boolean['z' + 1]; + private char[] t; + private boolean[] vis; private List ans = new ArrayList<>(); - private StringBuilder t = new StringBuilder(); public String[] permutation(String S) { s = S.toCharArray(); + int n = s.length; + vis = new boolean[n]; + t = new char[n]; dfs(0); return ans.toArray(new String[0]); } private void dfs(int i) { - if (i == s.length) { - ans.add(t.toString()); + if (i >= s.length) { + ans.add(new String(t)); return; } - for (char c : s) { - if (vis[c]) { - continue; + for (int j = 0; j < s.length; ++j) { + if (!vis[j]) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[c] = true; - t.append(c); - dfs(i + 1); - t.deleteCharAt(t.length() - 1); - vis[c] = false; } } } @@ -125,22 +124,20 @@ public: vector permutation(string S) { int n = S.size(); vector vis(n); + string t = S; vector ans; - string t; - function dfs = [&](int i) { + auto dfs = [&](this auto&& dfs, int i) { if (i >= n) { - ans.push_back(t); + ans.emplace_back(t); return; } for (int j = 0; j < n; ++j) { - if (vis[j]) { - continue; + if (!vis[j]) { + vis[j] = true; + t[i] = S[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push_back(S[j]); - dfs(i + 1); - t.pop_back(); - vis[j] = false; } }; dfs(0); @@ -153,23 +150,22 @@ public: ```go func permutation(S string) (ans []string) { - t := []byte{} - vis := make([]bool, len(S)) + t := []byte(S) + n := len(t) + vis := make([]bool, n) var dfs func(int) dfs = func(i int) { - if i >= len(S) { + if i >= n { ans = append(ans, string(t)) return } for j := range S { - if vis[j] { - continue + if !vis[j] { + vis[j] = true + t[i] = S[j] + dfs(i + 1) + vis[j] = false } - vis[j] = true - t = append(t, S[j]) - dfs(i + 1) - t = t[:len(t)-1] - vis[j] = false } } dfs(0) @@ -184,7 +180,7 @@ function permutation(S: string): string[] { const n = S.length; const vis: boolean[] = Array(n).fill(false); const ans: string[] = []; - const t: string[] = []; + const t: string[] = Array(n).fill(''); const dfs = (i: number) => { if (i >= n) { ans.push(t.join('')); @@ -195,9 +191,8 @@ function permutation(S: string): string[] { continue; } vis[j] = true; - t.push(S[j]); + t[i] = S[j]; dfs(i + 1); - t.pop(); vis[j] = false; } }; @@ -217,7 +212,7 @@ var permutation = function (S) { const n = S.length; const vis = Array(n).fill(false); const ans = []; - const t = []; + const t = Array(n).fill(''); const dfs = i => { if (i >= n) { ans.push(t.join('')); @@ -228,9 +223,8 @@ var permutation = function (S) { continue; } vis[j] = true; - t.push(S[j]); + t[i] = S[j]; dfs(i + 1); - t.pop(); vis[j] = false; } }; @@ -243,34 +237,31 @@ var permutation = function (S) { ```swift class Solution { - private var s: [Character] = [] - private var vis: [Bool] = Array(repeating: false, count: 128) - private var ans: [String] = [] - private var t: String = "" - func permutation(_ S: String) -> [String] { - s = Array(S) + var ans: [String] = [] + let s = Array(S) + var t = s + var vis = Array(repeating: false, count: s.count) + let n = s.count + + func dfs(_ i: Int) { + if i >= n { + ans.append(String(t)) + return + } + for j in 0.. permutation(string S) { int n = S.size(); vector vis(n); + string t = S; vector ans; - string t; - function dfs = [&](int i) { + auto dfs = [&](this auto&& dfs, int i) { if (i >= n) { - ans.push_back(t); + ans.emplace_back(t); return; } for (int j = 0; j < n; ++j) { - if (vis[j]) { - continue; + if (!vis[j]) { + vis[j] = true; + t[i] = S[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push_back(S[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.07.Permutation I/Solution.go b/lcci/08.07.Permutation I/Solution.go index 20d5c55fde..1f84fb6924 100644 --- a/lcci/08.07.Permutation I/Solution.go +++ b/lcci/08.07.Permutation I/Solution.go @@ -1,23 +1,22 @@ func permutation(S string) (ans []string) { - t := []byte{} - vis := make([]bool, len(S)) + t := []byte(S) + n := len(t) + vis := make([]bool, n) var dfs func(int) dfs = func(i int) { - if i >= len(S) { + if i >= n { ans = append(ans, string(t)) return } for j := range S { - if vis[j] { - continue + if !vis[j] { + vis[j] = true + t[i] = S[j] + dfs(i + 1) + vis[j] = false } - vis[j] = true - t = append(t, S[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.07.Permutation I/Solution.java b/lcci/08.07.Permutation I/Solution.java index 896ed99f9d..f65456f945 100644 --- a/lcci/08.07.Permutation I/Solution.java +++ b/lcci/08.07.Permutation I/Solution.java @@ -1,29 +1,30 @@ class Solution { private char[] s; - private boolean[] vis = new boolean['z' + 1]; + private char[] t; + private boolean[] vis; private List ans = new ArrayList<>(); - private StringBuilder t = new StringBuilder(); public String[] permutation(String S) { s = S.toCharArray(); + int n = s.length; + vis = new boolean[n]; + t = new char[n]; dfs(0); return ans.toArray(new String[0]); } private void dfs(int i) { - if (i == s.length) { - ans.add(t.toString()); + if (i >= s.length) { + ans.add(new String(t)); return; } - for (char c : s) { - if (vis[c]) { - continue; + for (int j = 0; j < s.length; ++j) { + if (!vis[j]) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[c] = true; - t.append(c); - dfs(i + 1); - t.deleteCharAt(t.length() - 1); - vis[c] = false; } } -} \ No newline at end of file +} diff --git a/lcci/08.07.Permutation I/Solution.js b/lcci/08.07.Permutation I/Solution.js index f1dcb5d98f..c18ebd79c0 100644 --- a/lcci/08.07.Permutation I/Solution.js +++ b/lcci/08.07.Permutation I/Solution.js @@ -6,7 +6,7 @@ var permutation = function (S) { const n = S.length; const vis = Array(n).fill(false); const ans = []; - const t = []; + const t = Array(n).fill(''); const dfs = i => { if (i >= n) { ans.push(t.join('')); @@ -17,9 +17,8 @@ var permutation = function (S) { continue; } vis[j] = true; - t.push(S[j]); + t[i] = S[j]; dfs(i + 1); - t.pop(); vis[j] = false; } }; diff --git a/lcci/08.07.Permutation I/Solution.py b/lcci/08.07.Permutation I/Solution.py index 537c2f0484..7e64e799f8 100644 --- a/lcci/08.07.Permutation I/Solution.py +++ b/lcci/08.07.Permutation I/Solution.py @@ -1,21 +1,19 @@ class Solution: def permutation(self, S: str) -> List[str]: def dfs(i: int): - if i == n: + if i >= n: ans.append("".join(t)) return for j, c in enumerate(S): - if vis[j]: - continue - vis[j] = True - t.append(c) - dfs(i + 1) - t.pop() - vis[j] = False + if not vis[j]: + vis[j] = True + t[i] = c + dfs(i + 1) + vis[j] = False + ans = [] n = len(S) vis = [False] * n - ans = [] - t = [] + t = list(S) dfs(0) return ans diff --git a/lcci/08.07.Permutation I/Solution.swift b/lcci/08.07.Permutation I/Solution.swift index 48803e420a..33a987fc01 100644 --- a/lcci/08.07.Permutation I/Solution.swift +++ b/lcci/08.07.Permutation I/Solution.swift @@ -1,30 +1,27 @@ class Solution { - private var s: [Character] = [] - private var vis: [Bool] = Array(repeating: false, count: 128) - private var ans: [String] = [] - private var t: String = "" - func permutation(_ S: String) -> [String] { - s = Array(S) + var ans: [String] = [] + let s = Array(S) + var t = s + var vis = Array(repeating: false, count: s.count) + let n = s.count + + func dfs(_ i: Int) { + if i >= n { + ans.append(String(t)) + return + } + for j in 0.. { if (i >= n) { ans.push(t.join('')); @@ -13,9 +13,8 @@ function permutation(S: string): string[] { continue; } vis[j] = true; - t.push(S[j]); + t[i] = S[j]; dfs(i + 1); - t.pop(); vis[j] = false; } }; diff --git a/lcci/08.08.Permutation II/README.md b/lcci/08.08.Permutation II/README.md index 90b72d44fb..936fb1b9d9 100644 --- a/lcci/08.08.Permutation II/README.md +++ b/lcci/08.08.Permutation II/README.md @@ -39,12 +39,12 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcci/08.08.Permutation%20I 我们可以先对字符串按照字符进行排序,这样就可以将重复的字符放在一起,方便我们进行去重。 -然后,我们设计一个函数 $dfs(i)$,表示当前需要填写第 $i$ 个位置的字符。函数的具体实现如下: +然后,我们设计一个函数 $\textit{dfs}(i)$,表示当前需要填写第 $i$ 个位置的字符。函数的具体实现如下: - 如果 $i = n$,说明我们已经填写完毕,将当前排列加入答案数组中,然后返回。 -- 否则,我们枚举第 $i$ 个位置的字符 $s[j]$,其中 $j$ 的范围是 $[0, n - 1]$。我们需要保证 $s[j]$ 没有被使用过,并且与前面枚举的字符不同,这样才能保证当前排列不重复。如果满足条件,我们就可以填写 $s[j]$,并继续递归地填写下一个位置,即调用 $dfs(i + 1)$。在递归调用结束后,我们需要将 $s[j]$ 标记为未使用,以便于进行后面的枚举。 +- 否则,我们枚举第 $i$ 个位置的字符 $\textit{s}[j]$,其中 $j$ 的范围是 $[0, n - 1]$。我们需要保证 $\textit{s}[j]$ 没有被使用过,并且与前面枚举的字符不同,这样才能保证当前排列不重复。如果满足条件,我们就可以填写 $\textit{s}[j]$,并继续递归地填写下一个位置,即调用 $\textit{dfs}(i + 1)$。在递归调用结束后,我们需要将 $\textit{s}[j]$ 标记为未使用,以便于进行后面的枚举。 -在主函数中,我们首先对字符串进行排序,然后调用 $dfs(0)$,即从第 $0$ 个位置开始填写,最终返回答案数组即可。 +在主函数中,我们首先对字符串进行排序,然后调用 $\textit{dfs}(0)$,即从第 $0$ 个位置开始填写,最终返回答案数组即可。 时间复杂度 $O(n \times n!)$,空间复杂度 $O(n)$。其中 $n$ 是字符串 $s$ 的长度。需要进行 $n!$ 次枚举,每次枚举需要 $O(n)$ 的时间来判断是否重复。另外,我们需要一个标记数组来标记每个位置是否被使用过,因此空间复杂度为 $O(n)$。 @@ -56,21 +56,20 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcci/08.08.Permutation%20I class Solution: def permutation(self, S: str) -> List[str]: def dfs(i: int): - if i == n: + 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 + for j, c in enumerate(s): + if not vis[j] and (j == 0 or s[j] != s[j - 1] or vis[j - 1]): + vis[j] = True + t[i] = c + dfs(i + 1) + vis[j] = False - cs = sorted(S) - n = len(cs) + s = sorted(S) ans = [] - t = [None] * n + t = s[:] + n = len(s) vis = [False] * n dfs(0) return ans @@ -80,35 +79,33 @@ class Solution: ```java class Solution { - private int n; - private char[] cs; - private List ans = new ArrayList<>(); + private char[] s; + private char[] t; private boolean[] vis; - private StringBuilder t = new StringBuilder(); + private List ans = new ArrayList<>(); public String[] permutation(String S) { - cs = S.toCharArray(); - n = cs.length; - Arrays.sort(cs); + int n = S.length(); + s = S.toCharArray(); + Arrays.sort(s); + t = new char[n]; vis = new boolean[n]; dfs(0); return ans.toArray(new String[0]); } private void dfs(int i) { - if (i == n) { - ans.add(t.toString()); + if (i >= s.length) { + ans.add(new String(t)); return; } - for (int j = 0; j < n; ++j) { - if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] == cs[j - 1])) { - continue; + for (int j = 0; j < s.length; ++j) { + if (!vis[j] && (j == 0 || s[j] != s[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.append(cs[j]); - dfs(i + 1); - t.deleteCharAt(t.length() - 1); - vis[j] = false; } } } @@ -120,26 +117,23 @@ class Solution { class Solution { public: vector permutation(string S) { - vector cs(S.begin(), S.end()); - sort(cs.begin(), cs.end()); - int n = cs.size(); - vector ans; + ranges::sort(S); + string t = S; + int n = t.size(); vector vis(n); - string t; - function dfs = [&](int i) { - if (i == n) { - ans.push_back(t); + vector ans; + auto dfs = [&](this auto&& dfs, int i) { + if (i >= n) { + ans.emplace_back(t); return; } for (int j = 0; j < n; ++j) { - if (vis[j] || (j && !vis[j - 1] && cs[j] == cs[j - 1])) { - continue; + if (!vis[j] && (j == 0 || S[j] != S[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = S[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push_back(cs[j]); - dfs(i + 1); - t.pop_back(); - vis[j] = false; } }; dfs(0); @@ -152,26 +146,23 @@ public: ```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) + s := []byte(S) + sort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) + t := slices.Clone(s) + vis := make([]bool, len(s)) var dfs func(int) dfs = func(i int) { - if i == n { + if i >= len(s) { 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 + for j := range s { + if !vis[j] && (j == 0 || s[j] != s[j-1] || vis[j-1]) { + vis[j] = true + t[i] = s[j] + dfs(i + 1) + vis[j] = false } - vis[j] = true - t = append(t, cs[j]) - dfs(i + 1) - t = t[:len(t)-1] - vis[j] = false } } dfs(0) @@ -183,25 +174,23 @@ func permutation(S string) (ans []string) { ```ts function permutation(S: string): string[] { - const cs: string[] = S.split('').sort(); - const ans: string[] = []; - const n = cs.length; + const s: string[] = S.split('').sort(); + const n = s.length; + const t = Array(n).fill(''); const vis: boolean[] = Array(n).fill(false); - const t: string[] = []; + const ans: string[] = []; const dfs = (i: number) => { - if (i === n) { + 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; + if (!vis[j] && (j === 0 || s[j] !== s[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push(cs[j]); - dfs(i + 1); - t.pop(); - vis[j] = false; } }; dfs(0); @@ -217,25 +206,23 @@ function permutation(S: string): string[] { * @return {string[]} */ var permutation = function (S) { - const cs = S.split('').sort(); - const ans = []; - const n = cs.length; + const s = S.split('').sort(); + const n = s.length; + const t = Array(n).fill(''); const vis = Array(n).fill(false); - const t = []; + const ans = []; const dfs = i => { - if (i === n) { + 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; + if (!vis[j] && (j === 0 || s[j] !== s[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push(cs[j]); - dfs(i + 1); - t.pop(); - vis[j] = false; } }; dfs(0); @@ -247,37 +234,31 @@ var permutation = function (S) { ```swift class Solution { - private var n: Int = 0 - private var cs: [Character] = [] - private var ans: [String] = [] - private var vis: [Bool] = [] - private var t: String = "" - func permutation(_ S: String) -> [String] { - cs = Array(S) - n = cs.count - cs.sort() - vis = Array(repeating: false, count: n) + var ans: [String] = [] + var s: [Character] = Array(S).sorted() + var t: [Character] = Array(repeating: " ", count: s.count) + var vis: [Bool] = Array(repeating: false, count: s.count) + let n = s.count + + func dfs(_ i: Int) { + if i >= n { + ans.append(String(t)) + return + } + for j in 0.. 0 && !vis[j - 1] && cs[j] == cs[j - 1]) { - continue - } - vis[j] = true - t.append(cs[j]) - dfs(i + 1) - t.removeLast() - vis[j] = false - } - } } ``` diff --git a/lcci/08.08.Permutation II/README_EN.md b/lcci/08.08.Permutation II/README_EN.md index d2d10fe8e2..ed17f322ab 100644 --- a/lcci/08.08.Permutation II/README_EN.md +++ b/lcci/08.08.Permutation II/README_EN.md @@ -45,16 +45,16 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcci/08.08.Permutation%20I ### Solution 1: Sorting + Backtracking -We can first sort the string by characters, which allows us to put duplicate characters together and makes it easier for us to remove duplicates. +We can first sort the string by characters, so that duplicate characters are placed together, making it easier to remove duplicates. -Then, we design a function $dfs(i)$, which means that we need to fill in the character at the $i$-th position. The specific implementation of the function is as follows: +Then, we design a function $\textit{dfs}(i)$, which represents the character that needs to be filled at the $i$-th position. The specific implementation of the function is as follows: -- If $i = n$, it means that we have finished filling in, add the current permutation to the answer array, and then return. -- Otherwise, we enumerate the character $s[j]$ at the $i$-th position, where the range of $j$ is $[0, n - 1]$. We need to ensure that $s[j]$ has not been used and is different from the previously enumerated characters, so as to ensure that the current permutation is not repeated. If the conditions are met, we can fill in $s[j]$, and continue to recursively fill in the next position, that is, call $dfs(i + 1)$. After the recursive call ends, we need to mark $s[j]$ as unused for later enumeration. +- If $i = n$, it means we have filled all positions, add the current permutation to the answer array, and then return. +- Otherwise, we enumerate the character $\textit{s}[j]$ for the $i$-th position, where the range of $j$ is $[0, n - 1]$. We need to ensure that $\textit{s}[j]$ has not been used and is different from the previously enumerated character to ensure that the current permutation is not duplicated. If the conditions are met, we can fill $\textit{s}[j]$ and continue to recursively fill the next position by calling $\textit{dfs}(i + 1)$. After the recursive call ends, we need to mark $\textit{s}[j]$ as unused to facilitate subsequent enumeration. -In the main function, we first sort the string, then call $dfs(0)$, that is, start filling from the $0$-th position, and finally return the answer array. +In the main function, we first sort the string, then call $\textit{dfs}(0)$ to start filling from the 0th position, and finally return the answer array. -The time complexity is $O(n \times n!)$, and the space complexity is $O(n)$. Here, $n$ is the length of the string $s$. $n!$ enumerations need to be performed, and each enumeration requires $O(n)$ time to determine whether it is repeated. In addition, we need a marker array to mark whether each position has been used, so the space complexity is $O(n)$. +The time complexity is $O(n \times n!)$, and the space complexity is $O(n)$. Here, $n$ is the length of the string $s$. We need to perform $n!$ enumerations, and each enumeration requires $O(n)$ time to check for duplicates. Additionally, we need a marker array to mark whether each position has been used, so the space complexity is $O(n)$. @@ -64,21 +64,20 @@ The time complexity is $O(n \times n!)$, and the space complexity is $O(n)$. Her class Solution: def permutation(self, S: str) -> List[str]: def dfs(i: int): - if i == n: + 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 + for j, c in enumerate(s): + if not vis[j] and (j == 0 or s[j] != s[j - 1] or vis[j - 1]): + vis[j] = True + t[i] = c + dfs(i + 1) + vis[j] = False - cs = sorted(S) - n = len(cs) + s = sorted(S) ans = [] - t = [None] * n + t = s[:] + n = len(s) vis = [False] * n dfs(0) return ans @@ -88,35 +87,33 @@ class Solution: ```java class Solution { - private int n; - private char[] cs; - private List ans = new ArrayList<>(); + private char[] s; + private char[] t; private boolean[] vis; - private StringBuilder t = new StringBuilder(); + private List ans = new ArrayList<>(); public String[] permutation(String S) { - cs = S.toCharArray(); - n = cs.length; - Arrays.sort(cs); + int n = S.length(); + s = S.toCharArray(); + Arrays.sort(s); + t = new char[n]; vis = new boolean[n]; dfs(0); return ans.toArray(new String[0]); } private void dfs(int i) { - if (i == n) { - ans.add(t.toString()); + if (i >= s.length) { + ans.add(new String(t)); return; } - for (int j = 0; j < n; ++j) { - if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] == cs[j - 1])) { - continue; + for (int j = 0; j < s.length; ++j) { + if (!vis[j] && (j == 0 || s[j] != s[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.append(cs[j]); - dfs(i + 1); - t.deleteCharAt(t.length() - 1); - vis[j] = false; } } } @@ -128,26 +125,23 @@ class Solution { class Solution { public: vector permutation(string S) { - vector cs(S.begin(), S.end()); - sort(cs.begin(), cs.end()); - int n = cs.size(); - vector ans; + ranges::sort(S); + string t = S; + int n = t.size(); vector vis(n); - string t; - function dfs = [&](int i) { - if (i == n) { - ans.push_back(t); + vector ans; + auto dfs = [&](this auto&& dfs, int i) { + if (i >= n) { + ans.emplace_back(t); return; } for (int j = 0; j < n; ++j) { - if (vis[j] || (j && !vis[j - 1] && cs[j] == cs[j - 1])) { - continue; + if (!vis[j] && (j == 0 || S[j] != S[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = S[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push_back(cs[j]); - dfs(i + 1); - t.pop_back(); - vis[j] = false; } }; dfs(0); @@ -160,26 +154,23 @@ public: ```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) + s := []byte(S) + sort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) + t := slices.Clone(s) + vis := make([]bool, len(s)) var dfs func(int) dfs = func(i int) { - if i == n { + if i >= len(s) { 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 + for j := range s { + if !vis[j] && (j == 0 || s[j] != s[j-1] || vis[j-1]) { + vis[j] = true + t[i] = s[j] + dfs(i + 1) + vis[j] = false } - vis[j] = true - t = append(t, cs[j]) - dfs(i + 1) - t = t[:len(t)-1] - vis[j] = false } } dfs(0) @@ -191,25 +182,23 @@ func permutation(S string) (ans []string) { ```ts function permutation(S: string): string[] { - const cs: string[] = S.split('').sort(); - const ans: string[] = []; - const n = cs.length; + const s: string[] = S.split('').sort(); + const n = s.length; + const t = Array(n).fill(''); const vis: boolean[] = Array(n).fill(false); - const t: string[] = []; + const ans: string[] = []; const dfs = (i: number) => { - if (i === n) { + 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; + if (!vis[j] && (j === 0 || s[j] !== s[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push(cs[j]); - dfs(i + 1); - t.pop(); - vis[j] = false; } }; dfs(0); @@ -225,25 +214,23 @@ function permutation(S: string): string[] { * @return {string[]} */ var permutation = function (S) { - const cs = S.split('').sort(); - const ans = []; - const n = cs.length; + const s = S.split('').sort(); + const n = s.length; + const t = Array(n).fill(''); const vis = Array(n).fill(false); - const t = []; + const ans = []; const dfs = i => { - if (i === n) { + 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; + if (!vis[j] && (j === 0 || s[j] !== s[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push(cs[j]); - dfs(i + 1); - t.pop(); - vis[j] = false; } }; dfs(0); @@ -255,37 +242,31 @@ var permutation = function (S) { ```swift class Solution { - private var n: Int = 0 - private var cs: [Character] = [] - private var ans: [String] = [] - private var vis: [Bool] = [] - private var t: String = "" - func permutation(_ S: String) -> [String] { - cs = Array(S) - n = cs.count - cs.sort() - vis = Array(repeating: false, count: n) + var ans: [String] = [] + var s: [Character] = Array(S).sorted() + var t: [Character] = Array(repeating: " ", count: s.count) + var vis: [Bool] = Array(repeating: false, count: s.count) + let n = s.count + + func dfs(_ i: Int) { + if i >= n { + ans.append(String(t)) + return + } + for j in 0.. 0 && !vis[j - 1] && cs[j] == cs[j - 1]) { - continue - } - vis[j] = true - t.append(cs[j]) - dfs(i + 1) - t.removeLast() - vis[j] = false - } - } } ``` diff --git a/lcci/08.08.Permutation II/Solution.cpp b/lcci/08.08.Permutation II/Solution.cpp index c706c3df75..c4efd6b143 100644 --- a/lcci/08.08.Permutation II/Solution.cpp +++ b/lcci/08.08.Permutation II/Solution.cpp @@ -1,29 +1,26 @@ class Solution { public: vector permutation(string S) { - vector cs(S.begin(), S.end()); - sort(cs.begin(), cs.end()); - int n = cs.size(); - vector ans; + ranges::sort(S); + string t = S; + int n = t.size(); vector vis(n); - string t; - function dfs = [&](int i) { - if (i == n) { - ans.push_back(t); + vector ans; + auto dfs = [&](this auto&& dfs, int i) { + if (i >= n) { + ans.emplace_back(t); return; } for (int j = 0; j < n; ++j) { - if (vis[j] || (j && !vis[j - 1] && cs[j] == cs[j - 1])) { - continue; + if (!vis[j] && (j == 0 || S[j] != S[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = S[j]; + dfs(i + 1); + vis[j] = false; } - 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 index bdb449b7c9..ce2be679b7 100644 --- a/lcci/08.08.Permutation II/Solution.go +++ b/lcci/08.08.Permutation II/Solution.go @@ -1,26 +1,23 @@ 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) + s := []byte(S) + sort.Slice(s, func(i, j int) bool { return s[i] < s[j] }) + t := slices.Clone(s) + vis := make([]bool, len(s)) var dfs func(int) dfs = func(i int) { - if i == n { + if i >= len(s) { 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 + for j := range s { + if !vis[j] && (j == 0 || s[j] != s[j-1] || vis[j-1]) { + vis[j] = true + t[i] = s[j] + dfs(i + 1) + vis[j] = false } - 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 index e0dffd2d0c..b03452a42c 100644 --- a/lcci/08.08.Permutation II/Solution.java +++ b/lcci/08.08.Permutation II/Solution.java @@ -1,33 +1,31 @@ class Solution { - private int n; - private char[] cs; - private List ans = new ArrayList<>(); + private char[] s; + private char[] t; private boolean[] vis; - private StringBuilder t = new StringBuilder(); + private List ans = new ArrayList<>(); public String[] permutation(String S) { - cs = S.toCharArray(); - n = cs.length; - Arrays.sort(cs); + int n = S.length(); + s = S.toCharArray(); + Arrays.sort(s); + t = new char[n]; vis = new boolean[n]; dfs(0); return ans.toArray(new String[0]); } private void dfs(int i) { - if (i == n) { - ans.add(t.toString()); + if (i >= s.length) { + ans.add(new String(t)); return; } - for (int j = 0; j < n; ++j) { - if (vis[j] || (j > 0 && !vis[j - 1] && cs[j] == cs[j - 1])) { - continue; + for (int j = 0; j < s.length; ++j) { + if (!vis[j] && (j == 0 || s[j] != s[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - 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 44aed97be1..4bb6b59170 100644 --- a/lcci/08.08.Permutation II/Solution.js +++ b/lcci/08.08.Permutation II/Solution.js @@ -3,25 +3,23 @@ * @return {string[]} */ var permutation = function (S) { - const cs = S.split('').sort(); - const ans = []; - const n = cs.length; + const s = S.split('').sort(); + const n = s.length; + const t = Array(n).fill(''); const vis = Array(n).fill(false); - const t = []; + const ans = []; const dfs = i => { - if (i === n) { + 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; + if (!vis[j] && (j === 0 || s[j] !== s[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push(cs[j]); - dfs(i + 1); - t.pop(); - vis[j] = false; } }; dfs(0); diff --git a/lcci/08.08.Permutation II/Solution.py b/lcci/08.08.Permutation II/Solution.py index e6b19ccba3..e39d27633f 100644 --- a/lcci/08.08.Permutation II/Solution.py +++ b/lcci/08.08.Permutation II/Solution.py @@ -1,21 +1,20 @@ class Solution: def permutation(self, S: str) -> List[str]: def dfs(i: int): - if i == n: + 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 + for j, c in enumerate(s): + if not vis[j] and (j == 0 or s[j] != s[j - 1] or vis[j - 1]): + vis[j] = True + t[i] = c + dfs(i + 1) + vis[j] = False - cs = sorted(S) - n = len(cs) + s = sorted(S) ans = [] - t = [None] * n + t = s[:] + n = len(s) vis = [False] * n dfs(0) return ans diff --git a/lcci/08.08.Permutation II/Solution.swift b/lcci/08.08.Permutation II/Solution.swift index a00ac743ff..84151d360d 100644 --- a/lcci/08.08.Permutation II/Solution.swift +++ b/lcci/08.08.Permutation II/Solution.swift @@ -1,33 +1,27 @@ class Solution { - private var n: Int = 0 - private var cs: [Character] = [] - private var ans: [String] = [] - private var vis: [Bool] = [] - private var t: String = "" - func permutation(_ S: String) -> [String] { - cs = Array(S) - n = cs.count - cs.sort() - vis = Array(repeating: false, count: n) + var ans: [String] = [] + var s: [Character] = Array(S).sorted() + var t: [Character] = Array(repeating: " ", count: s.count) + var vis: [Bool] = Array(repeating: false, count: s.count) + let n = s.count + + func dfs(_ i: Int) { + if i >= n { + ans.append(String(t)) + return + } + for j in 0.. 0 && !vis[j - 1] && cs[j] == cs[j - 1]) { - continue - } - vis[j] = true - t.append(cs[j]) - dfs(i + 1) - t.removeLast() - vis[j] = false - } - } } diff --git a/lcci/08.08.Permutation II/Solution.ts b/lcci/08.08.Permutation II/Solution.ts index 747891e4cf..d651c9946c 100644 --- a/lcci/08.08.Permutation II/Solution.ts +++ b/lcci/08.08.Permutation II/Solution.ts @@ -1,23 +1,21 @@ function permutation(S: string): string[] { - const cs: string[] = S.split('').sort(); - const ans: string[] = []; - const n = cs.length; + const s: string[] = S.split('').sort(); + const n = s.length; + const t = Array(n).fill(''); const vis: boolean[] = Array(n).fill(false); - const t: string[] = []; + const ans: string[] = []; const dfs = (i: number) => { - if (i === n) { + 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; + if (!vis[j] && (j === 0 || s[j] !== s[j - 1] || vis[j - 1])) { + vis[j] = true; + t[i] = s[j]; + dfs(i + 1); + vis[j] = false; } - vis[j] = true; - t.push(cs[j]); - dfs(i + 1); - t.pop(); - vis[j] = false; } }; dfs(0); diff --git a/lcci/08.09.Bracket/README.md b/lcci/08.09.Bracket/README.md index 6e4a46e576..7272118acc 100644 --- a/lcci/08.09.Bracket/README.md +++ b/lcci/08.09.Bracket/README.md @@ -104,8 +104,7 @@ class Solution { public: vector generateParenthesis(int n) { vector ans; - function dfs; - dfs = [&](int l, int r, string t) { + auto dfs = [&](this auto&& dfs, int l, int r, string t) { if (l > n || r > n || l < r) return; if (l == n && r == n) { ans.push_back(t); diff --git a/lcci/08.09.Bracket/README_EN.md b/lcci/08.09.Bracket/README_EN.md index 295bd24efe..36ee966e88 100644 --- a/lcci/08.09.Bracket/README_EN.md +++ b/lcci/08.09.Bracket/README_EN.md @@ -112,8 +112,7 @@ class Solution { public: vector generateParenthesis(int n) { vector ans; - function dfs; - dfs = [&](int l, int r, string t) { + auto dfs = [&](this auto&& dfs, int l, int r, string t) { if (l > n || r > n || l < r) return; if (l == n && r == n) { ans.push_back(t); diff --git a/lcci/08.09.Bracket/Solution.cpp b/lcci/08.09.Bracket/Solution.cpp index 4c9a371b25..d386301341 100644 --- a/lcci/08.09.Bracket/Solution.cpp +++ b/lcci/08.09.Bracket/Solution.cpp @@ -2,8 +2,7 @@ class Solution { public: vector generateParenthesis(int n) { vector ans; - function dfs; - dfs = [&](int l, int r, string t) { + auto dfs = [&](this auto&& dfs, int l, int r, string t) { if (l > n || r > n || l < r) return; if (l == n && r == n) { ans.push_back(t); @@ -15,4 +14,4 @@ public: dfs(0, 0, ""); return ans; } -}; \ No newline at end of file +};