From 031c52dfb04b42c003ad00f669118c1eefe029aa Mon Sep 17 00:00:00 2001 From: Jaeyeong son Date: Sat, 23 Jul 2022 14:54:50 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[=EC=86=90=EC=9E=AC=EC=98=81]=20level2=20?= =?UTF-8?q?=EB=B0=B0=EB=8B=AC=20=ED=92=80=EC=9D=B4=20=EB=B0=8F=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "level-2/\353\260\260\353\213\254.js" | 189 ++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 "level-2/\353\260\260\353\213\254.js" diff --git "a/level-2/\353\260\260\353\213\254.js" "b/level-2/\353\260\260\353\213\254.js" new file mode 100644 index 0000000..50a350c --- /dev/null +++ "b/level-2/\353\260\260\353\213\254.js" @@ -0,0 +1,189 @@ +//정답 1 - pereng11 +// 다익스트라 + 최소힙 O( N * logN ) +function solution ( N, road, K ) +{ + // [목적지, 거리] 노드를 값으로 가지는, 거리에 대한 최소힙 + class MinHeap{ + constructor () + { + this.heap = [ null ]; + } + // 맨 끝에 노드를 삽입 후 위로 올라가면서 정렬 + push ( val ) + { + this.heap.push(val); + let childIdx = this.heap.length-1; + let parentIdx = Math.floor(childIdx / 2); + while(parentIdx > 0 && this.heap[parentIdx][1] > this.heap[childIdx][1]){ + this.swap( childIdx, parentIdx ); + childIdx = parentIdx; + parentIdx = Math.floor(childIdx / 2); + } + } + pop () + { + if ( this.heap.length === 1 ) + { + return undefined; + } + // 최소값은 빼두었다가 리턴하고, 가장 끝 값을 맨 위로 가져와 아래로 내려가면서 정렬 + const minNode = this.heap[ 1 ]; + this.heap[ 1 ] = this.heap[ this.heap.length - 1 ]; + this.heap.pop(); + let parentIdx = 1; + let leftChildIdx = 2; + let rightChildIdx = 3; + while ( parentIdx < this.heap.length ) + { + // 자식이 없는 경우 + if ( !this.heap[ leftChildIdx ] ) + { + break; + } // 왼쪽 자식만 있는 경우 + else if ( !this.heap[ rightChildIdx ] ) + { + if ( this.heap[ parentIdx ][ 1 ] > this.heap[ leftChildIdx ][ 1 ] ) + { + this.swap( parentIdx, leftChildIdx ); + } + break; + // 둘 중 하나가 부모보다 작을 때, 더 작은 쪽으로 정렬 + } else if ( this.heap[ parentIdx ][ 1 ] > this.heap[ leftChildIdx ][ 1 ] || this.heap[ parentIdx ][ 1 ] > this.heap[ rightChildIdx ][ 1 ] ) + { + const minChildIdx = this.heap[ leftChildIdx ][ 1 ] < this.heap[ rightChildIdx ][ 1 ] ? leftChildIdx : rightChildIdx; + this.swap( parentIdx, minChildIdx ); + parentIdx = minChildIdx; + leftChildIdx = parentIdx * 2 + rightChildIdx = parentIdx * 2 + 1; + } else + { + // 끝까지 내려가지 않았더라도 부모가 가장 작으면 정렬 중지 + break; + } + } + return minNode; + } + swap ( idx1, idx2 ) + { + [ this.heap[ idx1 ], this.heap[ idx2 ] ] = [ this.heap[ idx2 ], this.heap[ idx1 ] ]; + } + length () + { + return this.heap.length; + } + } + + + const roadsTable = {}; //전체 도로 정보 + + // 도로 정보 초기화 roadTable[시작점] = [목적지, 거리] 배열 + for ( let i = 1; i <= N; i++ ) + { + roadsTable[ i ] = []; + } + road.forEach( road => + { + let [ sp, ep, dist ] = road; + roadsTable[ sp ].push( [ ep, dist ] ); + roadsTable[ ep ].push( [ sp, dist ] ); + } ); + + function djikstra ( sp ) + { + const visited = new Array( N + 1 ).fill( false ); //방문 확인 배열 + const dist = new Array( N + 1 ).fill( Infinity ); //목표지점까지 거리 + const heap = new MinHeap(); + + //시작점 삽입 + heap.push( [sp, 0] ); + + // 가장 가까운 목적지부터 순서대로 방문 + while ( heap.length() > 1 ) + { + //힙에 저장된 목적지 중 가장 가까운 거리의 목적지를 꺼냄 [목적지, 거리] + const [ ep, val ] = heap.pop(); + //아직 방문하지 않은 곳만 처리 + if ( !visited[ ep ] ) + { + //방문처리, 거리 저장 + visited[ ep ] = true; + dist[ ep ] = val; + //방문 지점을 거쳐서 가는 다른 목적지 구하기 + const nexts = roadsTable[ ep ]; + if ( nexts ) + { + nexts.forEach( n => + { + let [ nextEp, nextVal ] = n; + if ( !visited[ nextEp ] ) //아직 방문하지 않은 곳일 경우, '지금까지의 거리 + 현재 위치에서의 거리'로 힙에 삽입 + { + heap.push( [ nextEp, val + nextVal ] ); + } + }) + } + } + } + // 거리가 K이하인 지점의 개수 반환 + const result = dist.filter( d => d <= K ).length; + return result; + } + + const answer = djikstra( 1 ); + return answer; +} + +//정답 2 - pereng11 O(N * N); +//다익스트라 + 선형탐색 +function solution ( N, road, K ) +{ + + const roadsTable = {}; //전체 도로 정보 + + // 도로 정보 초기화 roadTable[시작점] = [목적지, 거리] 배열 + for ( let i = 1; i <= N; i++ ) + { + roadsTable[ i ] = []; + } + road.forEach( road => + { + let [ sp, ep, dist ] = road; + roadsTable[ sp ].push( [ ep, dist ] ); + roadsTable[ ep ].push( [ sp, dist ] ); + } ); + + function djikstra ( sp ) + { + const dist = new Array( N + 1 ).fill( Infinity ); //목표지점까지 거리 + const queue = []; + + queue.push( [sp, 0] ); + + while ( queue.length > 0 ) + { + const [ ep, val ] = queue.shift(); + if ( dist[ ep ] > val ) + { + dist[ ep ] = val; + const nexts = roadsTable[ ep ]; + if ( nexts ) + { + nexts.forEach( n => + { + let [ nextEp, nextVal ] = n; + //거리가 더 줄어드는 경우, '지금까지의 거리 + 현재 위치에서의 거리'로 힙에 삽입 + if ( dist[ nextEp ] > val + nextVal ) + { + queue.push( [ nextEp, val + nextVal ] ); + } + } ); + } + } + } + // 거리가 K이하인 지점의 개수 반환 + const result = dist.filter( d => d <= K ).length; + return result; + } + + const answer = djikstra( 1 ); + return answer; +} \ No newline at end of file From 8938fca9f0de91b554c407f81518732cc7685394 Mon Sep 17 00:00:00 2001 From: Jaeyeong son Date: Mon, 25 Jul 2022 20:38:10 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20=EC=B5=9C=EC=86=8C=ED=9E=99=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B0=94=EA=B9=A5=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC&=ED=8C=8C=EC=9D=BC=20=EC=BB=A8=EB=B2=A4=EC=85=98=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "level-2/\353\260\260\353\213\254.js" | 129 +++++++++++++------------- 1 file changed, 65 insertions(+), 64 deletions(-) diff --git "a/level-2/\353\260\260\353\213\254.js" "b/level-2/\353\260\260\353\213\254.js" index 50a350c..fb70325 100644 --- "a/level-2/\353\260\260\353\213\254.js" +++ "b/level-2/\353\260\260\353\213\254.js" @@ -1,79 +1,81 @@ +//https://github.com/codeisneverodd/programmers-coding-test +//완벽한 정답이 아닙니다. + //정답 1 - pereng11 // 다익스트라 + 최소힙 O( N * logN ) -function solution ( N, road, K ) -{ // [목적지, 거리] 노드를 값으로 가지는, 거리에 대한 최소힙 - class MinHeap{ - constructor () - { - this.heap = [ null ]; - } - // 맨 끝에 노드를 삽입 후 위로 올라가면서 정렬 - push ( val ) +class MinHeap{ + constructor () + { + this.heap = [ null ]; + } + // 맨 끝에 노드를 삽입 후 위로 올라가면서 정렬 + push ( val ) + { + this.heap.push(val); + let childIdx = this.heap.length-1; + let parentIdx = Math.floor(childIdx / 2); + while(parentIdx > 0 && this.heap[parentIdx][1] > this.heap[childIdx][1]){ + this.swap( childIdx, parentIdx ); + childIdx = parentIdx; + parentIdx = Math.floor(childIdx / 2); + } + } + pop () + { + if ( this.heap.length === 1 ) { - this.heap.push(val); - let childIdx = this.heap.length-1; - let parentIdx = Math.floor(childIdx / 2); - while(parentIdx > 0 && this.heap[parentIdx][1] > this.heap[childIdx][1]){ - this.swap( childIdx, parentIdx ); - childIdx = parentIdx; - parentIdx = Math.floor(childIdx / 2); - } + return undefined; } - pop () + // 최소값은 빼두었다가 리턴하고, 가장 끝 값을 맨 위로 가져와 아래로 내려가면서 정렬 + const minNode = this.heap[ 1 ]; + this.heap[ 1 ] = this.heap[ this.heap.length - 1 ]; + this.heap.pop(); + let parentIdx = 1; + let leftChildIdx = 2; + let rightChildIdx = 3; + while ( parentIdx < this.heap.length ) { - if ( this.heap.length === 1 ) + // 자식이 없는 경우 + if ( !this.heap[ leftChildIdx ] ) { - return undefined; - } - // 최소값은 빼두었다가 리턴하고, 가장 끝 값을 맨 위로 가져와 아래로 내려가면서 정렬 - const minNode = this.heap[ 1 ]; - this.heap[ 1 ] = this.heap[ this.heap.length - 1 ]; - this.heap.pop(); - let parentIdx = 1; - let leftChildIdx = 2; - let rightChildIdx = 3; - while ( parentIdx < this.heap.length ) + break; + } // 왼쪽 자식만 있는 경우 + else if ( !this.heap[ rightChildIdx ] ) { - // 자식이 없는 경우 - if ( !this.heap[ leftChildIdx ] ) - { - break; - } // 왼쪽 자식만 있는 경우 - else if ( !this.heap[ rightChildIdx ] ) - { - if ( this.heap[ parentIdx ][ 1 ] > this.heap[ leftChildIdx ][ 1 ] ) - { - this.swap( parentIdx, leftChildIdx ); - } - break; - // 둘 중 하나가 부모보다 작을 때, 더 작은 쪽으로 정렬 - } else if ( this.heap[ parentIdx ][ 1 ] > this.heap[ leftChildIdx ][ 1 ] || this.heap[ parentIdx ][ 1 ] > this.heap[ rightChildIdx ][ 1 ] ) - { - const minChildIdx = this.heap[ leftChildIdx ][ 1 ] < this.heap[ rightChildIdx ][ 1 ] ? leftChildIdx : rightChildIdx; - this.swap( parentIdx, minChildIdx ); - parentIdx = minChildIdx; - leftChildIdx = parentIdx * 2 - rightChildIdx = parentIdx * 2 + 1; - } else + if ( this.heap[ parentIdx ][ 1 ] > this.heap[ leftChildIdx ][ 1 ] ) { - // 끝까지 내려가지 않았더라도 부모가 가장 작으면 정렬 중지 - break; + this.swap( parentIdx, leftChildIdx ); } + break; + // 둘 중 하나가 부모보다 작을 때, 더 작은 쪽으로 정렬 + } else if ( this.heap[ parentIdx ][ 1 ] > this.heap[ leftChildIdx ][ 1 ] || this.heap[ parentIdx ][ 1 ] > this.heap[ rightChildIdx ][ 1 ] ) + { + const minChildIdx = this.heap[ leftChildIdx ][ 1 ] < this.heap[ rightChildIdx ][ 1 ] ? leftChildIdx : rightChildIdx; + this.swap( parentIdx, minChildIdx ); + parentIdx = minChildIdx; + leftChildIdx = parentIdx * 2 + rightChildIdx = parentIdx * 2 + 1; + } else + { + // 끝까지 내려가지 않았더라도 부모가 가장 작으면 정렬 중지 + break; } - return minNode; } - swap ( idx1, idx2 ) - { - [ this.heap[ idx1 ], this.heap[ idx2 ] ] = [ this.heap[ idx2 ], this.heap[ idx1 ] ]; - } - length () - { - return this.heap.length; - } - } + return minNode; + } + swap ( idx1, idx2 ) + { + [ this.heap[ idx1 ], this.heap[ idx2 ] ] = [ this.heap[ idx2 ], this.heap[ idx1 ] ]; + } + length () + { + return this.heap.length; + } +} - +function solution ( N, road, K ) +{ const roadsTable = {}; //전체 도로 정보 // 도로 정보 초기화 roadTable[시작점] = [목적지, 거리] 배열 @@ -136,7 +138,6 @@ function solution ( N, road, K ) //다익스트라 + 선형탐색 function solution ( N, road, K ) { - const roadsTable = {}; //전체 도로 정보 // 도로 정보 초기화 roadTable[시작점] = [목적지, 거리] 배열