问题描述
字符匹配问题
- 用p来匹配s. p中可能包含. *
- . 表示匹配任一个单一字符
- * 表示匹配0到多个前一个字符
- 要求p和s匹配
- Example 1:
- Input:
> s="aa"
> p = "a" - Output: false
- Explanation:
> "a" does not match the entire string "aa"
- Input:
- Example 2:
- Input:
> s="aa"
> p = "a*" - Output: true
- Explanation:
> "'*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa"
- Input:
- Example 3:
- Input:
> s="aab"
> p = "c*a*b" - Output: true
- Explanation:
> c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".
- Input:
思路
这是一道非常困难的题, 曾经害我苦思冥想了好几天。我刚开始甚至没想到居然能用DP解这个问题,后来苦苦求索翻阅leetcode一众大神的解释后才搞明白这个题用DP到底怎么搞
这是一道true false dp问题, dp[i][j] 表示了s前i个元素和p前j个元素的匹配情况
分情况讨论:
- 如果s[i] == p [j] || p[j] == '.' 这时候完全就看前面的情况 dp[i][j] = dp[i-1][j-1]
- 如果s[i] != p [j]这个也要分情况
- 2.1 如果p[j] == '*' (ba a* ab a*)
2.1.1 若 p[j-1] != s[i] && p[j-1] != '.'
此时, 由于上一个元素不匹配导致*无法复制,那么*只能让上一个元素清空:
> dp[i][j] = dp[i][j-2]2.1.2 除上面的情况外,即可以复制上一个元素达到匹配的目的,当然也可以不复制上一个元素:
> dp[i][j] = dp[i][j-2] (上一个元素清空) || dp[i][j-1] (*只代表一个元素) || dp[i-1][j] (代表多个元素,如果在i前面都能和p匹配,那加一个自然也能匹配*)
- 2.2 如果p[j] != '*'
> dp[i][j] = false
- 2.1 如果p[j] == '*' (ba a* ab a*)
特别解释一下,为什么在2.1.2中,当代表多个元素时,匹配的是dp[i-1][j]这个奇怪的搭配。让我们来举个栗子:
假设我们的有
> s: abbbbb
> p: cb*
我们看到这里的*,实际上是代表了5个b,但是当我们求dp[i][j]的时候,我们无法得匹配完这些b之后前面的元素是否匹配,我们删掉这些b
> s: a
> p: c
也就是说,a,c是否匹配已经在之前迭代了。如何得知a,c的迭代位置呢?
> dp[i][j] = dp[i-1][j] = …… = dp[i-6][j]
这是通过我们之前已经求到的结果迭代出来的,你会发现i递减的过程其实就是在找重复元素之前的元素,所以我们直接给出了dp[i-1][j]
标准代码
其实如果能看懂上面的解释的话,代码不成问题,上面的解释已经接近于伪代码了。
1 | public boolean isMatch(String s, String p) { |
终于啃完这个头疼的问题了,看张图片奖励下自己吧