LeetCode Top 100 高频算法题:10 Regular Expression Matching

LeetCode Top 100高频算法题,即LeetCode上最高频的100道求职面试算法题。小编和实验室同学之前面试找工作,也只刷了剑指offer和这top 100算法题,在实际面试中也遇到了很多LeetCode上的原题。剑指offer算法最优解之前和大家分享了,LeetCode Top 100这100道算法题,每道题小编都刷了很多遍,并且总结了一种最适合面试时手撕算法的最优解法。后续每天和大家分享一道LeetCode top 100高频算法题,以及小编总结的最优解法。

下面是第005是道算法题:

  1. 算法题顺序
    LeetCode Top 100 高频算法题系列的LeetCode算法题目就不帮大家翻译了,程序员应该需要能看懂。LeetCode算法题有一个技巧:先看每道题的example,大部分情况看完example就能理解题目意思;如果看完example还有疑惑,可以再回过头来看英文题目。这样也可以节省一点时间~

  2. 题目描述

Given an input string (s) and a pattern §, implement regular expression matching with support for ‘.’ and ‘’ where:
‘.’ Matches any single character.
'
’ Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).

简而言之,判断一个只包括字符 以及 ‘.’ 和 ‘*’ 的正则表达式是否能够完整匹配输入的字符串
2. Examples
1th example

Input: s = “aa”, p = “a”
Output: false
Explanation: “a” does not match the entire string “aa”.

2th example

Input: s = “aa”, p = “a*”
Output: true
Explanation: ‘*’ means zero or more of the preceding element, ‘a’. Therefore, by repeating ‘a’ once, it becomes “aa”.

3th example

Input: s = “ab”, p = “."
Output: true
Explanation: ".
” means “zero or more (*) of any character (.)”.

4th example

Input: s = “aab”, p = “cab”
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, it matches “aab”.

5th example

Input: s = “mississippi”, p = “misisp*.”
Output: false

  1. Constraints(输入的数据约束)

0 <= s.length <= 20
0 <= p.length <= 30
s contains only lowercase English letters.
p contains only lowercase English letters, ‘.’, and ‘’.
It is guaranteed for each appearance of the character '
’, there will be a previous valid character to match.

解析
在LeetCode上本题属于Hard难度。这道题也是一道典型的动态规划类型题目,动态规划类型题目非常重要,这类题目也是面试中的常客!!
直接上代码,代码中有详细的注释;

class Solution {
    /*
    dp[i+1][j+1]:s.subString(0,i+1)是否匹配p.substring(0,j+1),即前i个字符能否被pattern的前j个字符匹配
       初始化:dp[0][0]表示空pateen匹配空字符串,true
              i>=1,dp[i][0]应该为false, 因为空的pattern不能匹配任何非空的字符串,不过dp默认就是false
              i>=1,dp[0][i],取决于p.charAt(i-1)是否为*,以及dp[0][i-2]是否为true(即s.substring(0,i-2)是否可以匹配空串,s.charAt(i-2)不重要,因为可出现0次。                                                                                                                                  为可出现0次。
              
dp[0][i]表示当前的pattern是否可以匹配 “”空串,只有当dp[0][i-3]字符可以匹配空串并且第i-1位为*时才可以匹配空串
    1, If p.charAt(j) == s.charAt(i) :  dp[i+1][j+1] = dp[i][j];
    2, If p.charAt(j) == '.' : dp[i+1][j+1] = dp[i][j];  可以直接匹配
    
    3, If p.charAt(j) == '*': 
          here are two sub conditions:
               1   if p.charAt(j-1) != s.charAt(i) && p.charAt(i-1) != '.': dp[i+1][j+1] = dp[i+1][j-1]  // a* only counts as empty:*不能用上
               2   if p.charAt(i-1) == s.charAt(i) or p.charAt(i-1) == '.':
                             dp[i+1][j+1] = dp[i+1][j-1]   // in this case, a* counts as empty
                           or dp[i+1][j+1] = dp[i][j-1]   // in this case, a* counts as single a
                           or dp[i+1][j+1] = dp[i][j+1]    //in this case, a* counts as multiple a 
    4.其他情况表名pattern的前j个字符不能匹配上str的前i个字符
    */
    public boolean isMatch(String s, String p) {

    if (s == null || p == null) {
        return false;
    }
    boolean[][] dp = new boolean[s.length()+1][p.length()+1];//dp[s.length][p.length]:s的前length个字符能否被pattern的前length字符匹配
    dp[0][0] = true;
        
    for (int i = 0; i < p.length(); i++) {
        if (p.charAt(i) == '*' && dp[0][i-1]) {
            dp[0][i+1] = true;
        }
    }
        
        
    for (int i = 0 ; i < s.length(); i++) {
        for (int j = 0; j < p.length(); j++) {
            if (p.charAt(j) == s.charAt(i) || p.charAt(j) == '.') {
                dp[i+1][j+1] = dp[i][j];//直接匹配上
            }else if (p.charAt(j) == '*') {
                if (p.charAt(j-1) != s.charAt(i) && p.charAt(j-1) != '.') {//*无效,只能表示出现0次,
                    dp[i+1][j+1] = dp[i+1][j-1];//表示*匹配0次
                } else if(p.charAt(j-1) == s.charAt(i) || p.charAt(j-1) == '.'){//*有效,但是也可以选择匹配:0次、1次和多次
                    dp[i+1][j+1] = (dp[i+1][j-1] || dp[i][j-1] || dp[i][j+1] );
                }
            }//如果p.charAt(j) != '*',则表示patern的前j个字符不能匹配str的前i个字符,这种情况默认为false
        }
    }
    return dp[s.length()][p.length()];
}
}

/*
String match, and it is a typical DP problem.

create a two dimension table dp[s.length()+1][p.length()+1]

so dp[i][j] means whether string [0, i-1] matches pattern [0, j-1]
and dp[i+1][j+1] means whether string [0, i] matches pattern [0, j]

to initialize, dp[0][0] should be true, which means empty string matches empty string.
and dp[i][0] should be always false, when string is not empty, but the pattern is empty.
and dp[0][j] depends on whether there are ‘*, because * could match empty string, for example ‘a*’ could match an empty string

to get the value dp[i+1][j+1]:
1. the simplest way, if s[i]==p[j]|| p[j]==., that means we need to check whether s[0, i-1] matches p[0, j-1]
dp[i+1][j+1] = dp[i][j]

2. the complicated way, if(p[j]==*), that means we need to check the wildcard
the wildcard may take effective from 0 time to many times
if the wild card plays 0 time, then it matches an empty string with the previous character.
in this scenario, dp[i+1][j+1] = dp[i+1][j-1]

if the wild card plays once, then dp[i+1][j+1] = dp[i][j-1] && (s[i]==p[j-1] || p[j-1] ==.)

if the wild card plays many times, the dp[i+1][j+1] = dp[i][j+1] && (s[i]==p[j-1] || p[j-1] ==.)

3. the other scenarios, the default value “false” will be populated for the rest.
*/

其他文章

  1. 免费帮忙下载csdn和百度文库资料福利
  2. 学习笔记和学习资料汇总:前端 + 后端 + java + 大数据 + python + 100多实战项目 + C++
  3. 我的秋招经历总结:一站式秋招规划
  4. 零基础学爬虫
  5. 零基础C++学习总结

欢迎关注个人公众号【菜鸟名企梦】,公众号专注:互联网求职面经javapython爬虫大数据等技术分享:
公众号菜鸟名企梦后台发送“csdn”即可免费领取【csdn】和【百度文库】下载服务;

公众号菜鸟名企梦后台发送“资料”:即可领取5T精品学习资料java面试考点java面经总结,以及几十个java、大数据项目,资料很全,你想找的几乎都有

扫码关注,及时获取更多精彩内容。(博主985、A+学科硕士,今日头条大数据工程师)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值