[프로그래머스(파이썬/Python)] 보석 쇼핑(2020 카카오 개발자 인턴십)
kindof
·2021. 9. 3. 00:36
https://programmers.co.kr/learn/courses/30/lessons/67258
카카오의 효율성 문제를 풀면 눈물이 납니다.
이 문제를 풀 때도 1) O(N^2)으로 몇 가지 트릭을 넣은 풀이, 2) 이분 탐색으로 O(N*logN), 두 가지 방법을 시도해보았지만 모두 다 효율성 테스트를 통과하지 못했습니다...
사실, 이 문제에서 투 포인터를 써야겠다는 생각은 바로 들었지만 뭔가 계속 구현이 꼬이고 몇 가지 테스트 케이스가 틀리고를 반복하다보니 다른 방법으로 회피한 것 같은 느낌도 있었습니다.
그래도 어찌저찌 투 포인터(슬라이딩 윈도우)를 통해 정답 판정을 받은 뒤에는 약간 허무하기도 하고, 조금 더 연습을 해야겠다는 생각을 했습니다.
이 문제에서 투 포인터를 사용하는 전략은 간단합니다.
left, right 커서를 처음 지점에서 시작하고 right 커서를 오른쪽으로 이동시켜보면서(구간을 확장해보면서) 보석을 더 담아봅니다. 현재까지 보석의 종류의 개수가 모든 보석 종류의 개수와 같아졌을 때(문제의 조건을 만족했을 때), 왼쪽 커서를 오른쪽으로 이동시켜보면서 필요없는 보석이 담겨있는지 제거해주면 됩니다.
[풀이]
from collections import defaultdict
def solution(gems):
answer = []
# 전체 보석이 몇 개 있는지 확인
gemsDict = defaultdict(int)
totalGems = len(set(gems))
length = len(gems)
maxLength = 1000000
left, right = 0, 0
gemsDict[gems[left]] = 1
count = 1
# 투포인터를 구간 끝까지 탐색
while left < length and right < length:
# 모든 보석을 담았으면 왼쪽 포인터를 이동시켜본다.
if count == totalGems:
# 구간 길이가 최소이고, 인덱스가 작은 값을 기록
# 왼쪽에서 오른쪽으로 포인터가 이동하므로 자동으로 인덱스는 작은 것이 최종적으로 기록된다.
if right - left < maxLength:
maxLength = right - left
answer = [left + 1, right + 1]
gemsDict[gems[left]] -= 1
if gemsDict[gems[left]] == 0:
count -= 1
left += 1
# 보석이 부족하면 오른쪽으로 구간을 확장해본다.
else:
right += 1
if right < length:
gemsDict[gems[right]] += 1
if gemsDict[gems[right]] == 1:
count += 1
# 구간에 끝까지 갔으면 더 이상 추가할 보석이 없음
else:
break
return answer
'Algorithm' 카테고리의 다른 글
[프로그래머스(파이썬/Python)] 후보키(2019 카카오 블라인드) (0) | 2021.09.06 |
---|---|
[프로그래머스(파이썬/Python)] 모음사전 (0) | 2021.09.06 |
[백준(파이썬/Python)] 1644_소수의 연속합(투 포인터, 에라토스테네스의 체) (0) | 2021.08.30 |
[프로그래머스(파이썬/Python)] 수식 최대화(2020 카카오 블라인드 채용) (0) | 2021.08.29 |
[백준(파이썬/Python)] 9663_N-Queen - 백트랙킹 (0) | 2021.08.29 |