Algorithm - regularExpressionMatching(s, p)

2 분 소요

Problem

  • https://codefights.com/interview-practice/task/Sx8ndFtwEyCRRqF7q/
  • string s가 regular expression 으로 정의된 pattern p를 따르는지를 체크하는 함수를 만들어봅니당
    • regular expression은 많이 써보지는 않았지만, 쓰다보면 편하다고들 합니다. 물론 미리 배워둘 필요는 없을 것 같고 나중에 헤헤.
  • 여기서 전부를 다 만들지는 않고, 간단히 * , . 에 대해서 만듭니다.
      • 은 바로 이전에 나온 캐릭터가 0번에서 n 번까지 나올 수 있다는 것을 표현
    • . 은 어떤 캐릭터든 될 수 있다 를 말합니다.

regular expression example

  • 예시는 대략 다음과 같지만, 사실 아래만으로 헷갈릴 수 있습니다. 구글에서 ‘정규표현식’이라고 치시면 다양한 자료들이 나오니까 간단하게 보시면 좋을 것 같아용.
    • a* : “”, “a”, “aa”, …
    • b* : “”, “b”, “bb”, …
    • ab* : a, ab, abb, abbb.
    • a*b* : “”, “a”, “ab”, “abbb”, “aaabbbb”, …
    • . : a, b, c, d, e, ….
    • .* : can be any string.

solution

  • 우선 예제로 나오는 pattern에서는 . * 이 복잡하게 얽혀서 나오기 때문에, 입력받은 pattern을 * 로 split하는 함수를 만듭니다.
def splitPattern(p):
    if "*" in p:
        i = 0 
        j = i+1
        rs = []
        while j<len(p):
            if p[j]=="*":
                temp= p[i:j]+"*"
                if temp[:-2]!="":
                    rs.append(temp[:-2])
                rs.append(temp[-2:])
                i = j+1
                j = i+1
            else:
                j=j+1
        if i<len(p):
            rs.append(p[i:j])
        return rs
    else:
        return [p]
  • 그 다음 해당 string이 해당 pattern으로 시작하는지를 확인하는 함수를 만듭니다.
    • 여기서 pattern에는 * 가 포함되어 있지 않다고 가정했습니다.
def startWith(s, p):
    if len(s)<len(p):
        return False
    else:
        for i in range(0, len(p)):
            if p[i]=='.':
                continue
            else:
                if s[i]!=p[i]:
                    return False
        return True
  • 여기가 본 함수인데요, dynamic programming에서 가장 중요한 것은, 음 뭐 recursive라고 해도 상관없죠, 아무튼 여기서 중요한 것은 언제 break point가 걸리냐는 것인데, 가장 작을 때, 즉 우선 딱 하나의 pattern에 대해서만 완벽하게 처리하고 이후에는 다 남은 pattern에 대해서 처리하는 식으로 reduction을 하면 되는 것이긴 합니다.
  • 저는 앞서 설계한 splitPattern 이라는 함수를 활용해서 pattern을 쪼개주고 이후에는 이미 쪼개진 패턴을 argument로 입력받는 함수를 만들어 전개했습니다.

  • 여기서 제가 어려워 했던 부분은 .*부분인데요,
    • .* 은 같은 문자가 반복되지 않는 경우도 포함합니다.
      • ab, abc, abcd 모두 포함됩니다.
    • 따라서 이 부분이 조금 해결하기가 어렵죠. 물론 풀고 나면 너무 간단하기는 합니다만.
def regularExpressionMatching(s, p):
    def re_with_plst(st, ps):
        if len(ps)==1:
            if "*" in ps[0]:
                cand_lst = []
                if ps[0][0]=='.':
                    return True
                else:
                    c = ps[0][0]
                    for i in range(0, len(st)):
                        if st[i]!=c:
                            return False
                        else:
                            continue
                    return True
            else:
                if len(st)!=len(ps[0]):
                    return False
                else:
                    return startWith(st, ps[0])
        else:
            if "*" in ps[0]:
                if ps[0][0]=='.':
                    return any([re_with_plst(st[i:], ps[1:]) for i in range(0, len(st)+1)])
                else:
                    c = ps[0][0]
                    start_pos = 0
                    for i in range(0, len(st)):
                        if st[i]!=c:
                            start_pos=i
                            break
                    zero_count = re_with_plst(st, ps[1:])
                    nonzero_count = re_with_plst(st[start_pos:], ps[1:])
                    return any([zero_count, nonzero_count])
            else:
                if startWith(st, ps[0]):
                    return re_with_plst(st[len(ps[0]):], ps[1:])
                else:
                    return False
    return re_with_plst(s, splitPattern(p))

댓글남기기