diff --git a/solution/0800-0899/0836.Rectangle Overlap/README.md b/solution/0800-0899/0836.Rectangle Overlap/README.md index 8885ace81e0eb..8ea99ed24e464 100644 --- a/solution/0800-0899/0836.Rectangle Overlap/README.md +++ b/solution/0800-0899/0836.Rectangle Overlap/README.md @@ -50,6 +50,21 @@ +**方法一:判断不重叠的情况** + +我们记矩形 $rec1$ 的坐标点为 $(x_1, y_1, x_2, y_2)$,矩形 $rec2$ 的坐标点为 $(x_3, y_3, x_4, y_4)$。 + +那么当满足以下任一条件时,矩形 $rec1$ 和 $rec2$ 不重叠: + +- 满足 $y_3 \geq y_2$,即 $rec2$ 在 $rec1$ 的上方; +- 满足 $y_4 \leq y_1$,即 $rec2$ 在 $rec1$ 的下方; +- 满足 $x_3 \geq x_2$,即 $rec2$ 在 $rec1$ 的右方; +- 满足 $x_4 \leq x_1$,即 $rec2$ 在 $rec1$ 的左方。 + +当以上条件都不满足时,矩形 $rec1$ 和 $rec2$ 重叠。 + +时间复杂度 $O(1)$,空间复杂度 $O(1)$。 + ### **Python3** @@ -57,7 +72,11 @@ ```python - +class Solution: + def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool: + x1, y1, x2, y2 = rec1 + x3, y3, x4, y4 = rec2 + return not (y3 >= y2 or y4 <= y1 or x3 >= x2 or x4 <= x1) ``` ### **Java** @@ -65,7 +84,36 @@ ```java +class Solution { + public boolean isRectangleOverlap(int[] rec1, int[] rec2) { + int x1 = rec1[0], y1 = rec1[1], x2 = rec1[2], y2 = rec1[3]; + int x3 = rec2[0], y3 = rec2[1], x4 = rec2[2], y4 = rec2[3]; + return !(y3 >= y2 || y4 <= y1 || x3 >= x2 || x4 <= x1); + } +} +``` + +### **C++** + +```cpp +class Solution { +public: + bool isRectangleOverlap(vector& rec1, vector& rec2) { + int x1 = rec1[0], y1 = rec1[1], x2 = rec1[2], y2 = rec1[3]; + int x3 = rec2[0], y3 = rec2[1], x4 = rec2[2], y4 = rec2[3]; + return !(y3 >= y2 || y4 <= y1 || x3 >= x2 || x4 <= x1); + } +}; +``` + +### **Go** +```go +func isRectangleOverlap(rec1 []int, rec2 []int) bool { + x1, y1, x2, y2 := rec1[0], rec1[1], rec1[2], rec1[3] + x3, y3, x4, y4 := rec2[0], rec2[1], rec2[2], rec2[3] + return !(y3 >= y2 || y4 <= y1 || x3 >= x2 || x4 <= x1) +} ``` ### **...** diff --git a/solution/0800-0899/0836.Rectangle Overlap/README_EN.md b/solution/0800-0899/0836.Rectangle Overlap/README_EN.md index b8e0d1dc5cc96..ccbab1255bbac 100644 --- a/solution/0800-0899/0836.Rectangle Overlap/README_EN.md +++ b/solution/0800-0899/0836.Rectangle Overlap/README_EN.md @@ -38,13 +38,46 @@ ### **Python3** ```python - +class Solution: + def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool: + x1, y1, x2, y2 = rec1 + x3, y3, x4, y4 = rec2 + return not (y3 >= y2 or y4 <= y1 or x3 >= x2 or x4 <= x1) ``` ### **Java** ```java +class Solution { + public boolean isRectangleOverlap(int[] rec1, int[] rec2) { + int x1 = rec1[0], y1 = rec1[1], x2 = rec1[2], y2 = rec1[3]; + int x3 = rec2[0], y3 = rec2[1], x4 = rec2[2], y4 = rec2[3]; + return !(y3 >= y2 || y4 <= y1 || x3 >= x2 || x4 <= x1); + } +} +``` + +### **C++** + +```cpp +class Solution { +public: + bool isRectangleOverlap(vector& rec1, vector& rec2) { + int x1 = rec1[0], y1 = rec1[1], x2 = rec1[2], y2 = rec1[3]; + int x3 = rec2[0], y3 = rec2[1], x4 = rec2[2], y4 = rec2[3]; + return !(y3 >= y2 || y4 <= y1 || x3 >= x2 || x4 <= x1); + } +}; +``` + +### **Go** +```go +func isRectangleOverlap(rec1 []int, rec2 []int) bool { + x1, y1, x2, y2 := rec1[0], rec1[1], rec1[2], rec1[3] + x3, y3, x4, y4 := rec2[0], rec2[1], rec2[2], rec2[3] + return !(y3 >= y2 || y4 <= y1 || x3 >= x2 || x4 <= x1) +} ``` ### **...** diff --git a/solution/0800-0899/0836.Rectangle Overlap/Solution.cpp b/solution/0800-0899/0836.Rectangle Overlap/Solution.cpp index 8d6922d72fd2c..04554d400ba0e 100644 --- a/solution/0800-0899/0836.Rectangle Overlap/Solution.cpp +++ b/solution/0800-0899/0836.Rectangle Overlap/Solution.cpp @@ -1,14 +1,8 @@ class Solution { public: bool isRectangleOverlap(vector& rec1, vector& rec2) { - int l1 = rec1[1], u1 = rec1[0], r1 = rec1[3], d1 = rec1[2]; - int l2 = rec2[1], u2 = rec2[0], r2 = rec2[3], d2 = rec2[2]; - - //printf("1: (%d,%d), (%d,%d)\n", l1, u1, r1, d1) ; - //printf("2: (%d,%d), (%d,%d)\n", l2, u2, r2, d2) ; - - if (l1 < r2 && u1 < d2 && l2 < r1 && u2 < d1) - return true; - return false; + int x1 = rec1[0], y1 = rec1[1], x2 = rec1[2], y2 = rec1[3]; + int x3 = rec2[0], y3 = rec2[1], x4 = rec2[2], y4 = rec2[3]; + return !(y3 >= y2 || y4 <= y1 || x3 >= x2 || x4 <= x1); } }; \ No newline at end of file diff --git a/solution/0800-0899/0836.Rectangle Overlap/Solution.go b/solution/0800-0899/0836.Rectangle Overlap/Solution.go new file mode 100644 index 0000000000000..608e610335810 --- /dev/null +++ b/solution/0800-0899/0836.Rectangle Overlap/Solution.go @@ -0,0 +1,5 @@ +func isRectangleOverlap(rec1 []int, rec2 []int) bool { + x1, y1, x2, y2 := rec1[0], rec1[1], rec1[2], rec1[3] + x3, y3, x4, y4 := rec2[0], rec2[1], rec2[2], rec2[3] + return !(y3 >= y2 || y4 <= y1 || x3 >= x2 || x4 <= x1) +} \ No newline at end of file diff --git a/solution/0800-0899/0836.Rectangle Overlap/Solution.java b/solution/0800-0899/0836.Rectangle Overlap/Solution.java new file mode 100644 index 0000000000000..819fda1eae215 --- /dev/null +++ b/solution/0800-0899/0836.Rectangle Overlap/Solution.java @@ -0,0 +1,7 @@ +class Solution { + public boolean isRectangleOverlap(int[] rec1, int[] rec2) { + int x1 = rec1[0], y1 = rec1[1], x2 = rec1[2], y2 = rec1[3]; + int x3 = rec2[0], y3 = rec2[1], x4 = rec2[2], y4 = rec2[3]; + return !(y3 >= y2 || y4 <= y1 || x3 >= x2 || x4 <= x1); + } +} \ No newline at end of file diff --git a/solution/0800-0899/0836.Rectangle Overlap/Solution.py b/solution/0800-0899/0836.Rectangle Overlap/Solution.py new file mode 100644 index 0000000000000..7abf612583c69 --- /dev/null +++ b/solution/0800-0899/0836.Rectangle Overlap/Solution.py @@ -0,0 +1,5 @@ +class Solution: + def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool: + x1, y1, x2, y2 = rec1 + x3, y3, x4, y4 = rec2 + return not (y3 >= y2 or y4 <= y1 or x3 >= x2 or x4 <= x1) diff --git a/solution/0800-0899/0844.Backspace String Compare/README.md b/solution/0800-0899/0844.Backspace String Compare/README.md index 557abd62b3b90..4627c5217a502 100644 --- a/solution/0800-0899/0844.Backspace String Compare/README.md +++ b/solution/0800-0899/0844.Backspace String Compare/README.md @@ -58,7 +58,13 @@ **方法一:双指针** -时间复杂度 O(len(s) + len(t)),空间复杂度 O(1)。 +我们用双指针 $i$ 和 $j$ 分别指向字符串 $s$ 和 $t$ 的末尾。 + +每次向前移动一个字符,如果当前字符是退格符,则跳过当前字符,同时退格符的数量加一,如果当前字符不是退格符,则判断退格符的数量,如果退格符的数量大于 $0$,则跳过当前字符,同时退格符的数量减一,如果退格符的数量等于 $0$,那么该字符需要进行比较。 + +我们每次找到两个字符串中需要比较的字符,然后进行比较,如果两个字符不相等,则返回 $false$,如果遍历完两个字符串,都没有发现不相等的字符,则返回 $true$。 + +时间复杂度 $O(m + n)$,空间复杂度 $O(1)$。其中 $m$ 和 $n$ 分别是字符串 $s$ 和 $t$ 的长度。 diff --git a/solution/0800-0899/0847.Shortest Path Visiting All Nodes/README.md b/solution/0800-0899/0847.Shortest Path Visiting All Nodes/README.md index bc8b7a4ed45fa..68cb91a4f1a16 100644 --- a/solution/0800-0899/0847.Shortest Path Visiting All Nodes/README.md +++ b/solution/0800-0899/0847.Shortest Path Visiting All Nodes/README.md @@ -51,6 +51,8 @@ +**方法一:BFS(A\* 算法)** + 因为每条边权值一样,所以用 BFS 就能得出最短路径,过程中可以用**状态压缩**记录节点的访问情况。另外,同一个节点 u 以及对应的节点访问情况需要保证只被搜索过一次,因此可以用 `vis(u, state)` 表示是否已经被搜索过,防止无效的重复搜索。 本题也属于 BFS 最小步数模型,可以使用 A\* 算法优化搜索。 diff --git a/solution/0800-0899/0851.Loud and Rich/README.md b/solution/0800-0899/0851.Loud and Rich/README.md index da50f35b73142..ea165526c9331 100644 --- a/solution/0800-0899/0851.Loud and Rich/README.md +++ b/solution/0800-0899/0851.Loud and Rich/README.md @@ -57,9 +57,13 @@ answer[7] = 7, -根据 richer 关系构建有向图,如果 a 比 b 有钱,那么连一条从 b 到 a 的有向边,最终构建出一个有向无环图。 +**方法一:DFS** -我们知道,从图的任一点 i 出发,沿着有向边所能访问到的点,都比 i 更有钱。DFS 深搜即可。 +我们先用邻接表 $g$ 存储 $richer$ 数组中的信息,其中 $g[i]$ 表示所有比 $i$ 更有钱的人的集合。 + +然后对于每个人 $i$,我们用 DFS 遍历所有比 $i$ 更有钱的人,找到其中安静值最小的人,即为答案。 + +时间复杂度 $O(m + n)$,空间复杂度 $O(m + n)$。其中 $m$ 和 $n$ 分别为 $richer$ 数组和 $quiet$ 数组的长度。 @@ -70,13 +74,7 @@ answer[7] = 7, ```python class Solution: def loudAndRich(self, richer: List[List[int]], quiet: List[int]) -> List[int]: - n = len(quiet) - g = defaultdict(list) - for a, b in richer: - g[b].append(a) - ans = [-1] * n - - def dfs(i): + def dfs(i: int): if ans[i] != -1: return ans[i] = i @@ -85,6 +83,11 @@ class Solution: if quiet[ans[j]] < quiet[ans[i]]: ans[i] = ans[j] + g = defaultdict(list) + for a, b in richer: + g[b].append(a) + n = len(quiet) + ans = [-1] * n for i in range(n): dfs(i) return ans @@ -96,19 +99,22 @@ class Solution: ```java class Solution { - private Map> g; + private List[] g; + private int n; private int[] quiet; private int[] ans; public int[] loudAndRich(int[][] richer, int[] quiet) { - g = new HashMap<>(); + n = quiet.length; this.quiet = quiet; - ans = new int[quiet.length]; + g = new List[n]; + ans = new int[n]; Arrays.fill(ans, -1); - for (int[] r : richer) { - g.computeIfAbsent(r[1], k -> new ArrayList<>()).add(r[0]); + Arrays.setAll(g, k -> new ArrayList<>()); + for (var r : richer) { + g[r[1]].add(r[0]); } - for (int i = 0; i < quiet.length; ++i) { + for (int i = 0; i < n; ++i) { dfs(i); } return ans; @@ -119,10 +125,7 @@ class Solution { return; } ans[i] = i; - if (!g.containsKey(i)) { - return; - } - for (int j : g.get(i)) { + for (int j : g[i]) { dfs(j); if (quiet[ans[j]] < quiet[ans[i]]) { ans[i] = ans[j]; @@ -140,18 +143,25 @@ public: vector loudAndRich(vector>& richer, vector& quiet) { int n = quiet.size(); vector> g(n); - for (auto& r : richer) g[r[1]].push_back(r[0]); + for (auto& r : richer) { + g[r[1]].push_back(r[0]); + } vector ans(n, -1); function dfs = [&](int i) { - if (ans[i] != -1) return; + if (ans[i] != -1) { + return; + } ans[i] = i; for (int j : g[i]) { dfs(j); - if (quiet[ans[j]] < quiet[ans[i]]) ans[i] = ans[j]; + if (quiet[ans[j]] < quiet[ans[i]]) { + ans[i] = ans[j]; + } } }; - for (int i = 0; i < n; ++i) + for (int i = 0; i < n; ++i) { dfs(i); + } return ans; } }; @@ -161,35 +171,62 @@ public: ```go func loudAndRich(richer [][]int, quiet []int) []int { - n := len(quiet) - ans := make([]int, n) - g := make([][]int, n) - for i := 0; i < n; i++ { - ans[i] = -1 - g[i] = make([]int, 0) - } - for _, r := range richer { - g[r[1]] = append(g[r[1]], r[0]) - } + n := len(quiet) + g := make([][]int, n) + ans := make([]int, n) + for i := range g { + ans[i] = -1 + } + for _, r := range richer { + a, b := r[0], r[1] + g[b] = append(g[b], a) + } + var dfs func(int) + dfs = func(i int) { + if ans[i] != -1 { + return + } + ans[i] = i + for _, j := range g[i] { + dfs(j) + if quiet[ans[j]] < quiet[ans[i]] { + ans[i] = ans[j] + } + } + } + for i := range ans { + dfs(i) + } + return ans +} +``` - var dfs func(i int) - dfs = func(i int) { - if ans[i] != - 1 { - return +### **TypeScript** + +```ts +function loudAndRich(richer: number[][], quiet: number[]): number[] { + const n = quiet.length; + const g: number[][] = new Array(n).fill(0).map(() => []); + for (const [a, b] of richer) { + g[b].push(a); + } + const ans: number[] = new Array(n).fill(-1); + const dfs = (i: number) => { + if (ans[i] != -1) { + return ans; } - ans[i] = i - for _, j := range g[i] { - dfs(j) - if quiet[ans[j]] < quiet[ans[i]] { - ans[i] = ans[j] + ans[i] = i; + for (const j of g[i]) { + dfs(j); + if (quiet[ans[j]] < quiet[ans[i]]) { + ans[i] = ans[j]; } } + }; + for (let i = 0; i < n; ++i) { + dfs(i); } - - for i := 0; i < n; i++ { - dfs(i) - } - return ans + return ans; } ``` diff --git a/solution/0800-0899/0851.Loud and Rich/README_EN.md b/solution/0800-0899/0851.Loud and Rich/README_EN.md index 716f0dd735a30..34b24052a89ae 100644 --- a/solution/0800-0899/0851.Loud and Rich/README_EN.md +++ b/solution/0800-0899/0851.Loud and Rich/README_EN.md @@ -56,13 +56,7 @@ The other answers can be filled out with similar reasoning. ```python class Solution: def loudAndRich(self, richer: List[List[int]], quiet: List[int]) -> List[int]: - n = len(quiet) - g = defaultdict(list) - for a, b in richer: - g[b].append(a) - ans = [-1] * n - - def dfs(i): + def dfs(i: int): if ans[i] != -1: return ans[i] = i @@ -71,6 +65,11 @@ class Solution: if quiet[ans[j]] < quiet[ans[i]]: ans[i] = ans[j] + g = defaultdict(list) + for a, b in richer: + g[b].append(a) + n = len(quiet) + ans = [-1] * n for i in range(n): dfs(i) return ans @@ -80,19 +79,22 @@ class Solution: ```java class Solution { - private Map> g; + private List[] g; + private int n; private int[] quiet; private int[] ans; public int[] loudAndRich(int[][] richer, int[] quiet) { - g = new HashMap<>(); + n = quiet.length; this.quiet = quiet; - ans = new int[quiet.length]; + g = new List[n]; + ans = new int[n]; Arrays.fill(ans, -1); - for (int[] r : richer) { - g.computeIfAbsent(r[1], k -> new ArrayList<>()).add(r[0]); + Arrays.setAll(g, k -> new ArrayList<>()); + for (var r : richer) { + g[r[1]].add(r[0]); } - for (int i = 0; i < quiet.length; ++i) { + for (int i = 0; i < n; ++i) { dfs(i); } return ans; @@ -103,10 +105,7 @@ class Solution { return; } ans[i] = i; - if (!g.containsKey(i)) { - return; - } - for (int j : g.get(i)) { + for (int j : g[i]) { dfs(j); if (quiet[ans[j]] < quiet[ans[i]]) { ans[i] = ans[j]; @@ -124,18 +123,25 @@ public: vector loudAndRich(vector>& richer, vector& quiet) { int n = quiet.size(); vector> g(n); - for (auto& r : richer) g[r[1]].push_back(r[0]); + for (auto& r : richer) { + g[r[1]].push_back(r[0]); + } vector ans(n, -1); function dfs = [&](int i) { - if (ans[i] != -1) return; + if (ans[i] != -1) { + return; + } ans[i] = i; for (int j : g[i]) { dfs(j); - if (quiet[ans[j]] < quiet[ans[i]]) ans[i] = ans[j]; + if (quiet[ans[j]] < quiet[ans[i]]) { + ans[i] = ans[j]; + } } }; - for (int i = 0; i < n; ++i) + for (int i = 0; i < n; ++i) { dfs(i); + } return ans; } }; @@ -145,35 +151,62 @@ public: ```go func loudAndRich(richer [][]int, quiet []int) []int { - n := len(quiet) - ans := make([]int, n) - g := make([][]int, n) - for i := 0; i < n; i++ { - ans[i] = -1 - g[i] = make([]int, 0) - } - for _, r := range richer { - g[r[1]] = append(g[r[1]], r[0]) - } + n := len(quiet) + g := make([][]int, n) + ans := make([]int, n) + for i := range g { + ans[i] = -1 + } + for _, r := range richer { + a, b := r[0], r[1] + g[b] = append(g[b], a) + } + var dfs func(int) + dfs = func(i int) { + if ans[i] != -1 { + return + } + ans[i] = i + for _, j := range g[i] { + dfs(j) + if quiet[ans[j]] < quiet[ans[i]] { + ans[i] = ans[j] + } + } + } + for i := range ans { + dfs(i) + } + return ans +} +``` + +### **TypeScript** - var dfs func(i int) - dfs = func(i int) { - if ans[i] != - 1 { - return +```ts +function loudAndRich(richer: number[][], quiet: number[]): number[] { + const n = quiet.length; + const g: number[][] = new Array(n).fill(0).map(() => []); + for (const [a, b] of richer) { + g[b].push(a); + } + const ans: number[] = new Array(n).fill(-1); + const dfs = (i: number) => { + if (ans[i] != -1) { + return ans; } - ans[i] = i - for _, j := range g[i] { - dfs(j) - if quiet[ans[j]] < quiet[ans[i]] { - ans[i] = ans[j] + ans[i] = i; + for (const j of g[i]) { + dfs(j); + if (quiet[ans[j]] < quiet[ans[i]]) { + ans[i] = ans[j]; } } + }; + for (let i = 0; i < n; ++i) { + dfs(i); } - - for i := 0; i < n; i++ { - dfs(i) - } - return ans + return ans; } ``` diff --git a/solution/0800-0899/0851.Loud and Rich/Solution.cpp b/solution/0800-0899/0851.Loud and Rich/Solution.cpp index 074f52c0dd588..ba5ac1f27c2fd 100644 --- a/solution/0800-0899/0851.Loud and Rich/Solution.cpp +++ b/solution/0800-0899/0851.Loud and Rich/Solution.cpp @@ -3,18 +3,25 @@ class Solution { vector loudAndRich(vector>& richer, vector& quiet) { int n = quiet.size(); vector> g(n); - for (auto& r : richer) g[r[1]].push_back(r[0]); + for (auto& r : richer) { + g[r[1]].push_back(r[0]); + } vector ans(n, -1); function dfs = [&](int i) { - if (ans[i] != -1) return; + if (ans[i] != -1) { + return; + } ans[i] = i; for (int j : g[i]) { dfs(j); - if (quiet[ans[j]] < quiet[ans[i]]) ans[i] = ans[j]; + if (quiet[ans[j]] < quiet[ans[i]]) { + ans[i] = ans[j]; + } } }; - for (int i = 0; i < n; ++i) + for (int i = 0; i < n; ++i) { dfs(i); + } return ans; } }; \ No newline at end of file diff --git a/solution/0800-0899/0851.Loud and Rich/Solution.go b/solution/0800-0899/0851.Loud and Rich/Solution.go index 94bd0fc2227b7..49d625aa1d9ac 100644 --- a/solution/0800-0899/0851.Loud and Rich/Solution.go +++ b/solution/0800-0899/0851.Loud and Rich/Solution.go @@ -1,31 +1,29 @@ func loudAndRich(richer [][]int, quiet []int) []int { - n := len(quiet) - ans := make([]int, n) - g := make([][]int, n) - for i := 0; i < n; i++ { - ans[i] = -1 - g[i] = make([]int, 0) - } - for _, r := range richer { - g[r[1]] = append(g[r[1]], r[0]) - } - - var dfs func(i int) - dfs = func(i int) { - if ans[i] != - 1 { - return - } - ans[i] = i - for _, j := range g[i] { - dfs(j) - if quiet[ans[j]] < quiet[ans[i]] { - ans[i] = ans[j] - } - } - } - - for i := 0; i < n; i++ { - dfs(i) - } - return ans + n := len(quiet) + g := make([][]int, n) + ans := make([]int, n) + for i := range g { + ans[i] = -1 + } + for _, r := range richer { + a, b := r[0], r[1] + g[b] = append(g[b], a) + } + var dfs func(int) + dfs = func(i int) { + if ans[i] != -1 { + return + } + ans[i] = i + for _, j := range g[i] { + dfs(j) + if quiet[ans[j]] < quiet[ans[i]] { + ans[i] = ans[j] + } + } + } + for i := range ans { + dfs(i) + } + return ans } \ No newline at end of file diff --git a/solution/0800-0899/0851.Loud and Rich/Solution.java b/solution/0800-0899/0851.Loud and Rich/Solution.java index 07fed19067d83..4f41f83ace232 100644 --- a/solution/0800-0899/0851.Loud and Rich/Solution.java +++ b/solution/0800-0899/0851.Loud and Rich/Solution.java @@ -1,17 +1,20 @@ class Solution { - private Map> g; + private List[] g; + private int n; private int[] quiet; private int[] ans; public int[] loudAndRich(int[][] richer, int[] quiet) { - g = new HashMap<>(); + n = quiet.length; this.quiet = quiet; - ans = new int[quiet.length]; + g = new List[n]; + ans = new int[n]; Arrays.fill(ans, -1); - for (int[] r : richer) { - g.computeIfAbsent(r[1], k -> new ArrayList<>()).add(r[0]); + Arrays.setAll(g, k -> new ArrayList<>()); + for (var r : richer) { + g[r[1]].add(r[0]); } - for (int i = 0; i < quiet.length; ++i) { + for (int i = 0; i < n; ++i) { dfs(i); } return ans; @@ -22,10 +25,7 @@ private void dfs(int i) { return; } ans[i] = i; - if (!g.containsKey(i)) { - return; - } - for (int j : g.get(i)) { + for (int j : g[i]) { dfs(j); if (quiet[ans[j]] < quiet[ans[i]]) { ans[i] = ans[j]; diff --git a/solution/0800-0899/0851.Loud and Rich/Solution.py b/solution/0800-0899/0851.Loud and Rich/Solution.py index db5be9101de98..f37c47903ac73 100644 --- a/solution/0800-0899/0851.Loud and Rich/Solution.py +++ b/solution/0800-0899/0851.Loud and Rich/Solution.py @@ -1,12 +1,6 @@ class Solution: def loudAndRich(self, richer: List[List[int]], quiet: List[int]) -> List[int]: - n = len(quiet) - g = defaultdict(list) - for a, b in richer: - g[b].append(a) - ans = [-1] * n - - def dfs(i): + def dfs(i: int): if ans[i] != -1: return ans[i] = i @@ -15,6 +9,11 @@ def dfs(i): if quiet[ans[j]] < quiet[ans[i]]: ans[i] = ans[j] + g = defaultdict(list) + for a, b in richer: + g[b].append(a) + n = len(quiet) + ans = [-1] * n for i in range(n): dfs(i) return ans diff --git a/solution/0800-0899/0851.Loud and Rich/Solution.ts b/solution/0800-0899/0851.Loud and Rich/Solution.ts new file mode 100644 index 0000000000000..05a873916c1aa --- /dev/null +++ b/solution/0800-0899/0851.Loud and Rich/Solution.ts @@ -0,0 +1,24 @@ +function loudAndRich(richer: number[][], quiet: number[]): number[] { + const n = quiet.length; + const g: number[][] = new Array(n).fill(0).map(() => []); + for (const [a, b] of richer) { + g[b].push(a); + } + const ans: number[] = new Array(n).fill(-1); + const dfs = (i: number) => { + if (ans[i] != -1) { + return ans; + } + ans[i] = i; + for (const j of g[i]) { + dfs(j); + if (quiet[ans[j]] < quiet[ans[i]]) { + ans[i] = ans[j]; + } + } + }; + for (let i = 0; i < n; ++i) { + dfs(i); + } + return ans; +} diff --git a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README.md b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README.md index 980f7ba73dd23..c4b6baa1e9c19 100644 --- a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README.md +++ b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README.md @@ -60,6 +60,55 @@ +**方法一:记忆化搜索** + +我们设计一个函数 $dfs(i, j)$,表示将多边形的顶点 $i$ 到 $j$ 进行三角剖分后的最低分数。那么答案就是 $dfs(0, n - 1)$。 + +函数 $dfs(i, j)$ 的计算过程如下: + +如果 $i + 1 = j$,说明多边形只有两个顶点,无法进行三角剖分,返回 $0$; + +否则,我们枚举 $i$ 和 $j$ 之间的一个顶点 $k$,即 $i \lt k \lt j$,将多边形的顶点 $i$ 到 $j$ 进行三角剖分,可以分为两个子问题:将多边形的顶点 $i$ 到 $k$ 进行三角剖分,以及将多边形的顶点 $k$ 到 $j$ 进行三角剖分。这两个子问题的最低分数分别为 $dfs(i, k)$ 和 $dfs(k, j)$,而顶点 $i$, $j$ 和 $k$ 构成的三角形的分数为 $values[i] \times values[k] \times values[j]$。那么,此次三角剖分的最低分数为 $dfs(i, k) + dfs(k, j) + values[i] \times values[k] \times values[j]$,我们取所有可能的最小值,即为 $dfs(i, j)$ 的值。 + +为了避免重复计算,我们可以使用记忆化搜索,即使用哈希表或者数组来存储已经计算过的函数值。 + +最后,我们返回 $dfs(0, n - 1)$ 即可。 + +时间复杂度 $O(n^3)$,空间复杂度 $O(n^2)$。其中 $n$ 为多边形的顶点数。 + +**方法二:动态规划** + +我们可以将方法一中的记忆化搜索改为动态规划。 + +定义 $f[i][j]$ 表示将多边形的顶点 $i$ 到 $j$ 进行三角剖分后的最低分数。初始时 $f[i][j]=0$,答案为 $f[0][n-1]$。 + +对于 $f[i][j]$(这里要求 $i + 1 \lt j$),我们先将 $f[i][j]$ 初始化为 $\infty$。 + +我们枚举 $i$ 和 $j$ 之间的一个顶点 $k$,即 $i \lt k \lt j$,将多边形的顶点 $i$ 到 $j$ 进行三角剖分,可以分为两个子问题:将多边形的顶点 $i$ 到 $k$ 进行三角剖分,以及将多边形的顶点 $k$ 到 $j$ 进行三角剖分。这两个子问题的最低分数分别为 $f[i][k]$ 和 $f[k][j]$,而顶点 $i$, $j$ 和 $k$ 构成的三角形的分数为 $values[i] \times values[k] \times values[j]$。那么,此次三角剖分的最低分数为 $f[i][k] + f[k][j] + values[i] \times values[k] \times values[j]$,我们取所有可能的最小值,即为 $f[i][j]$ 的值。 + +综上,我们可以得到状态转移方程: + +$$ +f[i][j]= +\begin{cases} +0, & i+1=j \\ +\min_{i ### **Python3** @@ -67,7 +116,38 @@ ```python +class Solution: + def minScoreTriangulation(self, values: List[int]) -> int: + @cache + def dfs(i: int, j: int) -> int: + if i + 1 == j: + return 0 + return min(dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j] for k in range(i + 1, j)) + + return dfs(0, len(values) - 1) +``` +```python +class Solution: + def minScoreTriangulation(self, values: List[int]) -> int: + n = len(values) + f = [[0] * n for _ in range(n)] + for i in range(n - 3, -1, -1): + for j in range(i + 2, n): + f[i][j] = min(f[i][k] + f[k][j] + values[i] * values[k] * values[j] for k in range(i + 1, j)) + return f[0][-1] +``` + +```python +class Solution: + def minScoreTriangulation(self, values: List[int]) -> int: + n = len(values) + f = [[0] * n for _ in range(n)] + for l in range(3, n + 1): + for i in range(n - l + 1): + j = i + l - 1 + f[i][j] = min(f[i][k] + f[k][j] + values[i] * values[k] * values[j] for k in range(i + 1, j)) + return f[0][-1] ``` ### **Java** @@ -75,7 +155,215 @@ ```java +class Solution { + private int n; + private int[] values; + private Integer[][] f; + + public int minScoreTriangulation(int[] values) { + n = values.length; + this.values = values; + f = new Integer[n][n]; + return dfs(0, n - 1); + } + + private int dfs(int i, int j) { + if (i + 1 == j) { + return 0; + } + if (f[i][j] != null) { + return f[i][j]; + } + int ans = 1 << 30; + for (int k = i + 1; k < j; ++k) { + ans = Math.min(ans, dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j]); + } + return f[i][j] = ans; + } +} +``` + +```java +class Solution { + public int minScoreTriangulation(int[] values) { + int n = values.length; + int[][] f = new int[n][n]; + for (int i = n - 3; i >= 0; --i) { + for (int j = i + 2; j < n; ++j) { + f[i][j] = 1 << 30; + for (int k = i + 1; k < j; ++k) { + f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + values[i] * values[k] * values[j]); + } + } + } + return f[0][n - 1]; + } +} +``` + +```java +class Solution { + public int minScoreTriangulation(int[] values) { + int n = values.length; + int[][] f = new int[n][n]; + for (int l = 3; l <= n; ++l) { + for (int i = 0; i + l - 1 < n; ++i) { + int j = i + l - 1; + f[i][j] = 1 << 30; + for (int k = i + 1; k < j; ++k) { + f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + values[i] * values[k] * values[j]); + } + } + } + return f[0][n - 1]; + } +} +``` + +### **C++** + +```cpp +class Solution { +public: + int minScoreTriangulation(vector& values) { + int n = values.size(); + int f[n][n]; + memset(f, 0, sizeof(f)); + function dfs = [&](int i, int j) -> int { + if (i + 1 == j) { + return 0; + } + if (f[i][j]) { + return f[i][j]; + } + int ans = 1 << 30; + for (int k = i + 1; k < j; ++k) { + ans = min(ans, dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j]); + } + return f[i][j] = ans; + }; + return dfs(0, n - 1); + } +}; +``` + +```cpp +class Solution { +public: + int minScoreTriangulation(vector& values) { + int n = values.size(); + int f[n][n]; + memset(f, 0, sizeof(f)); + for (int i = n - 3; i >= 0; --i) { + for (int j = i + 2; j < n; ++j) { + f[i][j] = 1 << 30; + for (int k = i + 1; k < j; ++k) { + f[i][j] = min(f[i][j], f[i][k] + f[k][j] + values[i] * values[k] * values[j]); + } + } + } + return f[0][n - 1]; + } +}; +``` + +```cpp +class Solution { +public: + int minScoreTriangulation(vector& values) { + int n = values.size(); + int f[n][n]; + memset(f, 0, sizeof(f)); + for (int l = 3; l <= n; ++l) { + for (int i = 0; i + l - 1 < n; ++i) { + int j = i + l - 1; + f[i][j] = 1 << 30; + for (int k = i + 1; k < j; ++k) { + f[i][j] = min(f[i][j], f[i][k] + f[k][j] + values[i] * values[k] * values[j]); + } + } + } + return f[0][n - 1]; + } +}; +``` + +### **Go** + +```go +func minScoreTriangulation(values []int) int { + n := len(values) + f := [50][50]int{} + var dfs func(int, int) int + dfs = func(i, j int) int { + if i+1 == j { + return 0 + } + if f[i][j] != 0 { + return f[i][j] + } + f[i][j] = 1 << 30 + for k := i + 1; k < j; k++ { + f[i][j] = min(f[i][j], dfs(i, k)+dfs(k, j)+values[i]*values[k]*values[j]) + } + return f[i][j] + } + return dfs(0, n-1) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} +``` + +```go +func minScoreTriangulation(values []int) int { + n := len(values) + f := [50][50]int{} + for i := n - 3; i >= 0; i-- { + for j := i + 2; j < n; j++ { + f[i][j] = 1 << 30 + for k := i + 1; k < j; k++ { + f[i][j] = min(f[i][j], f[i][k]+f[k][j]+values[i]*values[k]*values[j]) + } + } + } + return f[0][n-1] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} +``` +```go +func minScoreTriangulation(values []int) int { + n := len(values) + f := [50][50]int{} + for l := 3; l <= n; l++ { + for i := 0; i+l-1 < n; i++ { + j := i + l - 1 + f[i][j] = 1 << 30 + for k := i + 1; k < j; k++ { + f[i][j] = min(f[i][j], f[i][k]+f[k][j]+values[i]*values[k]*values[j]) + } + } + } + return f[0][n-1] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} ``` ### **...** diff --git a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README_EN.md b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README_EN.md index 750e4b2b6444a..64696c2cba53c 100644 --- a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README_EN.md +++ b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/README_EN.md @@ -52,13 +52,252 @@ The minimum score is 144. ### **Python3** ```python +class Solution: + def minScoreTriangulation(self, values: List[int]) -> int: + @cache + def dfs(i: int, j: int) -> int: + if i + 1 == j: + return 0 + return min(dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j] for k in range(i + 1, j)) + return dfs(0, len(values) - 1) +``` + +```python +class Solution: + def minScoreTriangulation(self, values: List[int]) -> int: + n = len(values) + f = [[0] * n for _ in range(n)] + for i in range(n - 3, -1, -1): + for j in range(i + 2, n): + f[i][j] = min(f[i][k] + f[k][j] + values[i] * values[k] * values[j] for k in range(i + 1, j)) + return f[0][-1] +``` + +```python +class Solution: + def minScoreTriangulation(self, values: List[int]) -> int: + n = len(values) + f = [[0] * n for _ in range(n)] + for l in range(3, n + 1): + for i in range(n - l + 1): + j = i + l - 1 + f[i][j] = min(f[i][k] + f[k][j] + values[i] * values[k] * values[j] for k in range(i + 1, j)) + return f[0][-1] ``` ### **Java** ```java +class Solution { + private int n; + private int[] values; + private Integer[][] f; + + public int minScoreTriangulation(int[] values) { + n = values.length; + this.values = values; + f = new Integer[n][n]; + return dfs(0, n - 1); + } + + private int dfs(int i, int j) { + if (i + 1 == j) { + return 0; + } + if (f[i][j] != null) { + return f[i][j]; + } + int ans = 1 << 30; + for (int k = i + 1; k < j; ++k) { + ans = Math.min(ans, dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j]); + } + return f[i][j] = ans; + } +} +``` + +```java +class Solution { + public int minScoreTriangulation(int[] values) { + int n = values.length; + int[][] f = new int[n][n]; + for (int i = n - 3; i >= 0; --i) { + for (int j = i + 2; j < n; ++j) { + f[i][j] = 1 << 30; + for (int k = i + 1; k < j; ++k) { + f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + values[i] * values[k] * values[j]); + } + } + } + return f[0][n - 1]; + } +} +``` + +```java +class Solution { + public int minScoreTriangulation(int[] values) { + int n = values.length; + int[][] f = new int[n][n]; + for (int l = 3; l <= n; ++l) { + for (int i = 0; i + l - 1 < n; ++i) { + int j = i + l - 1; + f[i][j] = 1 << 30; + for (int k = i + 1; k < j; ++k) { + f[i][j] = Math.min(f[i][j], f[i][k] + f[k][j] + values[i] * values[k] * values[j]); + } + } + } + return f[0][n - 1]; + } +} +``` + +### **C++** + +```cpp +class Solution { +public: + int minScoreTriangulation(vector& values) { + int n = values.size(); + int f[n][n]; + memset(f, 0, sizeof(f)); + function dfs = [&](int i, int j) -> int { + if (i + 1 == j) { + return 0; + } + if (f[i][j]) { + return f[i][j]; + } + int ans = 1 << 30; + for (int k = i + 1; k < j; ++k) { + ans = min(ans, dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j]); + } + return f[i][j] = ans; + }; + return dfs(0, n - 1); + } +}; +``` + +```cpp +class Solution { +public: + int minScoreTriangulation(vector& values) { + int n = values.size(); + int f[n][n]; + memset(f, 0, sizeof(f)); + for (int i = n - 3; i >= 0; --i) { + for (int j = i + 2; j < n; ++j) { + f[i][j] = 1 << 30; + for (int k = i + 1; k < j; ++k) { + f[i][j] = min(f[i][j], f[i][k] + f[k][j] + values[i] * values[k] * values[j]); + } + } + } + return f[0][n - 1]; + } +}; +``` + +```cpp +class Solution { +public: + int minScoreTriangulation(vector& values) { + int n = values.size(); + int f[n][n]; + memset(f, 0, sizeof(f)); + for (int l = 3; l <= n; ++l) { + for (int i = 0; i + l - 1 < n; ++i) { + int j = i + l - 1; + f[i][j] = 1 << 30; + for (int k = i + 1; k < j; ++k) { + f[i][j] = min(f[i][j], f[i][k] + f[k][j] + values[i] * values[k] * values[j]); + } + } + } + return f[0][n - 1]; + } +}; +``` + +### **Go** + +```go +func minScoreTriangulation(values []int) int { + n := len(values) + f := [50][50]int{} + var dfs func(int, int) int + dfs = func(i, j int) int { + if i+1 == j { + return 0 + } + if f[i][j] != 0 { + return f[i][j] + } + f[i][j] = 1 << 30 + for k := i + 1; k < j; k++ { + f[i][j] = min(f[i][j], dfs(i, k)+dfs(k, j)+values[i]*values[k]*values[j]) + } + return f[i][j] + } + return dfs(0, n-1) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} +``` + +```go +func minScoreTriangulation(values []int) int { + n := len(values) + f := [50][50]int{} + for i := n - 3; i >= 0; i-- { + for j := i + 2; j < n; j++ { + f[i][j] = 1 << 30 + for k := i + 1; k < j; k++ { + f[i][j] = min(f[i][j], f[i][k]+f[k][j]+values[i]*values[k]*values[j]) + } + } + } + return f[0][n-1] +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} +``` + +```go +func minScoreTriangulation(values []int) int { + n := len(values) + f := [50][50]int{} + for l := 3; l <= n; l++ { + for i := 0; i+l-1 < n; i++ { + j := i + l - 1 + f[i][j] = 1 << 30 + for k := i + 1; k < j; k++ { + f[i][j] = min(f[i][j], f[i][k]+f[k][j]+values[i]*values[k]*values[j]) + } + } + } + return f[0][n-1] +} +func min(a, b int) int { + if a < b { + return a + } + return b +} ``` ### **...** diff --git a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.cpp b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.cpp new file mode 100644 index 0000000000000..b93d2f2c5d610 --- /dev/null +++ b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.cpp @@ -0,0 +1,22 @@ +class Solution { +public: + int minScoreTriangulation(vector& values) { + int n = values.size(); + int f[n][n]; + memset(f, 0, sizeof(f)); + function dfs = [&](int i, int j) -> int { + if (i + 1 == j) { + return 0; + } + if (f[i][j]) { + return f[i][j]; + } + int ans = 1 << 30; + for (int k = i + 1; k < j; ++k) { + ans = min(ans, dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j]); + } + return f[i][j] = ans; + }; + return dfs(0, n - 1); + } +}; \ No newline at end of file diff --git a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.go b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.go new file mode 100644 index 0000000000000..34e809ad0eb08 --- /dev/null +++ b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.go @@ -0,0 +1,26 @@ +func minScoreTriangulation(values []int) int { + n := len(values) + f := [50][50]int{} + var dfs func(int, int) int + dfs = func(i, j int) int { + if i+1 == j { + return 0 + } + if f[i][j] != 0 { + return f[i][j] + } + f[i][j] = 1 << 30 + for k := i + 1; k < j; k++ { + f[i][j] = min(f[i][j], dfs(i, k)+dfs(k, j)+values[i]*values[k]*values[j]) + } + return f[i][j] + } + return dfs(0, n-1) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} \ No newline at end of file diff --git a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.java b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.java new file mode 100644 index 0000000000000..544f769b24bb6 --- /dev/null +++ b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.java @@ -0,0 +1,26 @@ +class Solution { + private int n; + private int[] values; + private Integer[][] f; + + public int minScoreTriangulation(int[] values) { + n = values.length; + this.values = values; + f = new Integer[n][n]; + return dfs(0, n - 1); + } + + private int dfs(int i, int j) { + if (i + 1 == j) { + return 0; + } + if (f[i][j] != null) { + return f[i][j]; + } + int ans = 1 << 30; + for (int k = i + 1; k < j; ++k) { + ans = Math.min(ans, dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j]); + } + return f[i][j] = ans; + } +} \ No newline at end of file diff --git a/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.py b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.py new file mode 100644 index 0000000000000..b8c049ecbe6b0 --- /dev/null +++ b/solution/1000-1099/1039.Minimum Score Triangulation of Polygon/Solution.py @@ -0,0 +1,9 @@ +class Solution: + def minScoreTriangulation(self, values: List[int]) -> int: + @cache + def dfs(i: int, j: int) -> int: + if i + 1 == j: + return 0 + return min(dfs(i, k) + dfs(k, j) + values[i] * values[k] * values[j] for k in range(i + 1, j)) + + return dfs(0, len(values) - 1) diff --git a/solution/1000-1099/1053.Previous Permutation With One Swap/README.md b/solution/1000-1099/1053.Previous Permutation With One Swap/README.md index 5035a93ff78d2..e8e9e53c1596a 100644 --- a/solution/1000-1099/1053.Previous Permutation With One Swap/README.md +++ b/solution/1000-1099/1053.Previous Permutation With One Swap/README.md @@ -51,9 +51,9 @@ **方法一:贪心** -我们先从右到左遍历数组,找到第一个满足 `arr[i - 1] > arr[i]` 的下标 `i`,此时 `arr[i - 1]` 就是我们要交换的数字,我们再从右到左遍历数组,找到第一个满足 `arr[j] < arr[i - 1]` 且 `arr[j] != arr[j - 1]` 的下标 `j`,此时我们交换 `arr[i - 1]` 和 `arr[j]` 后返回即可。 +我们先从右到左遍历数组,找到第一个满足 $arr[i - 1] \gt arr[i]$ 的下标 $i$,此时 $arr[i - 1]$ 就是我们要交换的数字,我们再从右到左遍历数组,找到第一个满足 $arr[j] \lt arr[i - 1]$ 且 $arr[j] \neq arr[j - 1]$ 的下标 $j$,此时我们交换 $arr[i - 1]$ 和 $arr[j]$ 后返回即可。 -如果遍历完数组都没有找到满足条件的下标 `i`,说明数组已经是最小排列,直接返回原数组即可。 +如果遍历完数组都没有找到满足条件的下标 $i$,说明数组已经是最小排列,直接返回原数组即可。 时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为数组长度。 diff --git a/solution/1000-1099/1054.Distant Barcodes/README.md b/solution/1000-1099/1054.Distant Barcodes/README.md index 4c06952f12436..cbad32ced9c28 100644 --- a/solution/1000-1099/1054.Distant Barcodes/README.md +++ b/solution/1000-1099/1054.Distant Barcodes/README.md @@ -44,7 +44,7 @@ 重排条形码时,我们每次从堆顶弹出一个元素 `(v, k)`,将 `k` 添加到结果数组中,并将 `(v-1, k)` 放入队列 `q` 中。当队列长度大于 $1$ 时,弹出队首元素 `p`,若此时 `p.v` 大于 $0$,则将 `p` 放入堆中。循环,直至堆为空。 -时间复杂度 $O(n\log n)$,空间复杂度 $O(n)$。其中 $n$ 为条形码数组的长度。 +时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 为条形码数组的长度。 相似题目:[767. 重构字符串](/solution/0700-0799/0767.Reorganize%20String/README.md) diff --git a/solution/1300-1399/1312.Minimum Insertion Steps to Make a String Palindrome/README.md b/solution/1300-1399/1312.Minimum Insertion Steps to Make a String Palindrome/README.md index d4ea4b3d693ea..a62dcf02b3fb7 100644 --- a/solution/1300-1399/1312.Minimum Insertion Steps to Make a String Palindrome/README.md +++ b/solution/1300-1399/1312.Minimum Insertion Steps to Make a String Palindrome/README.md @@ -51,7 +51,23 @@ -**方法一:动态规划(区间 DP)** +**方法一:记忆化搜索** + +我们设计一个函数 $dfs(i, j)$,表示将字符串 $s[i..j]$ 变成回文串所需要的最少操作次数。那么答案就是 $dfs(0, n - 1)$。 + +函数 $dfs(i, j)$ 的计算过程如下: + +如果 $i \geq j$,此时无需插入任何字符,我们直接返回 $0$。 + +否则,我们判断 $s[i]$ 与 $s[j]$ 是否相等,如果 $s[i]=s[j]$,那么我们只需要将 $s[i+1..j-1]$ 变成回文串,那么我们返回 $dfs(i + 1, j - 1)$。否则,我们可以在 $s[i]$ 的左侧或者 $s[j]$ 的右侧插入一个与另一侧相同的字符,那么 $dfs(i, j) = \min(dfs(i + 1, j), dfs(i, j - 1)) + 1$。 + +为了避免重复计算,我们可以使用记忆化搜索,即使用哈希表或者数组来存储已经计算过的函数值。 + +最后,我们返回 $dfs(0, n - 1)$ 即可。 + +时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 为字符串 $s$ 的长度。 + +**方法二:动态规划(区间 DP)** 我们定义 $f[i][j]$ 表示将字符串 $s[i..j]$ 变成回文串所需要的最少操作次数。初始时 $f[i][j]=0$,答案即为 $f[0][n-1]$。 @@ -70,12 +86,30 @@ $$ 时间复杂度 $O(n^2)$,空间复杂度 $O(n^2)$。其中 $n$ 为字符串 $s$ 的长度。 +相似题目: + +- [1039. 多边形三角剖分的最低得分](/solution/1000-1099/1039.Minimum%20Score%20Triangulation%20of%20Polygon/README.md) + ### **Python3** +```python +class Solution: + def minInsertions(self, s: str) -> int: + @cache + def dfs(i: int, j: int) -> int: + if i >= j: + return 0 + if s[i] == s[j]: + return dfs(i + 1, j - 1) + return 1 + min(dfs(i + 1, j), dfs(i, j - 1)) + + return dfs(0, len(s) - 1) +``` + ```python class Solution: def minInsertions(self, s: str) -> int: @@ -109,6 +143,36 @@ class Solution: +```java +class Solution { + private Integer[][] f; + private String s; + + public int minInsertions(String s) { + this.s = s; + int n = s.length(); + f = new Integer[n][n]; + return dfs(0, n - 1); + } + + private int dfs(int i, int j) { + if (i >= j) { + return 0; + } + if (f[i][j] != null) { + return f[i][j]; + } + int ans = 1 << 30; + if (s.charAt(i) == s.charAt(j)) { + ans = dfs(i + 1, j - 1); + } else { + ans = Math.min(dfs(i + 1, j), dfs(i, j - 1)) + 1; + } + return f[i][j] = ans; + } +} +``` + ```java class Solution { public int minInsertions(String s) { @@ -150,6 +214,33 @@ class Solution { ### **C++** +```cpp +class Solution { +public: + int minInsertions(string s) { + int n = s.size(); + int f[n][n]; + memset(f, -1, sizeof(f)); + function dfs = [&](int i, int j) -> int { + if (i >= j) { + return 0; + } + if (f[i][j] != -1) { + return f[i][j]; + } + int ans = 1 << 30; + if (s[i] == s[j]) { + ans = dfs(i + 1, j - 1); + } else { + ans = min(dfs(i + 1, j), dfs(i, j - 1)) + 1; + } + return f[i][j] = ans; + }; + return dfs(0, n - 1); + } +}; +``` + ```cpp class Solution { public: @@ -195,6 +286,44 @@ public: ### **Go** +```go +func minInsertions(s string) int { + n := len(s) + f := make([][]int, n) + for i := range f { + f[i] = make([]int, n) + for j := range f[i] { + f[i][j] = -1 + } + } + var dfs func(i, j int) int + dfs = func(i, j int) int { + if i >= j { + return 0 + } + if f[i][j] != -1 { + return f[i][j] + } + ans := 1 << 30 + if s[i] == s[j] { + ans = dfs(i+1, j-1) + } else { + ans = min(dfs(i+1, j), dfs(i, j-1)) + 1 + } + f[i][j] = ans + return ans + } + return dfs(0, n-1) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} +``` + ```go func minInsertions(s string) int { n := len(s) diff --git a/solution/1300-1399/1312.Minimum Insertion Steps to Make a String Palindrome/README_EN.md b/solution/1300-1399/1312.Minimum Insertion Steps to Make a String Palindrome/README_EN.md index 6c7f0fabd4236..d12812c16fe47 100644 --- a/solution/1300-1399/1312.Minimum Insertion Steps to Make a String Palindrome/README_EN.md +++ b/solution/1300-1399/1312.Minimum Insertion Steps to Make a String Palindrome/README_EN.md @@ -49,6 +49,20 @@ ### **Python3** +```python +class Solution: + def minInsertions(self, s: str) -> int: + @cache + def dfs(i: int, j: int) -> int: + if i >= j: + return 0 + if s[i] == s[j]: + return dfs(i + 1, j - 1) + return 1 + min(dfs(i + 1, j), dfs(i, j - 1)) + + return dfs(0, len(s) - 1) +``` + ```python class Solution: def minInsertions(self, s: str) -> int: @@ -80,6 +94,36 @@ class Solution: ### **Java** +```java +class Solution { + private Integer[][] f; + private String s; + + public int minInsertions(String s) { + this.s = s; + int n = s.length(); + f = new Integer[n][n]; + return dfs(0, n - 1); + } + + private int dfs(int i, int j) { + if (i >= j) { + return 0; + } + if (f[i][j] != null) { + return f[i][j]; + } + int ans = 1 << 30; + if (s.charAt(i) == s.charAt(j)) { + ans = dfs(i + 1, j - 1); + } else { + ans = Math.min(dfs(i + 1, j), dfs(i, j - 1)) + 1; + } + return f[i][j] = ans; + } +} +``` + ```java class Solution { public int minInsertions(String s) { @@ -121,6 +165,33 @@ class Solution { ### **C++** +```cpp +class Solution { +public: + int minInsertions(string s) { + int n = s.size(); + int f[n][n]; + memset(f, -1, sizeof(f)); + function dfs = [&](int i, int j) -> int { + if (i >= j) { + return 0; + } + if (f[i][j] != -1) { + return f[i][j]; + } + int ans = 1 << 30; + if (s[i] == s[j]) { + ans = dfs(i + 1, j - 1); + } else { + ans = min(dfs(i + 1, j), dfs(i, j - 1)) + 1; + } + return f[i][j] = ans; + }; + return dfs(0, n - 1); + } +}; +``` + ```cpp class Solution { public: @@ -166,6 +237,44 @@ public: ### **Go** +```go +func minInsertions(s string) int { + n := len(s) + f := make([][]int, n) + for i := range f { + f[i] = make([]int, n) + for j := range f[i] { + f[i][j] = -1 + } + } + var dfs func(i, j int) int + dfs = func(i, j int) int { + if i >= j { + return 0 + } + if f[i][j] != -1 { + return f[i][j] + } + ans := 1 << 30 + if s[i] == s[j] { + ans = dfs(i+1, j-1) + } else { + ans = min(dfs(i+1, j), dfs(i, j-1)) + 1 + } + f[i][j] = ans + return ans + } + return dfs(0, n-1) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} +``` + ```go func minInsertions(s string) int { n := len(s)