라떼는말이야

[프로그래머스 lv2] 짝지어 제거하기 (파이썬) 본문

알고리즘/코딩 테스트

[프로그래머스 lv2] 짝지어 제거하기 (파이썬)

MangBaam 2021. 6. 21. 16:11
반응형

2017 팁스타운 문제이다

문제설명

짝지어 제거하기는, 알파벳 소문자로 이루어진 문자열을 가지고 시작합니다. 먼저 문자열에서 같은 알파벳이 2개 붙어 있는 짝을 찾습니다. 그다음, 그 둘을 제거한 뒤, 앞뒤로 문자열을 이어 붙입니다. 이 과정을 반복해서 문자열을 모두 제거한다면 짝지어 제거하기가 종료됩니다. 문자열 S가 주어졌을 때, 짝지어 제거하기를 성공적으로 수행할 수 있는지 반환하는 함수를 완성해 주세요. 성공적으로 수행할 수 있으면 1을, 아닐 경우 0을 리턴해주면 됩니다.

예를 들어, 문자열 S = baabaa 라면

b aa baa → bb aa → aa →

의 순서로 문자열을 모두 제거할 수 있으므로 1을 반환합니다.

 

제한사항

  • 문자열의 길이 : 1,000,000이하의 자연수
  • 문자열은 모두 소문자로 이루어져 있습니다.

입출력 예

입출력 예

입출력 예 설명

입출력 예 #1
    위의 예시와 같습니다.
입출력 예 #2
    문자열이 남아있지만 짝지어 제거할 수 있는 문자열이 더 이상 존재하지 않기 때문에 0을 반환합니다.

 


첫 번째 시도

def solution(s):
    idx = 0
    while idx >= 0 and idx < len(s) - 1:
        idx += 1
        if s[idx - 1] == s[idx]:
            s = s[:idx - 1] + s[idx + 1:]
            idx = 0

    return 0 if len(s) else 1

첫 번째 시도에서는 실제로 문자열에서 연속된 문자를 제거하며 결과를 만들어냈다.

s[idx - 1]와 s[idx]를 비교하며 만약 같다면 s에 s[idx - 1]과 s[idx]를 제거한 값을 저장한다.

그리고 다시 앞부터 검사하기 위해서 idx 를 0으로 재설정한다.

 

최종적으로 s가 ""(공백)이면 1을 리턴하고, s의 길이가 0보다 크다면 0을 반환하는 알고리즘을 짰다.

 

정확성, 효율성 테스트 결과1

그러나 결과는 위와 같았다.

 

 

 


두 번째 시도

def solution(s):
    if len(s) % 2 == 1: return 0 # 문자가 홀수개면 무조건 남는다.
    if len(s) == 2: # 문자가 2개이고, 같은 문자라면 무조건 가능
        return 1 if s[0] == s[1] else 0
    
    stack = [s[0], s[1]]
    
    for v in s[2:]:
        stack.append(v)
        if len(stack) >= 2 and stack[-1] == stack[-2]:
            stack.pop()
            stack.pop()
            
    return 0 if len(stack) else 1

 

두 번째 시도에서는 스택을 활용했다.

 

첫 번째 시도에서는 중복된 문자가 제거될 때마다 처음부터 다시 검사를 해서 비효율적이었다.

두 번째 시도에서는 스택을 이용해 스택의 top(마지막에 저장된 문자)과 새로 입력될 문자를 비교해서 같은 문자라면 제거하고, 아니라면 스택에 남겨둔다.

최종적으로 스택에 문자가 남아있다면 모두 제거에 실패한 것이고, 스택이 비었다면 모두 제거에 성공한 것이다.

 

추가적으로 문제의 조건에 1개 이상의 문자라고 했는데, 문자가 홀수 개라면 짝이 없는 문자가 존재하기 때문에 무조건 실패한다.

또한 문자가 2개일 경우 두 문자만 비교해서 같다면 성공, 다르다면 실패이므로 해당 조건도 추가했다.

 

정확성, 효율성 테스트 결과2


세 번째 시도 (성공)

def solution(s):
    if len(s) % 2 == 1: return 0 # 문자가 홀수개면 무조건 남는다.
    if len(s) == 2: # 문자가 2개이고, 같은 문자라면 무조건 가능
        return 1 if s[0] == s[1] else 0
            
    stack = [s[0]]
    
    for v in s[1:]:
        if len(stack) > 0 and stack[-1] == v:
            stack.pop()
        else:
            stack.append(v)
            
    return 0 if len(stack) else 1

두 번째 시도에서 스택을 사용한 방법이 가장 효율적인 방법이라고 생각했고, 두 번째 시도에서 무조건 값을 스택에 넣고, 상위 두개의 값을 비교하는 방법에서 스택에 삽입하지 않고, 비교 후 값이 같다면 top 값을 pop, 값이 다르다면 스택에 삽입하는 방식으로 바꿨다. (비교 방식만 바꾼 것)

 

정확성, 효율성 테스트 결과3

그런데 통과가 됐다... 흠...

리스트에 값을 삽입, 삭제 하는 것이 리스트의 크기가 크면 부담스러운 모양이다. 앞으로 코딩테스트 할 때 참고하면 좋을 것 같다.

반응형
Comments