本篇图文是LSGO软件技术团队组织的 第二期基础算法(Leetcode)刻意练习训练营 的打卡任务。本期训练营采用分类别练习的模式,即选择了五个知识点(数组、链表、字符串、树、贪心算法),每个知识点选择了 三个简单、两个中等、一个困难 等级的题目,共计三十道题,利用三十天的时间完成这组刻意练习。
本次任务的知识点:字符串
字符串或串(string) 是由数字、字母、下划线组成的一串字符。一般记为 s = “a1a2...an”(n >= 0)
。它是编程语言中表示文本的数据类型。
通常以串的整体作为操作对象,如:在串中查找某个子串在该串中首次出现的位置、在串的某个位置上插入一个子串以及删除一个子串等。两个字符串相等的充要条件是:长度相等,并且各个对应位置上的字符都相等。串通常以顺序的方式进行存储与实现。
- 题号:10
- 难度:困难
- https://leetcode-cn.com/problems/regular-expression-matching/
给你一个字符串s
和一个字符规律p
,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串s
的,而不是部分字符串。
说明:
s
可能为空,且只包含从 a-z 的小写字母。p
可能为空,且只包含从 a-z 的小写字母,以及字符 ‘.’ 和 ‘*’。示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:
s = "aa"
p = "a*"
输出: true
解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:
输入:
s = "ab"
p = ".*"
输出: true
解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:
输入:
s = "aab"
p = "c*a*b"
输出: true
解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 5:
输入:
s = "mississippi"
p = "mis*is*p*."
输出: false
第一种:回溯法
思路:这种匹配思路其实就是不断地减掉s
和p
的可以匹配首部,直至一个或两个字符串被减为空的时候,根据最终情况来得出结论。
如果只是两个普通字符串进行匹配,按序遍历比较即可:
if (s[i] == p[i])
如果正则表达式字符串p只有一种"."一种特殊标记,依然是按序遍历比较即可 :
if (s[i] == p[i] || p[i] == '.')
上述两种情况实现时还需要判断字符串长度和字符串判空的操作。
但是,"*"这个特殊字符需要特殊处理,当p的第i个元素的下一个元素是星号时会有两种情况:
i
元素需要出现0次,我们就保持s
不变,将p
的减掉两个元素,调用IsMatch
。例如s:bc、p:a*bc
,我们就保持s
不变,减掉p
的"a*",调用IsMatch(s:bc,p:bc)
。i
元素需要出现一次或更多次,先比较i
元素和s
首元素,相等则保持p
不变,s
减掉首元素,调用IsMatch
。例如s:aabb、p:a*bb
,就保持p
不变,减掉s
的首元素,调用IsMatch(s:abb,p:a*bb)
。此时存在一些需要思考的情况,例如s:abb、p:a*abb
,会用两种方式处理:
i
元素和s
首元素,发现相等就会减掉s
的首字符,调用IsMatch(s:bb,p:a*abb)
。在按照上述第一种情况减去p
的两个元素,调用IsMatch(s:bb,p:abb)
,最终导致false
。p
的两个元素,调用IsMatch(s:abb,p:abb)
,最终导致true
。所以说这算是一种暴力方法,会将所有的情况走一边,看看是否存在可以匹配的情况。
public class Solution
{
public bool IsMatch(string s, string p)
{
//若正则串p为空串,则s为空串匹配成功,s不为空串匹配失败。
if (string.IsNullOrEmpty(p))
return string.IsNullOrEmpty(s) ? true : false;
//判断s和p的首字符是否匹配,注意要先判断s不为空
bool headMatched = string.IsNullOrEmpty(s) == false
&& (s[0] == p[0] || p[0] == '.');
if (p.Length >= 2 && p[1] == '*')
{
//如果p的第一个元素的下一个元素是*,则分别对两种情况进行判断
return IsMatch(s, p.Substring(2)) ||
(headMatched && IsMatch(s.Substring(1), p));
}
else if (headMatched)
{
//否则,如果s和p的首字符相等
return IsMatch(s.Substring(1), p.Substring(1));
}
else
{
return false;
}
}
}
Python 语言
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if len(p) == 0:
return True if len(s) == 0 else False
headMatched = len(s) != 0 and (s[0] == p[0] or p[0] == '.')
if len(p) >= 2 and p[1] == '*':
return self.isMatch(s, p[2:]) or (headMatched and self.isMatch(s[1:], p))
elif headMatched == True:
return self.isMatch(s[1:], p[1:])
else:
return False
往期活动
LSGO软件技术团队会定期开展提升编程技能的刻意练习活动,希望大家能够参与进来一起刻意练习,一起学习进步!
我是 终身学习者“老马”,一个长期践行“结伴式学习”理念的 中年大叔。
我崇尚分享,渴望成长,于2010年创立了“LSGO软件技术团队”,并加入了国内著名的开源组织“Datawhale”,也是“Dre@mtech”、“智能机器人研究中心”和“大数据与哲学社会科学实验室”的一员。
愿我们一起学习,一起进步,相互陪伴,共同成长。
后台回复「搜搜搜」,随机获取电子资源!
欢迎关注,请扫描二维码: