리스트와 pop(), enumerate의 관계

SeongGyun Hong·2025년 1월 7일

Python

목록 보기
13/34

코테 백준 9012번 오답 풀이

  • 원래 나의 코드

import sys

num = int(input())

for _ in range(num):
    answer = 'NO'
    PS_list = list(sys.stdin.readline().strip())
    print(PS_list)

    if len(PS_list) % 2:
        print(answer)

    else:
        while PS_list and (PS_list[0] == '(') and (PS_list[-1] == ')'):
            for idx, ps in enumerate(PS_list):
                print(idx, ps)
                if ps == ')':                    
                    PS_list.pop(0)
                    PS_list.pop(idx)
                    if not PS_list:
                        answer = 'YES'
                    break
        print(answer)

자꾸 에러가 나서 보니까 이게 아래와 같은 문제가 있었음...

1. 리스트 수정 시 발생하는 문제

  • 리스트 수정:
    • pop(0) 또는 pop(idx)를 호출하면 리스트가 수정됨. pop(0)은 첫 번째 요소를 제거하고 나머지 요소들이 왼쪽으로 이동. 이로 인해 리스트의 크기와 요소들의 위치가 바뀌어 후속 작업에 영향을 줄 수 있음.
  • enumerate와 리스트 수정:
    • enumerate는 리스트의 원래 인덱스를 사용해서 순회함. 리스트가 수정되어도, enumerate수정 전의 인덱스를 사용함.
    • 예를 들어, pop(0)으로 첫 번째 요소를 제거하면 나머지 요소들이 왼쪽으로 한 칸씩 이동. 그런데 enumerate인덱스를 그대로 사용하기 때문에 잘못된 요소에 접근하게 됨.

2. 문제 예시

PS_list = ['(', '(', ')', '(', ')', ')', '(', '(', '(', ')', ')', ')']

for idx, ps in enumerate(PS_list):
    print(idx, ps)
    if ps == ')':
        PS_list.pop(0)  # 첫 번째 '(' 제거
        PS_list.pop(idx)  # 해당 ')' 제거
        break
  • 초기 상태:
    • PS_list = ['(', '(', ')', '(', ')', ')', '(', '(', '(', ')', ')', ')']
    • enumerateidx=0, idx=1, idx=2로 순회하면서 ps = ')'인 경우에 첫 번째 '('')'를 제거함.
  • pop(0) 실행 후:
    • 첫 번째 '('이 제거되고 나머지 요소들은 왼쪽으로 이동.
    • 리스트가 ['(', ')', '(', ')', ')', '(', '(', '(', ')', ')', ')']로 변경됨.
  • enumerate는 여전히 원래의 인덱스(0, 1, 2)를 참조.
    • pop(0)으로 첫 번째 요소를 제거했지만, enumerate는 여전히 idx=2를 참조하면서 두 번째 요소를 삭제하려고 시도.

3. 인덱스 불일치 문제

  • 수정 후 인덱스 불일치:
    • pop(0)이나 pop(idx)로 리스트를 수정하면 그 이후 enumerate는 수정된 리스트에서 올바른 인덱스를 참조하지 않음.
    • 예를 들어, pop(0)으로 첫 번째 요소를 제거한 후에 enumerate수정된 리스트에서 이동한 인덱스를 추적하지 않음. 그래서 원래의 인덱스가 잘못 참조됨.

4. 해결 방안

  • 리스트 수정과 순회 분리:

    • 리스트 수정과 순회를 동시에 하지 않음. 수정이 필요하면 순회 중에 인덱스를 기록하고 수정이 끝난 후에 한 번에 수정하는 방식이 안전함.
  • 인덱스 수동 관리:

    • enumerate 대신 수동으로 인덱스를 관리하며 리스트를 순회하거나, 수정 후 인덱스를 수정된 리스트 상태에 맞게 조정하여 작업함.
  • enumerate 대신 while 사용:

    • 리스트를 수정하면서 순회할 때는 for 대신 while을 사용하여 조건을 만족할 때마다 수정하고, 순회가 끝난 후 리스트를 한번에 수정하는 방식이 더 안정적임.

5. 결론

  • 리스트 수정 시 인덱스가 변하지 않도록 조심. enumerate는 수정 전 인덱스를 참조하고, 리스트의 상태가 변하면서 예기치 않은 결과가 나올 수 있음.
  • 리스트 순회 중 수정 시 인덱스 문제를 해결하려면 수동 인덱스 관리 또는 수정 후 일괄 처리하는 방식이 필요함.
  • 수정된 나의 코드 (Stack 사용)
import sys

num = int(input())
answer = ""


for _ in range(num):
    ps_list = list(sys.stdin.readline().strip())

    if (ps_list[0] == ')') or (ps_list[-1] == '('):
        answer = "NO"

    else:
        stack = []
        for ps in ps_list:
            stack.append(ps)
   
            if (stack[0] == '(') and (stack[-1] == ')'):
                first = stack.pop(0)
                last = stack.pop()

        if stack:
            answer = "NO"

        else:
            answer = "YES"

    print(answer)
profile
헤매는 만큼 자기 땅이다.

0개의 댓글