刻意练习:LeetCode实战 -- Task30.通配符匹配
背景
本篇图文是LSGO软件技术团队组织的 第二期基础算法(Leetcode)刻意练习训练营 的打卡任务。本期训练营采用分类别练习的模式,即选择了五个知识点(数组、链表、字符串、树、贪心算法),每个知识点选择了 三个简单、两个中等、一个困难 等级的题目,共计三十道题,利用三十天的时间完成这组刻意练习。
本次任务的知识点:贪心算法
贪心算法(greedy algorithm),又称贪婪算法,是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。
贪心算法在有最优子结构的问题中尤为有效。最优子结构的意思是局部最优解能决定全局最优解。简单地说,问题能够分解成子问题来解决,子问题的最优解能递推到最终问题的最优解。
贪心算法与动态规划的不同在于它对每个子问题的解决方案都做出选择,不能回退。动态规划则会保存以前的运算结果,并根据以前的结果对当前进行选择,有回退功能。
题目
- 题号:44
- 难度:困难
- https://leetcode-cn.com/problems/wildcard-matching/
给定一个字符串(s
) 和一个字符模式(p
) ,实现一个支持'?'
和'*'
的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
s
可能为空,且只包含从a-z
的小写字母。p
可能为空,且只包含从a-z
的小写字母,以及字符?
和*
。
示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:
s = "aa"
p = "*"
输出: true
解释: '*' 可以匹配任意字符串。
示例 3:
输入:
s = "cb"
p = "?a"
输出: false
解释: '?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。
示例 4:
输入:
s = "adceb"
p = "*a*b"
输出: true
解释: 第一个 '*' 可以匹配空字符串, 第二个 '*' 可以匹配字符串 "dce".
示例 5:
输入:
s = "acdcb"
p = "a*c?b"
输出: false
示例 6:
输入:
"abefcdgiescdfimde"
"ab*cd?i*de"
输出:true
示例 7:
输入:
"aaaa"
"***a"
输出:true
实现
第一种:双索引法
我们用i
和j
分别标记s
和p
的第一个字符下标,即都初始化为0。用istart
和jstart
分别标记s
和p
中'*'
匹配过的位置,即初始化为-1
。
和普通字符串匹配的思路差不多,已经匹配成功的部分就不再考虑了,所以要用i
和j
标记当前正在比较的字符;但是最近匹配过的'*'
可能会被重复使用去匹配更多的字符,所以我们要用istart
和jstart
分别标记s
和p
中最近匹配过'*'
的位置。
- 如果
i
和j
标记的字符正好相等或者j
字符是'?'
匹配成功,则"移除"i
和j
元素,即自增i
、j
。 - 否则如果
j
字符是'*'
依然可以匹配成功,则用istart
和jstart
分别标记i
元素和j
元素,自增j
。 - 再否则如果
istart>-1
说明之前匹配过'*'
,因为'*'
可以匹配多个字符,所以这里要再次利用这个最近匹配过的'*'
匹配更多的字符,移动i
标记istart
的下一个字符,再让istart
重新标记i
元素,同时移动j
标记jstart
的下一个字符。 - 上述三种情况都不满足,则匹配失败,返回
false
。
最后当s
中的字符都判断完毕,则认为s
为空,此时需要p
为空或者p
中只剩下星号的时候,才能成功匹配。
- 执行结果:通过
- 执行用时:92 ms, 在所有 C# 提交中击败了 95.00% 的用户
- 内存消耗:25.7 MB, 在所有 C# 提交中击败了 66.67% 的用户
public class Solution
{public bool IsMatch(string s, string p){//若正则串p为空串,则s为空串匹配成功,s不为空串匹配失败。if (string.IsNullOrEmpty(p))return string.IsNullOrEmpty(s) ? true : false;int i = 0, j = 0, istart = -1, jstart = -1, plen = p.Length;//判断s的所有字符是否匹配while (i < s.Length){//三种匹配成功情况以及匹配失败返回falseif (j < plen && (s[i] == p[j] || p[j] == '?')){i++;j++;}else if (j < plen && p[j] == '*'){istart = i;jstart = j;j++;}else if (istart > -1){i = istart + 1;istart = i;j = jstart + 1;}else{return false;}}//s中的字符都判断完毕,则认为s为空//此时需要p为空或者p中只剩下星号的时候,才能成功匹配。//如果p中剩余的都是*,则可以移除剩余的*while (j < plen && p[j] == '*'){j++;}return j == plen;}
}
第二种:动态规划
dp
数组的含义:dp[i,j]
意思是s
的前i
个元素能否被p
的前j
个元素成功匹配。
知道了dp
数组的含义之后,我们就知道了初始化细节:
bool
类型的dp
数组,大小是[s.length+1,p.length+1]
,因为存在s
前0个字符和p
前0个字符的情况,即s
为空串或p
为空串。dp[0,0]
一定是true
,因为s
空串和p
空串是可以匹配成功的;dp[1,0] ~ dp[s.length,0]
一定都是false
,因为s
不为空串而p
为空串是不能匹配成功的。dp[0,1] ~ dp[0,p.length]
当s为空串的时候,而p
不是空串的时候,当且仅当p
的j
字符以及前面都为'*'
才为true
。dp[s.length,p.length]
就得到了s
和p
最终的匹配情况。
有了上述理解之后,就可以初始化dp
数组了。
然后填写dp
数组剩余部分即可,状态转移方程:
- 当
s[i] == p[j]
或者p[j] == '?'
,则dp[i,j] = dp[i-1,j-1]
。可以理解为当前字符成功匹配后,只需要考虑之前的字符串是否匹配即可。 - 当
p[j] == '*'
,则dp[i,j] = dp[i-1,j] || dp[i,j-1]
。可以理解为当字符为'*'
的时候会出现两种情况,第一种是'*'
需要作为一个字母与s[i]
进行匹配;第二种是'*'
需要作为空字符(即不需要'*'
可以直接"移除"),所以dp[i,j-1]
;用逻辑或将两种情况连接,是因为只要有一种情况可以匹配成功则当前匹配成功,有点暴力算法的感觉。 - 最后当
s[i] !=p [j] && p[j] != '*'
,dp[i,j] = false
。这步可以省略,因为dp
数组元素的默认值就是false
,所以不必要进行显式的赋值为false
。
有了上面的理解,我们就可以写代码了。
- 执行结果:通过
- 执行用时:112 ms, 在所有 C# 提交中击败了 62.50% 的用户
- 内存消耗:28.6 MB, 在所有 C# 提交中击败了 22.22% 的用户
class Solution
{public bool IsMatch(string s, string p){if (string.IsNullOrEmpty(p))return string.IsNullOrEmpty(s) ? true : false;int slen = s.Length, plen = p.Length;bool[,] dp = new bool[slen + 1, plen + 1];//初始化dp数组//dp[1][0]~dp[s.length][0]默认值flase不需要显式初始化为falsedp[0, 0] = true;//dp[0][1]~dp[0][p.length]只有p的j字符以及前面所有字符都为'*'才为truefor (int j = 1; j <= plen; j++){dp[0, j] = p[j - 1] == '*' && dp[0, j - 1];}//填写dp数组剩余部分for (int i = 1; i <= slen; i++){for (int j = 1; j <= plen; j++){char si = s[i - 1], pj = p[j - 1];if (si == pj || pj == '?'){dp[i, j] = dp[i - 1, j - 1];}else if (pj == '*'){dp[i, j] = dp[i - 1, j] || dp[i, j - 1];}}}return dp[slen, plen];}
}
往期活动
LSGO软件技术团队会定期开展提升编程技能的刻意练习活动,希望大家能够参与进来一起刻意练习,一起学习进步!
- Python基础刻意练习活动即将开启,你参加吗?
- Task01:变量、运算符与数据类型
- Task02:条件与循环
- Task03:列表与元组
- Task04:字符串与序列
- Task05:函数与Lambda表达式
- Task06:字典与集合
- Task07:文件与文件系统
- Task08:异常处理
- Task09:else 与 with 语句
- Task10:类与对象
- Task11:魔法方法
- Task12:模块
我是 终身学习者“老马”,一个长期践行“结伴式学习”理念的 中年大叔。
我崇尚分享,渴望成长,于2010年创立了“LSGO软件技术团队”,并加入了国内著名的开源组织“Datawhale”,也是“Dre@mtech”、“智能机器人研究中心”和“大数据与哲学社会科学实验室”的一员。
愿我们一起学习,一起进步,相互陪伴,共同成长。
后台回复「搜搜搜」,随机获取电子资源!
欢迎关注,请扫描二维码:
刻意练习:LeetCode实战 -- Task30.通配符匹配相关推荐
- 打卡第三十天(Task30)----通配符匹配
Leetcode刻意练习----贪心算法6 题目 给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 '?' 和 '' 的通配符匹配. '?' 可以匹配任何单个字符. '' 可以匹配任意字符串 ...
- 刻意练习:LeetCode实战 -- Task18. 正则表达式匹配
背景 本篇图文是LSGO软件技术团队组织的 第二期基础算法(Leetcode)刻意练习训练营 的打卡任务.本期训练营采用分类别练习的模式,即选择了五个知识点(数组.链表.字符串.树.贪心算法),每个知 ...
- leetcode:44. 通配符匹配
给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配. '?' 可以匹配任何单个字符. '*' 可以匹配任意字符串(包括空字符串). 两个字符串完全匹配才算 ...
- LeetCode 44. 通配符匹配(DP)
1. 题目 给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配. '?' 可以匹配任何单个字符. '*' 可以匹配任意字符串(包括空字符串). 两个字符串 ...
- LeetCode 43字符串相乘44通配符匹配
原创公众号:bigsai,回复进群加入力扣打卡群. 字符串相乘 题目描述: 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形 ...
- LeetCode 44.通配符匹配(动态规划)
题目描述 给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 '?' 和 '' 的通配符匹配. '?' 可以匹配任何单个字符. '' 可以匹配任意字符串(包括空字符串). 两个字符串完全匹配才 ...
- LeetCode实战:环形链表 II
背景 为什么你要加入一个技术团队? 如何加入 LSGO 软件技术团队? 我是如何组织"算法刻意练习活动"的? 为什么要求团队的学生们写技术Blog 题目英文 Given a lin ...
- LeetCode实战:排序链表
背景 为什么你要加入一个技术团队? 如何加入 LSGO 软件技术团队? 我是如何组织"算法刻意练习活动"的? 为什么要求团队的学生们写技术Blog 题目英文 Sort a link ...
- LeetCode实战:除自身以外数组的乘积
背景 为什么你要加入一个技术团队? 如何加入 LSGO 软件技术团队? 我是如何组织"算法刻意练习活动"的? 为什么要求团队的学生们写技术Blog 题目英文 Given an ar ...
最新文章
- ICCV 2021 | 国科大提出首个CNN和Transformer双体主干网络!Conformer准确率高达84.1%!...
- 2.2 Java的基本数据类型
- css语言基础--css的选择符语法
- SAP OData执行的后台跟踪工具
- 阿里P8亲自讲解!java实例变量和类变量
- CentOS(rsync+crond实现定时备份)
- html cellpadding属性,HTML table标签 cellpadding 属性
- 最大似然估计程序c语言,极大似然估计(示例代码)
- 计算机房管理制度通知,计算机房管理制度.doc
- xp系统怎么telnet服务器,xp操作系统如何开启telnet服务?
- 扩展卡尔曼滤波python_扩展卡尔曼滤波EKF与多传感器融合
- android连接php还是asp,ASP或PHP如何判断是从电脑还是手机客户端访问页面的思路...
- 如何用ppt做自我介绍
- 163微信邮箱在哪里找到,你知道微信邮箱地址在哪里找到吗
- css3中-moz、-ms、-webkit、 - o -各什么意思
- 震撼来袭!剪映专业版出内测了!最新功能抢先使用!
- 支付宝自动续费申请PHP,APP是如何实现自动续费的?
- 天猫精灵连接蓝牙摸索4 STM32单片机和TG7100B实现数据上发和播报
- 服务注册与发现(下)
- 【whistle】Whistle 安装及使用