[LeetCode-896] 카운터가 아니라 플래그 두 개로 접근해야 하는 문제
[LeetCode-896] 카운터가 아니라 플래그 두 개로 접근해야 하는 문제
- 문제 링크: https://leetcode.com/problems/monotonic-array/
- 파일 경로:
src/main/java/coding_test/배열_리스트/LC0896_MonotonicArray.java - 난이도: Easy
문제 설명
배열이 계속 커지기만 하거나(단조 증가) 계속 작아지기만 하면(단조 감소) 그 배열을 “단조롭다(monotonic)”고 한다. 같은 값은 두 경우 모두 허용된다. 정수 배열 nums가 단조로우면 true, 아니면 false를 반환한다.
1
2
Input: nums = [1,3,2]
Output: false
시행착오
앞의 세 문제(485, 1550, 674)는 전부 “누적 카운터 하나로 최댓값을 갱신”하는 같은 모양이었는데, 이 문제는 그 패턴이 아예 안 맞았다. “증가했다”와 “감소했다”를 각각 별도로 기억해야 해서 increment, decrement 두 개의 불리언 플래그로 접근을 바꿨다. 여기서 네 단계를 거쳐서야 통과했다.
- 처음엔
current < nums[i]/current > nums[i](순수 부등호)로 짰는데, 값이 전부 같은 경우({2,2,2})를 제대로 처리하지 못했다. <=/>=로 바꿨더니, 이번엔 값이 같을 때도 플래그가 켜져버려서{2,2,1}처럼 “같다가 감소”하는 정상 케이스가false로 잘못 나왔다.- 그래서 다시 순수 부등호로 되돌리되, “값이 같을 때는 아무 플래그도 건드리지 않는다”는 걸 명확히 했다 — 같은 값은 증가도 감소도 아니므로 그냥 넘어가면 된다.
- 마지막으로
current를 루프 안에서 매번 갱신하지 않은 버그가 남아있었다 —{1,1,2,1}처럼 “올라갔다가 내려가는” 케이스에서 뒤쪽 변화를 못 잡았다.current = nums[i];를 루프 안 맨 끝으로 옮겨서 매 반복마다 갱신되게 고쳤다.
최종 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public boolean isMonotonic(int[] nums) {
boolean increment = false;
boolean decrement = false;
int current = nums[0];
for (int i = 1; i < nums.length; i++) {
if (current < nums[i]) {
increment = true;
} else if (current > nums[i]) {
decrement = true;
}
current = nums[i];
}
return !(increment && decrement);
}
오늘 배운 내용
“최댓값 하나를 추적하는” 문제와 “여러 조건이 동시에 참인지 거짓인지를 추적하는” 문제는 접근 자체가 다르다. 후자는 카운터가 아니라 플래그(boolean) 여러 개로 설계해야 하고, 그 플래그들은 매 반복마다 최신 상태로 갱신돼야 한다. 그리고 “값이 같은 경우”를 어느 쪽에도 속하지 않는 중립 상태로 두는 것과, 양쪽에 다 속하는 것처럼 처리하는 것은 완전히 다른 결과를 낳는다.
오답노트
- 틀렸던 패턴 1: 순수
</>만 사용 →{2,2,2}같이 값이 전부 같은 경우 두 플래그가 둘 다 안 켜져서 처리 자체는 맞았지만, 이 과정에서 “같음”을 어떻게 다룰지 명확히 결정하지 못한 채로 다음 단계로 넘어갔다. - 틀렸던 패턴 2:
<=/>=로 바꿈 → 값이 같을 때도 플래그가 켜져서,{2,2,1}(같다가 감소)이나{2,2,3}(같다가 증가) 같은 정상 케이스에서 반대쪽 플래그까지 함께 켜져 버려 오판했다. - 왜 틀렸나: “같다”를 증가/감소 어느 한쪽으로 억지로 분류하려고 했기 때문. 같음은 둘 다 아니어야 한다.
- 틀렸던 패턴 3:
current를 루프 밖에서 한 번만 설정하고 안 갱신 →{1,1,2,1}처럼 중간에 올라갔다 내려가는 케이스를 못 잡음. - 고친 패턴: 부등호는 순수
</>만 쓰고,current는 루프 안에서 매 반복 끝에 갱신. - 다음에 떠올릴 시점: 여러 상태를 동시에 추적해야 하는 문제를 보면 카운터가 아니라 플래그로 설계할지부터 판단하고, “같음”을 어느 쪽으로도 분류하지 않는 중립값으로 둘지 먼저 결정한다.
꿀팁
{2,2,1} / {2,2,3} / {1,1,2,1} / {5,5,4,9}처럼 “같은 값으로 시작한 뒤 방향이 바뀌는” 경우를 손으로 먼저 나열해두고 하나씩 검증한 게 버그를 전부 잡아내는 데 결정적이었다. 코드를 짜기 전에 이런 edge case를 먼저 적어두는 습관이 이번에 확실히 도움이 됐다.
This post is licensed under CC BY 4.0 by the author.