1. 해시(Hash)
완주하지 못한 선수
문제에서 선수의 이름이 주어졌다 -> 문자열로 접근할 수 있는 좋은 자료구조는 무엇일까?
def solution(participant, completion):
d = {}
for x in participant:
# d.get(x, 0) -> d에 키 x가 있으면 그 value를 반환, 없으면 0을 반환
d[x] = d.get(x, 0) + 1
for x in completion:
d[x] -= 1
dnf = [k for k, v in d.items() if v > 0]
return dnf[0]
# 시간 복잡도: O(N)
2. 탐욕법(Greedy)
알고리즘의 각 단계에서 그 순간에 최적이라고 생각되는 것을 선택하는 방법으로, 현재의 선택이 마지막 해답의 최적성을 해치치 않을 때 최적해를 찾을 수 있다.
빌려줄 학생들을 '정해진 순서'로 살펴야 하고, 이 '정해진 순서'에 따라 우선하여 빌려줄 방향을 정해야 한다.
# 배열을 이용하여 풀자
def solution(n, lost, reserve):
# 앞, 뒷번호를 검사할 때 편하게 배열의 길이를 n + 2로 하자
u = [1] * (n + 2)
for i in reserve:
u[i] += 1
for i in lost:
u[i] -= 1
for i in range(1, n + 1):
if u[i - 1] == 0 and u[i] == 2:
u[i - 1:i + 1] = [1, 1]
elif u[i] == 2 and u[i + 1] == 0:
u[i:i + 2] = [1, 1]
return len([i for i in u[1:-1] if i > 0])
# 정렬+해시를 이용하여 풀자
def solution(n, lost, reserve):
# 여벌을 가져온 학생 중 도난당한 학생을 고려하자
s = set(lost) & set(reserve)
l = set(lost) - s
r = set(reserve) - s
for x in sorted(r):
if x - 1 in l:
l.remove(x - 1)
elif x + 1 in l:
l.remove(x + 1)
return n - len(l)
원칙
- 앞 자리에 큰 수가 오는 것이 전체를 크게 만드므로, 큰 것을 우선해서 골라 담고 싶다.
- '앞쪽'에 있는 작은 수를 뺀다.
해결 방법
- 주어진 숫자 number의 앞 자리에서부터 하나씩 골라서 담되,
- 이미 모아둔 것 중 지금 담으려는 것 보다 작은 것들은 도로 뺀다.
- 단, 뺄 수 있는 수효에 도달할 때까지만!
- 이렇게 모은 숫자들을 자릿수 맞추어 반환한다.
- 이미 숫자가 정렬된 상태여서 뺄 개수 (k)를 채우지 못한 경우를 고려하자.
- 시간 복잡도는 O(N)
def solution(number, k):
collected = []
# 남아있는 수를 이어 붙이기 위해 i를 이용하자
for i, num in enumerate(number):
while len(collected) > 0 and collected[-1] < num and k > 0:
collected.pop()
k -= 1
# 뺄 수 있는 개수를 모두 충족한 경우
if k == 0:
collected += list(number[i:])
break
collected.append(num)
# 뺄 수 있는 개수가 남아있는 경우를 고려하자
collected = collected[:-k] if k > 0 else collected
return ''.join(collected)
3. 정렬(Sort)
def solution(numbers):
numbers = [str(x) for x in numbers]
numbers.sort(key=lambda x: (x * 4)[:4], reverse=True)
if numbers[0] == '0':
return '0'
else:
return ''.join(numbers)