【leetcode】Regular Expression Matching (hard) ★

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).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true

题目是让我们自己实现正则表达式中* 和 . 的匹配功能

. 匹配任意的一个字符

*  如a*是一个整体,表示有 0个a 或 1个a 或 2个a 或..... 任意多个a

如果是 .*可以匹配 0个任意字符 或一个任意字符 或 任意多个任意字符 但这些字符必须是相同的。

思路:

开始觉的跟wildcard matching差不多,后来发现不一样,wildcard matching里面*可以随意匹配,所以当遇到后面一个*之后,前面的*就可以不用管了。

而现在这道题,*只能匹配重复的字符,所以必须考虑多个*表示的范围,所以,问题的关键就在于每个 x*都表示了多少字符。

很容易想到递归,可是写完递归后我在提交的时候各种特殊情况都通不过,每次都对特殊情况加代码,结果越加越长,加到70行仍然没AC。我默默的知道我的思路肯定是有问题了...

看大神的代码,我终于知道问题在哪了。

因为我每次都是一个字符一个字符判断的,这样遇到*之后还需要判断很多*前一个字符的情况。

但大神每次都是针对p 2个字符为一组来判断的 根据*(p+1) == ‘*‘ 来区分不同的情况,一下子就容易了很多。

还有,大神的代码凡是遇到返回值是真的情况就返回答案,不再递归

class Solution {
public:
    bool matchFirst(const char *s, const char *p){
        return (*p == *s || (*p == ‘.‘ && *s != ‘\0‘));
    }

  bool isMatch(const char *s, const char *p) {
      if (*p == ‘\0‘) return *s == ‘\0‘;  //empty
  
      if (*(p + 1) != ‘*‘) {//without *
          if(!matchFirst(s,p)) return false;
          return isMatch(s + 1, p + 1);
      } else { //next: with a *
          if(isMatch(s, p + 2)) return true;    //try the length of 0
          while ( matchFirst(s,p) )       //try all possible lengths
              if (isMatch(++s, p + 2))return true;
      }
  }
};

动态规划的方法:

用dp[i][j]表示 s[0 ~ i-1] 与 p[0 ~ j - 1] 匹配的情况, 可以匹配时true 反之为 false

那么dp[i][j]只会在以下4种情况下为真:

①dp[i-1][j-1]为真,并且s[i-1]与p[j-1]匹配

②dp[i][j-1]为真,并且p[j-1]==‘*‘

③dp[i-1][j]为真, 并且p[j-1]==‘*‘ 并且 p[j-2]与s[i-1]匹配

④dp[i][j-2]为真,并且p[j-1]==‘*‘

边界:

dp[0][0] 都是空的肯定为真

dp[i][0] 字符串非空,匹配串为空,肯定为假

dp[0][j] 字符串空,匹配串非空,若p[j-1] == ‘*‘ 并且 dp[0][j-2]为真 的情况下 为真

代码是我参照大神的思路写的。

class Solution {
public:
bool isMatch(const char *s, const char *p)
    {
        int m = strlen(s);
        int n = strlen(p);
        vector<vector<bool>> dp(m+1, vector<bool>(n+1, false));
        dp[0][0] = true;
        for(int i = 1; i <= m; i++)
        {
            dp[i][0] = false;
        }
        for(int j = 1; j <= n; j++)
        {
            dp[0][j] = (p[j-1] == ‘*‘) && (j >= 2) && dp[0][j-2]; //第j个字符在p中的下标是j-1,因为是从0开始的
        }
        for(int i = 1; i <= m; i++)
        {
            for(int j = 1; j <= n; j++)
            {
                dp[i][j] = (dp[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == ‘.‘))
                       ||  (dp[i][j-1] && (p[j-1] == ‘*‘))
                       ||  (dp[i-1][j] && p[j-1] == ‘*‘ && ((j >= 2) && s[i-1] == p[j-2] || p[j-2] == ‘.‘))
                       ||  ((j >= 2) && dp[i][j-2] && (p[j-1] == ‘*‘));
            }
        }
        return dp[m][n];
    }
};
时间: 2024-08-05 07:06:42

【leetcode】Regular Expression Matching (hard) ★的相关文章

【leetcode】Regular Expression Matching

Regular Expression Matching 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). The

Leetcode 之Regular Expression Matching(31)

正则表达式的匹配,还是挺难的.可根据下一个字符是不是*分为两种情况处理,需要考虑多种情况. bool isMatch(const char *s, const char *p) { if (*p == '\0')return *s == '\0'; //如果下一个不是*(*可表示前一个字符的数量) //要么当前字符匹配,要么是.,不可跳过 if (*(p + 1) != '*') { if (*s == *p || (*p == '.' && *s != '\0')) return isM

LeetCode 10 Regular Expression Matching (正则表达式匹配)

翻译 实现支持"."和"*"的正则表达式匹配. "." 匹配支持单个字符 "*" 匹配零个或多个前面的元素 匹配应该覆盖到整个输入的字符串(而不是局部的). 该函数的原型应该是: bool isMatch(const char * s, const char * p) 示例: isMatch("aa","a") → false isMatch("aa","a

【LeetCode】数组--合并区间(56)

写在前面   老粉丝可能知道现阶段的LeetCode刷题将按照某一个特定的专题进行,之前的[贪心算法]已经结束,虽然只有三个题却包含了简单,中等,困难这三个维度,今天介绍的是第二个专题[数组] 数组(Array)是一种线性表数据结构.它用一组连续的内存空间,来存储一组具有相同类型的数据.在每一种编程语言中,基本都会有数组这种数据类型.不过,它不仅仅是一种编程语言中的数据类型,还是一种最基础的数据结构. 贪心算法回顾: [LeetCode]贪心算法--买卖股票的最佳时机II(122) [LeetC

【leetcode】Divide Two Integers (middle)☆

Divide two integers without using multiplication, division and mod operator. If it is overflow, return MAX_INT. 思路: 尼玛,各种通不过,开始用纯减法,超时了. 然后用递归,溢出了. 再然后终于开窍了,用循环,把被除数每次加倍去找答案,结果一遇到 -2147483648 就各种不行, 主要是这个数一求绝对值就溢出了. 再然后,受不了了,看答案. 发现,大家都用long long来解决溢

【leetcode】Count and Say (easy)

The count-and-say sequence is the sequence of integers beginning as follows:1, 11, 21, 1211, 111221, ... 1 is read off as "one 1" or 11.11 is read off as "two 1s" or 21.21 is read off as "one 2, then one 1" or 1211. Given an

【leetcode】Insertion Sort List (middle)

Sort a linked list using insertion sort. 思路: 用插入排序对链表排序.插入排序是指每次在一个排好序的链表中插入一个新的值. 注意:把排好序的部分和未排序的部分完全分开,指针不要有交叉. 即不会通过->next 重叠 class Solution { public: ListNode *insertionSortList(ListNode *head) { if(head == NULL) return NULL; ListNode * ans = hea

【leetcode】Combination Sum III(middle)

Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers. Ensure that numbers within the set are sorted in ascending order. Example 1

【leetcode】Reverse Linked List(easy)

Reverse a singly linked list. 思路:没啥好说的.秒... ListNode* reverseList(ListNode* head) { ListNode * rList = NULL, * tmp = NULL; while(head != NULL) { tmp = rList; rList = head; head = head->next; rList->next = tmp; } return rList; }