力扣(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
  1. 时间复杂度 : 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))
  2. 空间复杂度 : O ( 1 ) O(1) O(1) ,没有使用额外的线性空间 。
动态规划

sp
状态转移方程
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
  1. 时间复杂度 : 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)
  2. 空间复杂度 : 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)
致语
  • 理解思路很重要
  • 读者有问题请留言,清墨看到就会回复的。
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清墨韵染

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值