비어있는 공집합 S가 주어졌을 때, 아래 연산을 수행하는 프로그램을 작성하시오.
첫째 줄에 수행해야 하는 연산의 수 M (1 ≤ M ≤ 3,000,000)이 주어진다.
둘째 줄부터 M개의 줄에 수행해야 하는 연산이 한 줄에 하나씩 주어진다.
check 연산이 주어질때마다, 결과를 출력한다.
<입력>
26
add 1
add 2
check 1
check 2
check 3
remove 2
check 1
check 2
toggle 3
check 1
check 2
check 3
check 4
all
check 10
check 20
toggle 10
remove 20
check 10
check 20
empty
check 1
toggle 1
check 1
toggle 1
check 1
<출력>
1
1
0
1
0
1
0
1
0
1
1
0
0
0
1
0
처음 구현했을 때는 따로 알고리즘을 생각하지 않고 무작정 구현해서 풀었다.
m = int(input())
S = []
for i in range(m):
tmp = input()
if tmp == 'all':
S = list(range(1, 21))
elif tmp == 'empty':
S = []
else:
command, number = tmp.split()
if command == 'add' and number not in S:
S.append(number)
elif command == 'remove' and number in S:
S.remove(number)
elif command == 'check':
if number in S:
print(1)
elif number not in S:
print(0)
elif command == 'toggle':
if number in S: S.remove(number)
elif number not in S: S.append(number)
단순히 리스트 + 조건문으로 풀었더니 시간초과가 났다. list는 시간복잡도가 O(n)으로 속도가 느려 오래걸리기 때문에 시간초과가 날 수 밖에 없었다. 그래서 방법을 찾다가 상대적으로 속도가 빠른 set을 사용하거나 비트마스크 알고리즘을 활용해 풀어야 한다는 것을 알았다.
import sys
input = sys.stdin.readline
m = int(input())
S = 0
for i in range(m):
cmd = input().strip().split()
if cmd[0] == 'add':
S |= (1 << int(cmd[1]))
elif cmd[0] == 'remove':
S &= ~(1 << int(cmd[1]))
elif cmd[0] == 'check':
print(1 if S & (1 << int(cmd[1])) else 0)
elif cmd[0] == 'toggle':
S ^= (1 << int(cmd[1]))
elif cmd[0] == 'all':
S |= (1 << 21)-1
elif cmd[0] == 'empty':
S = 0
- list는 시간복잡도가 O(n)으로 속도가 느리다.
- set은 시간복잡도가 O(1)로 리스트보다 속도가 빠르다.
- 집합 문제는 비트마스크 알고리즘이 효율적!