[이것이 코딩 테스트다] 2. 그리디
그리디 알고리즘
- 현재 상황에서 지금 당장 좋은 것마을 고르는 방법
- 문제를 풀기 위한 최소한의 아이디어를 떠올릴 수 있는 능력을 요구함
- 문제 푸는 해법은 정당성 분석이다! -> 단순히 가장 좋아 보이는 것을 반복적으로 선택해도 최적의 해를 구할 수 있는지 검토.
(ex)
- 일반적 상황서 그리디 알고리즘은 최적의 해를 보장할 수 없을 때가 많다
but 코딩테스트 에서 대부분 그리디 알고리즘 문제는 그리디로 푼 해가 최적의 해가 되는 상황이다. 이를 추론하여야 풀릴 수 있도록 출제된다고 함.
<문제> 거스름 돈
당신은 음식점의 계산을 도와주는 점원입니다. 카운터에는 거스름돈으로 사용할 500원, 100원, 50원, 10원짜리 동전이 무한히 존재한다고 가정합니다.
손님에게 거슬러 주어야 할 돈이 N원일 때 거슬러 주어야 할 동전의 최소 개수를 구하세요.
단, 거슬러 줘야 할 돈 N은 항상 10의 배수입니다.
- 최적의 해를 구하기 위해선 가장 큰 화폐 단위부터 돈을 거슬러 주면 됨
<정당성 분석>
- 가장 큰 화폐 단위부터 돈을 거슬러 주는 이유? -> 가지고 있는 동전 중 큰 단위가 항상 작은 단위의 배수. 따라서 작은 단위의 동전들을 종합해 다른 해가 나올 순 없음
n = 1260
count = 0
# 큰 단위의 화폐부터 차례대로 확인하기
array = [500, 100, 50, 10]
for coin in array:
count += n // coin # 해당 화폐로 거슬러 줄 수 있는 동전의 개수 세기
n %= coin # 화페로 나눈 나머지 n에 대입
print(count)
- 화폐 종류가 K라고 할 때, 시간복잡도는 O(K)
- 시간복잡도는 금액과 무관하며, 동전의 총 종류에만 영향.
<문제> 1이 될 때까지
# 내 풀이 -> 시간 오래걸림..
import sys
n,k=map(int,sys.stdin.readline().split())
cnt=0
while n>1:
if n%k!=0:
n-=1
cnt+=1
else:
n=n//k
cnt+=1
print(cnt)
import sys
n,k=map(int,sys.stdin.readline().split())
result=0
while True:
target=(n//k)*k # n이 k로 나누어 떨어지지 않을 때, k의 배수에서 n보다 작은 수를 target에 넣음
result+=(n-target) # 1빼주는 연산 수행 횟수를 result에 더함.
n=target
if n<k:
break
result+=1 #
n=n//k
result+=(n-1)
print(result)
- 최대한 많이 나누는 작업을 수행하면 됨.
<문제> 곱하기 혹은 더하기
- 각 자리가 숫자(0부터 9)로만 이루어진 문자열 S가 주어졌을 때 왼쪽부터 오른쪽으로 하나씩 모든 숫자를 확인하며 숫자 사이에 '×' 혹은 '+' 연산자를 넣어 결과적으로 만들어질 수 있는 가장 큰 수를 구하는 프로그램을 작성하라
- 단, +보다 ×를 먼저 계산하는 일반적인 방식과는 달리 모든 연산은 왼쪽에서부터 순서대로 이루어진다고 가정한다
- 예를 들어 02984라는 문자열로 만들 수 있는 가장 큰 수는 ((((0 + 2) × 9) × 8) × 4) = 576 이다. 또한 만들어질 수 있는 가장 큰 수는 항상 20억 이하의 정수가 되도록 입력이 주어진다
내 답
- 그리디로 풀지 않았고, 문자열을 테이블로 나타낸 후, 경우를 나눠서 풀었다.
import sys
s=sys.stdin.readline()
num_list=[]
result=1
for num in s[:-1]: # 문자열을 배열로 분배.
num_list.append(int(num))
num_list.sort() #
if num_list[0]==0 or num_list[0]==1: # 첫 배열의 항목이 0, 1인 경우 예외 처리
result=num_list[0]+num_list[1]
num_list=num_list[2:]
for num in num_list:
result*=num
print(result)
코딩테스트 답
data = input()
# 첫 번째 문자를 숫자로 변경하여 대입
result = int(data[0])
for i in range(1, len(data)):
# 두 수 중에서 하나라도 '0' 혹은 '1'인 경우, 곱하기보다는 더하기 수행
num = int(data[i])
if num <= 1 or result <= 1:
result += num
else:
result *= num
print(result)
<문제> 모험가 길드: 문제 설명
- 한 마을에 모험가가 N명 있다. 모험가 길드에서는 N명의 모험가를 대상으로 '공포도'를 측정했는데, '공포도'가 높은 모험가는 쉽게 공포를 느껴 위험 상황에서 제대로 대처할 능력이 떨어진다
- 모험가 길드장인 동빈이는 모험가 그룹을 안전하게 구성하고자 공포도가 X인 모험가는 반드시 X명 이상으로 구성한 모험가 그룹에 참여해야 여행을 떠날 수 있도록 규정했다
- 동빈이는 최대 몇 개의 모험가 그룹을 만들 수 있는지 궁금하다. N명의 모험가에 대한 정보가 주어졌을때, 여행을 떠날 수 있는 그룹 수의 최댓값을 구하는 프로그램을 작성하라
- 예를 들어 N = 5이고, 각 모험가의 공포도가 다음과 같다고 가정한다
' 2 3 1 2 2 '- 이 경우 그룹 1에 공포도가 1, 2, 3인 모험가를 한 명씩 넣고, 그룹 2에 공포도가 2인 남은 두명을 넣게 되면 총 2개의 그룹을 만들 수 있다
- 또한 몇 명의 모험가는 마을에 그대로 남아 있어도 되기 때문에, 모든 모험가를 특정한 그룹에 넣을 필요는 없다
내 풀이
import sys
cnt=0
n=int(sys.stdin.readline())
data=list(map(int,sys.stdin.readline().split()))
data.sort()
while len(data)!=0:
max_fear=data.pop()
if max_fear==1:
cnt+=data.count(1)+1
break
else:
data=data[0:-max_fear+1]
cnt+=1
print(data)
print(cnt)
출제자 풀이
n = int(input())
data = list(map(int, input().split()))
data.sort()
result = 0 # 총 그룹의 수
count = 0 # 현재 그룹에 포함된 모험가의 수
for i in data: # 공포도를 낮은 것 부터 하나씩 확인하며
count += 1 # 현재 그룹에 해당 모험가를 포함시키기
if count >= i: # 현재 그룹에 포함된 모험가의 수가 현재의 공포도 이상이라면, 그룹 결성
result += 1 # 총 그룹의 수 증가시키기
count = 0 # 현재 그룹에 포함된 모험가의 수 초기화
print(result) # 총 그룹의 수 출력
Author And Source
이 문제에 관하여([이것이 코딩 테스트다] 2. 그리디), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@csy9604/이것이-코딩-테스트다-2.-그리디-구현저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)