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

<ul>
	<li>Arbitrarily <strong>split</strong> it into a <strong>sequence</strong> of some number of <strong>non-empty</strong> substrings.</li>
	<li>Arbitrarily choose some elements (possibly none) of the sequence, and <strong>replace</strong> each with <strong>its length</strong> (as a numeric string).</li>
	<li><strong>Concatenate</strong> the sequence as the encoded string.</li>
</ul>

<p>For example, <strong>one way</strong> to encode an original string <code>&quot;abcdefghijklmnop&quot;</code> might be:</p>

<ul>
	<li>Split it as a sequence: <code>[&quot;ab&quot;, &quot;cdefghijklmn&quot;, &quot;o&quot;, &quot;p&quot;]</code>.</li>
	<li>Choose the second and third elements to be replaced by their lengths, respectively. The sequence becomes <code>[&quot;ab&quot;, &quot;12&quot;, &quot;1&quot;, &quot;p&quot;]</code>.</li>
	<li>Concatenate the elements of the sequence to get the encoded string: <code>&quot;ab121p&quot;</code>.</li>
</ul>

<p>Given two encoded strings <code>s1</code> and <code>s2</code>, consisting of lowercase English letters and digits <code>1-9</code> (inclusive), return <code>true</code><em> if there exists an original string that could be encoded as <strong>both</strong> </em><code>s1</code><em> and </em><code>s2</code><em>. Otherwise, return </em><code>false</code>.</p>

<p><strong>Note</strong>: The test cases are generated such that the number of consecutive digits in <code>s1</code> and <code>s2</code> does not exceed <code>3</code>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> s1 = &quot;internationalization&quot;, s2 = &quot;i18n&quot;
<strong>Output:</strong> true
<strong>Explanation:</strong> It is possible that &quot;internationalization&quot; was the original string.
- &quot;internationalization&quot; 
  -&gt; Split:       [&quot;internationalization&quot;]
  -&gt; Do not replace any element
  -&gt; Concatenate:  &quot;internationalization&quot;, which is s1.
- &quot;internationalization&quot;
  -&gt; Split:       [&quot;i&quot;, &quot;nternationalizatio&quot;, &quot;n&quot;]
  -&gt; Replace:     [&quot;i&quot;, &quot;18&quot;,                 &quot;n&quot;]
  -&gt; Concatenate:  &quot;i18n&quot;, which is s2
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> s1 = &quot;l123e&quot;, s2 = &quot;44&quot;
<strong>Output:</strong> true
<strong>Explanation:</strong> It is possible that &quot;leetcode&quot; was the original string.
- &quot;leetcode&quot; 
  -&gt; Split:      [&quot;l&quot;, &quot;e&quot;, &quot;et&quot;, &quot;cod&quot;, &quot;e&quot;]
  -&gt; Replace:    [&quot;l&quot;, &quot;1&quot;, &quot;2&quot;,  &quot;3&quot;,   &quot;e&quot;]
  -&gt; Concatenate: &quot;l123e&quot;, which is s1.
- &quot;leetcode&quot; 
  -&gt; Split:      [&quot;leet&quot;, &quot;code&quot;]
  -&gt; Replace:    [&quot;4&quot;,    &quot;4&quot;]
  -&gt; Concatenate: &quot;44&quot;, which is s2.
</pre>

<p><strong class="example">Example 3:</strong></p>

<pre>
<strong>Input:</strong> s1 = &quot;a5b&quot;, s2 = &quot;c5b&quot;
<strong>Output:</strong> false
<strong>Explanation:</strong> It is impossible.
- The original string encoded as s1 must start with the letter &#39;a&#39;.
- The original string encoded as s2 must start with the letter &#39;c&#39;.
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= s1.length, s2.length &lt;= 40</code></li>
	<li><code>s1</code> and <code>s2</code> consist of digits <code>1-9</code> (inclusive), and lowercase English letters only.</li>
	<li>The number of consecutive digits in <code>s1</code> and <code>s2</code> does not exceed <code>3</code>.</li>
</ul>

class Solution(object):
    def values(self, s):
        if s in self.values_cache:
            return self.values_cache[s]
        if len(s)==1:
            self.values_cache[s] = [int(s),]
        elif len(s)==2:
            self.values_cache[s] = [int(s), int(s[0])+int(s[1])]
        elif len(s)==3:
            self.values_cache[s] = [int(s), int(s[0:2])+int(s[2]), int(s[0])+int(s[1:3]), int(s[0])+int(s[1])+int(s[2])]
        else:
            raise NotImplementedError
        return self.values_cache[s]
        
    def possiblyEqualsUtil(self, s1, s2, idx1, idx2, sum1, sum2):
        # print(s1[:idx1+1], sum1, s2[:idx2+1], sum2)
        if (idx1==-1 and sum1==0) and (idx2==-1 and sum2==0): # both s1 and s2 are exhausted means a match
            return True
        if (idx1==-1 and sum1==0) or (idx2==-1 and sum2==0): # either exhausted but other didn't
            return False
        if (idx1, idx2, sum1, sum2) in self.dp:
            return self.dp[(idx1, idx2, sum1, sum2)] 
        if sum1==0 and s1[idx1].isdigit(): # update sum1 when the idx1 is a digit and sum1 is 0
            next_idx1 = idx1
            while next_idx1>=0 and s1[next_idx1].isdigit():
                next_idx1 -= 1
            values1 = self.values(s1[next_idx1+1: idx1+1])
            answer = False
            for value1 in values1:
                answer = answer or self.possiblyEqualsUtil(s1, s2, next_idx1, idx2, value1, sum2)
            self.dp[(idx1, idx2, sum1, sum2)] = answer
        elif sum2==0 and s2[idx2].isdigit(): # update sum1 when the idx1 is a digit and sum1 is 0
            next_idx2 = idx2
            while next_idx2>=0 and s2[next_idx2].isdigit():
                next_idx2 -= 1
            values2 = self.values(s2[next_idx2+1: idx2+1])
            answer = False
            for value2 in values2:
                answer = answer or self.possiblyEqualsUtil(s1, s2, idx1, next_idx2, sum1, value2)
            self.dp[(idx1, idx2, sum1, sum2)] = answer
        else: # ready for comparisions
            if sum1 > 0 and sum2 > 0: # number-number compaision
                sum1, sum2 = sum1 - min(sum1, sum2), sum2 - min(sum1, sum2)
                self.dp[(idx1, idx2, sum1, sum2)] = self.possiblyEqualsUtil(s1, s2, idx1, idx2, sum1, sum2)
            elif sum1 > 0 and sum2 == 0 and s2[idx2].isalpha(): # number-alpha comparision
                self.dp[(idx1, idx2, sum1, sum2)] = self.possiblyEqualsUtil(s1, s2, idx1, idx2-1, sum1-1, sum2)
            elif sum2 > 0 and sum1 == 0 and s1[idx1].isalpha():  # number-alpha comparision
                self.dp[(idx1, idx2, sum1, sum2)] = self.possiblyEqualsUtil(s1, s2, idx1-1, idx2, sum1, sum2-1)
            elif s1[idx1].isalpha() and s2[idx2].isalpha(): # alpha-alpha comparision
                if s1[idx1]==s2[idx2]:
                    self.dp[(idx1, idx2, sum1, sum2)] = self.possiblyEqualsUtil(s1, s2, idx1-1, idx2-1, sum1, sum2)
                else:
                    self.dp[(idx1, idx2, sum1, sum2)] = False
            else:
                raise NotImplementedError
        return self.dp[(idx1, idx2, sum1, sum2)]

    def possiblyEquals(self, s1, s2):
        """
        :type s1: str
        :type s2: str
        :rtype: bool
        """
        self.values_cache = dict()
        self.dp = dict()
        return self.possiblyEqualsUtil(s1, s2, len(s1)-1, len(s2)-1, 0, 0)
18861