코테연습문제

[백준/Python] 5430 AC

SI-AH 2023. 5. 16. 23:34

문제만 봤을 때는 너무 간단해보여서 골드 문제도 척척 풀어내는 나, 어쩌면 성장했을지도?! 라고 생각하면서 아이패드에 어떤식으로 풀지 정리도 안하고 바로 코드를 술술 적어내려갔는데......

그럼 그렇지, 시간초과^^

 

1. 시간 초과 코드 & 설명

T = int(input())
for _ in range(T):
    operations = []
    x = []
    for i in (input()):
        operations.append(i)
    n = int(input())
    for i in (input()):
        if i.isdigit():
            x.append(int(i))

    for p in operations:
        if p == 'R':
            x = x[::-1]
        elif p == 'D':
            if len(x) == 0:
                break
            else:
                x = x[1:]
    if len(x) == 0:
        print('error')
    else:
        print(x)

보다시피 주석도 한 줄 없고 그냥 문제에서 보이는 그대로 코드를 작성했다.

심지어 나중에 생각해보니까 코드도 틀렸음...ㅋ 예제에서 

DD
1
[42]

이 부분에서 x가 ['4', '2'] 이렇게 되니까... 이 예제에서는 맞는 답이 나오지만 코드로나 시간초과로나 어쨋든 틀렸음....

 

나는 '시간초과'가 뜨면 뇌정지가 오는데, 시간 복잡도 공부를 제대로 해놓지 않은 탓에

어디에서 어떻게 시간을 줄여야할지, 좀 더 대공사를 해야한다면 어떻게 기존 방식을 버리고 새로운 방식으로 풀어봐야할지 전.혀. 생각을 할 수 없다는 것임......ㅜ 자랑은 아니고 훈련이 더 필요할 거 같음...

 

그래서 생각해낸 방법이 deque 이용하기.

계속 뒤집고 숫자 빼고, 숫자 빼고 뒤집고, 뒤집고 뒤집고 숫자빼고 뭐 이런 거 하는 거니까 앞/뒤에서 문자 추가/삭제에 용이한 deque를 이용하면 어떨까 하는 생각으로 deque의 시간복잡도를 검색해봤다!

list의 append/pop 시간복잡도는 O(n)인데, (고정된 사이즈를 갖는 array 형태라서)

deque의 append/pop 시간복잡도는 O(1) 이었다!!!!!!!

 

그래서 deque를 무.족.권. 이용해야겠다 싶어서 좀 더 생각을 해봤는데,

deque가 양방향 자료형이라 pop도 있고 popleft도 있잖음?

이 말이 무엇이냐,

reverse 한 번 하고 delete를 하는 거는 그냥 reverse를 안하고 맨 오른쪽에서 pop을 하는거고,

reverse 두 번 하고 delete를 하는 거는 reverse를 안하고 맨 왼쪽에서 popleft를 하는 거랑 똑같다는 말임

나는 reverse의 개수가 홀수 개일 때만 마지막에 reverse해서 출력만 해주면 되는거임~

 

 

2. 통과된 코드 & 풀이과정

from collections import deque

T = int(input())
for _ in range(T):
    operations = deque()
    for i in (input()):
        operations.append(i)
    n = int(input())
    x = deque(input()[1:-1].split(','))
    if n == 0:
        x = deque([])
    # print('len(x) =', len(x))
    # 마지막에 flag = 1이면 R의 개수가 홀수 개라고 판단하고 reverse 해서 출력하고,
    # flag = 0이면 reverse 안하고 출력
    flag = 0
    emptyFlag = 0
    while operations:
        op = operations.popleft()
        if op == 'R' and flag == 0:  # R 개수 짝수 개였는데 flag = 1 하면서 홀수 개라고 상태 update
            flag = 1
        elif op == 'R' and flag == 1:  # R 개수 홀수 개였는데 flag = 0 하면서 짝수 개라고 상태 update
            flag = 0

        elif op == 'D':
            if len(x) == 0:
                emptyFlag = 1  # print('error') 함
                break
            elif x and flag == 0:  # R 개수가 짝수 개이므로 delete는 왼쪽 끝에서
                x.popleft()
            elif x and flag == 1:  # R 개수가 홀수 개이므로 delete는 오른쪽 끝에서
                x.pop()

    if emptyFlag == 1:
        print('error')
    else:
        if flag == 1:
            # x = x[::-1]  =>  deque는 [::-1]로 슬라이싱이 안됨 -> .reverse() 사용
            x.reverse()

        print('[', end='')
        print(','.join(x), end='')
        print(']')

풀이과정

1. T, operations, n, x를 입력받는데, operations는 R 또는 D를 각각 리스트 형태로 받고, x는 숫자만 deque형태로 받음

 

2. flag를 이용해 R의 개수가 홀수인지 짝수인지 계산 → 마지막의 flag가 1이면 reverse 해줌

2-1. flag = 1은 R의 개수가 홀수 개인 상태

2-2. flag = 0은 R의 개수가 짝수 개인 상태

 

3. operations에 있는 수행할 함수를 하나씩 빼서 flag에 상태를 update

3-1. 함수가 R 이면, 현재 상태를 flag에 update한다

    (R의 개수가 짝수였는데, 또 R이 나왔다면 flag를 1로 바꾸어 현재 R의 개수가 홀수임을 update)

    (R의 개수가 홀수였는데, 또 R이 나왔다면 flag를 0로 바꾸어 현재 R의 개수가 짝수임을 update)

3-2.  함수가 D 일 때

    현재 flag = 1(R의 개수가 홀수)이면, 오른쪽 끝에서 요소를 빼는 pop()

    현재 flag = 0(R의 개수가 짝수)이면, 왼쪽 끝에서 요소를 빼는 popleft()

    현재 x에 아무것도 없으면, emptyFlag를 1로 바꾼 후 break해 while문을 빠져나감 (error 출력해야함)

 

4-1. emptyFlag = 0이면, error를 출력

4-2. flag = 1이면, x를 reverse해 출력

 

5. 현재 x는 deque이므로 .join()을 이용해 모든 요소들을 '예제출력'의 형태로 출력해줌

 

 

에러 설명

 

마지막에 reverse를 하는데 처음에 시간초과났던 코드에서 썼던 [::-1]를 쓰니까 에러가 남....... 마지막까지;;

찾아보니까 deque는 저런 슬라이싱 방법을 사용할 수 없다고 합니다....~

그래서 그냥 .reverse() 씀^~^

reverse()도 시간복잡도가 O(n)이라, 만약에 R이 나올 때마다 .reverse() 했으면 또 시간초과될 뻔;;;

얻어걸린 거지만 그래도 마지막에 R 개수가 홀수 개일때만 reverse하길 아주 잘한듯!!!~