Post

[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 두 개의 불리언 플래그로 접근을 바꿨다. 여기서 네 단계를 거쳐서야 통과했다.

  1. 처음엔 current < nums[i] / current > nums[i](순수 부등호)로 짰는데, 값이 전부 같은 경우({2,2,2})를 제대로 처리하지 못했다.
  2. <=/>=로 바꿨더니, 이번엔 값이 같을 때도 플래그가 켜져버려서 {2,2,1}처럼 “같다가 감소”하는 정상 케이스가 false로 잘못 나왔다.
  3. 그래서 다시 순수 부등호로 되돌리되, “값이 같을 때는 아무 플래그도 건드리지 않는다”는 걸 명확히 했다 — 같은 값은 증가도 감소도 아니므로 그냥 넘어가면 된다.
  4. 마지막으로 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.