자바스크립트 코딩테스트 강좌, 슬라이딩 윈도우

1. 슬라이딩 윈도우란?

슬라이딩 윈도우(Sliding Window) 기술은 주어진 배열이나 리스트에서 특정 조건을 만족하는 서브 배열(subarray) 또는 서브 문자열(substring)을 찾기 위해 사용되는 알고리즘 기법입니다. 주로 연속된 원소들이 필요한 문제에 적합하며, 문제에 따라 고정된 크기 또는 가변 크기 창(window)을 사용합니다.

1.1 슬라이딩 윈도우의 장점

슬라이딩 윈도우의 가장 큰 장점은 브루트 포스(brute force) 방법에 비해 시간 복잡도를 크게 줄일 수 있다는 점입니다. 일반적으로 O(n^2)에서 O(n)으로 줄일 수 있는 경우가 많습니다. 슬라이딩 윈도우는 두 개의 포인터를 사용하여 배열을 순회하며 효율적인 접근을 가능하게 합니다.

2. 알고리즘 문제 예시

문제: 최대 길이의 반복 문자 대체

주어진 문자열이 있을 때, ‘k’개의 다른 문자로 변경하여 만들 수 있는 가장 긴 부분 문자열의 길이를 반환하는 함수를 작성하세요.


    예시:
    입력: s = "AABABBA", k = 1
    출력: 4
    설명: 변경할 수 있는 문자는 'A' 또는 'B'이다. 'B' 두 개를 'A'로 바꿔 'AAAA'를 만들 수 있다.
    

문제 접근 방식

이 문제를 해결하기 위해 슬라이딩 윈도우를 사용할 수 있습니다. 여기서는 현재 윈도우에 포함된 문자의 개수를 세고, k개의 문자를 대체할 수 있는지 확인합니다.

2.1 알고리즘 단계

  1. 왼쪽 포인터(left)와 오른쪽 포인터(right)를 초기화한다.
  2. 부분 문자열의 문자를 세기 위해 HashMap을 사용한다.
  3. 현재 윈도우의 유효성을 확인한다.
  4. 유효하지 않으면 왼쪽 포인터를 이동시킨다.
  5. 현재 윈도우 크기를 기록하고, 오른쪽 포인터를 이동시킨다.
  6. 이 과정을 반복하여 최대 길이를 구한다.

3. 코드 구현

아래는 위에서 설명한 알고리즘을 바탕으로 작성한 자바스크립트 코드입니다.


    function characterReplacement(s, k) {
        const countMap = {};
        let left = 0;
        let maxLength = 0;
        let maxCount = 0;

        for (let right = 0; right < s.length; right++) {
            countMap[s[right]] = (countMap[s[right]] || 0) + 1;
            maxCount = Math.max(maxCount, countMap[s[right]]);

            while (right - left + 1 - maxCount > k) {
                countMap[s[left]]--;
                left++;
            }

            maxLength = Math.max(maxLength, right - left + 1);
        }

        return maxLength;
    }

    // 사용 예시
    console.log(characterReplacement("AABABBA", 1)); // 4
    

4. 코드 설명

위의 코드에서 우리는 ‘s’ 문자열을 주어진 ‘k’에 대해 반복적으로 처리하고 있습니다. 각 문자의 발생 빈도를 세기 위해 countMap을 사용하고 있으며, 현재 윈도우에서 가장 많이 나타나는 문자의 개수를 추적합니다.

4.1 주요 변수 설명

  • countMap: 각 문자의 개수를 세는 객체
  • left: 윈도우의 왼쪽 경계
  • maxLength: 최대 길이 저장
  • maxCount: 현 윈도우에서 가장 많이 나타나는 문자의 개수

4.2 슬라이딩 윈도우의 이동

오른쪽 포인터는 문자열의 끝까지 이동하며 증가시키고, 왼쪽 포인터는 현재 윈도우가 유효하지 않을 때만 이동합니다. 유효한 조건은 현재 윈도우의 크기에서 가장 많이 나타나는 문자의 개수를 빼고 그 결과가 ‘k’보다 작거나 같아야 합니다. 이는 특정 문자를 대체할 수 있는지를 체크하는 방식입니다.

5. 시간 복잡도와 공간 복잡도

이 알고리즘의 시간 복잡도는 O(n)입니다. 문자열의 각 문자를 한 번만 순회하며, 공간 복잡도는 O(1)입니다. 왜냐하면 알파벳 대문자만을 고려하기 때문에 단 26개의 문자를 저장할 수 있기 때문입니다.

6. 다양한 문제 해결 방법

슬라이딩 윈도우는 매우 다양하게 응용될 수 있는 기법입니다. 따라서 이 개념을 마스터 하는 것은 다른 많은 알고리즘 문제를 해결하는 데 도움이 됩니다. 예를 들어:

  • 최대 연속 1의 개수 문제
  • 최소 길이의 부분 수열 합 문제
  • 모든 아나그램 찾기 문제

6.1 추가 문제 예시

다음과 같은 문제도 슬라이딩 윈도우로 효율적으로 해결할 수 있습니다:


    문제: 가장 짧은 부분 수열의 경우
    주어진 배열에서 특정 수의 합을 만들기 위한 최소의 부분 수열 길이를 찾으세요.
    

7. 결론

이번 강좌를 통해 슬라이딩 윈도우 기술의 기본 개념과, 이를 활용한 알고리즘 문제를 하나 풀어보았습니다. 이 기법은 특히 문자열 처리와 서브 배열 그리기 문제에서 매우 유용하므로, 충분히 연습하고 숙지하여 다양한 변형 문제를 해결할 수 있도록 하세요.

슬라이딩 윈도우 패턴을 마스터하면 알고리즘 문제의 난이도를 크게 줄일 수 있으며, 실제로 회사의 코딩 테스트에서도 자주 등장하는 주제입니다. 앞으로 많은 연습을 통해 이 기법을 완벽히 습득하시길 바랍니다.

8. 추가 리소스

더 많은 슬라이딩 윈도우 문제를 풀어보고 싶다면 LeetCode, HackerRank와 같은 온라인 플랫폼에서 수많은 문제를 찾아보실 수 있습니다.

자바스크립트 코딩테스트 강좌, 카드 정렬하기

요즘 많은 회사들이 코딩테스트를 통해 지원자의 알고리즘과 문제 해결 능력을 평가하고 있습니다. 이번 시간에는 카드 정렬하기라는 주제를 가지고, 문제를 해결하는 과정을 같이 살펴보도록 하겠습니다. 카드 정렬하기는 아주 간단하면서도 자주 출제되는 문제 중 하나로, 알고리즘과 데이터 구조의 기본적인 이해가 필수적입니다.

문제 설명

카드게임을 위해 각 카드의 번호가 적힌 카드들을 정렬하려고 합니다. 카드의 개수는 N개이고, 각 카드에는 1부터 N까지의 정수 번호가 적혀 있습니다. 주어진 카드 배열을 오름차순으로 정렬한 후 카드의 최종 배열 상태를 출력해야 합니다.

입력 형식

첫 줄에 카드의 개수 N(1 ≤ N ≤ 1000)이 주어지고, 두 번째 줄에 카드의 번호가 공백으로 구분되어 주어집니다.

출력 형식

정렬된 카드의 번호를 공백으로 구분하여 출력합니다.

예제 입력

5
3 2 1 4 5
    

예제 출력

1 2 3 4 5
    

문제 접근 방법

문제를 해결하기 위해 다음과 같은 접근 방법을 사용할 수 있습니다.

  1. 입력 데이터 수집: 카드의 개수와 카드의 번호를 입력받습니다.
  2. 정렬 알고리즘 선택: 자바스크립트의 내장 메서드를 활용하여 배열을 정렬합니다.
  3. 출력 형식에 맞게 데이터 출력: 정렬된 배열을 출력합니다.

코드 작성

이제 본격적으로 코드를 작성해보겠습니다. 다음은 카드 정렬하기 문제를 해결하기 위한 자바스크립트 코드입니다.


function sortCards(cards) {
    return cards.sort((a, b) => a - b);
}

function main() {
    const n = parseInt(prompt("카드의 개수를 입력하세요:")); // 카드를 입력받기 위한 프롬프트
    const cardsInput = prompt("카드 번호를 입력하세요 (공백으로 구분):"); // 카드 번호 입력
    const cards = cardsInput.split(" ").map(Number); // 공백으로 구분된 문자열을 정수 배열로 변환

    const sortedCards = sortCards(cards); // 정렬 메서드 호출
    console.log(sortedCards.join(" ")); // 정렬된 카드 출력
}

main();

    

코드 설명

작성한 코드의 각 부분에 대해 설명하겠습니다.

sortCards 함수

sortCards 함수는 카드 번호 배열을 받아서 오름차순으로 정렬하여 반환합니다. 자바스크립트의 내장 메서드인 sort를 사용하였고, 숫자의 크기를 비교하기 위한 화살표 함수를 이용하였습니다.

main 함수

main 함수에서는 다음과 같은 작업을 수행합니다:

  • prompt를 이용해 카드의 개수를 입력받습니다.
  • 다시 prompt를 통해 카드 번호를 입력받아 문자열로 전달합니다.
  • split 메서드를 사용하여 공백으로 구분된 문자열을 배열로 변환하고, map 메서드를 이용하여 각 요소를 숫자로 변환합니다.
  • sortCards 함수를 호출하여 정렬된 배열을 얻습니다.
  • 결과를 join 메서드를 사용하여 문자열로 변환한 후 콘솔에 출력합니다.

테스트 및 검증

작성한 코드를 테스트하여 다양한 입력에 대해 올바르게 작동하는지 검증해보겠습니다.

테스트 케이스 1

입력:
5
3 2 1 4 5

출력:
1 2 3 4 5
    

테스트 케이스 2

입력:
4
8 3 5 2

출력:
2 3 5 8
    

결론

이번 강좌에서는 카드 정렬하기 문제를 통해 자바스크립트의 배열 메서드를 활용하여 문제를 해결하는 방법을 살펴보았습니다. 또한, 코드 작성을 통해 접근 방식과 각 함수의 역할을 이해하는 시간을 가졌습니다. 이와 같은 문제들은 알고리즘 시험에서 자주 출제되므로, 연습을 통해 문제 해결 능력을 향상시키는 것이 중요합니다.

추가적인 자료

더욱 심화된 알고리즘 문제를 연습하기 원하시는 분들은 아래 링크를 참고하시기 바랍니다:

  • LeetCode – 다양한 알고리즘 문제를 제공합니다.
  • HackerRank – 알고리즘 및 데이터 구조 문제를 제공합니다.
  • Codewars – 다양한 난이도의 문제를 제공하며, 커뮤니티와 상호작용할 수 있습니다.

이상으로 자바스크립트 코딩테스트 강좌를 마치겠습니다. 성공적인 코딩테스트 준비를 위해 항상 노력을 기울이시기 바랍니다!

자바스크립트 코딩테스트 강좌, 퀵 정렬

코딩테스트에서 자주 등장하는 문제 중 하나가 배열 정렬입니다. 이 강좌에서는 퀵 정렬(Quick Sort) 알고리즘에 대해 알아보고, 이를 자바스크립트로 구현하는 방법을 자세히 설명하겠습니다. 퀵 정렬은 효율적인 정렬 알고리즘으로, 분할 정복(Divide and Conquer) 기법을 이용합니다.

문제 설명

주어진 배열을 퀵 정렬 알고리즘을 사용하여 오름차순으로 정렬하시오.

예제 입력: [34, 7, 23, 32, 5, 62]
예제 출력: [5, 7, 23, 32, 34, 62]

퀵 정렬 알고리즘 개요

퀵 정렬은 아래와 같은 단계로 진행됩니다.

  1. 배열에서 하나의 원소를 피벗(pivot)으로 선택합니다.
  2. 피벗을 기준으로 배열을 두 개의 부분 배열로 나눕니다. 하나는 피벗보다 작은 원소들로 구성되고, 다른 하나는 피벗보다 큰 원소들로 구성됩니다.
  3. 각 부분 배열에 대해 동일한 방법을 재귀적으로 적용합니다.
  4. 부분 배열이 크기가 0 또는 1이 될 때까지 반복합니다.

예제 설명

입력 배열이 [34, 7, 23, 32, 5, 62]일 경우, 다음과 같은 과정을 거칩니다.

  1. 피벗 선택: 배열의 마지막 원소인 62를 피벗으로 선택합니다.
  2. 분할: 피벗인 62보다 작은 원소들([34, 7, 23, 32, 5])과 큰 원소([])로 배열을 나눕니다.
  3. 재귀 호출: 피벗보다 작은 부분 배열 [34, 7, 23, 32, 5]에 대해 동일한 과정을 반복합니다.
  4. 이 과정을 반복하여 최종적으로 배열이 정렬됩니다.

자바스크립트 구현

이제 퀵 정렬 알고리즘을 자바스크립트로 구현해 보겠습니다.

function quickSort(arr) {
    if (arr.length <= 1) {
        return arr; // 크기가 0 또는 1인 경우 그대로 반환
    }
    
    const pivot = arr[arr.length - 1]; // 피벗으로 마지막 원소 선택
    const left = []; // 피벗보다 작은 원소를 저장할 배열
    const right = []; // 피벗보다 큰 원소를 저장할 배열

    // 배열을 순회하며 피벗과 비교
    for (let i = 0; i < arr.length - 1; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }

    // 재귀 호출 및 결과 배열 반환
    return [...quickSort(left), pivot, ...quickSort(right)];
}

// 예제 배열
const array = [34, 7, 23, 32, 5, 62];
const sortedArray = quickSort(array);
console.log(sortedArray); // [5, 7, 23, 32, 34, 62]

알고리즘의 시간 복잡도

퀵 정렬 알고리즘의 평균적인 시간 복잡도는 O(n log n)입니다. 하지만 최악의 경우에는 O(n²)의 시간 복잡도를 가질 수 있습니다. 이는 피벗 선택이 불균형할 경우 발생할 수 있습니다. 이 때문에 퀵 정렬은 피벗을 무작위로 선택하는 등의 최적화 기법을 통해 성능을 향상시킬 수 있습니다.

퀵 정렬의 장단점

장점

  • 효율적인 정렬 알고리즘으로, 대규모 데이터 정렬에 적합합니다.
  • 메모리 사용량이 적어, 인플레이스(in-place) 정렬이 가능합니다.

단점

  • 최악의 경우 시간 복잡도가 O(n²)로 비효율적입니다.
  • 재귀적으로 호출되므로 스택 메모리 사용이 발생합니다.

결론

이번 강좌에서는 퀵 정렬 알고리즘과 함께, 이를 자바스크립트로 구현하는 방법에 대해 배워보았습니다. 퀵 정렬은 구현이 간단하고 효율적인 정렬 알고리즘으로, 코딩테스트와 알고리즘 문제 풀이에 자주 사용됩니다. 학습한 내용을 바탕으로 다양한 배열 정렬 문제를 풀어보시기 바랍니다.

다음 강좌에서는 다른 정렬 알고리즘인 머지 정렬(Merge Sort)에 대해 다룰 예정입니다. 관심을 가져 주시기 바랍니다!

자바스크립트 코딩테스트 강좌, 임계 경로 구하기

문제 설명

여러분은 다양한 작업이 연결되어 있는 프로젝트 관리 시스템을 관리하고 있습니다. 각 작업은 특정 시간 동안 수행되어야 하며, 어떤 작업은 다른 작업의 완료 후에만 시작할 수 있습니다. 이러한 관계를 파악하고, 프로젝트가 완료되는 데 필요한 최소 시간을 계산하는 알고리즘을 구현하세요.

프로젝트는 다음과 같은 정보로 구성됩니다:

  • n : 작업의 개수
  • dependencies : 각 작업 간의 종속 관계를 나타내는 배열
  • times : 각 작업을 수행하는 데 필요한 시간의 배열

함수의 형식은 다음과 같습니다:

function criticalPath(n, dependencies, times) {
    // 여기에 코드를 작성하세요.
}
    

입력 예시

n = 5
dependencies = [[1, 0], [2, 1], [3, 1], [3, 2], [4, 3]]
times = [3, 2, 5, 1, 2]
입력: criticalPath(n, dependencies, times)
    

출력 예시

출력: 11
    

문제 풀이 접근법

이 문제를 해결하기 위해서는 다음과 같은 단계를 거쳐야 합니다:

1. 그래프 모델링

작업과 그 간의 종속 관계를 그래프 형태로 변환하여 표현합니다. 각 작업을 정점으로, 종속 관계를 간선으로 표현할 수 있습니다.

2. 위상 정렬 (Topological Sort)

주어진 그래프의 위상 정렬을 통해 작업의 수행 순서를 정합니다. 위상 정렬은 방향 그래프의 모든 정점을 방문하는 선형 배열을 찾는 과정입니다.

3. 최장 경로 (Longest Path) 계산

위상 정렬을 이용하여 각 작업의 시작 시점을 계산하고, 최종적으로 모든 작업이 완료되는 데 걸리는 최소 시간을 구합니다.

구현 코드

다음은 위의 접근법을 구현한 자바스크립트 코드입니다:

function criticalPath(n, dependencies, times) {
    const adjList = Array.from({length: n}, () => []);
    const inDegree = Array(n).fill(0);
    
    // 1. 그래프와 진입 차수 계산
    for (const [next, prev] of dependencies) {
        adjList[prev].push(next);
        inDegree[next]++;
    }
    
    // 2. 위상 정렬을 위한 큐 생성
    const queue = [];
    const timeToComplete = Array(n).fill(0);
    
    for (let i = 0; i < n; i++) {
        timeToComplete[i] = times[i];
        if (inDegree[i] === 0) {
            queue.push(i);
        }
    }
    
    // 3. 최장 경로 계산
    let maxTime = 0;

    while (queue.length) {
        const current = queue.shift();
        maxTime = Math.max(maxTime, timeToComplete[current]);

        for (const neighbor of adjList[current]) {
            timeToComplete[neighbor] = Math.max(timeToComplete[neighbor], timeToComplete[current] + times[neighbor]);
            inDegree[neighbor]--;
            if (inDegree[neighbor] === 0) {
                queue.push(neighbor);
            }
        }
    }
    
    return maxTime;
}
    

코드 설명

이제 각 코드의 부분을 살펴보겠습니다:

1. 그래프 구성 및 진입 차수 계산

우선 입력으로 주어진 작업의 종속 관계를 기반으로 인접 리스트를 생성하고, 각 정점의 진입 차수를 계산합니다. 진입 차수가 0인 작업은 바로 시작할 수 있는 작업이므로 큐에 추가합니다.

2. 위상 정렬 및 최장 경로 계산

큐에서 작업을 하나씩 꺼내어 그 작업에 연결된 후속 작업들의 최장 완료 시간을 업데이트합니다. 만약 후속 작업의 진입 차수가 0이 된다면 다시 큐에 추가합니다. 모든 작업을 처리한 후 가장 긴 시간을 기록하면 그게 임계 경로입니다.

시간 복잡도 분석

이 알고리즘은 그래프의 정점과 간선을 각각 한 번씩 탐색하므로 시간 복잡도는 O(V + E) 입니다. 여기서 V는 작업의 개수, E는 작업 간의 종속 관계의 개수입니다.

최종 생각

임계 경로를 구하는 문제는 프로젝트 관리 및 일정 계획에서 중요한 요소로, 실제 산업에서도 많이 사용됩니다. 이 문제를 통해 그래프와 위상 정렬의 개념을 이해하고, 자바스크립트로 복잡한 문제를 해결하는 능력을 키울 수 있습니다.

추가 연습 문제

이제 여러분의 실력을 테스트하기 위해 다음과 같은 문제들을 연습해보세요:

  1. 작업 간의 종속 관계가 다를 때, 임계 경로의 변경을 추적하는 알고리즘을 구현하십시오.
  2. 작업의 시간뿐만 아니라 비용을 고려하여 최적의 경로를 찾는 문제가 있다. 이 문제를 해결하기 위한 접근법은 무엇인가요?
  3. 그래프가 다른 구조를 가질 때(예: 비순환 방향 그래프) 위상 정렬을 어떻게 응용할 수 있을까요?

참고 자료

임계 경로 문제를 더 자세히 알고 싶다면 아래 링크를 참고하세요:

자바스크립트 코딩테스트 강좌, 절댓값 힙 구현하기

이 강좌에서는 자바스크립트로 절댓값 힙(Absolute Value Heap)을 구현하는 방법에 대해 배워보겠습니다. 절댓값 힙은 두 가지 기준으로 정렬된 힙 구조로, 주로 절댓값을 기준으로 데이터를 정렬합니다. 예를 들어, 절댓값이 같은 경우에는 실제 값에 따라 정렬됩니다.

문제 설명

절댓값 힙을 구성하는 방법과 이를 통해 주어진 작업을 수행하는 알고리즘 문제를 해결해 보겠습니다. 문제는 다음과 같습니다.

정수로 이루어진 배열이 주어질 때, 절댓값 힙을 이용하여 가장 작은 절댓값을 가진 수를 삭제하고 그 값을 반환하는 작업을 진행하세요. 절댓값이 동일한 경우에는 더 작은 값을 우선하여 삭제합니다.

입력 형식


["I 5", "I -5", "I 3", "I -2", "I 0", "I 4", "D 1", "D 1"]
    

출력 형식


[0, -2, 3, 4]
    

문제 풀이 과정

절댓값 힙을 구현하기 위해, 자바스크립트의 배열을 사용할 수 있습니다. 배열을 선언하고, 이를 기반으로 삽입 및 삭제 작업을 수행하는 메서드를 구현합니다.

1단계: 힙 클래스 정의

우선 힙의 기본 구조를 설계합니다. 힙은 항상 특정한 규칙에 따라 부모 노드와 자식 노드가 관계를 맺어야 합니다. 절댓값이 작은 순서로 정렬되며, 절댓값이 같을 경우 원래 값이 작은 순서로 정렬됩니다.


class AbsoluteValueHeap {
    constructor() {
        this.heap = [];
    }

    insert(value) {
        this.heap.push(value);
        this.bubbleUp(this.heap.length - 1);
    }

    bubbleUp(index) {
        const element = this.heap[index];
        while (index > 0) {
            const parentIndex = Math.floor((index - 1) / 2);
            const parent = this.heap[parentIndex];
            if (this.isCorrectOrder(element, parent)) break;
            this.heap[index] = parent;
            index = parentIndex;
        }
        this.heap[index] = element;
    }

    isCorrectOrder(child, parent) {
        if (Math.abs(child) < Math.abs(parent)) return true;
        if (Math.abs(child) > Math.abs(parent)) return false;
        return child < parent;
    }

    delete() {
        if (this.heap.length === 0) return null;
        const min = this.heap[0];
        const end = this.heap.pop();
        if (this.heap.length > 0) {
            this.heap[0] = end;
            this.bubbleDown(0);
        }
        return min;
    }

    bubbleDown(index) {
        const element = this.heap[index];
        const length = this.heap.length;
        while (true) {
            let leftChildIndex = 2 * index + 1;
            let rightChildIndex = 2 * index + 2;
            let leftChild, rightChild;
            let swap = null;

            if (leftChildIndex < length) {
                leftChild = this.heap[leftChildIndex];
                if (!this.isCorrectOrder(element, leftChild)) {
                    swap = leftChildIndex;
                }
            }

            if (rightChildIndex < length) {
                rightChild = this.heap[rightChildIndex];
                if (
                    (swap === null && !this.isCorrectOrder(element, rightChild)) ||
                    (swap !== null && !this.isCorrectOrder(leftChild, rightChild))
                ) {
                    swap = rightChildIndex;
                }
            }

            if (swap === null) break;
            this.heap[index] = this.heap[swap];
            index = swap;
        }
        this.heap[index] = element;
    }

    peek() {
        return this.heap[0] || null;
    }
}
    

2단계: 작업 처리 함수 만들기

이제 절댓값 힙을 기반으로 다양한 명령어를 처리하는 함수를 만들겠습니다. 명령어는 ‘I’는 삽입, ‘D’는 삭제를 나타냅니다.


function processCommands(commands) {
    const heap = new AbsoluteValueHeap();
    const results = [];

    for (const command of commands) {
        const [action, value] = command.split(' ');
        const num = parseInt(value);

        if (action === 'I') {
            heap.insert(num);
        } else if (action === 'D' && num === 1) {
            const deleted = heap.delete();
            results.push(deleted !== null ? deleted : 0);
        } else if (action === 'D' && num === -1) {
            // Min heap으로 구현하기 때문에 삭제할 필요 없음
            const deleted = heap.delete();
            results.push(deleted !== null ? deleted : 0);
        }
    }
    return results;
}
    

3단계: 전체 코드 요약

이제까지 만들어진 코드를 모두 결합해 전체 코드를 정리해보겠습니다.


class AbsoluteValueHeap {
    // 이전에 정의한 코드를 활용합니다.
}

function processCommands(commands) {
    // 이전에 정의한 코드를 활용합니다.
}

// 테스트 예제 실행
const commands = ["I 5", "I -5", "I 3", "I -2", "I 0", "I 4", "D 1", "D 1"];
console.log(processCommands(commands)); // [0, -2, 3, 4]
    

결론

이번 강좌에서는 자바스크립트로 절댓값 힙을 구현하여 주어진 문제를 해결하는 과정을 살펴보았습니다. 알고리즘의 이해를 돕기 위해 기본적인 힙 정렬 개념과 절댓값을 기준으로 하는 힙의 동작 원리를 설명하였습니다. 이 강좌를 바탕으로 더 발전된 자료구조와 알고리즘 문제 해결 능력을 키워나가길 바랍니다.