Algorithm/프로그래머스
[프로그래머스][Java] 택배 배달과 수거하기 (267)
샤아이인
2023. 4. 27. 15:24
직접 풀어보고 올리는 코드입니다. 지적이나 더 좋은 방향에 대한 댓글은 항상 환영합니다.
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
생각의 흐름
생각이고 나발이고 문제 진짜 어렵다 생각 드는데, 이거 나처럼 greedy라고 생각 못한 사람은 끝까지 이 문제 못 건들이다가 끝났을것 같다.
일단 N제한이 100,000 이라 O(N^2), 즉 완전 탐색은 절대 안된다 생각했다.
여기서 문제다.
그럼 O(logN) = 5, O(NlogN) = 500,000, O(N) = 1000,000 이 가능 할탠데....
뭔가 정렬되 있는 순차 중에서 탐색을 하는 느낌은 아니라, O(logN)의 이진탐색 방식은 아닐꺼라 생각했고...
남은 O(NlogN) = 500,000, O(N) = 1000,000 중 하난데...
여기서 부터 계속 특정 알고리즘만 생각하다 Greedy 라는 점은 알아차리지 못했다.
(평소 탐욕 문제 잘 안풀어본 업보 인 것 같다)
이 문제를 위한 greedy 전략은 다음과 같습니다.
- 배달 및 수거할 택배 상자가 남은 가장 먼 집부터 택배를 배달 및 수거합니다.
- 트럭이 물류창고에서 출발해 가장 먼 집으로 이동할 때는 배달만 하고, 다시 물류창고로 돌아올 때는 수거만 합니다.
- 트럭이 물류창고에서 출발할 때 항상 택배를 최대 개수만큼 배달하고, 물류창고로 돌아갈 때 최대 개수만큼 수거합니다.
왕복 한번을 하나의 반복문이라 생각하고, 하나의 loop안에서 배달 한번, 수거 한번을 진행한후 이를 반복하면 됩니다.
나의 코드
import java.util.*;
class Solution {
public long solution(int cap, int n, int[] deliveries, int[] pickups) {
long answer = 0;
Stack<Info> go = new Stack<>();
Stack<Info> back = new Stack<>();
for(int i = 0; i < n; i++) {
if(deliveries[i] > 0) {
go.push(new Info(i + 1, deliveries[i]));
}
if(pickups[i] > 0) {
back.push(new Info(i + 1, pickups[i]));
}
}
while(!go.isEmpty() || !back.isEmpty()) {
int goLen = go.isEmpty() ? 0 : go.peek().houseNumber;
int backLen = back.isEmpty() ? 0 : back.peek().houseNumber;
if(goLen > backLen) {
answer += goLen * 2;
} else {
answer += backLen * 2;
}
int box = 0;
while(!go.isEmpty() && box <= cap) {
if(cap >= go.peek().cnt + box) { // 모두 배달 가능한 경우
box += go.peek().cnt;
} else { // 일부 배달 가능한 경우
go.peek().cnt -= (cap - box);
break;
}
go.pop();
}
box = 0;
while(!back.isEmpty() && box <= cap) {
if(cap >= back.peek().cnt + box) {
box += back.peek().cnt;
} else {
back.peek().cnt -= (cap - box);
break;
}
back.pop();
}
}
return answer;
}
static class Info {
public int houseNumber;
public int cnt;
public Info(int houseNumber, int cnt) {
this.houseNumber = houseNumber;
this.cnt = cnt;
}
}
}