본문 바로가기

DataStructures & Algorithm (Practice)

Leetcode #10 Regular Expression Matching

Writer: Steven, Lee

Date: 12/19, Wednesday

Purpose: Solving #10 Regular Expression Matching

Level: Hard

Percentage: 24.6% have solved this problem

Time: it took me 7 hours :)


Dynamic programming reference *  => https://www.youtube.com/watch?v=vYquumk4nWw


한국어 버전은 밑에 있습니다.


* Caution * Before you read the solution that I used, you need to solve this problem by yourself 


* Description *


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 *


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 precedeng 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


* What is the Idea? *

 Let's solve this problem with the specific  example, s = "aab" and p = "c*a*b".

1. we need to make a matrix like this.

         x     c     *     a     *     b

x

a

a

b      


2. Then, we need to set a default value wheater it's true or not

            x     c     *    a     *     b

    x      T     F    T    F     T     F

    a     F

    a     F

    b     F 


3. Next, we need to consider two cases of this problem 

 First, two alphabets of given s and p are same. or the alphabet of p is '.' then it should be true if the previous two chars are same. 

 =>if (s[i-1] == p[j-1] or p[j-1] == '.'), then T[i][j] should be T[i-1][j-1];

 Second, if p[j] is '*' then, it's a quite tricky thing. . because '*' can be multiple chars of previous char or it can be zero occurrence like this. 

"a*" can be "aaaaaaaa" or "" also ".*" can be "abcdef", "aaabcde", ""

is it difficult?? right. Let's keep doing. so we have to  deal with these cases 

=> if( p[j] == '*' ) and if(s[i-1] == p[j-2] || p[i-1] == '.'), 

                                                       then T[i][j] should be T[i-1][j] or T[i][j-2];

                                           else    then, T[i][j] should be T[i][j-2];


4. Final matrix looks like this. :)

            x     c     *    a     *     b

    x      T     F    T    F     T     F

    a      F     F    F    T    T     F

    a      F     F    F    F    T     F

    b      F     F    F    F    F   *T*  <= this might be T[s,length()][p.length()];


so return T[s.length()][p.length()];


5. clear :)


* Check *
you can check out your answer on this site.

https://leetcode.com/problems/regular-expression-matching/


(한국어)


* 난이도는 어려움입니다.
* 오직 24.6%만이 이 문제를 풀었습니다.
* 저는 7시간 정도가 걸렸습니다. ^^/

동적계획법을 이용하는 것을 추천합니다 => https://www.youtube.com/watch?v=vYquumk4nWw (참고자료)

* 주의 *  솔루션을 읽기 전에 스스로 문제를 푸실 수 있어야 합니다.


* 지문 *

문자열 input s와 패턴 문자열인 p가 주어집니다. 이 패턴 문자열은 regular expression matching이 '.'와 '*' 함께 가능하게 되어있습니다.

 '.'은 어떤 하나의 문자로 매칭이 될 수 있습니다. 

 '*'은 바로 이전의 문자를 없는 것으로 매칭을 할 수 있게 하며 혹은 그 문자가 여러번 나오는 것을 매칭이 될 수 있도록 합니다.

 노트: s는 오직 a-z 만 들어옵니다. p는 a-z와 '.', '*'가 들어올 수 있습니다.


s와 p가 매칭이 되면 true를 반환하고 매칭이 안되면 false를 반환하세요.


* 예시 *

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 precedeng 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


* 아이디어 *

  이 문제를 어떤 예시로 접근하겠습니다. s는 "aab"이고 p는 "c*a*b"

1. 먼저 메트릭스를 다음과 같이 만듭니다.

           x     c     *     a     *     b

x

a

a

b      


2. 그런 후, 다음과 같이 각 값마다 true인지 false인지 초기값을 줍니다. 

            x     c     *    a     *     b

    x      T     F    T    F     T     F

    a     F

    a     F

    b     F 


3. 다음으로, 이 문제에서 두 가지 케이스를 고려해야 합니다.

     첫 번째, 주어진 s와 p에서 얻은 두 개의 알파벳이 동일하다면 혹은 p에서 얻은 알파벳이 '.'고 이전의 두 개의 p와 s의 chars이 같으면 이것은 true입니다.

     =>if (s[i-1] == p[j-1] or p[j-1] == '.'), then T[i][j]은 T[i-1][j-1]이 되어야 합니다.

    두 번째, 만약 p[j]가 '*'이면 문제는 꽤 어렵게 됩니다. . 왜냐하면 '*'은 바로 이전의 문자가 여러번 올 수가 있고 아니면 이전의 문자가 없을 수 있습니다. 예를 들어보면, "a*"은 "aaaaaaaa" or ""가 될 수 있고 또한 ".*"은 "abcdef", "aaabcde", "" 될 수 있습니다.

꽤 어렵죠?? 맞아요. 계속 해볼까요?? 그래서 우리들은 이 모든 경우의 수를 생각해야 합니다.

=> if( p[j] == '*' ) and if(s[i-1] == p[j-2] || p[i-1] == '.'), 

                                                       then T[i][j]은 T[i-1][j] or T[i][j-2]입니다.

                                           else    then, T[i][j]은 T[i][j-2]입니다.


4. 마지막 메트릭스는 다음과 같이 생겼습니다.

            x     c     *    a     *     b

    x      T     F    T    F     T     F

    a      F     F    F    T    T     F

    a      F     F    F    F    T     F

    b      F     F    F    F    F   *T*  <= 이 부분은 아마도 T[s,length()][p.length()] 될 것입니다.


그래서 return T[s.length()][p.length()]입니다.


5. 완성


* Check *
이 사이트에서 정답의 유무를 확인하실 수 있습니다.

https://leetcode.com/problems/regular-expression-matching/



Code & 코드

You need to read the code by yourself

스스로 코드를 읽을 줄 알아야 합니다.



public class RegularExpressionMatching_10 {
public static boolean isMatch(String s, String p) {
boolean dp[][] = new boolean[s.length()+1][p.length()+1];
char sChar, pChar;
dp[0][0] = true;
for(int i = 2 ; i <= p.length() ; i++) {
if(p.charAt(i - 1) == '*' && dp[0][i-2]) dp[0][i] = true;
}
for(int i = 1 ; i <= s.length(); i++) {
sChar = s.charAt(i-1);
for(int j = 1 ; j <= p.length() ; j++) {
pChar = p.charAt(j-1);
if(sChar == pChar || pChar == '.') dp[i][j] = dp[i-1][j-1];
else if(pChar == '*') {
if(sChar == p.charAt(j-2) || p.charAt(j-2) == '.') dp[i][j] = dp[i-1][j] || dp[i][j-2];
else dp[i][j] = dp[i][j-2];
}
}
}
return dp[s.length()][p.length()];
}
public static void main(String[] args) {
String s = "aab";
String p = "c*a*c*b";
boolean result = isMatch(s, p);
System.out.println(result);
}
}