> For the complete documentation index, see [llms.txt](https://nataliekung.gitbook.io/ladder_code/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://nataliekung.gitbook.io/ladder_code/meta-2024/check-if-an-original-string-exists-given-two-encoded-strings.md).

# Check if an Original String Exists Given Two Encoded Strings

An original string, consisting of lowercase English letters, can be encoded by the following steps:

Arbitrarily split it into a sequence of some number of non-empty substrings. Arbitrarily choose some elements (possibly none) of the sequence, and replace each with its length (as a numeric string). Concatenate the sequence as the encoded string. For example, one way to encode an original string "abcdefghijklmnop" might be:

Split it as a sequence: \["ab", "cdefghijklmn", "o", "p"]. Choose the second and third elements to be replaced by their lengths, respectively. The sequence becomes \["ab", "12", "1", "p"]. Concatenate the elements of the sequence to get the encoded string: "ab121p". Given two encoded strings s1 and s2, consisting of lowercase English letters and digits 1-9 (inclusive), return true if there exists an original string that could be encoded as both s1 and s2. Otherwise, return false.

Note: The test cases are generated such that the number of consecutive digits in s1 and s2 does not exceed 3.

Example 1:

Input: s1 = "internationalization", s2 = "i18n" Output: true Explanation: It is possible that "internationalization" was the original string.

* "internationalization" -> Split: \["internationalization"] -> Do not replace any element -> Concatenate: "internationalization", which is s1.
* "internationalization" -> Split: \["i", "nternationalizatio", "n"] -> Replace: \["i", "18", "n"] -> Concatenate: "i18n", which is s2 Example 2:

Input: s1 = "l123e", s2 = "44" Output: true Explanation: It is possible that "leetcode" was the original string.

* "leetcode" -> Split: \["l", "e", "et", "cod", "e"] -> Replace: \["l", "1", "2", "3", "e"] -> Concatenate: "l123e", which is s1.
* "leetcode" -> Split: \["leet", "code"] -> Replace: \["4", "4"] -> Concatenate: "44", which is s2. Example 3:

Input: s1 = "a5b", s2 = "c5b" Output: false Explanation: It is impossible.

* The original string encoded as s1 must start with the letter 'a'.
* The original string encoded as s2 must start with the letter 'c'.

**Constraints:**

* `1 <= s1.length, s2.length <= 40`
* `s1` and `s2` consist of digits `1-9` (inclusive), and lowercase English letters only.
* The number of consecutive digits in `s1` and `s2` does not exceed `3`.

解题思路：

dfs+memo

* **State Tracking (`diff`)**:
  * `diff` tracks the difference in the length of substrings that have been skipped over due to digit expansions.
  * A positive `diff` means that `s1` is ahead of `s2` by `diff` characters, while a negative `diff` means that `s2` is ahead by `-diff` characters.
* **Digit Handling**:
  * The code carefully handles cases where a digit might represent a sequence of characters by iterating through possible digit lengths.
  * For each possible digit, it tries to match it against the other string's sequence.
* **Character Matching**:
  * When both `s1` and `s2` have characters (not digits) and `diff == 0`, the code attempts to match the characters directly.
* **Recursive Exploration**:
  * The function recursively explores all possible ways to align and match the strings. It returns `True` if a valid match is found, and `False` otherwise.

```
from functools import cache

class Solution:
    def possiblyEquals(self, s1: str, s2: str) -> bool:
        @cache
        def dfs(i: int, j: int, diff: int) -> bool:
            # When both strings have been processed, check if there is no length difference left
            if i == len(s1) and j == len(s2):
                return diff == 0

            # Explore possible digit expansions in s1
            if i < len(s1) and s1[i].isdigit():
                num = 0
                for k in range(i, len(s1)):
                    if not s1[k].isdigit():
                        break
                    num = num * 10 + int(s1[k])
                    if dfs(k + 1, j, diff - num):
                        return True

            # Explore possible digit expansions in s2
            if j < len(s2) and s2[j].isdigit():
                num = 0
                for k in range(j, len(s2)):
                    if not s2[k].isdigit():
                        break
                    num = num * 10 + int(s2[k])
                    if dfs(i, k + 1, diff + num):
                        return True

            # When diff is 0, and both characters are the same, proceed
            if i < len(s1) and j < len(s2) and diff == 0 and s1[i] == s2[j]:
                return dfs(i + 1, j + 1, diff)

            # Handle cases where diff is not zero
            # If diff > 0, it means s1 has extra characters to match against s2
            if diff > 0 and i < len(s1) and not s1[i].isdigit():
                return dfs(i + 1, j, diff - 1)

            # If diff < 0, it means s2 has extra characters to match against s1
            if diff < 0 and j < len(s2) and not s2[j].isdigit():
                return dfs(i, j + 1, diff + 1)

            return False
        
        return dfs(0, 0, 0)

```
