[프로그래머스/JS] Lv2. 더 맵게 (힙 자료구조, 우선순위 큐 구현)

2024. 6. 27. 00:04· JavaScript/프로그래머스

문제

https://school.programmers.co.kr/learn/courses/30/lessons/42626

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr


풀이

우선 순위 큐를 구현해야하는 문제이다. 자바에서는 라이브러리를 불러오면 쉽게 해결되지만, 자바스크립트에서는 직접 구현을 해야한다.

 

우선 순위 큐를 어떻게 구현할 수 있을까? 우선 순위 큐는 힙 자료 구조를 알면 쉽게 접근해볼 수 있다.

 

힙은 완전 이진 트리의 일종이다. 특징은 부모 노도의 키 값이 자식 노드의 키 값보다 항상 큰 이진 트리이다.

 

여기서 힙의 종류는 두 가지가 있다.

출처 : https://gmlwjd9405.github.io/2018/05/10/data-structure-heap.html

어려운 것은 아니고, 값이 큰 게 우선인가 작은 것이 우선인가로 나누어볼 수 있는 것이다.

 

 

 

그럼 이 힙을 어떻게 구현해야할까? 답은 배열로 구현할 수 있다.

출처 : https://gmlwjd9405.github.io/2018/05/10/data-structure-heap.html

 

 힙의 루트부터 아래로 인덱스를 매겨보면, 왼쪽 자식의 인덱스는 부모의 인덱스의 *2이고 오른쪽 자식 인덱스는 부모 인덱스 *2 +1 이라는 것을 확인할 수 있다. 반대로 부모의 인덱스는 자식의 인덱스/2 한 값이다. 이것을 배열에 넣으면 힙을 간접적으로 표현할 수 있는 것이다.

 

 

 힙에 대해서는 정리가 된 것 같다. 이제 그럼 우선 순위를 어떻게 나타낼 수 있을까? 새로운 요소를 삽입하고 삭제할 때, 그에 알맞게 정렬해주면 우선 순위를 유지할 수가 있다.

 

 

삽입하는 경우를 그림으로 쉽게 살펴보자.

 

 

 

삽입한 요소를 부모와 비교하며, 조건에 맞지 않을 때까지, 교환하는 과정을 거치는 것을 알 수 있다.

 

 

이것을 자바 스크립트 코드로 나타낸 것은 아래와 같다. 참고로 최소 힙을 구현한 것이다.

 

주석을 통해 코드를 설명했다.

 

class MinHeap{
    constructor(){
        this.heap = []; //배열을 선언한다.
    }
    push(item){ //삽입
        this.heap.push(item); //배열의 가장 마지막에 값을 삽입한다.
        let index = this.heap.length-1;

		//삽입한 값이 루트가 되거나, 부모값보다 작은 경우가 아닐 때까지 계속해서 스왑한다.
        while(index > 0 
              && this.heap[index] < this.heap[Math.floor((index-1)/2)])
            {
                const temp = this.heap[index];
                this.heap[index] = this.heap[Math.floor((index-1)/2)];
                this.heap[Math.floor((index-1)/2)] = temp;
                
                index = Math.floor((index-1)/2);
            }
    }
    
    pop(){ //최상단의 루트 값을 빼낸다. 빼내고 나서 재정렬을 해주어야한다.
        if(this.heap.length===0) return null;
        if(this.heap.length===1) return this.heap.pop(); //만약 하나밖에 없다면 오버헤드 줄이기
        
        const minValue = this.heap[0]; //반환해야할 값
        this.heap[0] = this.heap.pop();
        
        let index = 0;
        while(index*2+1 < this.heap.length){ //자식 인덱스가 전체 배열 길이보다 작다면 반복
            //교환할 자식 인덱스를 선택한다.
            let minChildIndex = index * 2 + 2 < this.heap.length // 오른쪽 자식이 힙의 길이보다 작은지를 체크한다.
                && this.heap[index * 2 + 2] < this.heap[index * 2 + 1] // 오른쪽자식 노드값이 왼쪽자식보다 작은지 확인한다.
                ? index * 2 + 2 조건에 부합하면 오른쪽
                : index * 2 + 1; 아니라면 왼쪽을 선택한다.
                 
            if(this.heap[index] < this.heap[minChildIndex]){ //만약 자식이 인덱스보다 크다면 거기서 멈춘다.
                break;
            }
        	//스왑
            const temp = this.heap[index];
            this.heap[index] = this.heap[minChildIndex];
            this.heap[minChildIndex] = temp;
            
            index = minChildIndex;
        }
        return minValue;
    }
}

 

 

 

 

 

 

이를 이용해 문제를 해결한 것은 아래와 같다.


소스 코드

function solution(scoville, K) {
    var answer = 0;
    
    let heap = new MinHeap();
    
    for(let i =0;i<scoville.length;i++){
        heap.push(scoville[i]);
    }
    
    let count = 0;
    while(heap.peek()<K){
        let food1 = heap.pop();
        let food2 = heap.pop();
        
        let newFood = food1+food2*2;
        heap.push(newFood);
        count++;
    }
    answer = heap.peek()>=K ? count: -1;
    return answer;
}

class MinHeap{
    constructor(){
        this.heap = [];
    }
    
    size(){
        return this.heap.length;
    }
    
    push(item){
        this.heap.push(item);
        let index = this.heap.length-1;

        while(index > 0 
              && this.heap[index] < this.heap[Math.floor((index-1)/2)])
            {
                const temp = this.heap[index];
                this.heap[index] = this.heap[Math.floor((index-1)/2)];
                this.heap[Math.floor((index-1)/2)] = temp;
                
                index = Math.floor((index-1)/2);
            }
    }
    
    pop(){
        if(this.heap.length===0) return null;
        if(this.heap.length===1) return this.heap.pop();
        
        const minValue = this.heap[0];
        this.heap[0] = this.heap.pop();
        
        let index = 0;
        while(index*2+1 < this.heap.length){
            
            let minChildIndex = index * 2 + 2<this.heap.length 
            && this.heap[index*2+2] < this.heap[index*2+1]?index*2+2:index*2+1;
            
            if(this.heap[index] < this.heap[minChildIndex]){
                break;
            }
            
            const temp = this.heap[index];
            this.heap[index] = this.heap[minChildIndex];
            this.heap[minChildIndex] = temp;
            
            index = minChildIndex;
        }
        return minValue;
    }
    
    peek(){
        return this.heap[0];
    }
}

 

 

 

 

참고자료

https://velog.io/@eldoradodo/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-JavaScript-%EB%8D%94-%EB%A7%B5%EA%B2%8C

https://velog.io/@eldoradodo/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-JavaScript-%EB%8D%94-%EB%A7%B5%EA%B2%8C

https://mingmeng030.tistory.com/293

 

'JavaScript > 프로그래머스' 카테고리의 다른 글

[프로그래머스/JS] Lv2. 게임 맵 최단거리 (큐 구현 방식)  (0) 2024.07.02
[프로그래머스/JS] Lv1. 올바른 괄호 (스택 구현)  (0) 2024.06.26
[프로그래머스/JS] Lv1. 같은 숫자는 싫어  (1) 2024.06.26
[프로그래머스/JS] Lv0. 문자열 반복해서 출력하기 (반복 출력)  (0) 2024.06.21
[프로그래머스/JS] Lv0. a와 b 출력하기 (구조 분해 할당)  (0) 2024.06.21
'JavaScript/프로그래머스' 카테고리의 다른 글
  • [프로그래머스/JS] Lv2. 게임 맵 최단거리 (큐 구현 방식)
  • [프로그래머스/JS] Lv1. 올바른 괄호 (스택 구현)
  • [프로그래머스/JS] Lv1. 같은 숫자는 싫어
  • [프로그래머스/JS] Lv0. 문자열 반복해서 출력하기 (반복 출력)
동구름이
동구름이
동구름이
동구름
동구름이
전체
오늘
어제
  • 분류 전체보기 (178)
    • Java (63)
      • Java 를 파헤쳐보자 (13)
      • BOJ (45)
      • 프로그래머스 (3)
      • SWEA (1)
      • Java GUI (1)
    • JavaScript (17)
      • JS를 파헤쳐보자 (7)
      • 프로그래머스 (7)
      • JS 학습 정리 (1)
    • Backend (33)
      • Spring (3)
      • HTTP (7)
      • 프로젝트 (10)
      • MySQL (6)
      • Redis (3)
      • Elastic Search (1)
      • 인증, 인가 (3)
    • CS (57)
      • 운영체제 (35)
      • Network (22)
    • Git (2)
    • 개발 관련 이것저것 (2)
    • etc (1)
    • 독서 (0)
    • 사설 (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 큐
  • Java
  • 네트워크
  • 한양대
  • 프로그래머스
  • BOJ
  • 구현
  • 자바
  • 인프런
  • 스택
  • JCF
  • 김영한
  • 자바스크립트
  • 반효경
  • 이석복
  • 운영체제
  • 백준
  • OS
  • 레디스
  • 모든 개발자를 위한 HTTP 웹 기본 지식

최근 글

hELLO · Designed By 정상우.v4.2.2
동구름이
[프로그래머스/JS] Lv2. 더 맵게 (힙 자료구조, 우선순위 큐 구현)
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.