135 - Candy
info
- 문제 보기: 135 - Candy
- 소요 시간: 51분
- 풀이 언어:
java
- 체감 난이도: 3️⃣
- 리뷰 횟수: ✅
풀이 키워드
스포주의
그리디
풀이 코드
info
- 메모리: 45700 KB
- 시간: 2 ms
class Solution {
public int candy(int[] ratings) {
// check continuous asc/desc rating order
int n = ratings.length;
int ans = n;
int asc[] = new int[n];
int desc[] = new int[n];
int v = 0;
for (int i = 1; i < n; ++i) {
asc[i-1] = v;
if (ratings[i-1] < ratings[i]) ++v;
else v = 0;
}
asc[n-1] = v;
v = 0;
for (int i = n-1; 0 < i; --i) {
desc[i] = v;
if (ratings[i-1] > ratings[i]) ++v;
else v = 0;
}
desc[0] = v;
for (int i = 0; i < n; ++i) {
ans += Math.max(asc[i], desc[i]);
}
return ans;
}
}
풀이 해설
rating이 인접 칸보다 높으면 반드시 사탕을 더 받게끔 하면서
배분된 총 사탕 개수는 최소로 만들어야 하는 문제이다.
이번에도 어김없는 말장난
You are giving candies to these children subjected to the following requirements:
Each child must have at least one candy.
Children with a higher rating get more candies than their neighbors.
더 높은 rating일 경우라고 명시했고, 같은 rating에 대해선 아무 언급이 없다.
없으면 뭐다? 해당 제약의 대상이 아니라는 것이다.
🙃 거꾸로 생각해보자
{1, 5, 7}
만약 값들이 오름차순으로 되어있다면 사탕을 점점 1씩 늘려가며 배분해주면 된다. 아주 EZ하다.
그런데 내림차순은?
{9, 3, 2}
'그냥 연속된 내림차순 구간 길이를 구하면 되지 않나?'라고 생각할 수 있지만,
그렇게 한꺼번에 구하면 다음과 같은 케이스에서 사탕 배분이 까다로워진다.
{1, 2, 3, 2, 1}
이러면 다음 값이 오름차순일 경우, 같을 경우, 내림차순일 경우를 나눠서 i
, j
인덱스, 연속 구간 길이, 배분할 사탕 수 등의 여러 상태 변수를 계속 관리해주어야 한다.
하지만 수행 시간 약간만 희생하면 이런 복잡한 상태관리를 안해도 된다.
➡️ 오름차순 기준으로만 정방향 스캔해서 배분한 결과와
⬅️ 오름차순 기준으로만 역방향 스캔해서 배분한 결과를 따로 저장해놓고 둘이 비교하면 되기 때문이다.
기준에 맞지 않는다면 배분할 사탕 수를 0으로 초기화해서 총 배분 수를 최소화하고
마지막엔 동일 인덱스에 대하여 두 배분 결과 중 더 큰 값을 선택한다.
(정방향에서 0인데 역방향은 기준에 해당해서 1일 수 있고 그러니까)
결과적으로 의 시간복잡도를 가지게 된다.
꼬다리 처리해주기
for문 내에서 i
번째 칸에 값을 넣어주고 있는데, i
가 모든 인덱스를 순회하는 것이 아니므로 순회 후 따로 꼬다리로 남은 인덱스를 처리해주어야 한다.
for (int i = 1; i < n; ++i) { ... }
asc[n-1] = v;
for (int i = n-1; 0 < i; --i) { ... }
desc[0] = v;
물론 순회 끝난 i
값을 참조해도 되는데, 이러면 i
의 스코프를 밖으로 빼야 하고 조금 덜 직관적인 것 같아 n-1, 0으로 인덱싱했다.
메모
- 처음에 또 오름차순 내림차순 연속구간을 한꺼번에 처리하려고 투포인터로 짜다가 2359번의 메모 내용이 떠올라서 해당 방식으로 드리프트했는데 현명한 선택이었음 ㅇㅅㅇb