2024. 3. 12. 07:45ㆍCoding Test/Python
'이것이 취업을 위한 코딩테스트다'를 읽고 정리한 내용입니다.
그리디(Greedy) : 현재 상황에서 지금 당장 좋은 것만 고르는 방법
그리디 알고리즘은 기준에 따라 좋은 것을 선택하는 알고리즘이기에 문제에서 '가장 큰 순서대로', '가장 작은 순서대로'와 같이 힌트를 제공!
예제 3-1 거스름돈
'가장 큰 화폐 단위부터' 돈을 거슬러 주는 것
n = 1260
count = 0
# 큰 단위의 화폐부터 차례대로 확인
coin_types = [500,100,50,10]
for coin in coin_types:
count += n//coin # 해당 화폐로 거슬러 줄 수 있는 동전 세기
n %= coin
print(count)
가지고 있는 동전 중에서 큰 단위가 항상 작은 단위의 배수이므로 작은 단위의 동전들을 종합해 다른 해가 나올 수 없기 때문이다.
대부분의 그리디 알고리즘 문제에서는 이처럼 문제 풀이를 위한 최소한의 아디어를 떠올리고 이것이 정당한지 검토할 수 있어야 답을 도출할 수 있다!
'10원짜리로만 모두 거슬러줄 경우' -> '최적의 해x' -> '500원짜리부터 거슬러 가장 작은 10원짜리까지 차례대로 거슬러 준다면?' -> '거스름돈 문제에서는 큰 단위가 항상 작은 단위의 배수 형태이므로, 최적의 해 보장!'
화폐의 단위가 무작위로 주어진 경우에는 그리디 알고리즘으로 해결할 수 없다.
예제 3-2 큰 수의 법칙
def solution(n,m,k,num):
num.sort(reverse=True)
num_1 = num[0]
num_2 = num[1]
answer = num_1*k*(m//k) + num_2*(m%k)
return answer
num = [2,4,5,4,6]
print(solution(5,8,3,num))
반복되는 수열에 대해서 파악!
{6,6,6,5}가 반복되며 반복되는 수열의 길이가 바로 (K+1)이다.
M을 (K+1)로 나눈 몫이 수열이 반복되는 횟수가 된다.
M이 (K+1)로 나누어떨어지지 않는 경우:
M을 (K+1)로 나눈 나머지만큼 가장 큰 수가 추가로 더해지므로 이를 고려해주어야 한다.
가장 큰 숫자가 더해지는 횟수는 : (M//(K+1))*K+M%(K+1) = 반복되는 횟수*수열의 길이 + 나머지만큼 가장 큰수가 더해짐
[6,5,4,4,2], M=8, K=3일 경우 : (8//4)*3 + 8%4
6+6+6+5 + 6+6+6+5
[4,4,3,3,3], M=7, K=2일 경우 :
4+4 + 4+4 + 4+4 + 4
def solution(n,m,k,num):
num.sort(reverse=True)
num_1 = num[0]
num_2 = num[1]
# 가장 큰 숫자가 더해지는 횟수
first = (m//(k+1))*k + m%(k+1)
second = m-first
answer = num_1*first + second*num_2
return answer
예제 3-3 숫자 카드 게임
각 행마다 가장 작은 수를 찾은 뒤에 그 수 중에서 가장 큰 수를 찾기!
1) 이중반복문을 쓰지 않을 경우
num = [[3,1,2],[4,1,4],[2,2,2]]
print(num)
def solution(n,m,num):
result = []
for i in range(n): # 행마다 반복
min_value = min(num[i])
result.append(min_value)
return max(result)
2) 이중반복문 쓸 경우
def solution(n,m,num):
result = []
for i in range(n):
for j in num:
min_value = min(j)
result.append(min_value)
return max(result)
예제 3-4 1이 될 때까지
def solution(n,k):
answer = 0
while n!=1:
if n%k!=0:
n = n-1
answer += 1
else:
n = n//k
answer += 1
return answer
N이 매우 큰 수일 경우 빠르게 동작하기 위해서는 N이 K의 배수가 되도록 효율적으로 한번에 빼는 방식이 필요.
def solution(n,k):
result = 0
while True:
# n==k로 나누어떨어지는 수가 될 때까지 1씩 빼기
target = (n//k)*k # 24
result += (n-target) # 1
n = target
# n이 k보다 작을 때 반복분 탈출
if n<k:
break
result += 1 # 2
n //= k # 8
# 마지막으로 남은 수에 대하여 1씩 빼기
result += (n-1)
return result
Q1. 모험가 길드 : N명의 모험가에 대한 정보가 주어졌을 때, 여행을 떠날 수 있는 그룹의 최댓값을 구하는 프로그램 작성하기.
공포도를 오름차순으로 정렬해서 순서대로 그룹을 묶는다.
why?
- 공포도가 오름차순으로 정렬되어 있다면 그룹을 편성할 때 이미 그룹에 포함되어 있는 인원은 생각하지 않아도 된다.
- 최소한의 모험가의 수만으로 그룹이 편성된다.
- 최소한의 인원으로 그룹을 만들어야 그룹의 수도 최대가 된다.
num = [2,3,1,2,2]
def solution(n, num):
num.sort()
result = 0
count = 0
for i in num:
count += 1
if count >= i:
result += 1
count = 0
return result
i=1일 때, count=1이라서 result +1, count = 0
i=2일 때, count=1이라서 count +1
i=2일 때, count=2라서 result +1, count=0
Q2. 곱하기 혹은 더하기 : 두 수에 대하여 연산을 수행할 때, 두 수 중에서 하나라도 1 이하인 경우에는 더하며, 두 수가 모두 2 이상인 경우에는 곱하면 된다.
def solution(s):
num = []
for i in range(len(s)):
num.append(int(s[i]))
answer = num[0]
for j in range(1,len(num)):
if num[j]<=1 or answer<=1:
answer += num[j]
else:
answer *= num[j]
return answer
Q3. 문자열 뒤집기 : 전부 0으로 바꾸는 경우와 전부 1로 바꾸는 경우 중에서 더 적은 수를 가지는 경우를 계산
def solution(s):
count_0 = 0
count_1 = 0
# 첫 번째 원소
if s[0]=='1':
count_0 += 1
else:
count_1 += 1
# 모두 0으로 바꾸는 경우
for i in range(len(s)-1):
if s[i] != s[i+1]:
if s[i+1]=='1':
count_0 += 1
else:
count_1 += 1
return min(count_0, count_1)
Q4. 만들 수 없는 금액 : 만들 수 없는 양의 정수 금액 중 최솟값을 구하는 프로그램
coin_types = [1,2,3,8]
step 0 : 처음에는 금액 1을 만들 수 있는지 확인하기 위해 target = 1로 설정한다.
step 1 : target = 1을 만족할 수 있는 지 확인한다. 화폐 단위가 1인 동전이 있기에 이 동전을 이용해서 금액 1을 만들 수 있다. 이어서 target = 1+1 =2로 업데이트를 한다. (1까지의 모든 금액을 만들 수 있다는 말과 같다.)
step 2 : target = 2를 만족할 수 있는지 확인한다. 화폐 단위가 2인 동전이 있다. 따라서 target = 2+2 = 4가 된다. (3까지의 모든 금액을 만들 수 있다는 말과 같다.)
step 3 : target = 4를 만족할 수 있는지 확인한다. 3인 동전이 있기에 target = 4+3 = 7이 된다.(6까지의 모든 금액을 만들 수 있다는 말과 같다.)
step 4 : target = 7을 만족할 수 있는지 확인한다. 이보다 큰 화폐 단위가 8인 동전이 있기에 따라서 금액 7을 만드는 방법은 없다.
def solution(n, coin_types):
coin_types.sort()
answer = 1
for i in coin_types:
if answer < i:
break
answer += i
return answer
Q5. 볼링공 고르기
내가 푼 코드 :
def solution(n,m,ball):
answer = 0
for i in range(len(ball)-1):
for j in range(i+1,len(ball)):
if ball[i]!=ball[j]:
answer += 1
return answer
내가 푼 코드 2(24.03.28) :
from collections import deque
def solution(data):
queue = deque([i, ball] for i, ball in enumerate(data))
answer = 0
while queue:
q = queue.popleft()
for i in queue:
if q[1] != i[1]:
answer += 1
return answer
이렇게 하면 n과 m 없이 풀 수 있지만 두 코드 모두 시간 복잡도가 O(N^2)이 된다.
동빈나님 코드 :
def solution(n, m, ball):
array = [0]*11
for x in ball:
array[x] += 1
result = 0
for i in range(1, m+1):
n -= array[i]
result += array[i] * n
print(result)
1) 문제에 1부터 10까지의 볼링공 무게가 있다고 했기 때문에 array로 무게 리스트를 만든다.
2) array에 ball에 있는 무게들을 추가하여 무게 몇 개수를 확인!
3) 전체 개수 n에서 특정 무게 개수를 빼고 남은 볼링공과 곱하면 된다!
무게마다 볼링공이 몇 개 있는지를 계산해야 한다.
- 무게가 1인 볼링공 : 1개
- 무게가 2인 볼링공 : 2개
- 무게가 3인 볼링공 : 2개
이 때 A가 특정한 무게의 볼링공을 선택했을 때, 이어서 B가 볼링공을 선택하는 경우를 차례대로 계산하여 문제를 해결할 수 있다. A를 기준으로 무게가 낮은 볼링공부터 무게가 높은 볼링공까지 순서대로 하나씩 확인을 한다고 했을 때 다음과 같다.
step 1 : A가 무게가 1인 공을 선택할 때의 경우의 수는
1(무게가 1인 공의 개수) X 4(B가 선택하는 경우의 수) = 4가지
step 2 : A가 무게가 2인 공을 선택할 때의경우의 수는
2(무게가 2인 공의 개수) X 2(B가 선택하는 경우의 수) = 4가지
step 3 : A가 무게가 3인 공을 선택할 때의 경우의 수는
2(무게가 3인 공의 개수) X 0(B가 선택하는 경우의 수) = 0가지
단계가 진행됨에 따라 'B가 선택하는 경우의 수'는 줄어드는데, 이미 계산했던 경우(조합)는제외하기 때문.
또한, 볼링공의 무게가 1부터 10까지만 존재할 수 있다고 명시되어 있다. 따라서 하나의 리스트 변수를 선언해서, 각 무게별로 볼링공이 몇 개가 존재하는지 기록할 수 있다.
Q6. 무지의 먹방 라이브
내가 푼 코드 :
def solution(food_times, k):
result = 0
time = 0
while time>k:
for i in range(len(food_times)):
if food_times[i]!=0:
food_times[i] = foold_times[i]-1
time +=1
else:
food_times[::-1] = food
result = time%len(food_times)+1
return result
이렇게 풀었지만 책에 나와있는
food_times=[8,6,4], K=15일 경우 틀린다.
'Coding Test > Python' 카테고리의 다른 글
| [Python] 프로그래머스 / 알고리즘 고득점 Kit / hash 정리 / items() (0) | 2024.03.20 |
|---|---|
| [Python] 힙(heapq) 정리 (0) | 2024.03.15 |
| [Python] 프로그래머스 / 스택/큐 / 주식가격 / 리스트 숫자 비교 (0) | 2024.03.09 |
| [Python] 프로그래머스 / 스택/큐 / 다리를 지나는 트럭 (0) | 2024.03.09 |
| [Python] 프로그래머스 / 스택/큐 / 프로세스 / any() (0) | 2024.03.06 |