Leetcode 10 Regular Expression Matching 简单正则匹配
难度: Hard 这道题要求我们实现简单的正则表达式的匹配,只要求普通字符 . *的匹配,了解正则的同学都清楚,.代表任意单个字符,*代表0个或多个前面的字符,比如a*可以匹配到空字符串,也可以匹配 a,aaa等等. 题目还要求,我们判定正则是否匹配给定的字符串,要判定整个字符串,而不是其中一部分匹配就算ok. 这是个典型的动态规划的题,作者在leetcode出来之前几乎不做算法,本着死磕到底不看答案不看别人解答的精神,我尝试了不止一种解法,这里贴出两个AC的解法. 第一个AC的解法主要思路为:
代码如下 public class Solution2 { public class Symbol { public Symbol() { rep = false; } public Symbol(char f,boolean s) { c = f; rep = s; } public char c; public boolean rep; } public class Pair<T> { public T first; public T second; public Pair() { first = null; second = null; } public Pair(T _f,T _s) { first = _f; second = _s; } } /** * AC,but slow */ public boolean isMatch(String s,String p) { // parse pattern List<Symbol> pl = new ArrayList<Symbol>(); int i = 0; while (i < p.length()) { char c; boolean rep = false; char a = p.charAt(i); if (a != '*') { c = a; } else { // regex wrong return false; } i++; if (i < p.length() && p.charAt(i) == '*') { rep = true; i++; } pl.add(new Symbol(c,rep)); } // do match Stack<Pair<Integer>> q = new Stack<Pair<Integer>>(); q.push(new Pair<Integer>(0,0)); while (!q.isEmpty()) { Pair<Integer> pr = q.pop(); if (isMatch(s,pr.first,pl,pr.second,q)) { return true; } } return false; } private boolean isMatch(String s,int sPos,List<Symbol> pl,int pPos,Stack<Pair<Integer>> q) { while (sPos < s.length() && pPos < pl.size()) { Symbol sym = pl.get(pPos); if (sym.rep) { if (sym.c == '.' || sym.c == s.charAt(sPos)) { q.push(new Pair<Integer>(sPos,pPos + 1)); q.push(new Pair<Integer>(sPos + 1,pPos)); } else { q.push(new Pair<Integer>(sPos,pPos + 1)); } return false; } else { if (sym.c != s.charAt(sPos) && sym.c != '.') { return false; } } sPos++; pPos++; } if (sPos < s.length()) { return false; } if (pPos < pl.size()) { while (pPos < pl.size()) { if (!pl.get(pPos).rep) { return false; } pPos++; } } return true; } public static void main(String[] args) { Solution2 s = new Solution2(); System.out.println(s.isMatch("aa","a")); System.out.println(s.isMatch("aa","aa")); System.out.println(s.isMatch("aaa","aa")); System.out.println(s.isMatch("aa","a*")); System.out.println(s.isMatch("aa",".*")); System.out.println(s.isMatch("aab","c*a*b")); System.out.println(s.isMatch("ab",".*")); System.out.println(s.isMatch("aaab",".*ab")); System.out.println(s.isMatch("aaa","a*a")); System.out.println(s.isMatch("aaa","aaab*")); System.out.println(s.isMatch("bbab","b*")); System.out.println(s.isMatch("bbab","a*")); System.out.println(s.isMatch("bbab","b*a*")); System.out.println(s.isMatch("bbab","....")); System.out.println(s.isMatch("abbabaaaaaaacaa","a*.*b.a.*c*b*a*c*")); System.out.println(s.isMatch("bbabaaaaaaacaa","b.a.*c*b*a*c*")); System.out.println(s.isMatch("baaaaaaacaa",".*c*b*a*c*")); System.out.println(s.isMatch("caa","c*b*a*c*")); System.out.println(s.isMatch("caa","c*b*a*")); System.out.println(s.isMatch("a","a*b*")); System.out.println(s.isMatch("a","a*.*")); System.out.println(s.isMatch("ab","a*b")); System.out.println(s.isMatch("b",".*b")); System.out.println(s.isMatch("ab",".*b")); System.out.println(s.isMatch("aaaaaaaaaaaaab","a*a*a*a*a*a*a*a*a*a*a*a*b")); } }
于是尝试了第二个解法,跟第一个很不同,主要思路为:
public class Solution3 { /** * AC,fast enough */ public boolean isMatch(String s,String p) { List<String> plist = new ArrayList<String>(); int pi = 0; while (pi < p.length()) { if (p.charAt(pi) == '*') { // regex wrong return false; } if (pi + 1 < p.length() && p.charAt(pi + 1) == '*') { plist.add(p.substring(pi,pi + 2)); pi += 2; } else { plist.add(p.substring(pi,pi + 1)); pi += 1; } } return isMatch(s,s.length(),plist,plist.size()); } /** * * @param s string to be matched * @param ss start position of s (inclusive) * @param se end position of s (exclusive) * @param plist pattern list * @param ps start position of plist (inclusive) * @param pe end position of plist (exclusive) * @return */ public boolean isMatch(String s,int ss,int se,List<String> plist,int ps,int pe) { if (ps == pe) { if (ss != se) { return false; } else { return true; } } while (ps < pe && plist.get(ps).length() == 1 && ss < se) { char c = plist.get(ps).charAt(0); if (c != '.' && c != s.charAt(ss)) { return false; } ss++; ps++; } while (ps < pe && plist.get(pe - 1).length() == 1 && ss < se) { char c = plist.get(pe - 1).charAt(0); if (c != '.' && c != s.charAt(se - 1)) { return false; } se--; pe--; } if (ps == pe && ss == se) { return true; } if (ps == pe) { return false; } if (ss == se) { for (int i = ps; i < pe; i++) { if (plist.get(i).length() == 1) { return false; } } return true; } // select one single sub-pattern int pi = 0; for (pi = ps; pi < pe; pi++) { if (plist.get(pi).length() == 1) { break; } } if (pi < pe) { // found single sub-pattern char c = plist.get(pi).charAt(0); for (int si = ss; si < se; si++) { if (c == '.' || s.charAt(si) == c) { boolean b1 = isMatch(s,ss,si,ps,pi); if (!b1) { // early termination continue; } boolean b2 = isMatch(s,si + 1,se,pi + 1,pe); if (b2) { return true; } } } return false; } // single sub-pattern not found,all * patterns // do greedy for (pi = ps; pi < pe; pi++) { char c = plist.get(pi).charAt(0); if (c == '.') { // will consume all return true; } while (ss < se && (s.charAt(ss) == c)) { ss++; } if (ss == se) { return true; } } return false; } public static void main(String[] args) { Solution3 s = new Solution3(); System.out.println(s.isMatch("aa","a*a*a*a*a*a*a*a*a*a*a*a*b")); } }
以上是我的解法,不知道是否有更好更清晰的解. 另: 这道题跟 Leetcode 44 通配符匹配很相似,稍后给出Leetcode 44的解. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |