Skip to content

Commit 478bf97

Browse files
author
robot
committed
feat: $1638
1 parent 0c1cb29 commit 478bf97

File tree

3 files changed

+190
-0
lines changed

3 files changed

+190
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。
424424
- [1574. 删除最短的子数组使剩余数组有序](./problems/1574.shortest-subarray-to-be-removed-to-make-array-sorted.md)
425425
- [1589. 所有排列中的最大和](./problems/1589.maximum-sum-obtained-of-any-permutation.md)
426426
- [1631. 最小体力消耗路径](./problems/1631.path-with-minimum-effort.md)
427+
- [1638. 统计只差一个字符的子串数目](./problems/1638.count-substrings-that-differ-by-one-character.md)
427428
- [1658. 将 x 减到 0 的最小操作数](./problems/1658.minimum-operations-to-reduce-x-to-zero.md)
428429
- [1697. 检查边长度限制的路径是否存在](./problems/1697.checking-existence-of-edge-length-limited-paths.md)
429430
- [1737. 满足三条件之一需改变的最少字符数](./problems/1737.change-minimum-characters-to-satisfy-one-of-three-conditions.md) 👍

SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@
259259
- [1558. 得到目标数组的最少函数调用次数](./problems/1558.minimum-numbers-of-function-calls-to-make-target-array.md) 👍
260260
- [1574. 删除最短的子数组使剩余数组有序](./problems/1574.shortest-subarray-to-be-removed-to-make-array-sorted.md)
261261
- [1631. 最小体力消耗路径](./problems/1631.path-with-minimum-effort.md)
262+
- [1638. 统计只差一个字符的子串数目](./problems/1638.count-substrings-that-differ-by-one-character.md)
262263
- [1658. 将 x 减到 0 的最小操作数](./problems/1658.minimum-operations-to-reduce-x-to-zero.md)
263264
- [1697. 检查边长度限制的路径是否存在](./problems/1697.checking-existence-of-edge-length-limited-paths.md)
264265
- [1737. 满足三条件之一需改变的最少字符数](./problems/1737.change-minimum-characters-to-satisfy-one-of-three-conditions.md) 👍
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
2+
## 题目地址(1638. 统计只差一个字符的子串数目)
3+
4+
https://leetcode.cn/problems/count-substrings-that-differ-by-one-character/
5+
6+
## 题目描述
7+
8+
```
9+
给你两个字符串 s 和 t ,请你找出 s 中的非空子串的数目,这些子串满足替换 一个不同字符 以后,是 t 串的子串。换言之,请你找到 s 和 t 串中 恰好 只有一个字符不同的子字符串对的数目。
10+
11+
比方说, "computer" and "computation" 只有一个字符不同: 'e'/'a' ,所以这一对子字符串会给答案加 1 。
12+
13+
请你返回满足上述条件的不同子字符串对数目。
14+
15+
一个 子字符串 是一个字符串中连续的字符。
16+
17+
 
18+
19+
示例 1:
20+
21+
输入:s = "aba", t = "baba"
22+
输出:6
23+
解释:以下为只相差 1 个字符的 s 和 t 串的子字符串对:
24+
("aba", "baba")
25+
("aba", "baba")
26+
("aba", "baba")
27+
("aba", "baba")
28+
("aba", "baba")
29+
("aba", "baba")
30+
加粗部分分别表示 s 和 t 串选出来的子字符串。
31+
32+
示例 2:
33+
输入:s = "ab", t = "bb"
34+
输出:3
35+
解释:以下为只相差 1 个字符的 s 和 t 串的子字符串对:
36+
("ab", "bb")
37+
("ab", "bb")
38+
("ab", "bb")
39+
加粗部分分别表示 s 和 t 串选出来的子字符串。
40+
41+
示例 3:
42+
输入:s = "a", t = "a"
43+
输出:0
44+
45+
46+
示例 4:
47+
48+
输入:s = "abe", t = "bbc"
49+
输出:10
50+
51+
52+
 
53+
54+
提示:
55+
56+
1 <= s.length, t.length <= 100
57+
s 和 t 都只包含小写英文字母。
58+
```
59+
60+
## 前置知识
61+
62+
- 枚举
63+
- 递推
64+
- 动态规划
65+
66+
## 公司
67+
68+
- 暂无
69+
## 暴力枚举
70+
### 思路
71+
72+
枚举 s 和 t 的所有子串。我们可以通过枚举 s 和 t 的子串开始位置 i 和 j,这需要 $m * n$ 的时间, 其中 m 和 n 分别为 s 和 t 的长度。
73+
74+
接下来,我们只需要从 i 和 j 开始逐位匹配,即枚举子串长度 k,由于两个子串长度相同, 因此一个 k 就够了。
75+
76+
如果 s[i+k-1] == t[j+k-1] 不同, 那么 diff + 1,如果 diff 等于 1(意味着两个子串只有一个字符不同),那么答案加 1,最后返回答案即可。
77+
78+
### 关键点
79+
80+
- 枚举 s 和 t 的起点 i 和 j, 接下来枚举子串长度 k
81+
82+
### 代码
83+
84+
- 语言支持:Python3
85+
86+
Python3 Code:
87+
88+
```python
89+
90+
# 方法 1
91+
class Solution:
92+
def countSubstrings(self, s: str, t: str) -> int:
93+
m, n = len(s), len(t)
94+
ans = 0
95+
for i in range(m):
96+
for j in range(n):
97+
diff = 0
98+
k = 0
99+
while i + k < m and j + k < n:
100+
diff += int(s[i + k] != t[j + k])
101+
if diff > 1:
102+
break
103+
if diff == 1:
104+
ans += 1
105+
k += 1
106+
return ans
107+
108+
```
109+
110+
111+
**复杂度分析**
112+
113+
令 m, n 为 s 和 t 的长度。
114+
115+
- 时间复杂度:$O(m * n * min(m, n))$
116+
- 空间复杂度:$O(1)$
117+
118+
## 递推 + 枚举
119+
120+
### 思路
121+
122+
这个思路主要是通过空间换时间, 换的是内层枚举 k 的时间。
123+
124+
上面的思路枚举的 s 和 t 的起点, 这个思路是枚举 s 和 t 的字符不同的点 i 和 j(即中间的点),然后向左找能够**完全匹配的长度**,然后向右找能够**完全匹配的长度**,这两个长度相乘就等于以 s[i] 和 t[j] 为不同字符的子串个数。
125+
126+
如果求向左和向右的**完全匹配的长度** 呢?
127+
128+
可以利用递推实现。定义 L[i][j] 为以 s[i] 和 t[j] 为不同字符向左完全匹配个数。 如果 s[i] 和 t[j] 相同, 那么 L[i][j] 就为 0,否则 L[i][j] 为 L[i-1][j-1] + 1
129+
130+
向右匹配同理。
131+
132+
### 关键点
133+
134+
- 枚举不同的那个字符,向左向右扩展
135+
136+
### 代码
137+
138+
- 语言支持:Python3
139+
140+
Python3 Code:
141+
142+
```python
143+
144+
# 方法 2
145+
class Solution:
146+
def countSubstrings(self, s: str, t: str) -> int:
147+
L = [[0] * (len(t)+1) for _ in range(len(s)+1)] # L[i][j] 表示 s[i] != s[j] 情况下可以向左扩展的最大长度
148+
R = [[0] * (len(t)+1) for _ in range(len(s)+1)] # R[i][j] 表示 s[i] != s[j] 情况下可以向右扩展的最大长度
149+
ans = 0
150+
for i in range(1,len(s)+1):
151+
for j in range(1,len(t)+1):
152+
if s[i-1] != t[j-1]:
153+
L[i][j] = 0
154+
else:
155+
L[i][j] = L[i-1][j-1] + 1
156+
for i in range(len(s)-1,-1,-1):
157+
for j in range(len(t)-1,-1,-1):
158+
if s[i] != t[j]:
159+
R[i][j] = 0
160+
else:
161+
R[i][j] = R[i+1][j+1] + 1
162+
# 枚举不同的那个字符,这样就只需向左向右匹配即可
163+
for i in range(len(s)):
164+
for j in range(len(t)):
165+
# L 前面有哨兵,因此 L[i][j] 相当于没有哨兵的 L[i-1][j-1]
166+
if s[i] != t[j]: ans += (L[i][j] + 1) * (R[i+1][j+1] + 1)
167+
return ans
168+
169+
```
170+
171+
172+
**复杂度分析**
173+
174+
令 m, n 为 s 和 t 的长度。
175+
176+
- 时间复杂度:$O(m * n)$
177+
- 空间复杂度:$O(m * n)$
178+
179+
180+
> 此题解由 [力扣刷题插件](https://leetcode-pp.github.io/leetcode-cheat/?tab=solution-template) 自动生成。
181+
182+
力扣的小伙伴可以[关注我](https://leetcode-cn.com/u/fe-lucifer/),这样就会第一时间收到我的动态啦~
183+
184+
以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 40K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。
185+
186+
关注公众号力扣加加,努力用清晰直白的语言还原解题思路,并且有大量图解,手把手教你识别套路,高效刷题。
187+
188+
![](https://tva1.sinaimg.cn/large/007S8ZIlly1gfcuzagjalj30p00dwabs.jpg)

0 commit comments

Comments
 (0)