#数据结构与算法学习笔记#剑指Offer50:正则表达式匹配 + 动态规划(Java、C/C++)

234 篇文章 1 订阅
80 篇文章 0 订阅

2019.4.20更新

刷了LeetCode一道原题,靠着回忆手撕了递归的方法,没想到在Leetcode上效率排名很低,才发现这道题可以用DP大法来解。参考我新发的博文:LeetCode(10):正则表达式匹配 Regular Expression Matching(Java)

 

2019.2.19     《剑指Offer》从零单刷个人笔记整理(66题全)目录传送门

一开始做这道正则表达式题不断用判别和循环,理了一大堆逻辑还是没法满足所有特殊情况,最后才知道要用递归做。

需要注意的是,字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。比如当表达式pattern等于“.*”的时候,输入字符str可以为任意个字符(包括空“”)。具体递归思路如下:

首先设定递归的终止条件:

1.若str和pattern同时前进至最后一个字符,则说明完全匹配,返回true。

2.若pattern比str先进行到尾部,则匹配失败,返回false。(这里注意str可以先进行到尾部,比如str="",pattern={.*})

递归情况分类:

1.pattern下一个字符存在且是‘*’号,考虑两种情形:

1-1 str当前字符与pattern当前字符匹配,考虑可能是pattern当前字符出现0次或1次或多次的情况,递归分别进行0次(pattern+2)、1次(pattern+2、str+1)、多次(pattern、str+1),其中一种满足即可(逻辑或)。

1-2 str当前字符与pattern当前字符不匹配,只可能是pattern当前字符出现0次的情况,pattern跳过两个字符,pattern+2递归继续进行。

2.pattern下一个字符不是‘*’号,且当前字符匹配或当前字符为‘.’号,当作匹配成功,pattern+1,str+1递归继续进行。

3.其他情况只可能匹配失败,返回false。


题目描述

请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配


Java实现:

/**
 * 
 * @author ChopinXBP
 * 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。
 * 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配。
 *
 */

public class Match_51 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		char[] str = {'a', 'a', 'a'};
		char[] str2 = {'a', 'a', '.', 'a'};
		char[] pattern1 = {'a', '.', 'a'};
		char[] pattern2 = {'a', 'b', '*', 'a', 'c', '*', 'a'};
		char[] pattern3 = {'a', 'b', '*', 'a'};
		System.out.println(match(str, pattern1));
		System.out.println(match(str, pattern2));
		System.out.println(match(str2, pattern3));
		
		char[] str4 = new char[0];
		char[] pattern4 = {'.', '*'};
		System.out.println(match(str4, pattern4));
	}
	
    public static boolean match(char[] str, char[] pattern)
    {
    	if(str == null && pattern == null)return true;
        if(str != null && pattern == null)return false;
        
        int stridx = 0;
        int patidx = 0;
        return Solution(str, pattern, stridx, patidx);
    }

    public static boolean Solution(char[] str, char[] pattern, int stridx, int patidx) {
    	
    	int strlen = str.length;
    	int patlen = pattern.length;
    	//递归终止条件:从头到尾匹配成功
    	if(stridx == strlen && patidx == patlen) {
    		return true;
    	}
    	//pattern先到尾部,匹配失败(可以str先到尾,例如str="",pattern={.*})
    	else if(stridx != strlen && patidx == patlen) {
    		return false;
    	}
    	//pattern下一个字符是*号
    	else if(patidx + 1 < patlen && pattern[patidx + 1] == '*') {
    		//str当前字符匹配,考虑可能是pattern当前字符出现0次或1次或多次的情况
    		if(stridx != strlen && (pattern[patidx] == '.' || str[stridx] == pattern[patidx])) {
    			return Solution(str, pattern, stridx, patidx + 2)			//出现0次
    					|| Solution(str, pattern, stridx + 1, patidx + 2)	//出现1次
    					|| Solution(str, pattern, stridx + 1, patidx);		//出现多次
    		}
    		//str当前字符不匹配,只可能是pattern当前字符出现0次的情况
    		else {
    			return Solution(str, pattern, stridx, patidx + 2);
    		}
    		
    	}
    	//pattern下一个字符不是*号,且当前字符匹配或当前字符为.号
    	else if(stridx != strlen && (pattern[patidx] == '.' || pattern[patidx] == str[stridx])) {
    		return Solution(str, pattern, stridx + 1, patidx + 1);
    	}
    	else {
    		return false;
    	}
    }
}

C++实现示例:

class Solution {
public:
    bool match(char* str, char* pattern)
    {
        if (*str == '\0' && *pattern == '\0')
            return true;
        if (*str != '\0' && *pattern == '\0')
            return false;
        //if the next character in pattern is not '*'
        if (*(pattern+1) != '*')
        {
            if (*str == *pattern || (*str != '\0' && *pattern == '.'))
                return match(str+1, pattern+1);
            else
                return false;
        }
        //if the next character is '*'
        else
        {
            if (*str == *pattern || (*str != '\0' && *pattern == '.'))
                return match(str, pattern+2) || match(str+1, pattern);
            else
                return match(str, pattern+2);
        }
    }
};

#Coding一小时,Copying一秒钟。留个言点个赞呗,谢谢你#

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值