cache cell (i, j) = does p.substring(j) match s.substring(i) · → skip x* (j + 2) · ↓ x* eats s.charAt(i) · ↘ one char matched
Call stack bottom → top
public boolean isMatch(String s, String p) { Boolean[][] cache = new Boolean[s.length() + 1][p.length() + 1]; return dfs(0, 0, s, p, cache);}private boolean dfs(int i, int j, String s, String p, Boolean[][] cache) { if (cache[i][j] != null) { return cache[i][j]; } if (i >= s.length() && j >= p.length()) { return true; } if (j >= p.length()) { return false; } boolean match = i < s.length() && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.'); if (j + 1 < p.length() && p.charAt(j + 1) == '*') { cache[i][j] = dfs(i, j + 2, s, p, cache) // skip x* || (match && dfs(i + 1, j, s, p, cache)); // use x* return cache[i][j]; } if (match) { cache[i][j] = dfs(i + 1, j + 1, s, p, cache); return cache[i][j]; } cache[i][j] = false; return false;}
- i, j
- —
- match
- —
- cache entries
- 0
- memo hits
- 0
Why it works
- Brute force backtracks over how many characters each
x*swallows. With several stars the choices multiply, and on inputs like"aaaaaaab"against"a*a*a*a*c"the work grows exponentially. - Everything depends on (i, j): how much of
sand ofpis left. A star gives two moves: skipx*entirely (j + 2), or, ifxmatchess.charAt(i), let it eat that character and stay on the same star (i + 1). Without a star, one character must match and both move on. - Complexity: (m+1)·(n+1) states, each solved once with O(1) work: O(m·n) time and space.
- Pitfall: look ahead at
p.charAt(j + 1)before trying to matchp.charAt(j):"c*"can match nothing even though'c'does not match. Andsrunning out is not failure:dfs(s.length(), j)can still succeed while the rest ofpis allx*pairs. - Related: Wildcard Matching (44) uses
*as "any sequence" on its own, and the same table works with a simpler star rule.