728x90
반응형
본문은 저자 나동빈님의 『이것이 취업을 위한 코딩테스트다 with 파이썬』 책을 공부하며 작성한 내용입니다. 글은 편의상 반말로 작성되었습니다.
최초 작성일 : 20.01.24
최종 수정일 : 20.01.30
개념
단순하지만 강력한 문제 해결 방법으로, 현재 상황에서 지금 당장 좋은 것만 고르는 방법이다. 매 순간 가장 좋아 보이는 것을 선택하며, 현재의 선택이 나중에 미칠 영향에 대해 고려하지 않는다.
특성
- 사전에 외우고 있지 않아도 풀 수 있을 가능성이 높은 문제 유형
- 매우 다양하게 출제되어 암기만으로 모든 문제를 잘 풀 수 없다.
- 특정 문제를 만났을 때 현재 상황에서 가장 좋아 보이는 것만 선택해도 문제를 풀 수 있는지 파악할 수 있어야 한다.
- 자주 정렬 알고리즘과 짝을 이뤄 출제
예제
1. 거스름돈
작성 코드
price = int(input())
A, B, C, D = 0, 0, 0, 0
if price / 500 > 0:
A = int(price / 500)
price %= 500
if price / 100 > 0:
B = int(price / 100)
price %= 100
if price / 50 > 0:
C = int(price / 50)
price %= 50
if price / 10 > 0:
D = int(price / 10)
price %= 10
print(A + B + C + D)
- 동전 종류에 따라 변수를 따로 지정해 동전 개수를 따로 저장
- 일일이 if문으로 하나하나 비교 후 실행
답안 예시
n = 1260
count = 0
# 큰 단위의 화폐부터 차례대로 확인
coin_types = [500, 100, 50, 10]
for coin in coin_types:
count += n // coin # 해당 화폐로 거슬러 줄 수 있는 동전의 개수 세기
n %= coin
print(count)
- list에 동전 종류를 순서대로 저장, 동전 개수는 한 가지 변수에 계속 저장
- list에 저장된 동전 종류를 순서대로 가져와 반복하여 바로 계산
피드백
- // 연산자를 이용하면 나누기 연산의 정수 결과만 얻을 수 있음
- list와 for문으로 원하는 단위를 순서대로 반복 계산
- 단위별 변수를 따로 지정할 필요가 없음 (어차피 동전 총 개수를 구하는 것)
- 직관적인 변수명은 코드 이해에 도움이 됨
2. 큰 수의 법칙
작성 코드
N, M, K = map(int, input().split(" "))
array = list(map(int, input().split(" ")))
sumNum = 0
array.sort(reverse=True)
for i in range(0, M):
if i == 0 or i % K != 0:
sumNum += array[0]
else:
sumNum += array[1]
print(sumNum)
- .sort()에서 reverse를 사용해 내림차순 정렬
- for문으로, i가 0부터 M까지 증가하면서 그 이상이 되면 for문이 끝나도록
답안 예시 (1)
M이 10,000 이하일 때
# N, M, K를 공백으로 구분하여 입력받기
n, m, k = map(int, input().split())
# N개의 수를 공백으로 구분하여 입력받기
data = list(map(int, input().split()))
data.sort() # 입력받은 수들 정렬하기
first = data[n - 1]
second = data[n - 2]
result = 0
while True:
for i in range(k): # 가장 큰 수를 K번 더하기
if m == 0: # m이 0이라면 반복문 탈출
break
result += first
m -= 1 # 더할 때마다 1씩 빼기
if m == 0: # m이 0이라면 반복문 탈출
break
result += second # 두 번째로 큰 수를 한 번 더하기
m -= 1 # 더할 때마다 1씩 빼기
print(result) # 최종 답안 출력
- .sort()로 오름차순 정렬하면 n값도 사용하여 코드를 작성할 수 있음
(오름차순이기 때문에 전체 길이 n에서 -1, -2) - 계산을 한 번 할 때마다 m에서 1씩 빼서 m이 0일 때 while문을 탈출하도록, m을 인덱스로 활용
- while 안에 가장 큰 수를 k번만큼 더하기 위해 for문 사용. 해당 for문이 끝나면 두 번째 큰 수를 더한 후 다시 for문으로
답안 예시 (2)
M이 100억 이상일 때
# N, M, K를 공백으로 구분하여 입력받기
n, m, k = map(int, input().split())
# N개의 수를 공백으로 구분하여 입력받기
data = list(map(int, input().split()))
data.sort() # 입력받은 수 정렬
first = data[n - 1] # 가장 큰 수
second = data[n - 2] # 두 번째로 큰 수
# 가장 큰 수가 더해지는 횟수 계산
count = int(m / (k + 1)) * k
count += m % (k + 1)
result = 0
result += (count) * first # 가장 큰 수 더하기
result += (m - count) * second # 두 번째로 큰 수 더하기
print(result) # 최종 답안 출력
- 반복되는 수열을 파악하여 코드 설계
* 정확히 이해되지 않아서 일단 넘어가고 다음에 다시 보기 *
: 가장 큰 수가 더해지는 횟수를 구하는 것이 헷갈림(책 94p 체크한 부분)
피드백
- 입력 값을 공백으로 나눌 때는 .split(" ") 대신 .split() 사용 가능
- 0부터 M까지 반복할 때는 range(0, M) 대신 range(M) 사용 가능
- 가장 큰 수와 다음으로 큰 수를 변수에 저장하여 사용하면 더 보기 좋은 코드가 됨
3. 숫자 카드 게임
작성 코드
N, M = map(int, input().split())
array = []
result = 0
for _ in range(N):
a = list(map(int, input().split()))
array.append(a)
for i in range(N):
minNum = 99999
for j in range(M):
if array[i][j] < minNum:
minNum = array[i][j]
if result < minNum:
result = minNum
print(result)
- 2차원 리스트로 입력 받은 후 결과 구함
(개념 정리가 부족했던 2차원 리스트 초기화/입력받기는 따로 포스팅) - min() 함수를 사용하고 싶었지만 기억이 안나서 직접 구현
(손코딩이라 min() 함수 검색 X)
답안 예시 (1)
min() 함수 이용
# N, M을 공백으로 구분하여 입력받기
n, m = map(int, input().split())
result = 0
# 한 줄씩 입력받아 확인
for i in range(n):
data = list(map(int, input().split()))
# 현재 줄에서 '가장 작은 수' 찾기
min_value = min(data)
# '가장 작은 수'들 중에서 가장 큰 수 찾기
result = max(result, min_value)
print(result) # 최종 답안 출력
- 한 줄 입력받을 때마다 해당 줄에서 가장 작은 수를 구함
- 구한 수를 result와 비교하여 더 큰 수를 result에 저장
- max로 값을 비교하고 적절한 결과 저장
- 아래 예시와 차이점 : min(data)로 리스트 내의 값 중 가장 작은 수를 바로 구해 min_value에 저장
답안 예시 (2)
2중 반복문 구조 이용
# N, M을 공백으로 구분하여 입력받기
n, m = map(int, input().split())
result = 0
# 한 줄씩 입력받아 확인
for i in range(n):
data = list(map(int, input().split()))
# 현재 줄에서 '가장 작은 수' 찾기
min_value = 10001
for a in data:
min_value = min(min_value, a)
# '가장 작은 수'들 중에서 가장 큰 수 찾기
result = max(result, min_value)
print(result) # 최종 답안 출력
- 위 예시 (1)과 동일하게 매번 입력받을 때마다 결과 도출
- 위 예시와 차이점 : data 리스트를 처음부터 끝까지 반복 후 min(min_value, a)로 비교하여 가장 작은 값을 min_value에 저장
피드백
- 여러 줄을 입력받고 결과를 구해야 할 경우, 굳이 2차원 리스트로 저장할 필요가 없다.
(쓸데없이 for문을 많이 쓰게 되고, 저장하고 다시 꺼내서 계산하는 과정이 비효율적)
한 줄 입력받고 바로 바로 결과를 구할 수 있는지 생각해보자. - 내장 함수를 잘 알아두자
4. 1이 될 때까지
작성 코드
N, K = map(int, input().split())
count = 0
while 1:
if N == 1:
break
if N % K == 0:
N /= K
else:
N -= 1
count += 1
print(count)
- N이 1이 될 때까지 반복
- 하나의 while문으로 계산
답안 예시 (1)
단순하게 푸는 방법
n, k = map(int, input().split())
result = 0
# N이 K 이상이라면 K로 계속 나누기
while n >= k:
# N이 K로 나누어 떨어지지 않는다면 N에서 1씩 빼기
while n % k != 0:
n -= 1
result += 1
# K로 나누기
n //= k
result += 1
# 마지막으로 남은 수에 대해 1씩 빼기
while n > 1:
n -= 1
result += 1
print(result)
- n >= k가 조건인 while문과 n > 1이 조건인 while문으로 나누어 계산
답안 예시 (2)
# N, K를 공백으로 구분하여 입력받기
n, k = map(int, input().split())
result = 0
while True:
# (N == K로 나누어떨어지는 수)가 될 때까지 1씩 빼기
target = (n // k) * k
result += (n - target)
n = target
# N이 K보다 적을 때(더 이상 나눌 수 없을 때) 반복문 탈출
if n < k:
break
# K로 나누기
result += 1
n //= k
# 마지막으로 남은 수에 대해 1씩 빼기
result += (n - 1)
print(result)
- target은 n이 k로 나누어 떨어지지 않을 때, 가장 가까운 k로 나누어 떨어지는 수를 구해줌
- 남은 수 n을 빼는 횟수를 (n - 1)로 바로 result에 더해 불필요한 반복문을 사용하지 않음
- 반복문이 한 번 실행될 때마다 n이 k로 나누어지는 연산이 수행
> 반복 횟수에 따라 기하급수적으로 n이 빠르게 줄어듦 (log 시간 복잡도)
피드백
- // 연산자 사용할 수 있는 상황을 잘 캐치하자
728x90
반응형
'알고리즘' 카테고리의 다른 글
[그리디] 백준 11047번 동전 0 Python 풀이 (0) | 2021.01.31 |
---|---|
[그리디] 백준 11399번 ATM Python 풀이 (0) | 2021.01.31 |
[그리디] 백준 2839번 설탕 배달 Python 풀이 (0) | 2021.01.30 |
알고리즘 문제를 풀며 주의해야 할 사항 (0) | 2020.06.21 |
알고리즘 알아보기(1) (0) | 2020.04.13 |