zoukankan      html  css  js  c++  java
  • 0010. Regular Expression Matching (H)

    Regular Expression Matching (H)

    Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'.

    '.' Matches any single character.
    '*' Matches zero or more of the preceding element.
    

    The matching should cover the entire input string (not partial).

    Note:

    • s could be empty and contains only lowercase letters a-z.
    • p could be empty and contains only lowercase letters a-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 = "a*"
    Output: true
    Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
    

    Example 3:

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

    Example 4:

    Input:
    s = "aab"
    p = "c*a*b"
    Output: true
    Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore, it matches "aab".
    

    Example 5:

    Input:
    s = "mississippi"
    p = "mis*is*p*."
    Output: false
    

    题意

    实现一个包含'.'、'*'的正则匹配判定。

    思路

    递归法:

    递归边界为,当p空时,若s非空则返回false,若s空则返回true。(反过来s空p非空时无法作为边界,因为如果s为空,p为 ".*",则同样满足匹配)。

    当p的第二位不为 '*' 时,如果当前s和p的第一位匹配,那么只要递归判断isMatch(s.subString(1), p.subString(1))即可;
    当p的第二位为 '*' 时,说明要对p的第一位字符进行多次匹配判断,这里可以分为两种情况 (记 '*' 前字符为x):1. s的第一位与x匹配,递归判断s第一位之后的子字符串是否与p匹配 (因为 "x*" 表示x可以出现0次或多次,所以每次递归可以理解为去除了一个匹配的x);2. s的第一位与x不匹配,但与 '*' 后的第一个字符匹配,或者s的第一位既与x匹配,也与 '*' 后的第一个字符匹配,那么要判断s是否与 "x*" 之后的正则表达式相匹配。以上两种情况满足其一即可说明匹配成功。

    记忆化搜索:

    可以看到,在递归的过程中存在着许多重复的计算(即相同的s和p子串出现了多次),因此可以用一个数组将中间状态保存下来。

    动态规划:

    参考 [LeetCode] 10. Regular Expression Matching 正则表达式匹配


    代码实现

    Java

    递归

    class Solution {
        public boolean isMatch(String s, String p) {
            // 递归边界,只能以p空为判断点
            if (p.isEmpty()) {
                return s.isEmpty();
            } 
    
            boolean isFirstMatch = (!s.isEmpty() && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.'));
            if (p.length() >= 2 && p.charAt(1) == '*') {
                return ((isFirstMatch && isMatch(s.substring(1), p)) || isMatch(s, p.substring(2)));
            } else {
                return isFirstMatch && isMatch(s.substring(1), p.substring(1));
            }
        }
    }
    

    记忆化搜索优化

    class Solution {
        public boolean isMatch(String s, String p) {
            return isMatch(s, 0, p, 0, new int[s.length() + 1][p.length() + 1]);
        }
    
        private boolean isMatch(String s, int sHead, String p, int pHead, int[][] record) {
            if (pHead == p.length()) {
                return sHead == s.length();
            }
    
            if (record[sHead][pHead] != 0) {
                return record[sHead][pHead] == 1 ? true : false;
            }
    
            boolean matched = false;
            boolean firstMatch = sHead < s.length() && (s.charAt(sHead) == p.charAt(pHead) || p.charAt(pHead) == '.');
            if (pHead < p.length() - 1 && p.charAt(pHead + 1) == '*') {
                matched = firstMatch && isMatch(s, sHead + 1, p, pHead, record) || isMatch(s, sHead, p, pHead + 2, record);
            } else {
                matched = firstMatch && isMatch(s, sHead + 1, p, pHead + 1, record);
            }
    
            record[sHead][pHead] = matched ? 1 : -1;
            return matched;
        }
    }
    

    动态规划

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

    JavaScript

    /**
     * @param {string} s
     * @param {string} p
     * @return {boolean}
     */
    var isMatch = function (s, p) {
      if (p.length === 0) {
        return s.length === 0
      }
    
      let firstMatch = s.length !== 0 && (s[0] === p[0] || p[0] === '.')
    
      if (p.length >= 2 && p[1] === '*') {
        return (firstMatch && isMatch(s.slice(1), p)) || isMatch(s, p.slice(2))
      } else {
        return firstMatch && isMatch(s.slice(1), p.slice(1))
      }
    }
    
  • 相关阅读:
    108.Convert Sorted Array to Binary Search Tree
    111.Minimum Depth of Binary Tree
    118.Pascal's Triangle
    122.Best Time to Buy and Sell Stock II
    35.搜索插入位置
    OSI参考模型
    虚拟机访问tomcat
    linux输入ifconfig找不到IP的解决办法
    分层协议、协议、接口、服务
    Spring Boot项目的创建
  • 原文地址:https://www.cnblogs.com/mapoos/p/13161103.html
Copyright © 2011-2022 走看看