2026-10-08:一次替换后的子序列。用go语言,给定两个只包含小写字母的字符串 s 和 t。你可以在 s 中至多改动一个位置上的字符,把它换成

🤖 AI总结

主题

力扣3983题:至多修改一个字符使s成为t的子序列。

摘要

力扣3983题要求判断能否至多修改s中一个字符使其成为t的子序列,采用双状态动态规划,遍历t一次即可求解,时间复杂度O(n),空间O(1)。

关键信息

  • 1 使用双状态动态规划,分别记录未修改和已修改一次时的匹配进度。
  • 2 遍历t一次,每次更新两个状态,时间复杂度O(t.length),空间复杂度O(1)。
  • 3 提供Go、Python、C++三种语言的完整实现。

2026-10-08:一次替换后的子序列。用go语言,给定两个只包含小写字母的字符串 s 和 t。你可以在 s 中至多改动一个位置上的字符,把它换成任意一个小写字母。问经过这样的至多一次改动后,能否让 s 按原有先后顺序出现在 t 中。也就是说,能否从 t 里删掉一些字符后,得到完整的 s;只要求字符顺序一致,不要求连续。如果能够做到,结果为 true;否则为 false。

1 <= s.length, t.length <= 100000。

s 和 t 仅由小写英文字母组成。

输入: s = “cat”, t = “chat”。

输出: true。

解释:

将 s[1] 从 ‘a’ 替换为 ‘h’,得到字符串 “cht”。

“cht” 是 “chat” 的子序列,因为可以按顺序匹配 ‘c’、’h’ 和 ‘t’。

题目来自力扣3983。

大体步骤如下:

• 状态一:表示完全没有使用过修改机会时,s 的前面已经有多少个字符成功按顺序匹配到了 t 的当前前缀中。

  • • 状态二:表示最多使用一次修改机会时,s 的前面已经有多少个字符成功按顺序匹配到了 t 的当前前缀中。这里“最多一次”可以是一次都没用,也可以是已经用掉了那唯一的一次修改。

    一开始,两个状态都从 0 开始,表示还没有匹配任何字符。如果 s 的长度比 t 还长,那肯定不可能成为子序列,直接返回 false。

    然后从左到右依次扫描 t 中的每一个字符。对于当前字符,会做几件事:

    1. 先尝试让“已经用过修改机会”的状态继续正常匹配。
    也就是看 s 中当前待匹配的那个字符,是否正好等于 t 的当前字符。如果相等,就不需要额外修改,直接让这个状态往后走一位。

  • 2. 再考虑在当前字符处使用修改机会。
    如果“完全没用过修改机会”的状态已经匹配了 s 的前若干个字符,那么我们可以把 s 中下一个还没匹配的字符改成当前 t 的字符,这样就能强行多匹配一个字符。于是“已经用过修改机会”的状态至少可以推进到“未用修改机会的状态 + 1”。如果原来这个状态已经更靠后,就保持不变。这一步体现了“最多改一个字符”的选择。

  • 3. 然后更新“完全没用过修改机会”的状态。
    看 s 中当前待匹配的字符是否正好等于 t 的当前字符。如果相等,就正常匹配,这个状态也往后走一位。

  • 4. 每次处理完当前字符后,检查“已经用过修改机会”的状态是否已经达到了 s 的总长度。
    如果达到了,说明整个 s 已经按顺序出现在 t 的处理过的部分里,而且最多只改了一个字符,因此可以直接返回 true。

    如果 t 的所有字符都扫描完了,这个状态仍然没有达到 s 的总长度,说明无法做到,返回 false。

    用例子 s = “cat”,t = “chat” 来看:

    • 初始两个状态都是 0。

  • • 遇到 t 的 ‘c’:s 的第一个字符也是 ‘c’,所以两个状态都可以正常前进,都变成 1。

  • • 遇到 ‘h’:s 的第二个字符是 ‘a’,不等于 ‘h’。未用修改的状态不能前进,仍然是 1。但已用修改的状态可以借助修改机会,把 s 的第二个字符 ‘a’ 改成 ‘h’,于是这个状态推进到 2。

  • • 遇到 ‘a’:已用修改的状态当前待匹配的是 s 的第三个字符 ‘t’,不等于 ‘a’,不能正常前进;但它已经用过一次修改,不能再改,所以保持 2。未用修改的状态此时待匹配的是 s 的第二个字符 ‘a’,正好等于 ‘a’,所以前进到 2。

  • • 遇到 ‘t’:已用修改的状态待匹配的是 s 的第三个字符 ‘t’,正好等于 ‘t’,于是前进到 3。此时已达到 s 的总长度 3,返回 true。

    整个过程中,只遍历了 t 一次,每个字符只做了常数次比较和更新操作,所以总的时间复杂度是 O(t 的长度)。额外使用的变量只有几个整数状态,不随字符串长度增长,所以总的额外空间复杂度是 O(1)。

    Go完整代码如下:

    package main

    import (
    "fmt"
    )

    func canMakeSubsequence(s, t string)bool {
    n := len(s)
    if n > len(t) {
    returnfalse
    }

    j0 := 0// 在不修改的情况下,s 的前缀 [0, j0-1] 是 t 的当前前缀的子序列
    j1 := 0// 在改过一次的情况下,s 的前缀 [0, j1-1] 是 t 的当前前缀的子序列
    for _, ch := range t {
    // j1 普通匹配
    if s[j1] == byte(ch) {
    j1++
    }

    // 也可以修改 s[j0] 为 ch,强行匹配
    j1 = max(j1, j0+1)

    // j0 普通匹配
    if s[j0] == byte(ch) {
    j0++
    }

    if j1 == n {
    // s 是 t 的子序列
    returntrue
    }
    }
    returnfalse
    }

    func main() {
    s := "cat"
    t := "chat"
    result := canMakeSubsequence(s, t)
    fmt.Println(result)
    }

    2026-10-08:一次替换后的子序列。用go语言,给定两个只包含小写字母的字符串 s 和 t。你可以在 s 中至多改动一个位置上的字符,把它换成

    Python完整代码如下:

    # -*-coding:utf-8-*-

    def canMakeSubsequence(s: str, t: str) -> bool:
    n = len(s)
    if n > len(t):
    return False

    if n == 0:
    return True

    j0 = 0 # 不修改时,s 的前缀 [0, j0-1] 已匹配
    j1 = 0 # 最多修改一次时,s 的前缀 [0, j1-1] 已匹配

    for ch in t:
    # j1 尝试正常匹配
    if j1 < n and s[j1] == ch:
    j1 += 1

    # 也可以把 s[j0] 修改为 ch,强行多匹配一个字符
    j1 = max(j1, j0 + 1)

    # j0 尝试正常匹配
    if j0 < n and s[j0] == ch:
    j0 += 1

    if j1 == n:
    return True

    return False

    if __name__ == "__main__":
    s = "cat"
    t = "chat"
    result = canMakeSubsequence(s, t)
    print(result)

    2026-10-08:一次替换后的子序列。用go语言,给定两个只包含小写字母的字符串 s 和 t。你可以在 s 中至多改动一个位置上的字符,把它换成

    C++完整代码如下:

      
    


    bool canMakeSubsequence(const std::string& s, const std::string& t) {
    int n = static_cast(s.size());
    if (n > static_cast(t.size())) {
    returnfalse;
    }
    if (n == 0) {
    returntrue;
    }

    int j0 = 0; // 不修改时,s 的前缀 [0, j0-1] 已匹配
    int j1 = 0; // 最多修改一次时,s 的前缀 [0, j1-1] 已匹配

    for (char ch : t) {
    // j1 尝试正常匹配
    if (j1 < n && s[j1] == ch) {
    ++j1;
    }

    // 也可以把 s[j0] 修改为 ch,强行多匹配一个字符
    if (j0 < n) {
    j1 = std::max(j1, j0 + 1);
    }

    // j0 尝试正常匹配
    if (j0 < n && s[j0] == ch) {
    ++j0;
    }

    if (j1 == n) {
    returntrue;
    }
    }
    returnfalse;
    }

    int main() {
    std::string s = "cat";
    std::string t = "chat";
    bool result = canMakeSubsequence(s, t);
    std::cout << std::boolalpha << result << std::endl;
    return0;
    }

    2026-10-08:一次替换后的子序列。用go语言,给定两个只包含小写字母的字符串 s 和 t。你可以在 s 中至多改动一个位置上的字符,把它换成

    我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。

    © 版权声明

    相关文章