'탐욕스러운 알고리즘' : 나중을 생각하지 않고 지금 할 수 있는 최선의 선택을 한다.
특징
동전 {500, 100, 50, 10, 5, 1} 으로 1200원을 거슬러줄 때 최소 동전 개수를 구하라.
public class GreedyPractice {
static void main(String[] args) {
int[] moneyList = {500, 100, 50, 10, 5, 1};
int amount = 1200;
int totalCount = 0;
for (int money : moneyList) {
int count = amount / money;
if (count > 0) {
System.out.println(money + "짜리 동전 X " + count + "개");
totalCount += count;
amount -= money * count;
}
if (amount == 0) break;
}
System.out.println("최소 동전 개수 : " + totalCount + "개");
}
}
500짜리 동전 X 2개
100짜리 동전 X 2개
최소 동전 개수 : 4개
내림차순으로 정렬된 동전 배열을 반복문으로 돌려 제일 큰 동전부터 선택한다.
int count = amount / money; // 현재 동전으로 줄 수 있는 최대 개수
→ 1200 / 500 = 2개
totalCount += count; // 총 개수에 더하기
amount -= money * count; // 금액에서 빼기
→ totalCount = 2, amount = 1200 - 1000 = 200원 남음
다음 동전 100원이 들어오면
→ 200 / 100 = 2개
→ totalCount = 4, amount = 200 - 200 = 0원
if (amount == 0) break; // 금액이 0이면 종료
→ 반복문 종료, 최소 동전 개수 4개 출력
문제 : 하나의 회의실에서 겹치지 않게 최대한 많은 회의를 열어라. 각 회의는 {시작 시간, 종료 시간} 으로 주어진다.
int[][] meetings = {
{1, 4}, {3, 5}, {0, 6}, {5, 9}, {3, 7},
{5, 9}, {6, 10}, {8, 11}, {8, 12}, {2, 14}, {12, 16}
};
Arrays.sort(meetings, (a, b) -> a[1] - b[1]);
int count = 0;
int lastEnd = 0;
for (int[] meeting : meetings) {
int start = meeting[0];
int end = meeting[1];
if (lastEnd <= start) {
lastEnd = end;
count += 1;
System.out.println(count + "번째 회의! 시작 시간 : " + start + ", 끝 시간 : " + end);
}
}
System.out.println("총 회의 수 : " + count);
1번째 회의! 시작 시간 : 1, 끝 시간 : 4
2번째 회의! 시작 시간 : 5, 끝 시간 : 9
3번째 회의! 시작 시간 : 12, 끝 시간 : 16
총 회의 수 : 3
종료 시간이 짧을수록 새로운 회의를 더 많이 열 수 있으므로 종료 시간을 기준으로 오름차순 정렬한다.
Arrays.sort(meetings, (a, b) -> a[1] - b[1]);
a[1] - b[1] 의 반환값으로 정렬 방향을 결정한다.
a = 5, b = 6 → 5 - 6 = -1 (음수) → 자리 유지 → 오름차순
a = 6, b = 5 → 6 - 5 = 1 (양수) → 자리 바꿈 → 오름차순
그러므로 a[1] - b[1]는 어떤 값이 들어와도 항상 오름차순이 된다.
내림차순을 하고 싶으면 b[1] - a[1] 이와 같이 작성하면 된다.
정렬 후 반복문으로 종료 시간이 짧은 회의부터 가져온다.
if (lastEnd <= start) {
lastEnd = end;
count += 1;
}
이전 회의 종료 시간(lastEnd)과 현재 회의 시작 시간(start)을 비교해서 현재 회의 시작 시간이 같거나 늦다면 회의를 시작할 수 있으므로 count 를 1 증가시키고 lastEnd 를 현재 회의 종료 시간으로 갱신한다.
코드를 보고 선생님의 설명을 들을 때는 이해가 됐다고 생각했는데, 막상 문제만 놓고 혼자 풀어보려니 쉽지 않았다.
그리디는 단순히 코드를 외우는 게 아니라 문제마다 어떤 기준이 최선인지를 파악하는 게 핵심인 것 같다.
앞으로 문제를 많이 풀어보면서 감을 익혀야겠다. 💪