Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions members/박종권/1주차/Level 2 미로탈출.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#### 1. 문제 파악
- 문제의 요점 : 너비우선탐색 BFS방식을 통해 최단거리를 구하는 방식

#### 2. 내 풀이
``` javascript
function findDistance(maps, start, target) {
var moveCount = 0;
let moveX = [1,-1,0,0];
let moveY = [0,0,1,-1];

var goX = 0;
var goY = 0;

maps[start[0]][start[1]] = 'X'

var queue = [start];

while (queue.length > 0) {
var size = queue.length;
for(var i=0; i<size; i++){
let [x,y] = queue.shift();
for(var k = 0;k<4;k++) {
goX = x + moveX[k];
goY = y + moveY[k];
if(goX>=0 && goX<maps.length && goY>=0 && goY<maps[0].length && maps[goX][goY]!=='X'){
if(maps[goX][goY] === target){
return moveCount+1;
} else {
queue.push([goX,goY]);
maps[goX][goY] = 'X';
}
} else {
continue;
}
}
}
moveCount++;
}

return -1;
}

function solution(maps) {
var answer = 0;
var findLever = -1;
var findExit = -1;

var start = [];
var lever = [];

// Find Start Point, Lever Point (Starting Point)
for(let i=0; i<maps.length; i++) {
for(let k=0; k<maps[i].length; k++) {
if(maps[i][k] === "S") {
start = [i,k];
} else if(maps[i][k] === "L") {
lever = [i,k];
}
}
}

let mapsLever = maps.map(item => item.split(''));
let mapsExit = maps.map(item => item.split(''));
findLever = findDistance(mapsLever, start, 'L');
findExit = findDistance(mapsExit, lever, 'E');

if (findLever !== -1 && findExit !== -1) {
answer = findLever + findExit;
} else {
answer = -1;
}

return answer;
}
```
##### 풀이 방식
- 우선적으로 start포인트, lever포인트를 찾아야 한다고 생각했다.
- 그렇게 잡은 start포인트와 lever포인트를 사용하여, start -> lever , lever -> end까지의 두번의 최단거리를 찾아, 찾은 두개의 최단거리를 더해 최종값을 반환하는 구조로 설계했다.
- javascript에서 함수로 인자값을 보낼 경우, 파라미터의 값이 변경되는 문제가 발견해, mapsLever, mapsExit 두개의 map을 구성하여 진행하였다.
- 최단거리를 구하는 알고리즘으로 BFS를 사용하였으며, queue의 값이 모두 없어질 때까지 무한루프를 돌면서, 만약 target이 발견되어 횟수를 return 하여 탈출하거나 모두 없어졌음에도 target을 발견하지 못한 경우에는 탈출 불가능으로 간주하여 -1을 반환하는 로직으로 설계했다.

##### 느낀 점
코딩테스트 lv2를 이번에 본격적으로 처음 접해봤는데, 확실히 자료구조의 구현 방법에 대해 공부 및 연구할 필요성을 느꼈다. 특히 이번 문제는 BFS를 사용하지 않으면 타임아웃으로 실패를 뜬 것을 확인하여, 이를 해결하고자 javascript로 BFS를 공부 및 구현하는 데에 집중을 하여 해결하였다. 이를 통해 자료구조 공부의 필요성을 느꼈고, 이를 활용하면 협업에서 성능 개선에 큰 도움을 줄 것으로 생각이 되었다.
68 changes: 68 additions & 0 deletions members/박종권/1주차/Level2 더 맵게.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
##### 1. 문제 파악
- 문제의 요점 : 기준치 보다 낮은 음식들을 조합해 기준치 이상의 음식들을 만들어 내는 문제

##### 2. 내 풀이
``` javascript
class PriorityQueue {
constructor() {
this.heap = [];
}

enqueue(value) {
this.heap.push(value);
let index = this.heap.length - 1;
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
if (this.heap[parentIndex] <= this.heap[index]) break;
[this.heap[parentIndex], this.heap[index]] = [this.heap[index], this.heap[parentIndex]];
index = parentIndex;
}
}

dequeue() {
if (this.heap.length === 1) return this.heap.pop();

const min = this.heap[0];
this.heap[0] = this.heap.pop();
let index = 0;
while (true) {
let smallest = index;
const left = 2 * index + 1;
const right = 2 * index + 2;

if (left < this.heap.length && this.heap[left] < this.heap[smallest]) {
smallest = left;
}
if (right < this.heap.length && this.heap[right] < this.heap[smallest]) {
smallest = right;
}
if (smallest === index) break;

[this.heap[index], this.heap[smallest]] = [this.heap[smallest], this.heap[index]];
index = smallest;
}
return min;
}
}

function solution(scoville, K) {
var answer = 0;
var newScoville = new PriorityQueue();
scoville.forEach(element => newScoville.enqueue(element));
while(newScoville.heap[0] < K && newScoville.heap.length > 1){
answer++;
newScoville.enqueue(newScoville.dequeue() + newScoville.dequeue()*2);
}
if(newScoville.heap[0] < K) {
return -1;
}
return answer;
}
```

##### 풀이 과정
- minHeap을 사용한 우선순위큐를 활용해 낮은 음식들을 골라 계산식을 추가해 다시 우선순위큐에 넣는 로직으로 풀었다.
- heap의 최상단 0번째 노드에 음식들의 스코빌이 가장 낮은 음식이 있기 때문에, 먼저 꺼내고 두번째 꺼낸 음식을 토대로 수식을 사용해 조합해 다시 추가하는 로직을 사용했다.

##### 느낀 점
만약 이전 문제에서 minHeap을 사용한 우선순위큐를 구현하지 않았다면 시간적으로 꽤 걸렸을 문제라고 생각한다. 계산식은 이미 문제에서 정의내렸기 때문에, 결국엔 문제풀이의 요점은 minHeap을 사용한 우선순위큐를 구현할 수 있는지 없는지인 것으로 생각한다.
62 changes: 62 additions & 0 deletions members/박종권/1주차/Level2 도넛과 막대 그래프.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
##### 1. 문제 파악
- 문제의 요점 : edges를 활용해 그래프를 확인하여 정점과 도넛, 막대, 8자의 갯수를 찾는 문제

##### 2. 내 풀이

``` javascript
function solution(edges) {
const answer = new Array(4).fill(0);

// 정점 : input이 없고 output만 있는 점 -> input = 0, outout > 1
// 도넛 : input/output이 동일한 점, 1개인 경우 -> 그 외 나머지
// 막대 : input이 있고 끝에 output이 없는 경우 -> output = 0
// 8자 : input/output이 동일한 점, 2개인 경우 -> input = 2, output = 2

// 각 점마다의 input, output을 분석해야 함
// key의 첫번째 요소는 input, 두번째 요소는 output,
// key의 1번째 요소를 map의 키 값으로 정의

const edgesMap = edges.reduce((map, key) => {
if (!map.has(key[0])) {
map.set(key[0], [0, 1]);
} else {
const [input, output] = map.get(key[0]);
map.set(key[0], [input, output+1]);
}

if(!map.has(key[1])){
map.set(key[1], [1, 0]);
} else {
const [input, output] = map.get(key[1]);
map.set(key[1], [input+1, output]);
}
return map;
}, new Map());

for(const [key, info] of edgesMap){
const [input, output] = info;
if(input == 0 && output > 1){
answer[0] = key
} else if (output == 0){
answer[2]++;
} else if (input >= 2 && output >= 2){
answer[3]++;
}
}

answer[1] = edgesMap.get(answer[0])[1] - (answer[2] + answer[3]);

return answer;
}
```
##### 풀이 과정
- 문제를 처음 봤을 때, 문제가 원하는 답과 그 답에 대한 조건이 뭔지 파악하는 게 우선이었다. 그림이랑 주어진 예시를 통해 내가 내린 조건은 아래와 같다.
- 정점 : input이 없고 output만 있는 점 -> input = 0, outout > 1
- 도넛 : input/output이 동일한 점, 1개인 경우 -> 그 외 나머지
- 막대 : input이 있고 끝에 output이 없는 경우 -> output = 0
- 8자 : input/output이 동일한 점, 2개인 경우 -> input = 2, output = 2
- map과 reduce을 사용하여 edges를 각 키와 input,output을 구별하여 계산하였고, 이를 토대로 조건에 맞는 갯수를 찾아냈다.
- 그러나 정답을 수정하는 과정에서 8자는 input/output이 2개가 아니라 2개 이상임을 발견하였고 이를 토대로 수정작업을 진행하여 에러를 해결해나갔다.

##### 느낀 점
javascript에서 reduce와 map을 사용한 경험이 부족해 이를 활용해서 코드를 짜는 데에 어려움이 있었다. 그리고 또한 그래프의 정의 및 도넛 갯수를 구하는 데 이해가 잘 안되어 어려움이 있었다. 그래서 이 문제는 푼 것만으로 끝이 아니라 좀 더 그래프에 대해 연구하고 javascript array 주요 기능들에 대해 연구 및 학습을 진행할 필요성을 느꼈다.
177 changes: 177 additions & 0 deletions members/박종권/1주차/Level2 타워디펜스.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#### 1. 문제 파악
- 무적권을 사용하여 유저가 주어진 유닛 수로 최대로 갈 수 있는 라운드의 수를 구하는 문제
#### 2. 내 풀이 및 풀이방법
``` javascript
function findMax(arr){
var maxIndex = 0;
for(var i=0;i<arr.length;i++){
if(arr[maxIndex] < arr[i]) {
maxIndex = i;
}
}
return maxIndex;
}

function solution(n, k, enemy) {
var answer = 0;
var enemySum = 0;
var faceEnemy = [];
for(var r=0; r<enemy.length; r++) {
faceEnemy.push(enemy[r]);
enemySum += faceEnemy[r];
if(n < enemySum) {
if(k>0) {
var maxIndex = findMax(faceEnemy);
enemySum -= faceEnemy[maxIndex];
faceEnemy[maxIndex] = 0;
k=k-1;
} else {
return faceEnemy.length-1;
}
}
}

return enemy.length;
}

```
처음 로직을 짤 때는
1. enemy 하나씩 더해서 n보다 커질 때를 체크
2. n보다 커질 때, 무적권(k)를 사용해 가장 큰 값을 0으로 변경
3. 가장 큰 값을 제거한 후 그 이후 enemy를 값을 추가해가며 체크 -> 이 과정을 루프로 돎
4. n보다 클 때, 무적권(k)가 없을 때 버틴 라운드 수를 체크
- 일단 enemy의 값을 더한 값을 저장하는 enemySum이라는 변수 필요
- 해치운 enemy 배열의 값을 저장하는 clearEnemy 배열 값 필요
- 해치운 enemy 배열의 최댓값 구하는 건 Math.max함수 사용 -> 런타임 에러가 뜨는 경우가 발생해 함수를 직접 구현
5. 게임 종료는 enemy의 합이 n보다 커졌을 때 k가 0인 경우로 생각

위 방식대로 시도하였으나, 시간 초과로 인한 2번의 테스트가 실패로 뜸
그래서 확인해보니, 우선순위 큐 또는 이분탐색을 사용해 푸는 문제란 걸 깨닫고
우선순위 큐를 통해 문제를 해결해보는 걸로 진행

``` javascript
class PriorityQueue {
constructor() {
this.queue = [];
}

enqueue(element) {
for(let i=0; i<this.queue.length; i++) {
if(this.queue[i] < element) {
this.queue.splice(i, 0, element);
return
}
}
this.queue.push(element);
}

front() {
return this.queue[0];
}

dequeue(){
return this.queue.shift();
}

pop() {
var front = this.queue[0];
this.queue.shift();
return front
}

show() {
return this.queue;
}
}

function solution(n, k, enemy) {
let arr = new PriorityQueue();
var capacity = 0;
for(let i=0;i<enemy.length;i++) {
arr.enqueue(enemy[i]);
var popNum = arr.front();
console.log(i);
if(popNum+capacity > n){
if (k>0){
arr.dequeue();
k = k-1;
} else {
return i+1;
}
} else {
arr.enqueue(enemy[i]);
}
capacity+=popNum;
}

return enemy.length;
}
```
<풀이법>
``` javascript
class PriorityQueue {
constructor() {
this.heap = [];
}

enqueue(value) {
this.heap.push(value);
let index = this.heap.length - 1;
while (index > 0) {
const parentIndex = Math.floor((index - 1) / 2);
if (this.heap[parentIndex] <= this.heap[index]) break;
[this.heap[parentIndex], this.heap[index]] = [this.heap[index], this.heap[parentIndex]];
index = parentIndex;
}
}

dequeue() {
if (this.heap.length === 1) return this.heap.pop();

const min = this.heap[0];
this.heap[0] = this.heap.pop();
let index = 0;
while (true) {
let smallest = index;
const left = 2 * index + 1;
const right = 2 * index + 2;

if (left < this.heap.length && this.heap[left] < this.heap[smallest]) {
smallest = left;
}
if (right < this.heap.length && this.heap[right] < this.heap[smallest]) {
smallest = right;
}
if (smallest === index) break;

[this.heap[index], this.heap[smallest]] = [this.heap[smallest], this.heap[index]];
index = smallest;
}
return min;
}
}

function solution(n, k, enemy) {
let queue = new PriorityQueue();
enemy.slice(0, k).forEach(v => queue.enqueue(v));
var capacity = 0;
for(let i=k;i<enemy.length;i++) {
queue.enqueue(enemy[i]);
const min = queue.dequeue();
if(capacity+min > n){
return i;
} else {
capacity = capacity+min
}
}

return enemy.length;
}
```

- 최솟값 heap을 사용해 우선순위 큐를 구현하는 방식을 연구하여 작성하여 문제를 진행했다. 가장 중요한 enqueue와 dequeue를 구현을 하여 k(무적권)만큼 queue에 push한 후, 이후 라운드 진행될 때, 우선적으로 enemy의 수를 queue에 넣은 후, queue의 가장 최솟값을 꺼내 enemy의 수에 더한 값이 n(병사수)보다 작을 때 계속 더해가며, 만약 n보다 커질 때 최종 라운드의 수를 반환하는 방식으로 진행하였다.

##### 느낀 점
우선순위 큐를 javascript에서 직접 구현해본 적이 처음이라 구현함에 있어서 어려웠었다. 처음에 문제만 봤을 때, 그냥 최댓값만 0으로 치환하면 되지 않을까? 라는 생각으로 진행했다가 32번의 테스트 중 단 2개의 테스트만 시간 초과로 나와 실패처리 되었을 때의 충격은 가히 말할 수 없었다... 그래서 좀 더 오래 고민하고 우선순위 큐를 최적으로 구현할 수 있는 방법 그리고 그 방법을 내가 이해할 수 있게 바꾸는 방법에 대해 오래 고민했던 것 같다.

이분탐색으로 한 코드도 괜찮음
Loading