
그리디 (탐욕법)
현재 상황에서 지금 당장 좋은 것만 고르는 방법을 의미한다.
탐욕적으로!!
예시
[문제 상황] 루트 노드부터 시작하여 거쳐가는 노드 값의 합을 최대로 만들고 싶다.

최적의 해는 ?
5-7-9 가 제일 큰 값이다. (최적의해 21)
단순히 매 상황에서 가장 큰 값만 고른다면 ?? (단순하게 직관적이게 = 탐욕적이게?)
5-10-4 이렇게 될텐데, 이러면 19가 된다.
일반적인 상황에서 그리디 알고리즘은 최적의 해를 보장할 수 없을 때가 많다.
일반적으로 그리디를쓰면 최적의해에 가깝게 얻을수있을수있다.
하지만 코테에서 대부분 그리디 문제는 탐욕법으로 얻은 해가 최적의 해가 되는 상황에서, 이를 추론할 수 있어야 풀리도록 출제된다.
해답
500원 먼저 주면 2개 (1000원) 남은돈 260원
100원 은 2개 (200원) 남은돈 60원
이후 50원 , 10원 1개씩 60원
정당성 분석
시간복잡도 분석 = 동전의 종류의 수 = K , 일때 O(K)이다.
//js
function solution(n){
let cnt ;
let coinTypes = [500,100,50,10];
coinTypes.map((el)=>{
cnt += n / el;
n %= el;
})
return cnt;
}
solution(1260)
시간제한 2초?
1이상 10만 이하의 수 N
2이상 10만 이하의 수 K
각각 자연수
해답
| 단계 | 연산 과정 | N의 값 |
|---|---|---|
| 0단계 | N = 25 | |
| 1단계 | N에서 1 빼기 | N = 24 |
| 2단계 | N을 K로 나누기 | N = 8 |
| 3단계 | N에서 1 빼기 | N = 7 |
| 4단계 | N에서 1 빼기 | N = 6 |
| 5단계 | N을 K로 나누기 | N = 2 |
| 6단계 | N에서 1 빼기 | N = 1 |
정당성 분석
optimal한 해)를 항상 보장할 수 있을까?실제 입력값들이 10만정도이기때문에 매번 반복문으로 확인을 해도된다.
하지만 코드 효율성과 시간복잡도를 줄이기위해 테크닉을 가미한다.
function solution(input){
let n = input.split(" ")[0];
let k = input.split(" ")[1];
let result = 0;
let target;
while(true){
// N이 K로 나누어 떨어지는 수가 될 때까지 빼기
target = Math.floor(n / k) * k;
result += (n - target);
n = target;
// N이 K보다 작을 때 (더 이상 나눌 수 없을 때) 반복문 탈출
if(n<k){
break;
}
// K로 나누기
result += 1
n /= k
}
// 마지막으로 남은 수에 대하여 1씩 빼기
result += (n-1)
return result;
}
solution("25 3")
위 로직은 O(logK) 로그 시간 복잡도를 가집니다.
해답
- 대부분의 경우 '+'보다는 'x'가 더 값을 크게 만듭니다.
- 예를 들어 5 + 6 = 11이고, 5 x 6 = 30입니다.
- 다만 두 수 중에서 하나라도 '0' 혹은 '1'인 경우, 곱하기보다는 더하기를 수핵하는 것이 효율적이다.
- 따라서 두 수에 대하여 연산을 수행할때, 두 수 중에서 하나라도 1이하인 경우에는 더하며, 두 수가 모두 2이상인 경우에는 곱하면 정답입니다.
function solution(input){
let result = Number(input[0]);
for(let i=1; i<input.length; i++){
if(input[i]<=1 || result<=1){
result += Number(input[i])
}else{
result *= Number(input[i])
}
}
return result
}
solution("02984")
해답
오름차순 정렬 이후에 공포도가 가장 낮은 모험가부터 하나씩 확인합니다.
앞에서부터 공포도를 하나씩 확이하며 '현재 그룹에 포함된 모험가의 수'가 '현재 확인하고 있는 공포도'보다 크거나 같으면 이를 그룹으로 설정하면 된다.
만약 이방법을 사용하면 오름차순 정렬되서, 항상 최소한의 모험가의 수만 포함하여 그룹을 결성하게된다. = 즉 전체 그룹수는 정답일수 있지만, 그룹을 카운팅할 당시 그룹원들은 optical하지 않을수 있다는것이다. 하지만 문제에서 요구하는 전체 그룹수는 optical하다.
조금 헷갈렸는데
핵심은 참여 조건이다.
X공포도인 모험가는 X명이상으로 구성된 그룹에 참여할수있다.
문제자체가 이해가안된다면 위 문구를 다시한번생각해보는게 좋을거같다.
function solution(input){
let data = input.split(" ")
let result = 0; // 총 그룹의 수
let count = 0; // 현재 그룹에 포함된 모험가의 수
data.sort() // 오름차순 정렬
for(let i=0; i<data.length; i++){
count += 1; //현재그룹에 해당 모험가(현재선택된 i)를 포함시킨다.
if(count >=i){ //현재 그룹에 포함된 모험가의 수가 현재의 공포도 이하라면, 그룹결성
//조건확인 : 아니기때문에 새그룹 생성
result += 1; // 총 그룹의 수 증가시키기
count = 0; // 현재 그룹에 포함된 모험가의 수 초기화
}
}
return result;
}
solution("2 3 1 2 2")