LeetCode 题解工作台

同源字符串检测

原字符串由小写字母组成,可以按下述步骤编码: 任意将其 分割 为由若干 非空 子字符串组成的一个 序列 。 任意选择序列中的一些元素(也可能不选择),然后将这些元素替换为元素各自的长度(作为一个数字型的字符串)。 重新 顺次连接 序列,得到编码后的字符串。 例如,编码 "abcdefghijklmn…

category

2

题型

code_blocks

1

代码语言

hub

3

相关题

当前训练重点

困难 · 状态·转移·动态规划

bolt

答案摘要

function possiblyEquals(s1: string, s2: string): boolean { const n = s1.length,

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

原字符串由小写字母组成,可以按下述步骤编码:

  • 任意将其 分割 为由若干 非空 子字符串组成的一个 序列
  • 任意选择序列中的一些元素(也可能不选择),然后将这些元素替换为元素各自的长度(作为一个数字型的字符串)。
  • 重新 顺次连接 序列,得到编码后的字符串。

例如,编码 "abcdefghijklmnop" 的一种方法可以描述为:

  • 将原字符串分割得到一个序列:["ab", "cdefghijklmn", "o", "p"]
  • 选出其中第二个和第三个元素并分别替换为它们自身的长度。序列变为 ["ab", "12", "1", "p"]
  • 重新顺次连接序列中的元素,得到编码后的字符串:"ab121p"

给你两个编码后的字符串 s1s2 ,由小写英文字母和数字 1-9 组成。如果存在能够同时编码得到 s1s2 原字符串,返回 true ;否则,返回 false

注意:生成的测试用例满足 s1s2 中连续数字数不超过 3

 

示例 1:

输入:s1 = "internationalization", s2 = "i18n"
输出:true
解释:"internationalization" 可以作为原字符串
- "internationalization" 
  -> 分割:      ["internationalization"]
  -> 不替换任何元素
  -> 连接:      "internationalization",得到 s1
- "internationalization"
  -> 分割:      ["i", "nternationalizatio", "n"]
  -> 替换:      ["i", "18",                 "n"]
  -> 连接:      "i18n",得到 s2

示例 2:

输入:s1 = "l123e", s2 = "44"
输出:true
解释:"leetcode" 可以作为原字符串
- "leetcode" 
  -> 分割:       ["l", "e", "et", "cod", "e"]
  -> 替换:       ["l", "1", "2",  "3",   "e"]
  -> 连接:       "l123e",得到 s1
- "leetcode" 
  -> 分割:       ["leet", "code"]
  -> 替换:       ["4",    "4"]
  -> 连接:       "44",得到 s2

示例 3:

输入:s1 = "a5b", s2 = "c5b"
输出:false
解释:不存在这样的原字符串
- 编码为 s1 的字符串必须以字母 'a' 开头
- 编码为 s2 的字符串必须以字母 'c' 开头

示例 4:

输入:s1 = "112s", s2 = "g841"
输出:true
解释:"gaaaaaaaaaaaas" 可以作为原字符串
- "gaaaaaaaaaaaas"
  -> 分割:       ["g", "aaaaaaaaaaaa", "s"]
  -> 替换:       ["1", "12",           "s"]
  -> 连接:       "112s",得到 s1
- "gaaaaaaaaaaaas"
  -> 分割:       ["g", "aaaaaaaa", "aaaa", "s"]
  -> 替换:       ["g", "8",        "4",    "1"]
  -> 连接         "g841",得到 s2

示例 5:

输入:s1 = "ab", s2 = "a2"
输出:false
解释:不存在这样的原字符串
- 编码为 s1 的字符串由两个字母组成
- 编码为 s2 的字符串由三个字母组成

 

提示:

  • 1 <= s1.length, s2.length <= 40
  • s1s2 仅由数字 1-9 和小写英文字母组成
  • s1s2 中连续数字数不超过 3
lightbulb

解题思路

方法一

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
function possiblyEquals(s1: string, s2: string): boolean {
    const n = s1.length,
        m = s2.length;
    let dp: Array<Array<Set<number>>> = Array.from({ length: n + 1 }, v =>
        Array.from({ length: m + 1 }, w => new Set()),
    );
    dp[0][0].add(0);

    for (let i = 0; i <= n; i++) {
        for (let j = 0; j <= m; j++) {
            for (let delta of dp[i][j]) {
                // s1为数字
                let num = 0;
                if (delta <= 0) {
                    for (let p = i; i < Math.min(i + 3, n); p++) {
                        if (isDigit(s1[p])) {
                            num = num * 10 + Number(s1[p]);
                            dp[p + 1][j].add(delta + num);
                        } else {
                            break;
                        }
                    }
                }

                // s2为数字
                num = 0;
                if (delta >= 0) {
                    for (let q = j; q < Math.min(j + 3, m); q++) {
                        if (isDigit(s2[q])) {
                            num = num * 10 + Number(s2[q]);
                            dp[i][q + 1].add(delta - num);
                        } else {
                            break;
                        }
                    }
                }

                // 数字匹配s1为字母
                if (i < n && delta < 0 && !isDigit(s1[i])) {
                    dp[i + 1][j].add(delta + 1);
                }

                // 数字匹配s2为字母
                if (j < m && delta > 0 && !isDigit(s2[j])) {
                    dp[i][j + 1].add(delta - 1);
                }

                // 两个字母匹配
                if (i < n && j < m && delta == 0 && s1[i] == s2[j]) {
                    dp[i + 1][j + 1].add(0);
                }
            }
        }
    }
    return dp[n][m].has(0);
}

function isDigit(char: string): boolean {
    return /^\d{1}$/g.test(char);
}
speed

复杂度分析

指标
时间complexity depends on the number of states, roughly O(n1 * n2 * maxCount^2), where n1 and n2 are lengths of s1 and s2 and maxCount is the maximum consecutive digit value. Space complexity is similar due to memoization storage of each unique DP state.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Are you considering digits in s1 and s2 as letter counts correctly?

  • question_mark

    Can you describe the DP state and its transitions for this problem?

  • question_mark

    Have you memoized overlapping subproblems to avoid recomputation?

warning

常见陷阱

外企场景
  • error

    Misinterpreting multi-digit numbers in s1 or s2 as separate counts instead of a single placeholder.

  • error

    Forgetting to track remaining letters when a digit consumes multiple positions in the original string.

  • error

    Assuming all letters must match directly without accounting for numeric replacements.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Check if an original string exists given multiple encoded strings, extending to more than two inputs.

  • arrow_right_alt

    Allow digits in encoding to represent zero letters, introducing optional skips in the original string.

  • arrow_right_alt

    Constrain original strings to only certain alphabets or lengths, adding additional DP restrictions.

help

常见问题

外企场景

同源字符串检测题解:状态·转移·动态规划 | LeetCode #2060 困难