2060. 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 boths1 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.
from functools import lru_cache
class Solution:
def possiblyEquals(self, s1: str, s2: str) -> bool:
def getNextNonDigit(s,start):
end = start
while end < len(s) and s[end].isdigit(): end += 1
return end
@lru_cache(None)
def possibleLengths(s): # This itself is an interesting problem
"""Return all possible lengths represented by numeric string s."""
ans = {int(s)}
for i in range(1, len(s)):
# add all lengths by splitting numeric string s at i
ans |= {x+y for x in possibleLengths(s[:i]) for y in possibleLengths(s[i:])}
return ans
@lru_cache(None)
def dp(i, j, diff):
"""Return True if s1[i:] matches s2[j:] with given differences."""
# Invalid cases
if i > len(s1) or j > len(s2):
return False
# If both have reached end return true if none of them are leading
if i == len(s1) and j == len(s2):
return diff == 0
# s1 has not reached end and s1 starts with a digit
if i < len(s1) and s1[i].isdigit():
i2 = getNextNonDigit(s1, i)
for L in possibleLengths(s1[i:i2]):
# substract since lead of s2 decreases by L
if dp(i2, j, diff-L): return True
# s2 has not reached end and s2 starts with a digit
elif j < len(s2) and s2[j].isdigit():
j2 = getNextNonDigit(s2, j)
for L in possibleLengths(s2[j:j2]):
# add since lead of s2 increase by L
if dp(i, j2, diff+L): return True
# if none of them have integer prefix or a lead over the other
elif diff == 0:
# if only one of them has reached end or current alphabets are not the same
if i == len(s1) or j == len(s2) or s1[i] != s2[j]:
return False
# skip same alphabets
return dp(i+1, j+1, 0)
# if none of them have integer prefix & s2 lead over s1
elif diff > 0:
# move s1 pointer forward and reduce diff
return dp(i+1, j, diff-1)
# if none of them have integer prefix & s1 lead over s2
else:
# move s2 pointer forward and increase diff
return dp(i, j+1, diff+1)
# start with starts of both s1 and s2 with no lead by any of them
return dp(0, 0, 0)