力扣(LeetCode)1638. 统计只差一个字符的子串数目(C++/Python3)
暴力枚举
检测 s
的子串能否只改变一个字符,成为 t
的子串,暴力的做法是比较 s
的所有子串和 t
的所有子串,能否只改变一个字符而相同。
没有必要生成子串。可以接受的方法是:枚举 s
子串的起点,枚举 t
子串的起点,枚举子串的长度。当前位置相同,则向后遍历;当前位置不同,则 diff ++
;当diff = 1
,找到一组符合题意的子串,答案加一;当 diff > 1
,这组子串再变长,不同元素也多于两个,提前剪枝。
class Solution {
public:
int countSubstrings(string s, string t) {
int diff = 0, ans = 0;
for (int i = 0; i < s.size(); i ++) {
for (int j = 0; j < t.size(); j ++) {
diff = 0;
for (int k = 0; i + k < s.size() && j + k < t.size(); k ++) {
diff += (s[i + k] != t[j + k]);
if (diff > 1) break;
ans += (diff == 1);
}
}
}
return ans;
}
};
class Solution:
def countSubstrings(self, s: str, t: str) -> int:
ans = 0
for i in range(len(s)):
for j in range(len(t)):
diff, k = 0, 0
while i + k < len(s) and j + k < len(t):
diff += (s[i + k] != t[j + k])
if diff > 1:
break
ans += (diff == 1)
k += 1
return ans
- 时间复杂度 : O ( n × m × m i n ( n , m ) ) O(n \times m \times min(n,m)) O(n×m×min(n,m)) , n n n 是数组 s s s 的长度, m m m 是数组 t t t 的长度。枚举 s s s 的起点,再枚举 t t t 的起点,再枚举子串长度,时间复杂度 O ( n × m × m i n ( n , m ) ) O(n \times m \times min(n,m)) O(n×m×min(n,m))。
- 空间复杂度 : O ( 1 ) O(1) O(1) ,没有使用额外的线性空间 。
动态规划
状态转移方程
当 s[i]
等于 t[j]
①f[i][j][0] = f[i - 1][j - 1][0] + 1;
②f[i][j][1] = f[i - 1][j - 1][1];
- 在
s[i]
和t[j]
处,生成一个新的相等子串。等式①,多了一个子串。
当 s[i]
不等于 t[j]
③f[i][j][1] = f[i - 1][j - 1][0] + 1;
④f[i][j][0] = 0
- 在
s[i]
和t[j]
处,生成一个新的只差一个字符子串。等式③,多了一个子串
提示:
k
k
k 取
0
0
0,表示子串相同,
k
k
k 取
1
1
1,表示只差一个字符。
class Solution {
public:
int countSubstrings(string s, string t) {
int m = s.size(), n = t.size();
vector<vector<vector<int>>> f(m + 1, vector<vector<int>>(n + 1, vector<int>(2)));
int ans = 0;
for (int i = 1; i <= m; i ++)
for (int j = 1; j <= n; j ++) {
if (s[i - 1] == t[j - 1]) {
f[i][j][0] = f[i - 1][j - 1][0] + 1;
f[i][j][1] = f[i - 1][j - 1][1];
} else {
f[i][j][1] = f[i - 1][j - 1][0] + 1;
}
ans += f[i][j][1];
}
return ans;
}
};
class Solution:
def countSubstrings(self, s: str, t: str) -> int:
m, n = len(s), len(t)
f = [[[0] * 2 for i in range(n + 1)] for i in range(m + 1)]
i = 1
ans = 0
while i <= m:
j = 1
while j <= n:
if s[i - 1] == t[j - 1]:
f[i][j][0] = f[i - 1][j - 1][0] + 1
f[i][j][1] = f[i - 1][j - 1][1]
else:
f[i][j][1] = f[i - 1][j - 1][0] + 1
ans += f[i][j][1]
j += 1
i += 1
return ans
- 时间复杂度 : O ( n × m ) O(n \times m) O(n×m) , n n n 是数组 s s s 的长度,状态数量 O ( n × m × 2 ) O(n \times m \times 2) O(n×m×2),状态转移的时间复杂度 O ( 1 ) O(1) O(1),二者是相乘关系,总时间复杂度 O ( n × m ) O(n \times m) O(n×m)。
- 空间复杂度 : O ( n × m ) O(n \times m) O(n×m) ,所有状态的空间复杂度 O ( n × m × k ) O(n \times m \times k) O(n×m×k) ,本题 k k k 只取 0 0 0 或 1 1 1,空间复杂度 O ( n × m ) O(n \times m) O(n×m) 。
致语
- 理解思路很重要
- 读者有问题请留言,清墨看到就会回复的。