题目:

Implement wildcard pattern matching with support for '?' and '*'.

'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence). The matching should cover the entire input string (not partial). The function prototype should be:
bool isMatch(const char *s, const char *p) Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false

链接:  http://leetcode.com/problems/wildcard-matching/

题解:

这道题是一刷里放弃的6道题中第一道。看过<挑战程序设计>以后还是决定好好对待这道题目。 前些天专门学习了NFA,但对这道题目还是会time out。试过把*预处理为"?*"之后可以用regular expression的DP方法来过,但是速度比较慢。 这道题也是Two Sigma上午三轮技术面里必考的一道题。 以后再遇到这类题目,我要尽可能使用DP来做,好好练习DP。

又做到了这一题,下面用dp来解决。虽然AC但是速度很慢,有很多地方需要优化,比如更多的pruning,Space Complexity减少为O(n)等等。Reference里有三个解得就非常好。 留给三刷继续深入研究这道题目。

下面使用DP解决的思路。代码大部分和 10. Regular Expression Matching 一样。直接拷贝自己的解释。

使用DP的方法:

  1. 在初始的判断之后,首先建立dp矩阵res[][] = new boolean[m + 1][n + 1]。其中res[i][j]是指s到字符i - 1,p到字符j - 1的match情况,true为match。
  2. res[0][0] = true表示s和p都为""的时候match成功
  3. 接下来对pattern p的首行'*'号的0 match情况进行初始化,res[0][j] = res[0][j - 1] && p.charAt(j - 1) == '*'。这里表示,假如res[0][j - 1],也就是""与p.charAt(j - 2)成功match,那么因为当前字符p.charAt(j - 1) = '*'可以代表空字符串,所以res[0][j]也肯定match成功。我们发现在10. Regular Expression Matching与这一题44. Wildcard Matching中, 合理得初始化都是都是必不可少的步骤。
  4. 之后我们就可以从从位置(1, 1)开始对res矩阵进行二维dp,主要分为两种情况
    1. p.charAt(i - 1)不等于'*': 这里表示matching transition,假如s和p的上一个字符match, 即res[i - 1][j - 1] == true,同时新的字符s.charAt(i - 1) == p.charAt(j - 1),或者p.charAt(j - 1) == '?', 那么我们可以确定res[i][j] = true,这表示到 s 和 p 到 i - 1和j - 1的位置是match的
    2. 假如p.charAt(i - 1) == '*': 这里表示epsilon transition,系统可能处于不同的状态,我们要分多种情况进行考虑,只要有一个状态为true,在这个位置的结果就为true,是一个“或”的关系:
      1. res[i][j - 1] == true,即s.charAt(i - 1) match p.charAt(j - 2),这里'*'号可以当作"",表示0 matching,这种情况下,我们可以认为状态合理,res[i][j] = true。 例 "C" match "C*", i = 2, j = 2,这里C match C,'*'作为空字符串"",所以我们match成功
      2. res[i - 1][j] == true,即s.charAt(i - 2) match p.charAt(j - 1),这里'*'号是被当做"s[j - 2]" + "s[j - 1]"这两个字符拼起来的字符串。因为'*'可以代表任意字符串,所以假如res[i - 1][j] == true,那么res[i][j]也一定是true,其实这样类推下去,res[i + 1][j]也是true,这一列都是true。 (根据这个特性其实我们可以巧妙地改写一下,提前把这一列剩下元素都设置为true,可以减少不少数组访问)。 例 "AC" match "*", i = 2, j = 1,这时候'*'可以作为'AC',所以也是match成功。
  5. 数组全部遍历完毕之后我们返回res[m][n]

Time Complexity - O(mn), Space Complexity - O(mn)

public class Solution {
public boolean isMatch(String s, String p) {
if (s == null || p == null) {
return false;
}
if (p.length() == 0) {
return s.length() == 0;
}
int m = s.length(), n = p.length();
boolean[][] res = new boolean[m + 1][n + 1];
res[0][0] = true;
for (int j = 1; j <= n; j++) {
if (res[0][j - 1] && p.charAt(j - 1) == '*') {
res[0][j] = true;
}
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (p.charAt(j - 1) == '*') {
if (res[i][j - 1] || res[i - 1][j]) {
res[i][j] = true;
}
} else {
if (res[i - 1][j - 1] && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?')) {
res[i][j] = true;
}
}
}
}
return res[m][n];
}
}

Test Case:

("aab", "c*a*b")

("aa", "a")

("aa", "*")

二刷:

这里我们依然使用二维DP来做这道题。 空间还可以继续优化到一维DP。 时间也可以继续优化。这道题也是Two Sigma上午onsite第二轮的必考题。 这道题dp并非最优解。

下面我们来分析dp解法。

  1. 找出base状态。这里依然是s和p均为空字符串时,两串match,返回true
  2. 初始化。 这时候我们要创建2维DP矩阵。 矩阵里面的 dp[i][j]的意思是, 到串s的第i - 1个字符和串p的第j - 1个字符是否match。我们还要对i = 0时,即s为空串时的dp数组进行初始化。这时假如dp[0][j - 1]为true,并且p.charAt(j - 1)为*的话, 因为'*'可以match任何串,dp[0][j]为true, 直到我们遇到一个非'*'的字符为止。
  3. 分析转移方程。
    1. 当p.charAt(j - 1) = '*'时,我们只需要查看之前保存下来的结果,当dp[i - 1][j]或者dp[i][j - 1]为true的时候,我们可以设置dp[i][j] = true。 即我们可以从 (i - 1, j)或者(i, j - 1)扩展到(i, j)。
    2. 否则p.charAt(j - 1)不为'*'。我们按照regular expression matching的老方法, 在dp[i - 1][j - 1]即前两个字母match的情况下,查看现在s中的字符s.charAt(i - 1)是否等于现在p中的字符p.charAt(j - 1),或者现在p的字符是否为通配符'?'
  4. 返回结果

Java:

Time Complexity - O(mn), Space Complexity - O(mn)

public class Solution {
public boolean isMatch(String s, String p) {
if (s == null || p == null) return s == p;
if (p.length() == 0) return s.length() == 0;
int sLen = s.length(), pLen = p.length();
boolean[][] dp = new boolean[sLen + 1][pLen + 1];
dp[0][0] = true;
for (int j = 1; j <= pLen; j++) {
if (!dp[0][j - 1] || (p.charAt(j - 1) != '*')) break;
else dp[0][j] = true;
} for (int i = 1; i <= sLen; i++) {
for (int j = 1; j <= pLen; j++) {
if (p.charAt(j - 1) != '*') {
dp[i][j] = dp[i - 1][j - 1] && ((s.charAt(i - 1) == p.charAt(j - 1)) || (p.charAt(j - 1) == '?'));
} else {
dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
}
}
}
return dp[sLen][pLen];
}
}

Reference:

https://leetcode.com/discuss/10133/linear-runtime-and-constant-space-solution

https://leetcode.com/discuss/29445/my-java-dp-solution

https://leetcode.com/discuss/26399/python-dp-solution

http://www.1point3acres.com/bbs/thread-101201-1-1.html

https://github.com/Linzertorte/LeetCode-in-Python/blob/master/WildcardMatching.py

http://codeganker.blogspot.com/2014/03/wildcard-matching-leetcode.html

http://www.cnblogs.com/grandyang/p/4401196.html

http://blog.csdn.net/linhuanmars/article/details/21198049

http://yucoding.blogspot.com/2013/02/leetcode-question-123-wildcard-matching.html

https://leetcode.com/discuss/49254/fastest-non-dp-solution-with-o-1-space

http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741374.html

http://sunzone.iteye.com/blog/1856387

44. Wildcard Matching的更多相关文章

  1. LeetCode - 44. Wildcard Matching

    44. Wildcard Matching Problem's Link --------------------------------------------------------------- ...

  2. leetcode 10. Regular Expression Matching 、44. Wildcard Matching

    10. Regular Expression Matching https://www.cnblogs.com/grandyang/p/4461713.html class Solution { pu ...

  3. 【LeetCode】44. Wildcard Matching (2 solutions)

    Wildcard Matching Implement wildcard pattern matching with support for '?' and '*'. '?' Matches any ...

  4. [LeetCode] 44. Wildcard Matching 外卡匹配

    Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '? ...

  5. 【一天一道LeetCode】#44. Wildcard Matching

    一天一道LeetCode系列 (一)题目 Implement wildcard pattern matching with support for '?' and '*'. '?' Matches a ...

  6. [leetcode]44. Wildcard Matching万能符匹配

    Given an input string (s) and a pattern (p), implement wildcard pattern matching with support for '? ...

  7. 44. Wildcard Matching (String; DP, Back-Track)

    Implement wildcard pattern matching with support for '?' and '*'. '?' Matches any single character. ...

  8. 44. Wildcard Matching 有简写的字符串匹配

    [抄题]: Given an input string (s) and a pattern (p), implement wildcard pattern matching with support ...

  9. 44. Wildcard Matching *HARD*

    '?' Matches any single character. '*' Matches any sequence of characters (including the empty sequen ...

随机推荐

  1. 每日一“酷”之pprint

    pprint – 美观打印 作用:美观打印数据结构 pprint 包含一个“美观打印机”,用于生成数据结构的一个美观视图.格式化工具会生成数据结构的一些表示,不仅可以由解释器正确地解析,而且便于人类阅 ...

  2. 关于字符串 “*****AB**C*D*****” 中前缀、后缀和中间 '*' 的处理

    一.删除前缀 '*' #include<iostream> #include<cstdio> using namespace std; //主函数 int main() { ] ...

  3. Oracle 10g下载链接

    用迅雷下载: http://download.oracle.com/otn/linux/oracle10g/10201/10201_database_linux_x86_64.cpio.gz http ...

  4. 使用WinSetupFromUSB来U盘安装WINDOWS2003

    今天用UltraISO制作WINDOWS2003的U盘的安装启动,在安装系统的时候发现错误提示“INF file txtsetup.sif is corrupt or missing .status ...

  5. stringlist

    #ifndef _STRINGLIST_HPP_#define _STRINGLIST_HPP_ #include "../global.hpp"#include <type ...

  6. Entity Framework(一) 映射

    ADO.NET Entity Framework通过Modeel First和DataBase First,提供了几个把数据库表映射到对象上的曾.通过Database First,可以从一个数据库架构 ...

  7. Week1 Team Homework #3: 软件工程在北航

    在组内成员的共同努力,我们采访了几个学长学姐,顺利完成任务.反馈信息如下: 平均每周花在这门课上的时间 平均写的代码总行数 学到的最有用的部分 最没用的部分 <软件工程>最应该改进的地方 ...

  8. 服务器端spice配置详解

    1. 安装必要的工具 sudo apt-get install build-essential autoconf git-core intltool 2. 安装必要的依赖包 -dev libxfixe ...

  9. IIS Express start introduction and applicationHost modification

    1. First you need create a web project in VS 2. When you finish your project, click start then IIS E ...

  10. [设计模式] 15 解释器模式 Interpreter

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对解释器模式是这样说的:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子.如果一种特定类 ...