PracticeNeetCode ↗LeetCode ↗
Given a string s and a pattern p where . matches any single character and * matches zero or more of the element immediately before it, determine whether p matches the entire string s.
* always pairs with the character right before it, and it offers two independent options: skip that pair entirely (zero occurrences), or consume one matching character from s and stay on the same spot in p (one more occurrence).. always counts as a match against any single character, so matching logic needs to check for it alongside exact character equality.(len(s)+1) × (len(p)+1), with the bottom-right corner (both strings fully consumed) set to True.s and p match directly (accounting for .).*, the cell is True if either skipping the x* pair works, or the current characters match and consuming one from s (staying on the same pattern position) works.True only if the current characters match and the diagonal (both advance by one) is True.Time: O(m · n) — Space: O(m · n)
def isMatch(s: str, p: str) -> bool:
m, n = len(s), len(p)
dp = [[False] * (n + 1) for _ in range(m + 1)]
dp[m][n] = True
for i in range(m, -1, -1):
for j in range(n - 1, -1, -1):
first_match = i < m and p[j] in (s[i], ".")
if j + 1 < n and p[j + 1] == "*":
dp[i][j] = dp[i][j + 2] or (first_match and dp[i + 1][j])
else:
dp[i][j] = first_match and dp[i + 1][j + 1]
return dp[0][0]How the solution above works, piece by piece.
dp[i][j] = does s[i:] match p[j:]? Two empty suffixes match: dp[m][n] = True.first_match: s[i] exists and equals p[j] or p[j] is ..p[j+1] is *: either use zero copies (skip two pattern characters, dp[i][j+2]) or, if the first character matches, consume it and keep the same pattern (dp[i+1][j]).dp[i+1][j+1].Running it on s = "aa", p = "a*":
a* entirely or consumes one matching character and stays on the same pattern position, which is how a* matches both letters.NeetCode — Dynamic Programming Top-Down Memoization, LeetCode 10