Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- 리액트커뮤니티
- HTML5
- 몽고DB
- CSS
- 백준
- 백준구현
- 백준골드
- 프로그래머스JS
- 자바스크립트
- css기초
- 백준구현문제
- 코테
- 백준알고리즘
- JS프로그래머스
- js코테
- 백준nodejs
- JS
- dp알고리즘
- 안드로이드 스튜디오
- 포이마웹
- HTML
- 백준js
- 다이나믹프로그래밍
- 코딩테스트
- 알고리즘
- 리액트
- 프로그래머스
- 프로그래머스코테
- 리액트댓글기능
- 익스프레스
Archives
- Today
- Total
개발새발 로그
[JS] 백준 1715번 - 카드 정렬하기 - 우선순위 큐, 최소 힙 본문
https://www.acmicpc.net/problem/1715
1715번: 카드 정렬하기
정렬된 두 묶음의 숫자 카드가 있다고 하자. 각 묶음의 카드의 수를 A, B라 하면 보통 두 묶음을 합쳐서 하나로 만드는 데에는 A+B 번의 비교를 해야 한다. 이를테면, 20장의 숫자 카드 묶음과 30장
www.acmicpc.net
우선순위 큐를 활용해야하는 문제이다.
📋풀이방법
1.최소힙 구조로 우선순위 큐에 주어진 값을 넣고, 루트노드를 두 개 A와 B의 뺀 값 C를 total값에 누적하고, 다시 최소힙에 더한 값 total을 넣으면 원하는 결과가 나온다.
2. 이 때 중요한 것은 우선순위큐 구조를 만드는 것이다.
https://chamdom.blog/heap-using-js/
[자료구조] JavaScript로 힙(Heap) 구현하기
힙이란? 힙(heap) 은 완전 이진 트리의 일종으로 우선순위 큐 를 위하여 만들어진 자료구조이다. 힙은 완전히 정렬된 것은 아니지만 전혀 정렬 되지 않은 상태도 아닌 반정렬 …
chamdom.blog
🤟내 제출
const fs = require("fs");
const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
let input = fs.readFileSync(filePath).toString().trim();
input = input.replace(/\r/g, "").split("\n");
let N = Number(input[0]);
let arr = [];
for (let i = 0; i < N; i++) {
arr[i] = Number(input[i + 1]);
}
class MinHeap {
constructor() {
this.heap = [];
}
getLength = () => {
return this.heap.length;
};
push = (node) => {
this.heap.push(node);
this.bubbleUp();
};
//bubbleUp이란
/*
힙에 값을 삽입할 때 부모와 비교해서 값이 크거나 작으면(최소 힙의 경우 부모가 자신보다 크면, 최대 힙의 경우 부모가 자신보다 작으면)
부모와 값을 교환해서 올바르게 정렬이 될 때 까지 올라가는 것을 bubbleUp이라 한다.
*/
bubbleUp() {
let i = this.heap.length - 1;
let parentI = Math.floor((i - 1) / 2);
while (
this.heap[parentI] && //부모노드가 존재하고
this.heap[parentI] > this.heap[i] //새로운 노드가 부모노드보다 작은경우
) {
this.swap(i, parentI); //두 노드 값을 교체
i = parentI;
parentI = Math.floor((i - 1) / 2);
}
}
//bubbleDown이란
/*
루트 노드를 삭제하고 마지막 노드를 루트로 올리고 루트 노드와 아래 자식 노드들과 비교해서 값이 크거나 작으면(최소 힙의 경우 자식이 자신보다 값이 작으면, 최대 힙의 경우 자식이 자신보다 값이 크면)
자식과 값을 교환해서 올바르게 정렬이 될 때 까지 내려가는 것을 bubbleDown이라 한다.
*/
pop = () => {
if (this.heap.length === 1) {
return this.heap.pop();
}
const result = this.heap[0];
this.heap[0] = this.heap.pop();
this.bubbleDown();
return result;
};
bubbleDown() {
let i = 0; // 루트 노드의 index
let leftI = i * 2 + 1, // 왼쪽 자식 노드의 index
rightI = i * 2 + 2; // 오른쪽 자식 노드의 index
while (
// 왼쪽 자식 노드가 존재 하면서 값이 루트 노드보다 작거나
(this.heap[leftI] && this.heap[leftI] < this.heap[i]) ||
// 오른쪽 자식 노드가 존재 하면서 값이 루트 노드보다 작은 경우
(this.heap[rightI] && this.heap[rightI] < this.heap[i])
) {
let smallerIdx = leftI; // 왼쪽 자식 노드가 더 작다고 가정
if (
this.heap[rightI] &&
this.heap[rightI] < this.heap[smallerIdx] // 오른쪽 자식 노드가 더 작다면
) {
smallerIdx = rightI; // 오른쪽 자식 노드의 index로 변경
}
this.swap(i, smallerIdx);
i = smallerIdx;
leftI = i * 2 + 1; // 왼쪽 자식 노드의 index 계산
rightI = i * 2 + 2; // 오른쪽 자식 노드의 index 계산
}
}
swap = (a, b) => {
const temp = this.heap[a];
this.heap[a] = this.heap[b];
this.heap[b] = temp;
};
}
const minHeap = new MinHeap();
for (let i = 0; i < N; i++) {
minHeap.push(arr[i]);
}
let totalCompareCount = 0;
//힙안의 값이 하나가 될 때 까지
while (minHeap.getLength() > 1) {
let aCount = minHeap.pop(); //최소힙이므로
let bCount = minHeap.pop(); //루트노드를 두개 빼온다
let compareCount = aCount + bCount; //그 최솟값 두 개를 더하고
totalCompareCount += compareCount; //누적한다.
minHeap.push(compareCount); //누적값을 다시 힙에 넣어서 정렬된다.
}
console.log(totalCompareCount);
💢어려웠던 점
1. 아직 우선순위큐에 대해서 숙지하지 못했다.
2. 최소힙과 최대힙의 차이를 숙지하자
-최소힙과 최대힙의 차이는 bubbleUp과 bubbleDown의 차이이다.
-아래 코드를 추가해봤다.
-주석처리한 곳을 사용하면 최대힙으로 사용가능하다.
const fs = require("fs");
const filePath = process.platform === "linux" ? "/dev/stdin" : "./input.txt";
let input = fs.readFileSync(filePath).toString().trim();
input = input.replace(/\r/g, "").split("\n");
let N = Number(input[0]);
let arr = [];
for (let i = 0; i < N; i++) {
arr[i] = Number(input[i + 1]);
}
class MinHeap {
constructor() {
this.heap = [];
}
getLength = () => {
return this.heap.length;
};
push = (node) => {
this.heap.push(node);
this.bubbleUp();
};
//bubbleUp이란
/*
힙에 값을 삽입할 때 부모와 비교해서 값이 크거나 작으면(최소 힙의 경우 부모가 자신보다 크면, 최대 힙의 경우 부모가 자신보다 작으면)
부모와 값을 교환해서 올바르게 정렬이 될 때 까지 올라가는 것을 bubbleUp이라 한다.
*/
bubbleUp() {
let i = this.heap.length - 1;
let parentI = Math.floor((i - 1) / 2);
while (
this.heap[parentI] && //부모노드가 존재하고
this.heap[parentI] > this.heap[i] //새로운 노드가 부모노드보다 작은경우
) {
this.swap(i, parentI); //두 노드 값을 교체
i = parentI;
parentI = Math.floor((i - 1) / 2);
}
}
//bubbleDown이란
/*
루트 노드를 삭제하고 마지막 노드를 루트로 올리고 루트 노드와 아래 자식 노드들과 비교해서 값이 크거나 작으면(최소 힙의 경우 자식이 자신보다 값이 작으면, 최대 힙의 경우 자식이 자신보다 값이 크면)
자식과 값을 교환해서 올바르게 정렬이 될 때 까지 내려가는 것을 bubbleDown이라 한다.
*/
pop = () => {
if (this.heap.length === 1) {
return this.heap.pop();
}
const result = this.heap[0];
this.heap[0] = this.heap.pop();
this.bubbleDown();
return result;
};
bubbleDown() {
let i = 0; // 루트 노드의 index
let leftI = i * 2 + 1, // 왼쪽 자식 노드의 index
rightI = i * 2 + 2; // 오른쪽 자식 노드의 index
while (
// 왼쪽 자식 노드가 존재 하면서 값이 루트 노드보다 작거나
(this.heap[leftI] && this.heap[leftI] < this.heap[i]) ||
// 오른쪽 자식 노드가 존재 하면서 값이 루트 노드보다 작은 경우
(this.heap[rightI] && this.heap[rightI] < this.heap[i])
) {
let smallerIdx = leftI; // 왼쪽 자식 노드가 더 작다고 가정
if (
this.heap[rightI] &&
this.heap[rightI] < this.heap[smallerIdx] // 오른쪽 자식 노드가 더 작다면
) {
smallerIdx = rightI; // 오른쪽 자식 노드의 index로 변경
}
this.swap(i, smallerIdx);
i = smallerIdx;
leftI = i * 2 + 1; // 왼쪽 자식 노드의 index 계산
rightI = i * 2 + 2; // 오른쪽 자식 노드의 index 계산
}
}
swap = (a, b) => {
const temp = this.heap[a];
this.heap[a] = this.heap[b];
this.heap[b] = temp;
};
//최대힙과 최소힙의 차이는 bubbleUP과 bubbelDown이 어떻게 되느냐의 차이다.
// bubbleUp() {
// let index = this.heap.length - 1;
// let parentI = Math.floor((index - 1) / 2);
// while (
// this.heap[parentI] !== undefined &&
// this.heap[parentI] < this.heap[index]
// ) {
// this.swap(index, parentI);
// index = parentI;
// parentI = Math.floor((index - 1) / 2);
// }
// }
// bubbleDown() {
// let index = 0;
// let leftI = index * 2 + 1, // 왼쪽 자식 노드의 index
// rightI = index * 2 + 2; // 오른쪽 자식 노드의 index
// while (
// this.heap[leftI] !== undefined &&
// (this.heap[leftI] > this.heap[index] ||
// this.heap[rightI] > this.heap[index])
// ) {
// let largerIndex = this.heap[leftI];
// if (
// this.heap[rightI] !== undefined &&
// this.heap[rightI] > this.heap[largerIndex]
// ) {
// largerIndex = this.heap[rightI];
// }
// this.swap(largerIndex, index);
// index = largerIndex;
// leftI = index * 2 + 1; // 왼쪽 자식 노드의 index 계산
// rightI = index * 2 + 2; // 오른쪽 자식 노드의 index 계산
// }
// }
}
const minHeap = new MinHeap();
for (let i = 0; i < N; i++) {
minHeap.push(arr[i]);
}
let totalCompareCount = 0;
//힙안의 값이 하나가 될 때 까지
while (minHeap.getLength() > 1) {
let aCount = minHeap.pop(); //최소힙이므로
let bCount = minHeap.pop(); //루트노드를 두개 빼온다
let compareCount = aCount + bCount; //그 최솟값 두 개를 더하고
totalCompareCount += compareCount; //누적한다.
minHeap.push(compareCount); //누적값을 다시 힙에 넣어서 정렬된다.
}
console.log(totalCompareCount);
728x90
반응형
LIST
'알고리즘' 카테고리의 다른 글
[JS] 백준 2164 : 카드2 - 큐, 스택, 링크드리스트(push,pop의 비효율) (0) | 2023.09.12 |
---|---|
[JS] 백준 2493번 : 탑 - 자료구조, 스택 (0) | 2023.08.20 |
[JS] 백준 2110번 : 공유기 설치 - 이분 탐색 (0) | 2023.08.15 |
[JS] 백준 1806번 : 부분합 - 누적 합, 투 포인터, 효울성 (0) | 2023.08.14 |
[JS] 백준 2580번 : 스도쿠 - 백트래킹, DFS (0) | 2023.08.11 |