Stay Hungry Stay Foolish

BOJ 코딩테스트/Silver

BOJ 11723번 : 집합 (Python/구현/Silver 5)

dev스카이 2024. 3. 12. 18:09
 

11723번: 집합

첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다. 둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.

www.acmicpc.net


설명

비어있는 공집합 S가 주어졌을 때,
• add x: S에 x를 추가한다. (1 ≤ x ≤ 20) S에 x가 이미 있는 경우에는 연산을 무시한다.
• remove x: S에서 x를 제거한다. (1 ≤ x ≤ 20) S에 x가 없는 경우에는 연산을 무시한다.
• check x: S에 x가 있으면 1을, 없으면 0을 출력한다. (1 ≤ x ≤ 20)
• toggle x: S에 x가 있으면 x를 제거하고, 없으면 x를 추가한다. (1 ≤ x ≤ 20)
• all: S를 {1, 2, ..., 20} 으로 바꾼다.
• empty: S를 공집합으로 바꾼다

풀이

1. 문자형으로 입력을 받는다. (개행문자도 동시에 제거)

2. 공백이 없는 것과 있는 것을 구분해 조건문을 만든다. isalpha()를 통해 공백 유무를 판별한다.

3. 공백이 없을 때

  • 명령어가 'all'일 경우, 반복문을 통해 리스트를 1부터 20까지 채운다. 
  • 명령어가 'empty'일 경우, 리스트를 비운다.

4. 공백이 있을 때

  • 공백을 기준으로 나누고, 숫자로 된 문자는 정수형으로 변환한다. split()을 통해 공백을 기준으로 나눌 수 있다.
  • 명령어가 'add'이면서 집합에 해당 정수가 없는 경우 추가한다. append()를 통해 리스트에 추가할 수 있다.
  • 명령어가 'remove'이면서 집합에 해당 정수가 있을 경우 제거한다. remove()를 통해 리스트에서 제거할 수 있다.
  • 명령어가 'check'일 때 
    • 집합에 해당 정수가 있으면 1을 출력
    • 집합에 해당 정수가 없으면 0을 출력
  • 명령어가 'toggle'일 때
    • 집합에 해당 정수가 있으면 제거
    • 집합에 해당 정수가 없으면 추가

 

Solution

import sys
input = sys.stdin.readline

m = int(input())
s = [] #공집합
for _ in range(m):
    num = input().strip() #1. 문자형으로 입력 받기
    if num.isalpha() == True: #문자만 있으면(공백이 없으면)
        if num == 'all':
            s = [0]*20 #이렇게 안 해주면 out of range 뜸
            for i in range(20):
                s[i] = i+1
        if num == 'empty':
            s = []

    if num.isalpha() == False: #공백이 있으면
        comm, x = num.split()  # 공백을 기준으로 나누기
        x = int(x)
        if comm == 'add' and x not in s:  # 명령어가 add일 때 x가 없는 경우 x를 공집합에 추가
            s.append(x)
        if comm == 'remove' and x in s:  # 명령어가 remove일 때 x가 있는 경우 x를 공집합에서 제거
            s.remove(x)
        if comm == 'check':
            if x in s:
                print(1)
            else:
                print(0)
        if comm == 'toggle':
            if x in s:
                s.remove(x)
            else:
                s.append(x)

TIL

- set(map(str, num)) : 중복된 것을 제거한 리스트를 반환한다.

- list(map(str, num)) : set과 다르게 중복을 제거하지 않는다.

- strip() : 문자열 양끝 공백 문자를 제거한다.

- rstrip()/lstrip() : 문자열 오른쪽/왼쪽 공백 문자를 제거한다.

- replace(old, new) : 원하는 문자로 변경한 새로운 문자열을 반환한다. 

 

숫자, 문자 판별

- isalpha() : 문자열이 모두 문자인지 판별(단, 공백이 있을 경우 False 반환)

- isdigit() : 문자열이 모두 숫자인지 판별(단, 공백이 있을 경우 False 반환)

- isdecimal() : 어떤 문자열이 int형으로 변환이 가능하면 True 반환

- isnumeric() : 숫자값 표현에 해당하는 문자열이면 True 반환 (예: 32,½ ...)

- isalnum() : 숫자와 문자열이 모두 있는지 판별(단, 공백이 있을 경우 False 반환)

 

효율적인 코드

import sys
input = sys.stdin.readline

s = []

def calc(command, x):
    global s
    if command == "add":
        if x not in s:
            s.append(x)
    elif command == "remove":
        if x in s:
            s.remove(x)
    elif command == "check":
        if x in s: 
            print(1)
        else: 
            print(0)
    elif command == "toggle":
        if x in s:
            s.remove(x)
        else: 
            s.append(x)
    elif command == "all": 
        s = [i for i in range(1,21)]
    elif command == "empty": 
        s=[]

m = int(input())

for _ in range(m):
    command = input().strip()
    if command == "all" or command == "empty":
        calc(command, 0)
    else : 
        command, x = command.split()
        calc(str(command), int(x))

👩‍💻 회고

공백 때문에 시간을 많이 허비했다. 문자와 숫자를 판별하는 함수를 작성할 때 공백이 있을 경우 False를 반환하는지 몰랐던 탓에 거의 다 풀었는데도 안 돼서 포기할 뻔 했다. ㅜㅜ 그래도 풀어서 다행이었다. 내 코드는 시간이 좀 걸려서 다른 풀이를 봤는데 훨씬 효율이 좋았다. 난 왜 저렇게 생각을 못했을까 한심스럽기도 하다.

숫자와 문자를 구분할 필요가 있을 때 잘 기억해두자.