From fc2973178761a88af39293a7037d0823c5108aa6 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Sun, 26 Mar 2023 20:17:49 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1638 No.1638.Count Substrings That Differ by One Character --- .../README.md | 165 +++++++++++++++--- .../README_EN.md | 151 +++++++++++++--- .../Solution.cpp | 23 ++- .../Solution.go | 27 ++- .../Solution.java | 24 +-- .../Solution.py | 22 ++- .../README.md | 2 +- 7 files changed, 332 insertions(+), 82 deletions(-) diff --git a/solution/1600-1699/1638.Count Substrings That Differ by One Character/README.md b/solution/1600-1699/1638.Count Substrings That Differ by One Character/README.md index c226231892fd9..2ca3f40cafa80 100644 --- a/solution/1600-1699/1638.Count Substrings That Differ by One Character/README.md +++ b/solution/1600-1699/1638.Count Substrings That Differ by One Character/README.md @@ -72,9 +72,19 @@ **方法一:枚举** -枚举不同的那个字符,然后向两边扩展。 +我们可以枚举字符串 $s$ 和 $t$ 中不同的那个字符位置,然后分别向两边扩展,直到遇到不同的字符为止,这样就可以得到以该位置为中心的满足条件的子串对数目。我们记左边扩展的相同字符个数为 $l$,右边扩展的相同字符个数为 $r$,那么以该位置为中心的满足条件的子串对数目为 $(l + 1) \times (r + 1)$,累加到答案中即可。 -时间复杂度 $O(m \times n \times min(m, n))$,空间复杂度 $O(1)$。其中 $m$ 和 $n$ 分别是字符串 $s$ 和 $t$ 的长度。 +枚举结束后,即可得到答案。 + +时间复杂度 $O(m \times n \times \min(m, n))$,空间复杂度 $O(1)$。其中 $m$ 和 $n$ 分别为字符串 $s$ 和 $t$ 的长度。 + +**方法二:预处理 + 枚举** + +方法一中,我们每次需要分别往左右两边扩展,得出 $l$ 和 $r$ 的值。实际上,我们可以预处理出以每个位置 $(i, j)$ 结尾的最长相同后缀的长度,以及以每个位置 $(i, j)$ 开头的最长相同前缀的长度,分别记录在数组 $f$ 和 $g$ 中。 + +接下来,与方法一类似,我们枚举字符串 $s$ 和 $t$ 中不同的那个字符位置 $(i, j)$,那么以该位置为中心的满足条件的子串对数目为 $(f[i][j] + 1) \times (g[i + 1][j + 1] + 1)$,累加到答案中即可。 + +时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为字符串 $s$ 和 $t$ 的长度。 @@ -86,15 +96,36 @@ class Solution: def countSubstrings(self, s: str, t: str) -> int: ans = 0 + m, n = len(s), len(t) for i, a in enumerate(s): for j, b in enumerate(t): if a != b: - l = r = 1 - while i >= l and j >= l and s[i - l] == t[j - l]: + l = r = 0 + while i > l and j > l and s[i - l - 1] == t[j - l - 1]: l += 1 - while i + r < len(s) and j + r < len(t) and s[i + r] == t[j + r]: + while i + r + 1 < m and j + r + 1 < n and s[i + r + 1] == t[j + r + 1]: r += 1 - ans += l * r + ans += (l + 1) * (r + 1) + return ans +``` + +```python +class Solution: + def countSubstrings(self, s: str, t: str) -> int: + ans = 0 + m, n = len(s), len(t) + f = [[0] * (n + 1) for _ in range(m + 1)] + g = [[0] * (n + 1) for _ in range(m + 1)] + for i, a in enumerate(s, 1): + for j, b in enumerate(t, 1): + if a == b: + f[i][j] = f[i - 1][j - 1] + 1 + for i in range(m - 1, -1, -1): + for j in range(n - 1, -1, -1): + if s[i] == t[j]: + g[i][j] = g[i + 1][j + 1] + 1 + else: + ans += (f[i][j] + 1) * (g[i + 1][j + 1] + 1) return ans ``` @@ -105,19 +136,47 @@ class Solution: ```java class Solution { public int countSubstrings(String s, String t) { - int m = s.length(), n = t.length(); int ans = 0; + int m = s.length(), n = t.length(); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (s.charAt(i) != t.charAt(j)) { - int l = 1, r = 1; - while (i - l >= 0 && j - l >= 0 && s.charAt(i - l) == t.charAt(j - l)) { + int l = 0, r = 0; + while (i - l > 0 && j - l > 0 && s.charAt(i - l - 1) == t.charAt(j - l - 1)) { ++l; } - while (i + r < m && j + r < n && s.charAt(i + r) == t.charAt(j + r)) { + while (i + r + 1 < m && j + r + 1 < n && s.charAt(i + r + 1) == t.charAt(j + r + 1)) { ++r; } - ans += l * r; + ans += (l + 1) * (r + 1); + } + } + } + return ans; + } +} +``` + +```java +class Solution { + public int countSubstrings(String s, String t) { + int ans = 0; + int m = s.length(), n = t.length(); + int[][] f = new int[m + 1][n + 1]; + int[][] g = new int[m + 1][n + 1]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (s.charAt(i) == t.charAt(j)) { + f[i + 1][j + 1] = f[i][j] + 1; + } + } + } + for (int i = m - 1; i >= 0; --i) { + for (int j = n - 1; j >= 0; --j) { + if (s.charAt(i) == t.charAt(j)) { + g[i][j] = g[i + 1][j + 1] + 1; + } else { + ans += (f[i][j] + 1) * (g[i + 1][j + 1] + 1); } } } @@ -132,21 +191,51 @@ class Solution { class Solution { public: int countSubstrings(string s, string t) { + int ans = 0; int m = s.size(), n = t.size(); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (s[i] != t[j]) { + int l = 0, r = 0; + while (i - l > 0 && j - l > 0 && s[i - l - 1] == t[j - l - 1]) { + ++l; + } + while (i + r + 1 < m && j + r + 1 < n && s[i + r + 1] == t[j + r + 1]) { + ++r; + } + ans += (l + 1) * (r + 1); + } + } + } + return ans; + } +}; +``` + +```cpp +class Solution { +public: + int countSubstrings(string s, string t) { int ans = 0; + int m = s.length(), n = t.length(); + int f[m + 1][n + 1]; + int g[m + 1][n + 1]; + memset(f, 0, sizeof(f)); + memset(g, 0, sizeof(g)); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (s[i] == t[j]) { - continue; + f[i + 1][j + 1] = f[i][j] + 1; } - int l = 1, r = 1; - while (i - l >= 0 && j - l >= 0 && s[i - l] == t[j - l]) { - ++l; - } - while (i + r < m && j + r < n && s[i + r] == t[j + r]) { - ++r; + } + } + for (int i = m - 1; i >= 0; --i) { + for (int j = n - 1; j >= 0; --j) { + if (s[i] == t[j]) { + g[i][j] = g[i + 1][j + 1] + 1; + } else { + ans += (f[i][j] + 1) * (g[i + 1][j + 1] + 1); } - ans += l * r; } } return ans; @@ -158,17 +247,47 @@ public: ```go func countSubstrings(s string, t string) (ans int) { + m, n := len(s), len(t) for i, a := range s { for j, b := range t { if a != b { - l, r := 1, 1 - for i >= l && j >= l && s[i-l] == t[j-l] { + l, r := 0, 0 + for i > l && j > l && s[i-l-1] == t[j-l-1] { l++ } - for i+r < len(s) && j+r < len(t) && s[i+r] == t[j+r] { + for i+r+1 < m && j+r+1 < n && s[i+r+1] == t[j+r+1] { r++ } - ans += l * r + ans += (l + 1) * (r + 1) + } + } + } + return +} +``` + +```go +func countSubstrings(s string, t string) (ans int) { + m, n := len(s), len(t) + f := make([][]int, m+1) + g := make([][]int, m+1) + for i := range f { + f[i] = make([]int, n+1) + g[i] = make([]int, n+1) + } + for i, a := range s { + for j, b := range t { + if a == b { + f[i+1][j+1] = f[i][j] + 1 + } + } + } + for i := m - 1; i >= 0; i-- { + for j := n - 1; j >= 0; j-- { + if s[i] == t[j] { + g[i][j] = g[i+1][j+1] + 1 + } else { + ans += (f[i][j] + 1) * (g[i+1][j+1] + 1) } } } diff --git a/solution/1600-1699/1638.Count Substrings That Differ by One Character/README_EN.md b/solution/1600-1699/1638.Count Substrings That Differ by One Character/README_EN.md index 7ef1a7b51ccfc..6a65dc927f914 100644 --- a/solution/1600-1699/1638.Count Substrings That Differ by One Character/README_EN.md +++ b/solution/1600-1699/1638.Count Substrings That Differ by One Character/README_EN.md @@ -58,15 +58,36 @@ The underlined portions are the substrings that are chosen from s and t. class Solution: def countSubstrings(self, s: str, t: str) -> int: ans = 0 + m, n = len(s), len(t) for i, a in enumerate(s): for j, b in enumerate(t): if a != b: - l = r = 1 - while i >= l and j >= l and s[i - l] == t[j - l]: + l = r = 0 + while i > l and j > l and s[i - l - 1] == t[j - l - 1]: l += 1 - while i + r < len(s) and j + r < len(t) and s[i + r] == t[j + r]: + while i + r + 1 < m and j + r + 1 < n and s[i + r + 1] == t[j + r + 1]: r += 1 - ans += l * r + ans += (l + 1) * (r + 1) + return ans +``` + +```python +class Solution: + def countSubstrings(self, s: str, t: str) -> int: + ans = 0 + m, n = len(s), len(t) + f = [[0] * (n + 1) for _ in range(m + 1)] + g = [[0] * (n + 1) for _ in range(m + 1)] + for i, a in enumerate(s, 1): + for j, b in enumerate(t, 1): + if a == b: + f[i][j] = f[i - 1][j - 1] + 1 + for i in range(m - 1, -1, -1): + for j in range(n - 1, -1, -1): + if s[i] == t[j]: + g[i][j] = g[i + 1][j + 1] + 1 + else: + ans += (f[i][j] + 1) * (g[i + 1][j + 1] + 1) return ans ``` @@ -75,19 +96,47 @@ class Solution: ```java class Solution { public int countSubstrings(String s, String t) { - int m = s.length(), n = t.length(); int ans = 0; + int m = s.length(), n = t.length(); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (s.charAt(i) != t.charAt(j)) { - int l = 1, r = 1; - while (i - l >= 0 && j - l >= 0 && s.charAt(i - l) == t.charAt(j - l)) { + int l = 0, r = 0; + while (i - l > 0 && j - l > 0 && s.charAt(i - l - 1) == t.charAt(j - l - 1)) { ++l; } - while (i + r < m && j + r < n && s.charAt(i + r) == t.charAt(j + r)) { + while (i + r + 1 < m && j + r + 1 < n && s.charAt(i + r + 1) == t.charAt(j + r + 1)) { ++r; } - ans += l * r; + ans += (l + 1) * (r + 1); + } + } + } + return ans; + } +} +``` + +```java +class Solution { + public int countSubstrings(String s, String t) { + int ans = 0; + int m = s.length(), n = t.length(); + int[][] f = new int[m + 1][n + 1]; + int[][] g = new int[m + 1][n + 1]; + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (s.charAt(i) == t.charAt(j)) { + f[i + 1][j + 1] = f[i][j] + 1; + } + } + } + for (int i = m - 1; i >= 0; --i) { + for (int j = n - 1; j >= 0; --j) { + if (s.charAt(i) == t.charAt(j)) { + g[i][j] = g[i + 1][j + 1] + 1; + } else { + ans += (f[i][j] + 1) * (g[i + 1][j + 1] + 1); } } } @@ -102,21 +151,51 @@ class Solution { class Solution { public: int countSubstrings(string s, string t) { + int ans = 0; int m = s.size(), n = t.size(); + for (int i = 0; i < m; ++i) { + for (int j = 0; j < n; ++j) { + if (s[i] != t[j]) { + int l = 0, r = 0; + while (i - l > 0 && j - l > 0 && s[i - l - 1] == t[j - l - 1]) { + ++l; + } + while (i + r + 1 < m && j + r + 1 < n && s[i + r + 1] == t[j + r + 1]) { + ++r; + } + ans += (l + 1) * (r + 1); + } + } + } + return ans; + } +}; +``` + +```cpp +class Solution { +public: + int countSubstrings(string s, string t) { int ans = 0; + int m = s.length(), n = t.length(); + int f[m + 1][n + 1]; + int g[m + 1][n + 1]; + memset(f, 0, sizeof(f)); + memset(g, 0, sizeof(g)); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (s[i] == t[j]) { - continue; - } - int l = 1, r = 1; - while (i - l >= 0 && j - l >= 0 && s[i - l] == t[j - l]) { - ++l; + f[i + 1][j + 1] = f[i][j] + 1; } - while (i + r < m && j + r < n && s[i + r] == t[j + r]) { - ++r; + } + } + for (int i = m - 1; i >= 0; --i) { + for (int j = n - 1; j >= 0; --j) { + if (s[i] == t[j]) { + g[i][j] = g[i + 1][j + 1] + 1; + } else { + ans += (f[i][j] + 1) * (g[i + 1][j + 1] + 1); } - ans += l * r; } } return ans; @@ -128,17 +207,47 @@ public: ```go func countSubstrings(s string, t string) (ans int) { + m, n := len(s), len(t) for i, a := range s { for j, b := range t { if a != b { - l, r := 1, 1 - for i >= l && j >= l && s[i-l] == t[j-l] { + l, r := 0, 0 + for i > l && j > l && s[i-l-1] == t[j-l-1] { l++ } - for i+r < len(s) && j+r < len(t) && s[i+r] == t[j+r] { + for i+r+1 < m && j+r+1 < n && s[i+r+1] == t[j+r+1] { r++ } - ans += l * r + ans += (l + 1) * (r + 1) + } + } + } + return +} +``` + +```go +func countSubstrings(s string, t string) (ans int) { + m, n := len(s), len(t) + f := make([][]int, m+1) + g := make([][]int, m+1) + for i := range f { + f[i] = make([]int, n+1) + g[i] = make([]int, n+1) + } + for i, a := range s { + for j, b := range t { + if a == b { + f[i+1][j+1] = f[i][j] + 1 + } + } + } + for i := m - 1; i >= 0; i-- { + for j := n - 1; j >= 0; j-- { + if s[i] == t[j] { + g[i][j] = g[i+1][j+1] + 1 + } else { + ans += (f[i][j] + 1) * (g[i+1][j+1] + 1) } } } diff --git a/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.cpp b/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.cpp index b8feb7b4b25d7..57d870e12139b 100644 --- a/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.cpp +++ b/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.cpp @@ -1,21 +1,26 @@ class Solution { public: int countSubstrings(string s, string t) { - int m = s.size(), n = t.size(); int ans = 0; + int m = s.length(), n = t.length(); + int f[m + 1][n + 1]; + int g[m + 1][n + 1]; + memset(f, 0, sizeof(f)); + memset(g, 0, sizeof(g)); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { if (s[i] == t[j]) { - continue; + f[i + 1][j + 1] = f[i][j] + 1; } - int l = 1, r = 1; - while (i - l >= 0 && j - l >= 0 && s[i - l] == t[j - l]) { - ++l; - } - while (i + r < m && j + r < n && s[i + r] == t[j + r]) { - ++r; + } + } + for (int i = m - 1; i >= 0; --i) { + for (int j = n - 1; j >= 0; --j) { + if (s[i] == t[j]) { + g[i][j] = g[i + 1][j + 1] + 1; + } else { + ans += (f[i][j] + 1) * (g[i + 1][j + 1] + 1); } - ans += l * r; } } return ans; diff --git a/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.go b/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.go index 002ba5d5cce5d..96c92ec4007b4 100644 --- a/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.go +++ b/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.go @@ -1,15 +1,24 @@ func countSubstrings(s string, t string) (ans int) { + m, n := len(s), len(t) + f := make([][]int, m+1) + g := make([][]int, m+1) + for i := range f { + f[i] = make([]int, n+1) + g[i] = make([]int, n+1) + } for i, a := range s { for j, b := range t { - if a != b { - l, r := 1, 1 - for i >= l && j >= l && s[i-l] == t[j-l] { - l++ - } - for i+r < len(s) && j+r < len(t) && s[i+r] == t[j+r] { - r++ - } - ans += l * r + if a == b { + f[i+1][j+1] = f[i][j] + 1 + } + } + } + for i := m - 1; i >= 0; i-- { + for j := n - 1; j >= 0; j-- { + if s[i] == t[j] { + g[i][j] = g[i+1][j+1] + 1 + } else { + ans += (f[i][j] + 1) * (g[i+1][j+1] + 1) } } } diff --git a/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.java b/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.java index 9d7f1b9b7d2db..80d91f277fa24 100644 --- a/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.java +++ b/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.java @@ -1,18 +1,22 @@ class Solution { public int countSubstrings(String s, String t) { - int m = s.length(), n = t.length(); int ans = 0; + int m = s.length(), n = t.length(); + int[][] f = new int[m + 1][n + 1]; + int[][] g = new int[m + 1][n + 1]; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { - if (s.charAt(i) != t.charAt(j)) { - int l = 1, r = 1; - while (i - l >= 0 && j - l >= 0 && s.charAt(i - l) == t.charAt(j - l)) { - ++l; - } - while (i + r < m && j + r < n && s.charAt(i + r) == t.charAt(j + r)) { - ++r; - } - ans += l * r; + if (s.charAt(i) == t.charAt(j)) { + f[i + 1][j + 1] = f[i][j] + 1; + } + } + } + for (int i = m - 1; i >= 0; --i) { + for (int j = n - 1; j >= 0; --j) { + if (s.charAt(i) == t.charAt(j)) { + g[i][j] = g[i + 1][j + 1] + 1; + } else { + ans += (f[i][j] + 1) * (g[i + 1][j + 1] + 1); } } } diff --git a/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.py b/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.py index d927657925cb1..063dcc07c4fcb 100644 --- a/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.py +++ b/solution/1600-1699/1638.Count Substrings That Differ by One Character/Solution.py @@ -1,13 +1,17 @@ class Solution: def countSubstrings(self, s: str, t: str) -> int: ans = 0 - for i, a in enumerate(s): - for j, b in enumerate(t): - if a != b: - l = r = 1 - while i >= l and j >= l and s[i - l] == t[j - l]: - l += 1 - while i + r < len(s) and j + r < len(t) and s[i + r] == t[j + r]: - r += 1 - ans += l * r + m, n = len(s), len(t) + f = [[0] * (n + 1) for _ in range(m + 1)] + g = [[0] * (n + 1) for _ in range(m + 1)] + for i, a in enumerate(s, 1): + for j, b in enumerate(t, 1): + if a == b: + f[i][j] = f[i - 1][j - 1] + 1 + for i in range(m - 1, -1, -1): + for j in range(n - 1, -1, -1): + if s[i] == t[j]: + g[i][j] = g[i + 1][j + 1] + 1 + else: + ans += (f[i][j] + 1) * (g[i + 1][j + 1] + 1) return ans diff --git a/solution/2300-2399/2397.Maximum Rows Covered by Columns/README.md b/solution/2300-2399/2397.Maximum Rows Covered by Columns/README.md index ad1368a6dc23a..e60ed0cf34ed8 100644 --- a/solution/2300-2399/2397.Maximum Rows Covered by Columns/README.md +++ b/solution/2300-2399/2397.Maximum Rows Covered by Columns/README.md @@ -56,7 +56,7 @@ 我们先将矩阵中的每一行转换成一个二进制数,记录在数组 $rows$ 中,其中 $rows[i]$ 表示第 $i$ 行对应的二进制数,而 $rows[i]$ 的第 $j$ 位表示第 $i$ 行第 $j$ 列的值。 -接下来,我们枚举所有的 $2^n$ 种列选择方案,其中 $n$ 为矩阵的列数。对于每一种列选择方案,我们判断是否选中了 $numSelect$ 列,如果不是,则跳过。否则,我们统计矩阵中有多少行中的所有 $1$ 都被选中的列覆盖,即统计有多少行的二进制数 $rows[i]$ 与列选择方案 $mask$ 按位与的结果等于 $rows[i]$,并更新最大的行数。 +接下来,我们枚举所有的 $2^n$ 种列选择方案,其中 $n$ 为矩阵的列数。对于每一种列选择方案,我们判断是否选中了 `numSelect` 列,如果不是,则跳过。否则,我们统计矩阵中有多少行中的所有 $1$ 都被选中的列覆盖,即统计有多少行的二进制数 $rows[i]$ 与列选择方案 $mask$ 按位与的结果等于 $rows[i]$,并更新最大的行数。 时间复杂度 $O(2^n \times m)$,空间复杂度 $O(m)$。其中 $m$ 和 $n$ 分别为矩阵的行数和列数。