문제 설명
- N개의 과일이 꽂혀 있는 과일 탕후루
- 과일은 1번부터 9번까지 번호가 있음
- 한 꼬치에 과일을 두 종류 이하로 사용해야함
- 앞에서 a개 뒤에서 b개를 빼서 N-(a+b)의 최댓값은?
입력값
- N (1<=N<=200,000)
- 탕후루에 꽂힌 N개의 과일 번호
출력값
- 과일의 개수가 가장 많은 탕후루의 과일 개수
처음 생각한 풀이 코드
# 반례발견! 오답
# 반례 : 1 1 3 7 8 9 9 9
import sys
sys.stdin = open('백준/test.txt')
# 앞에서 제거
def front(lst) :
lst.pop(0)
return lst
# 뒤에서 제거
def back(lst) :
lst.pop()
return lst
N = int(input())
tang = list(map(int,input().split()))
# 탕후루 과일 종류 개수 확인
set_tang = set(tang)
# 과일 종류 개수가 2개 이하일 때 종료
while len(set_tang) > 2 :
if tang[0] == tang[1] : # 0번과 1번이 같으면 뒤에서 빼기
back(tang)
# print('back',tang)
else :
front(tang)
# print('front',tang)
set_tang = set(tang)
print(len(tang))
- 과일 종류가 2개 이하가 될 때까지 앞, 뒤에거 제거
- 앞의 2개가 같으면 뒤에거 제거하는 방식
- 뒤에거가 3개 연달아 같은게 있을 경우 앞을 제거하는게 더 이득 =>반례
정답 코드 : 투포인터 방법 사용
# 36952KB, 180ms(Python3)
# 투포인트 방법
from collections import defaultdict # 딕셔너리 기본값 관리
N = int(input())
tang = list(map(int,input().split()))
def max_fruit_length(tang) :
l, r = 0,0
max_length = 0
fruit_type = defaultdict(int)
while r < len(tang) :
fruit_type[tang[r]] += 1 # 현재 과일 추가
while len(fruit_type) > 2 :
fruit_type[tang[l]] -= 1 # 과일 하나 제거
if fruit_type[tang[l]] == 0 : # 과일이 0이면 과일 종류 리스트에서 제거
del fruit_type[tang[l]]
l += 1
max_length = max(max_length, r-l+1)
r += 1
return max_length
ans = max_fruit_length(tang)
print(ans)
- 위와 같이 과일 번호를 저장하는 딕셔너리를 만들고, L,R(투포인터)를 두고 구간을 조정하며 최대 길이를 구하는 방법
- 즉, 과일의 종류가 2개인 최대 구간을 구하는 방법
예시 2
10
1 2 3 2 2 1 3 1 2 1
- 이런식으로 최대 길이를 찾을 수 있음
줄마다 주석으로 설명한 코드
from collections import defaultdict # 딕셔너리 기본값 관리
# 입력 받기
sys.stdin = open('백준/test.txt') # 테스트를 위해 입력 파일 사용
N = int(input()) # 과일 개수
tang = list(map(int, input().split())) # 과일 종류 리스트
# 투 포인터를 사용한 최대 구간 길이 계산 함수
def max_fruit_length(tang):
left, right = 0, 0 # 두 포인터 초기화: 구간의 시작(left), 끝(right)
fruit_count = defaultdict(int) # 현재 구간에 포함된 과일 개수를 저장
max_length = 0 # 최대 구간 길이를 저장할 변수
# 오른쪽 포인터를 한 칸씩 이동하며 탐색 시작
while right < len(tang):
fruit_count[tang[right]] += 1 # 현재 과일을 추가 (right 포인터가 가리키는 과일)
# 과일 종류가 2개를 초과하면, left 포인터를 이동시켜 구간 줄이기
while len(fruit_count) > 2:
fruit_count[tang[left]] -= 1 # left 포인터가 가리키는 과일 개수 감소
if fruit_count[tang[left]] == 0:
del fruit_count[tang[left]] # 개수가 0이 되면 딕셔너리에서 제거
left += 1 # 구간의 시작점 이동
# 현재 구간 길이를 계산하고 최대값 갱신
max_length = max(max_length, right - left + 1)
right += 1 # 구간의 끝점을 한 칸 늘림
return max_length # 최대 구간 길이 반환
# 결과 출력
print(max_fruit_length(tang)) # 구한 최대 구간 길이 출력
from collections import defaultdict
- 딕셔너리의 기본값을 자동으로 설정해주는 라이브러리
- 일반 딕셔너리는 키를 명시적으로 추가해야하지만(dict[key]=val)
- defaultdict는 키가 없을 경우 기본값을 자동으로 추가한다(키가 없는 상태에서도 dict[key] +=1 가능)
- defaultdict(기본값)
- int : 0 / list : [] / str : '' / lambda:42 : 42
# 일반 딕셔너리
d = {}
d['key'] # KeyError 발생!
# defaultdict
from collections import defaultdict
d = defaultdict(int) # 기본값으로 0을 설정
print(d['key']) # 0 출력 (KeyError 발생하지 않음)
# 예시
d = defaultdict(list)
d['key'].append(1) # 'key'의 기본값이 []로 초기화되고 1 추가
print(d) # {'key': [1]}
활용1 : 문자 빈도 계산
from collections import defaultdict
s = "hello world"
freq = defaultdict(int)
for char in s:
freq[char] += 1
print(freq) # {'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1}
활용2 : 과일 종류별 개수 카운트
from collections import defaultdict
tang = [1, 2, 3, 2, 2, 1, 3, 1, 2, 1]
fruit_count = defaultdict(int)
for fruit in tang:
fruit_count[fruit] += 1
print(fruit_count) # {1: 4, 2: 4, 3: 2}
'개발새발문제' 카테고리의 다른 글
백준 7569 토마토 골드5 (BFS) (0) | 2024.12.27 |
---|---|
백준 12865 평범한 배낭 (DP) (0) | 2024.12.18 |
백준 11723 집합(set, remove, discard, .copy) (0) | 2024.12.16 |
백준 1629_곱셈(파이썬 거듭제곱 내장함수 pow, 분할정복 알고리즘) (1) | 2024.12.15 |
1 대 1 가위바위보, 자릿수 더하기, 중간값 찾기 (0) | 2024.07.16 |
댓글