선택하는 데이터 구조에 따라 적용 가능한 알고리즘이 달라집니다.
1. 완주할 수 없었던 선수(Hash)
Hash의 특징을 살펴 보겠습니다.
- 이름 대신 번호가 주어지면? → 선형 배열(인덱스에서 일부 요소에 액세스할 수 있습니다.
) - 배열의 인덱스가 아닌 문자열로 액세스 할 수있는 좋은 데이터 구조는 무엇입니까? → Hash!
!
! - 캐릭터 라인을 key 로 보고 hash table 에 mapping 시킬 수가 있는 데이터 구조.
- 각 키 값은 hash function에서 mapping 가능.
- 해시 버킷이 많을수록 다른 버킷에 대해 생각할 가능성이 높아집니다.
- 같은 버킷에 들어가면 충돌이 일어난다.
파이썬 사전를 생각해 볼 수 있다.
사전을 구현할 때 내부적으로 해시 테이블을 사용하기 때문에 사전의 요소는 해시를 사용하여 O(1)에 액세스할 수 있습니다.
temp 사전을 만들고 → get()으로 모든 요소를 넣습니다.
→완주한 선수는 -1 적용
내 잔디
# 참가자 / 완주자
# 완주하지 못한 선수들의 이름을 return
def solution(participant, completion):
answer = ()
for i in range(len(participant)):
if participant(i) not in completion:
answer.append(participant(i))
else:
completion.remove(participant(i))
return ''.join(answer)
왜 잘못되었는가
– 같은 이름이이다 고려하지 않았다.
이후 동명가임을 고려해 해방해 보았지만 시간의 복잡성도 고려하지 않았다.
어떤 데이터 구조로 액세스할 수 있는지 우선적으로 생각하자.
강사 수영장
def solution(participant, completion):
d = {}
# 아래의 for문 시간 복잡도는 participant 길이에 비례
for x in participant:
d(x) = d.get(x, 0) + 1 # 처음 등장하면 1
# 아래의 for문 시간 복잡도는 completion 길이에 비례
for x in completion:
d(x) -= 1
# list comprehension -> 사전의 크기에 비례하는 시간 복잡도
dnf = (k for k, v in d.items() if v > 0) # value가 0보다 큰 key값 담음.
answer = dnf(0)
return answer
# 결과적으로 시간 복잡도는 n에 비례하는 linear time 복잡도.
2. 체조복
Greedy 문제
- 알고리즘의 각 단계에서 순간이 최적이라고 생각하는 것을 선택합니다.
- 탐욕법으로 최적해를 찾을 수 있는 문제는 현재의 선택이 마지막 대답의 최적성을 해치지 않는 경우가 해당된다.
(=지금 좋은 것이 끝에도 좋다.
) - 탐욕법의 적용 가능성을 어떻게 확인합니까? → 빌리는 학생 정해진 순서로 봐야 합니다.
정해진 순서에 따라 우선적으로 빌려주는 방향을 결정해야 한다.
그 문제에서 가장 분명한 방법을 살펴 보겠습니다.
착안점 : 학생수는 기껏해야 30명.
학생수만큼 배열을 확보하고, 여기에 각자가 가지고 있는 체육복수를 기록한다.
→ 번호순으로 스캔하면서 빌려주는 관계를 결정한다.
내 잔디
def solution(n, lost, reserve):
answer = n - len(lost)
for i in range(len(lost)):
if lost(i) in reserve:
lost.remove(lost(i))
reserve.remove(lost(i))
elif lost(i)+1 in reserve:
answer += 1
reserve.remove(lost(i)+1)
elif lost(i)-1 in reserve:
answer += 1
reserve.remove(lost(i)-1)
return answer
왜 잘못 되었습니까?
시간의 복잡성도 고려하지 않는다.
Greedy에 접근해야합니다!
생각하면 그에 따라 새로운 배열을 하나 만들어야 한다.
해결은 바로 아래 코드처럼 보입니다.
내가 접근한 방법이라면 추가 수영장에서 풀 수 있습니다.
set를 잘 활용해야 한다.
n이 상대적으로 큰 경우 추가 풀과 같은 방법으로 액세스하는 것이 좋습니다.
강사 수영장
def solution(n, lost, reserve):
u = (1) * (n+2) # 모든 원소를 1로 초기화. 2개는 맨 앞, 뒤에 추가
for i in reserve: # 여벌 있는 인원 +1 -> O(n)
u(i) += 1
for i in lost: # 도난 -> O(n)
u(i) -= 1
for i in range(1, n+1): # 정확히 n회 반복 -> O(n)
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((x for x in u(1:-1) if x>0)) # O(n)
여벌을 가져온 학생 처리: reserve의 길이에 비례
체조복의 잃어버린 학생 처리 : lost의 길이에 비례
스포츠웨어 대출 처리: 학생의 총 수(n)에 비례
→ O(n) Linear time Algorithm
추가 수영장
set의 복잡도도 굳이 보면 O(n)이다.
sort 의 복잡도 : set(r) 의 요소수 = k -> klogk 를 복잡도로 가진다.
def solution(n, lost, reserve):
s = set(lost) & set(reserve) # 교집합
l = set(lost) - s
r = set(reserve) - s
for x in sorted(r): # x = 체육복을 빌려줄 수 있는 학생 번호
if x-1 in l:
l.remove(x-1)
elif x+1 in l:
l.remove(x+1)
return n - len(l)