Stay Hungry Stay Foolish

SWEA

[SWEA] 1229. [S/W 문제해결 기본] 8일차 - 암호문2 (Python/D3)

dev스카이 2024. 10. 30. 21:09

[문제 링크] 👇

 

SW Expert Academy

SW 프로그래밍 역량 강화에 도움이 되는 다양한 학습 컨텐츠를 확인하세요!

swexpertacademy.com


풀이

명령어 분리 및 처리

  • 명령어는 삽입(I)과 삭제(D) 두 가지가 주어지므로, 이를 구분해 작업을 수행한다.
  • 명령어를 split()으로 분리하거나 특정 구분자로 나눠, I 또는 D를 구분한다.
  • replace() 후 split() 사용하기

 

삽입 및 삭제 처리

  • 구분한 리스트를 for 문으로 하나씩 꺼내어 명령어를 따로 저장한다.
  • 개별 명령어는 맨 앞에 I 혹은 D 가 있어서 명령어의 첫 번째 인덱스를 기준으로 조건을 분리한다.
  • 슬라이싱을 이용하여 삽입과 삭제 연산을 한다.

 

출력

  • 암호문의 앞 10개 숫자를 출력한다.

 

Solution

for test_case in range(1, 11):
    _ = int(input())
    origin = list(map(int, input().split()))
    _ = int(input())
    commands = input().replace("I", ";I").replace("D", ";D")  # I와 D를 기준으로 구분
    # ";"로 나눠 명령어 분리
    commands = commands.split(";")[1:]  # 첫 부분은 빈 문자열이므로 제외

    for i in commands:
        command = list(map(str, i.split()))  # 명령어 따로 저장

        if command[0] == "I":  # insert 연산
            int_command = list(map(int, command[1:]))
            insert_position = int_command[0]  # 삽입할 위치
            insert_command = int_command[2:]  # 명령어 저장
            origin[insert_position:insert_position] = insert_command
        else:  #delete 연산
            int_command = list(map(int, command[1:]))
            del origin[int_command[0]:int_command[0] + int_command[1]] 

    print(f"#{test_case} {' '.join(map(str, origin[:10]))}")

 

개선할 부분

  • 불필요한 변환 줄이기
    • command = list(map(str, i.split())) 대신 i.split()만으로 충분하다. 또한 int_command로 변환할 때도 필요할 경우에만 숫자로 변환하면 된다.
  • 리스트 슬라이싱을 활용한 삽입
    • origin[insert_position:insert_position] = insert_command는 효율적이지만, 대량 삽입을 할 때 origin.insert()를 여러 번 사용하는 방식도 가능하다.
  • del로 삭제 최적화
    • 삭제 부분은 origin.pop()을 사용하여 각 요소를 반복적으로 삭제하는 것이 더 메모리를 효율적으로 사용할 수 있지만, 여기서는 슬라이싱이 효율적일 수 있다.

 

최적화된 코드

for test_case in range(1, 11):
    _ = int(input())  # 원본 암호문 길이
    origin = list(map(int, input().split()))  # 원본 암호문
    _ = int(input())  # 명령어 개수
    commands = input().replace("I", ";I").replace("D", ";D")  # I와 D로 구분하여 명령어 분리
    commands = commands.split(";")[1:]  # 빈 첫 부분 제외

    for i in commands:
        command = i.split()  # 명령어 분리
        cmd_type, x, y = command[0], int(command[1]), int(command[2])

        if cmd_type == "I":  # insert 연산
            s = map(int, command[3:])  # 삽입할 숫자들
            origin[x:x] = s  # 리스트 슬라이싱으로 한번에 삽입
        elif cmd_type == "D":  # delete 연산
            del origin[x:x + y]  # 리스트 슬라이싱으로 삭제

    print(f"#{test_case} {' '.join(map(str, origin[:10]))}")

 

 

👩‍💻 회고

import re 사용한 풀이

import re

for test_case in range(1, 11):
    _ = int(input())
    origin = list(map(int, input().split()))
    _ = int(input())
    commands = input()
    commands = re.split('[I|D]', commands)  # 여러 구분자 사용, I와 D로 구분한다.

    for i in commands[1:]:  # 첫 번째 인덱스는 공백이기 때문에 패스
        command = list(map(int, i.split()))  # 명령어 따로 저장

        # insert 와 delete 인걸 구분하려면 길이로 판단
        if len(command) >= 3:  # 길이가 2보다 크면 insert 연산
            insert_position = command[0]  # 삽입할 위치
            insert_command = command[2:]  # 명령어 저장
            origin[insert_position:insert_position] = insert_command
        else:  # 2 이하이면 delete 연산
            del origin[command[0]:command[0] + command[1]]

    print(f"#{test_case} {' '.join(map(str, origin[:10]))}")

swea 에서는 import re 가 안 된다는 걸 잊고 풀다가 낭패 봤다. 이전에 삭제 처리가 없는 암호문 문제를 풀고 와서 삽입 삭제 처리하는 부분은 어렵지 않게 했었다. 그러나 여러 구분자로 분리하는 방법을 몰라서 난이도 급상승.. 심지어 re.split() 도 안 돼서 막막했었다. 아마 import re 를 허용해줬으면 맞지 않았을까 싶다.

 

기억해야 하는 점

문자열은 굳이 map과 list로 감쌀 필요가 없다.! split() 을 사용하고 싶을 때도 사용할 필요가 없이 알아서 리스트화를 해준다.