题意解析
给定两个字符串,S1、S2,字符串中仅包含数字和小写字符,连续的数字串能代表相应数目的任意字符。
问两个串能否匹配?
解释下连续的数字串能代表相应数目的任意字母,如'ab12c'这个串,按照'12'这个数字子串的不同拆法,可以拆成1和2,或者12,(以字符?指代任意字母) 那么相应地可以匹配
- ab(?)(??)c
- ab(????????????)c
解法
回想字符串匹配问题,都是用动态规划解决的,那么这里是不是也可以这样解决呢?
动态规划问题最核心的是怎么表达状态。
传统的字符串匹配问题,都是用dp[i][j]代表字串S1[0:i]和子串S2[0:j]的匹配状态。那么这个问题依旧用(i,j)二元组代表状态可以吗?不可以,因为(i,j)的对应的子串有多种拆解方法(此处一个字符可以指代多个字符,如字符'9'可以指代9个字符,串'19'可以指代10个字符或者19个字符),(i,j)二元组并不足以表达一个完整的状态。
考虑加一维?那么新的一维代表什么呢?
i, j的范围都是40, 那么目前状态数已有1600,考虑到算法效率,第三维不会超过10000。
同时串中唯一存在多种拆法的子串只有纯数字部分,但数字子串代表任意字符,所以是无需关心具体是什么字符的。那么第三维可以表示成目前子串中末尾部分的数字串是多长。但如果两个串分开表示,需要增加两维,1000 * 1000,已经超过了10000的限制。不可行!
还可以在简化一下,我们并不关心两个串末尾到底都多长,我们只关心他们的长度是否匹配上。
因此第三维结合两个串的长度,第三维表示两个子串(S1_Prefix, S2_Prefix)目前末尾部分数字串的长度差。
代码(Python实现)
import icecream as ice
class Solution:
def possiblyEquals(self, s1: str, s2: str) -> bool:
n, m = len(s1), len(s2)
status = {}
ord1 = [ord(c) for c in s1]
ord2 = [ord(c) for c in s2]
zero_ord, nine_ord = ord('0'), ord('9')
# i, j 分别是两个串当前位置的指针
# diff是串1当前子串字符数-串2当前子串的字符数
def dfs(i, j, diff):
# ice.ic(i, j, diff)
if i >= n and j >= m and diff == 0:
return True
if (i >= n and diff <= 0) or (j >= m and diff >= 0):
return False
if (i, j, diff) in status.keys():
return status[(i, j, diff)]
status_rep = (i, j, diff)
if diff == 0 and ord1[i] not in range(zero_ord, nine_ord + 1) and ord2[j] not in range(zero_ord, nine_ord + 1):
if ord1[i] != ord2[j]:
status[status_rep] = False
return False
status[status_rep] = dfs(i + 1, j + 1, 0)
return status[status_rep]
current_status_available = False
if diff <= 0:
if i < n:
if ord1[i] in range(zero_ord, nine_ord + 1):
ti = i
num = 0
while ti < n and ord1[ti] in range(zero_ord, nine_ord + 1):
num = num * 10 + ord1[ti] - zero_ord
if dfs(ti + 1, j, diff + num):
current_status_available = True
break
ti += 1
else:
current_status_available = dfs(i + 1, j, diff + 1)
else:
if j < m:
if ord2[j] in range(zero_ord, nine_ord + 1):
tj = j
num = 0
while tj < m and ord2[tj] in range(zero_ord, nine_ord + 1):
num = num * 10 + ord2[tj] - zero_ord
if dfs(i, tj + 1, diff - num):
current_status_available = True
break
tj += 1
else:
current_status_available = dfs(i, j + 1, diff - 1)
status[status_rep] = current_status_available
return current_status_available
return dfs(0, 0, 0)
def main():
inputs = [
("ab", "1"),
("internationalization", "i18n"),
("l123e", "44"),
("a5b", "c5b"),
("112s", "g841"),
("ab", "a2"),
("7a59b6", "671a")
]
outputs = [
False,
True,
True,
False,
True,
False,
False
]
sol = Solution()
for idx, input in enumerate(inputs):
expected = outputs[idx]
actual = sol.possiblyEquals(input[0], input[1])
ice.ic(actual, expected)
if __name__ == '__main__':
main()
```