Leetcode solution 44: WildcardMatching
原文链接
https://blog.baozitraining.org/2019/04/leetcode-solution-44-wildcard-matching.html
Problem Statement
Given an input string (s
) and a pattern (p
), 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).
Note:
-
s
could be empty and contains only lowercase lettersa-z
. -
p
could be empty and contains only lowercase lettersa-z
, and characters like?
or*
.
Example 1:
Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
Example 2:
Input:
s = "aa"
p = "*"
Output: true
Explanation: '*' matches any sequence.
Example 3:
Input:
s = "cb"
p = "?a"
Output: false
Explanation: '?' matches 'c', but the second letter is 'a', which does not match 'b'.
Example 4:
Input:
s = "adceb"
p = "*a*b"
Output: true
Explanation: The first '*' matches the empty sequence, while the second '*' matches the substring "dce".
Example 5:
Input:
s = "acdcb"
p = "a*c?b"
Output: false
Problem link
Video Tutorial
You can find the detailed video tutorial here
Thought Process
It seems an easy problem first using recursion and brute forcefully solving the problem, but the OJ will quickly throw a TLE (Time Limit Exceeded) error since it is exponential time. Well, if you were like me, tried really hard to optimize my brute force solution, either using some heuristics or pruning on the recursion, however, still no luck :( DP (Dynamic Programming) is normally a great way when trying to answer below two types of questions, and string related questions are a majority use case of DP
- Only Yes/No, True/False question without returning detailed step by step results
- Extreme values, e.g., Max, Min, Best optimal value
I have posted several videos on how to solve DP problems using a template, essentially
- Initialize your lookup array, could be 2 dimensional or 1 dimensional using rolling arrays
- Initialize the init values in your array
- Get the math formula for a[i] = a[i-1] * m - n or whatever condition you need
- Code it up
You can find the video tutorial on this problem here
Solutions
Brute force recursion, TLE
public boolean isMatchTLE(String s, String p) { |
|
---|---|
if (s == null || p == null) { |
|
return false; |
|
} |
|
return isMatchHelper(s, 0, p, 0); |
|
} |
|
// b*b*ab**ba*b**b***bba , this should trim some of the recursion time |
|
public String removeDuplicateStars(String p) { |
|
String newP = ""; |
|
for (int i = 0; i < p.length(); i++) { |
|
if (p.charAt(i) != '*') { |
|
newP += p.charAt(i); |
|
} else { |
|
if (newP.length() == 0 || newP.charAt(newP.length() - 1) != '*') { |
|
newP += "*"; |
|
} |
|
} |
|
} |
|
return newP; |
|
} |
|
// Even after all those optimizations, this would still TLE, n*2^m |
|
private boolean isMatchHelper(String s, int i, String p, int j) { |
|
if (j == p.length()) { |
|
return i == s.length(); |
|
} |
|
p = this.removeDuplicateStars(p); |
|
if (p.charAt(j) == '*') { |
|
// s = "abcdef" |
|
// p = "*bc*def" |
|
if (isMatchHelper(s, i, p, j + 1)) { |
|
return true; |
|
} |
|
if (i == s.length() - 1 && j == p.length() - 1) { |
|
return true; |
|
} |
|
for (int k = i + 1; k < s.length(); k++) { |
|
return isMatchHelper(s, k, p, j); |
|
} |
|
} else { |
|
if (isCharMatch(s, i, p, j)) { |
|
return isMatchHelper(s, i + 1, p, j + 1); |
|
} |
|
return false; |
|
} |
|
return false; |
|
} |
|
// compare if char is the same or it is a '?' |
|
private boolean isCharMatch(String s, int i, String p, int j) { |
|
if (i >= s.length() || j >= p.length()) { |
|
return false; |
|
} |
|
return s.charAt(i) == p.charAt(j) || p.charAt(j) == '?'; |
|
} |
view rawbruteforce.java hosted with ❤ by GitHub
Time Complexity: assuming S length is M, P length is N, this is O(M*2^N), exponential basically Space Complexity: No extra space needed other than the additional recursion function stack
DP solution
// This is the DP solution, and falls perfectly using the DP template |
|
---|---|
// Also this is only boolean answer (not find all steps) || find the extreme values (min,max) |
|
public boolean isMatch(String s, String p) { |
|
if (s == null || p == null) { |
|
return false; |
|
} |
|
int row = s.length(); |
|
int col = p.length(); |
|
boolean[][] lookup = new boolean[row + 1][col + 1]; |
|
lookup[0][0] = true; |
|
// initialize lookup init values, for the string (s) part, it all default to false |
|
// since a char matches to empty is false anyway |
|
for (int j = 1; j <= col; j++) { |
|
if (p.charAt(j - 1) == '*' && lookup[0][j - 1]) { |
|
lookup[0][j] = true; |
|
} |
|
} |
|
for (int i = 1; i <= row; i++) { |
|
for (int j = 1; j <= col; j++) { |
|
if (p.charAt(j - 1) == '*') { |
|
lookup[i][j] = lookup[i][j - 1] || lookup[i - 1][j]; |
|
} else { |
|
if (lookup[i - 1][j - 1] && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?')) { |
|
lookup[i][j] = true; |
|
} |
|
} |
|
} |
|
} |
|
return lookup[row][col]; |
|
} |
view rawwildcardMatching.java hosted with ❤ by GitHub
Time Complexity: assuming S length is M, P length is N, this is O(M*N) because all we need to do is build up that lookup matrix Space Complexity: assuming S length is M, P length is N, this is O(M*N), again, that lookup matrix
References
- A good DP video tutorial
- Grandyang very funny writings in Chinese
- Yu's garden, a not very well explained but very clever(hacky) solution
- .NET Core的日志[2]:将日志输出到控制台
- 2017年高等教育十大战略性技术(二)
- 通过实例模拟ASP.NET MVC的Model绑定机制:数组
- 《全球贸易信息动态》
- .NET Core的日志[3]:将日志写入Debug窗口
- Code2Cloud:比ALM中断更大
- .NET Core的日志[4]:将日志写入EventLog
- 微信小程序不行了?看小马哥带你忆童年
- ASP.NET MVC三个重要的描述对象:ControllerDescriptor和ActionDescriptor的创建
- .NET Core的日志[5]:利用TraceSource写日志
- 物联网芯片正在积极开发 明年将得到爆发
- 韩国全球首测5G网络下自动驾驶 为汽车安全保驾护航的竟是路灯
- 通过与Quickbuild和Mist.io的持续集成实现云管理和使用监控
- .NET Core的文件系统[1]:读取并监控文件的变化
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SpringBoot源码学习(五)
- SpringBoot源码学习(六)
- SpringBoot源码学习(七)
- LeetCode52|有序数组中的单一元素
- LeetCode53|搜索二维矩阵II
- LeetCode54|二叉树的层次遍历
- LeetCode55|二叉树的层次遍历II
- LeetCode56|二叉树的层平均值
- LeetCode57|二叉树的锯齿形层次遍历
- LeetCode58|N叉树的层序遍历
- 技术创作101训练营-CRC校验没那么难
- 栈与队列:有没有想过计算机是如何处理表达式的?
- 栈与队列:滑动窗口里求最大值引出一个重要数据结构
- 栈与队列:求前 K 个高频元素和队列有啥关系?
- 手写一个抖音视频去水印工具,千万别刚一个程序员