반응형
풀이
두개의 포인터를 이용하여 문제를 해결할 수 있다. 두 포인터를 left와 right라고 했을 때(left < right), 포인터를 이동시키는 과정은 다음을 따른다.
- 두 포인터가 가르키고 있는 보석의 종류가 같을 경우
-> left를 이동시켜서 구간의 길이를 감소시킨다. left가 가르키고 있는 보석은 right에 이미 있으므로 left에 있는 보석은 구간에서 제외해도 상관없다. 구간의 길이가 줄어들었으므로 기존의 가장 짧은 구간과 비교하여 더 짧은 구간으로 답을 갱신한다. - 두 포인터가 가르키고 있는 보석의 종류가 다를 경우
- right가 가르키고 있는 보석이 처음 등장한 보석일 경우
-> 새로운 종류의 보석을 포함한 구간으로 답을 갱신한 후 right를 이동시킨다.
- 현재 구간에서 left가 가르키고 있는 보석의 개수가 right가 가르키고 있는 보석의 개수보다 많을 경우
-> left를 이동시켜 구간의 길이를 감소시킨다. left가 가르키고 있는 보석은 현재 구간 안에 2개 이상이므로 left에 있는 보석은 제외해도 상관없다. 구간의 길이가 줄어들었으므로 기존의 가장 짧은 구간과 비교하여 더 짧은 구간으로 답을 갱신한다. - 현재 구간에서 right가 가르키고 있는 보석의 개수가 left가 가르키고 있는 보석의 개수보다 많거나 같을 경우
-> right를 이동시켜 구간의 길이를 늘린다. left에 있는 보석의 개수가 구간 내에 1개라면 left가 가르키고 있는 보석을 제거해서는 안된다. 따로 조건을 주어 이를 분리할 수 있지만 1과 2-2를 통해서 구간을 줄여나갈 수 있기 때문에 이 경우에는 right를 늘려 준다.
- right가 가르키고 있는 보석이 처음 등장한 보석일 경우
위와 같은 규칙으로 포인터를 적절하게 이동시켜 구간의 길이를 구해줄 수 있다.
코드
def solution(gems):
start, end = 0, 0 # 모든 종류의 보석을 담은 구간 중 가장 짧은 구간
left, right = 0, 1 # 탐색에 사용될 포인터
gemDict = {gems[left]: 1} # 각 보석이 [left, right]에 몇 개인지를 체크하기 위한 딕셔너리
change = right # left와 right중 이동한 포인터를 기록하기 위한 변수
while True:
if right == len(gems): # right가 gems 배열을 벗어나면 while문 종료
break
if left == right: # left와 right가 같은 곳에 위치하면 right를 이동시킴
right += 1
change = right
continue
leftGem, rightGem = gems[left], gems[right] # 두 포인터가 가르키고 있는 구간 내에서 각 보석의 개수
# right가 가르키고 있는 보석이 새로운 종류일 경우
if rightGem not in gemDict:
gemDict[rightGem] = 1 # 딕셔너리에 보석 등록
start, end = left, right # 새로운 보석을 포함하고 있는 범위로 start와 end 업데이트
right += 1 # 그 후 right를 이동시킨다.
change = right
continue
if change == right: # 이전에 이동시킨 포인터가 right일 경우 딕셔너리에 카운트
gemDict[rightGem] += 1
# 각 포인터가 가르키고 있는 보석의 개수
leftGemCount, rightGemCount = gemDict[leftGem], gemDict[rightGem]
# 1-1. 두 포인터가 가르키고 있는 보석이 같은 보석이거나
# 1-2. 현재 구간에서 left가 가르키고 있는 보석의 개수가 right가 가르키고 있는 보석의 개수보다 많을 경우
if leftGem == rightGem or leftGemCount > rightGemCount:
left += 1 # left를 한 칸 이동시킨다.
change = left
gemDict[leftGem] -= 1 # 기존의 left가 가르키고 있던 보석의 개수를 감소시킨다.
# left가 이동했기 때문에 범위의 길이가 줄어들었으므로 길이를 비교하여 더 짧아졌을 경우 구간 정보를 갱신한다.
if (right - left) < (end - start):
start, end = left, right
else: # 2. 두 포인터가 가르키고 있는 보석의 종류가 다르고 right가 가르키고 있는 보석의 개수가 left가 가르키고 있는 보석의 개수보다 많거나 같을 경우
right += 1 # right를 한 칸 이동시킨다.
change = right # 이 경우 구간의 길이가 늘어났으므로 구간 정보 갱신 여부를 체크할 필요가 없다.
return [start + 1, end + 1]
반응형
'Algorithm > Programmers' 카테고리의 다른 글
[2020 카카오 인턴십] 수식 최대화 (0) | 2022.05.05 |
---|---|
[2020 카카오 인턴십] 키패드 누르기 (0) | 2022.05.05 |
[고득점 Kit(정렬)] H-Index (Python) (0) | 2022.02.08 |
[고득점 Kit(정렬)] 가장 큰 수 (Swift, Python) (0) | 2022.02.03 |
[고득점 Kit(힙)] 이중우선순위큐 (Python) (0) | 2022.01.29 |
댓글