n | lost | reserve | return |
---|---|---|---|
5 | [2, 4] | [1, 3, 5] | 5 |
=> 1번 학생이 2번 학생에게 체육복을 빌려주고, 3번 학생이나 5번 학생이 4번 학생에게 체육복을 빌려주면 학생 5명이 체육 수업을 들을 수 있습니다.
n | lost | reserve | return |
---|---|---|---|
5 | [2, 4] | [3] | 4 |
=> 3번 학생이 2번 학생이나 4번 학생에게 체육복을 빌려주면 학생 4명이 체육 수업을 들을 수 있습니다.
n | lost | reserve | return |
---|---|---|---|
3 | [3] | [1] | 2 |
=> 2번 또는 4번 학생이 여벌 체육복을 갖고 있지 않기 때문에 3번 학생은 체육 수업을 들을 수 없고 학생 2명이 체육 수업을 들을 수 있습니다.
알고리즘의 각 단계에서 그 순간에 최적이라고 생각되는 것을 선택
정해진 순서에 우선하여 빌려줄 방향을 정해야 함
전체 학생 수는 최대 30명으로 적은 편
학생 수만큼 배열을 확보하고 각 학생이 갖고 있는 체육복 수를 저장
번호 순서대로 배열을 스캔하면서 빌려줄 관계를 정함
def solution(n, lost, reserve):
u = [1] * (n + 2) # 1로 초기화, 맨 앞과 맨 뒤도 추가
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] # i - 1과 i번 원소를 1로 만듦
# 뒷 사람이 체육복이 없고, 내가 여벌을 갖고 있다면
elif u[i] == 2 and u[i + 1] == 2:
u[i:i + 2] = [1, 1]
return len([x for x in u[1:-1] if x > 0]) # 체육복이 있는 학생 수
- 여벌을 가져온 학생을 처리하는 과정은 reserve의 길이에 비례
- 체육복을 잃어버린 학생을 처리하는 과정은 lost의 길이에 비례
- 체육복 빌려주는 것을 처리하는 과정은 전체 학생 수인 n에 비례
- 알고리즘의 복잡도는 O(n)
=> 전체 학생 수가 너무 크면 복잡해짐
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)
def solution(n, lost, reserve):
lost_set = set(lost) - set(reserve)
reserve_set = set(reserve) - set(lost)
for i in reserve_set:
if i - 1 in lost_set:
lost_set.remove(i - 1)
elif i + 1 in lost_set:
lost_set.remove(i + 1)
answer = n - len(lost_set)
return answer
- 전체 학생 수인 n은 그대로인데 여벌의 체육복을 가져온 학생 수인 k가 훨씬 더 적으면 유리한 방식임
=> reserve 정렬 : O(klogk)- 빌려줄 수 있는 다른 학생을 찾는 것은 해시를 사용해서 상수 시간에 처리할 수 있음
=> 체육복을 빌려줄 수 있는 학생 확인 후 처리 : O(k) * O(1)- 전체 알고리즘 시간 복잡도 O(klogk)