콤푸타/프로그래밍

[알고리즘] 개미수열(look and say sequence)

어둠의다크 2024. 7. 7. 07:56
얼마 전 개미 수열 이라는걸 알게 됐는데, 베르나르 베르베르의 개미 라는 소설에서 처음 등장했다하는(사실인지 아닌지는 잘 몰라요..) 수열로 쉽게 설명하자면 다음과 같다.
 
초항이 1 또는 임의의 수이고 다음 항부터는 이전 항에 어떤 숫자가 몇번이나 연속되었는지 같이 작성해준다.
예를들면 이런식이다.
 
1    <- 초항
11    <- 이전 항에 1이 1번
21    <- 이전 항에 1이 2번
1211    <- 이전 항에 2가 1번, 1이 1번
111221    <- 이전항에 1이 1번,  2가 1번, 1이 2번
 
이런 식이다.
횟수가 먼저오느냐, 숫자 값이 먼저 오느냐에 따라서 작성법에 차이는 있지만 크게 중요한건 아니고.. 이런 개미수열을 작성하는 여러가지 방법이 있다는 것이다.
 
그 중 하나가 정규식을 활용한 방법이었는데 생각해보면 정수 연산이 아니고 문자열 처리이기 때문에 효율은 둘째치고 정규식을 쓰면 당연히 가능할것이란 생각이 들었다.
 
다음은 파이썬 정규식으로 작성된 개미수열 코드다
각각 인자로 이전 항의 문자열을 받아 다음 개미수열을 만들어낸다.

 

어떻게 그렇게 동작하는지는 여러분이 한번 공부해보면 좋지않을까! ㅎㅎ
 
import re

def re_sub(_s):

    # "그룹 \d와 같은것들을 찾아서, 람다함수로 리플레이스"
    # 길이가 1인 경우가 있어서 +는 사용x.
    # group() = group(0) 매치된 전체 문자열
    # match 객체의 regs 멤버는 순서대로 그룹 위치에 대한 정보를 갖고있는 튜플 리스트, 0번은 매치된 전제 문자열 인덱싱
    # sub는 재귀적으로 동작
    s = re.sub(r'(\d)(\1*)', lambda x: str(len(x.group(0)))+x.group(1), _s)
    return s


def re_findall(_s):
    ras1 = re.compile(r'(\d)(\1*)')
    #ras2 = re.compile(r'((\d)\2*)')

    res1 = ras1.findall(_s)
    # res2 = ras2.findall(_s)

    # findall은 tuple list 반환
    s1 = "".join([str(len(i+j))+i for i, j in ras1.findall(_s) ])
    # s2 = "".join([str(len(i))+j for i, j in ras2.findall(_s) ])

    return s1
 
 

쓰다보니  정규식이 뭔지도 얘기안하고 내 하고싶은말만 한것 같네요.

 
근데 정규식은 설명을 잘 한 글들이 워낙 많아서 내가 굳이 해야할까 싶기도하고..