Skip to content

Commit 9494956

Browse files
authored
[wjsdncl] 24.12.03 (#114)
* 217 / Contains Duplicate / easy / 22m * 268 / Missing Number / easy / 13m * 121 / Best Time to Buy and Sell Stock / easy / 16m * 252 / Meeting Room / easy / 26m * 15 / 3sum / medium / 42m * 242 / Valid Anagram / Easy / 15m33 * 238 / Product of Array Except Self / Medium / 35m16 * 191 / Number of 1 Bits / Easy / 14m32s * 100 / Same Tree / Easy / 24m40s * 746 / Min Cost Climbing Stairs / Easy / 29m35s * 746 / Min Cost Climbing Stairs / Easy / 29m35s (수정) * 1 / Two Sum / easy / 20m 31s * 104 / Maximun Depth of Binary Tree / easy / 38m 21s * 141 / Linked List Cycle / easy / 32m 15s * 202 / Happy Number / Easy / 29m 21s * 20 / Valid Parentheses / easy / 22m 41s * 338 / Counting Bits / Easy / 17m * 70 / Climbing Stairs / Easy / 19m * 21 / Merge Two Sorted Lists / easy / 28m * 48 / Rotate Image / medium / 31m * 1046 / Last Stone Weight / easy / 21m * 136 / Single Number / Easy / 12m * 110 / Balanced Binary Tree / Easy / 35m * 54 / Spiral Matrix / Medium / 38m * 973 / K Closest Points to Origin / Medium / 21m * 155 / Min Stack / Medium / 31m * 128 / Longest Consecutive Sequence / Medium / 26m * 371 / Sum of Two Integers / Medium / 17m * 208 / Implement Trie (Prefix Tree) / Medium / 24m * 226 / Invert Binary Tree / Easy / 13m * 543 / Diameter of Binary Tree / Easy / 26m * 102 / Binary Tree Level Order Traversal / Medium / 32m * 572 / Subtree Of Another Tree / Easy / 23m * 213 / House Robber II / Medium / 36m * 207 / Course Schedule / Medium / 39m * 150 / Evaluate Reverse Polish Notation / Medium / 19m * 56 / Merge Intervals / medium / 21m * 1584 / Min Cost to Connect All Points / Medium / 38m * 235 / Lowest Common Ancestor of a Binary Search Tree / Medium / 28m * 139 / Word Break / Medium / 13m * 215 / Kth Largest Element in an Array / Medium / 13m * 7 / Reverse Interger / Medium / 14m * 743 / Network Delay Time / Medium / 37m * 39 / Combination Sum / Medium / 29m * 2013 / Detect Squares / Medium / 51m * 57 / Insert Interval / Medium / 32m
1 parent 88a7e5b commit 9494956

10 files changed

+377
-0
lines changed

wjsdncl/139_word_break.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* 13m38s 소요
3+
*
4+
* 시간복잡도: O(n^2)
5+
*
6+
* 단어 s가 주어지고, 단어 사전 wordDict가 주어집니다.
7+
* 단어 s를 단어 사전을 이용하여 구성할 수 있는지 여부를 반환하는 문제입니다.
8+
*
9+
* dp를 사용하여 풀 수 있습니다.
10+
* dp[i]는 s의 0부터 i까지의 부분 문자열이 단어 사전을 이용하여 구성 가능한지 여부를 나타냅니다.
11+
* dp[0]은 빈 문자열이므로 true로 초기화합니다.
12+
* dp[i]를 구하기 위해 dp[j]를 검사합니다. (0 <= j < i)
13+
* dp[j]가 true이고, s의 j부터 i까지의 부분 문자열이 단어 사전에 있는 경우 dp[i]를 true로 설정합니다.
14+
* dp[s.length]를 반환합니다.
15+
*/
16+
var wordBreak = function (s, wordDict) {
17+
const wordSet = new Set(wordDict); // 빠른 검색을 위한 Set 생성
18+
const dp = new Array(s.length + 1).fill(false);
19+
dp[0] = true; // 빈 문자열은 항상 구성 가능
20+
21+
// dp[i]를 구하기 위해 dp[j]를 검사
22+
for (let i = 1; i <= s.length; i++) {
23+
// dp[j]가 true이고, s의 j부터 i까지의 부분 문자열이 단어 사전에 있는 경우 dp[i]를 true로 설정
24+
for (let j = 0; j < i; j++) {
25+
if (dp[j] && wordSet.has(s.slice(j, i))) {
26+
dp[i] = true;
27+
break; // 가능한 경우를 찾으면 더 이상 탐색하지 않음
28+
}
29+
}
30+
}
31+
32+
return dp[s.length];
33+
};
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* 38m17s 소요
3+
*
4+
* 시간 복잡도: O(N^2)
5+
*
6+
* 어떻게 풀어야 할지 감이 안와서 풀이와 GPT의 도움을 받았습니다.
7+
* Prim's Algorithm 또는 Kruskal's Algorithm 중 하나를 사용하여 풀 수 있다고 합니다.
8+
*
9+
* 모든 점들을 연결하는 최소 비용을 구하는 문제입니다.
10+
*
11+
* 시작점을 0으로 설정하고, 시작점에서 가장 가까운 점을 선택하여 MST에 추가합니다.
12+
* 이후 추가된 점에서 가장 가까운 점을 선택하여 MST에 추가합니다.
13+
* 이를 반복하여 모든 점을 연결할 때까지 반복합니다.
14+
* 최종적으로 MST에 추가된 비용의 합을 반환합니다.
15+
*/
16+
var minCostConnectPoints = function (points) {
17+
const n = points.length;
18+
const minCost = new Array(n).fill(Infinity); // 최소 비용 배열
19+
const visited = new Array(n).fill(false); // 방문 여부
20+
minCost[0] = 0; // 시작점의 비용은 0
21+
let totalCost = 0;
22+
23+
// 모든 점을 연결할 때까지 반복
24+
for (let i = 0; i < n; i++) {
25+
let currMin = Infinity;
26+
let currPoint = -1;
27+
28+
// 최소 비용으로 연결할 점 선택
29+
for (let j = 0; j < n; j++) {
30+
if (!visited[j] && minCost[j] < currMin) {
31+
currMin = minCost[j];
32+
currPoint = j;
33+
}
34+
}
35+
36+
// 현재 점을 MST에 추가
37+
visited[currPoint] = true;
38+
totalCost += currMin;
39+
40+
// 다른 점들의 최소 비용 업데이트
41+
for (let j = 0; j < n; j++) {
42+
if (!visited[j]) {
43+
const dist = Math.abs(points[currPoint][0] - points[j][0]) + Math.abs(points[currPoint][1] - points[j][1]);
44+
minCost[j] = Math.min(minCost[j], dist);
45+
}
46+
}
47+
}
48+
49+
return totalCost;
50+
};

wjsdncl/2013_detect_squares.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* 51m18s 소요
3+
*
4+
* 시간복잡도: O(n) (n: 점의 개수)
5+
*
6+
* 주어진 점들로부터 정사각형을 만들 수 있는 경우의 수를 구하는 문제입니다.
7+
*
8+
* 어떻게 풀어야 할지 감이 전혀 안와서 풀이랑 GPT의 도움을 받았습니다.
9+
*
10+
* 점들의 빈도를 저장하기 위한 맵을 생성합니다.
11+
* 새로운 점을 추가할 때마다 빈도를 증가시킵니다.
12+
* 정사각형을 만들 수 있는 경우의 수를 구합니다.
13+
* 대각선의 조건을 만족하는 점들을 찾습니다.
14+
* 대각선 점을 기준으로 나머지 두 점의 빈도를 곱하여 더합니다.
15+
* 결과를 반환합니다.
16+
*/
17+
var DetectSquares = function () {
18+
// 점들의 빈도를 저장하기 위한 맵
19+
this.points = new Map();
20+
};
21+
22+
DetectSquares.prototype.add = function (point) {
23+
const [x, y] = point;
24+
const key = `${x},${y}`;
25+
if (!this.points.has(key)) {
26+
this.points.set(key, 0);
27+
}
28+
this.points.set(key, this.points.get(key) + 1);
29+
};
30+
31+
DetectSquares.prototype.count = function (point) {
32+
const [px, py] = point;
33+
let count = 0;
34+
35+
// 모든 점을 탐색하며 정사각형의 가능성을 확인
36+
for (let [key, freq] of this.points) {
37+
const [x, y] = key.split(",").map(Number);
38+
39+
// x나 y가 같으면 대각선이 될 수 없으므로 스킵
40+
if (x === px || y === py) continue;
41+
42+
// 대각선의 조건: 두 점 간의 x, y 차이가 같아야 함
43+
if (Math.abs(x - px) === Math.abs(y - py)) {
44+
// 대각선 점을 기준으로 나머지 두 점의 빈도를 곱함
45+
const point1 = `${x},${py}`;
46+
const point2 = `${px},${y}`;
47+
count += (this.points.get(point1) || 0) * (this.points.get(point2) || 0) * freq;
48+
}
49+
}
50+
return count;
51+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* 13m25s 소요
3+
*
4+
* 시간복잡도: O(N log K) (N: nums의 길이, K: k)
5+
*
6+
* 배열에서 k번째로 큰 요소를 찾는 문제입니다.
7+
*
8+
* 최소 힙을 사용하여 풀 수 있습니다.
9+
* 배열을 순회하며 힙에 요소를 삽입합니다.
10+
* 힙 크기가 k를 초과하면 가장 작은 값을 제거합니다.
11+
* 힙의 첫 번째 요소가 k번째로 큰 값입니다
12+
*/
13+
var findKthLargest = function (nums, k) {
14+
const minHeap = new MinPriorityQueue(); // 최소 힙 생성
15+
16+
for (let num of nums) {
17+
minHeap.enqueue(num); // 힙에 삽입
18+
19+
// 힙 크기가 k를 초과하면 가장 작은 값 제거
20+
if (minHeap.size() > k) {
21+
minHeap.dequeue();
22+
}
23+
}
24+
25+
// 힙의 첫 번째 요소가 k번째로 큰 값
26+
return minHeap.front().element;
27+
};
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* 28m41s 소요
3+
*
4+
* 시간복잡도: O(n) (n: 트리의 높이)
5+
*
6+
* 트리 문제라 어려울 줄 알았는데 생각보다 쉬웠습니다.
7+
*
8+
* 이진 탐색 트리에서 두 노드의 가장 가까운 공통 조상을 찾는 문제입니다.
9+
*
10+
* 현재 노드의 값이 두 노드보다 크면 왼쪽으로 이동하고,
11+
* 현재 노드의 값이 두 노드보다 작으면 오른쪽으로 이동합니다.
12+
* 현재 노드가 두 노드 사이에 있는 경우 현재 노드가 최소 공통 조상입니다.
13+
*
14+
* 최소 공통 조상을 찾지 못한 경우 null을 반환합니다.
15+
*/
16+
var lowestCommonAncestor = function (root, p, q) {
17+
while (root) {
18+
// 현재 노드 값이 두 노드보다 크면 왼쪽으로 이동
19+
if (root.val > p.val && root.val > q.val) {
20+
root = root.left;
21+
}
22+
// 현재 노드 값이 두 노드보다 작으면 오른쪽으로 이동
23+
else if (root.val < p.val && root.val < q.val) {
24+
root = root.right;
25+
}
26+
// 현재 노드가 LCA인 경우
27+
else {
28+
return root;
29+
}
30+
}
31+
return null; // 트리 순회가 끝난 경우
32+
};

wjsdncl/39_combination_sum.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* 29m41s 소요
3+
*
4+
* 시간복잡도: O(2^n)
5+
*
6+
* 주어진 숫자 배열에서 합이 target이 되는 모든 조합을 구하는 문제입니다.
7+
*
8+
* 백트래킹을 사용하여 모든 조합을 구합니다.
9+
* 현재 합이 target과 같으면 결과 배열에 추가합니다.
10+
* 현재 합이 target보다 크면 더 이상 탐색하지 않습니다.
11+
* 현재 합이 target보다 작으면 다음 인덱스부터 탐색합니다.
12+
* 탐색이 끝나면 결과 배열을 반환합니다.
13+
*/
14+
var combinationSum = function (candidates, target) {
15+
const result = [];
16+
17+
const backtrack = (current, remain, start) => {
18+
if (remain === 0) {
19+
result.push([...current]);
20+
return;
21+
}
22+
if (remain < 0) return;
23+
24+
for (let i = start; i < candidates.length; i++) {
25+
current.push(candidates[i]);
26+
backtrack(current, remain - candidates[i], i); // 같은 위치에서 다시 시작
27+
current.pop(); // 탐색이 끝난 후 원래 상태로 복구
28+
}
29+
};
30+
31+
backtrack([], target, 0);
32+
return result;
33+
};

wjsdncl/56_merge_intervals.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* 21m41s 소요
3+
*
4+
* 시간복잡도: O(n log n)
5+
*
6+
* 배열의 모든 겹치는 구간을 병합하고 겹치지 않는 구간은 그대로 반환하는 문제입니다.
7+
*
8+
* 시작점을 기준으로 구간을 정렬하고, 결과 배열에 첫 구간을 넣어둡니다.
9+
* 그 다음 구간부터 시작점이 이전 구간의 끝점보다 작거나 같은 경우 두 구간을 병합하고,
10+
* 그렇지 않은 경우 결과 배열에 추가합니다.
11+
*/
12+
var merge = function (intervals) {
13+
if (intervals.length <= 1) return intervals;
14+
15+
// 시작점 기준으로 구간 정렬
16+
intervals.sort((a, b) => a[0] - b[0]);
17+
18+
const result = [intervals[0]]; // 초기 결과 배열
19+
20+
for (let i = 1; i < intervals.length; i++) {
21+
const prev = result[result.length - 1]; // 결과 배열의 마지막 구간
22+
const curr = intervals[i]; // 현재 구간
23+
24+
if (prev[1] >= curr[0]) {
25+
// 겹치는 경우 병합
26+
prev[1] = Math.max(prev[1], curr[1]);
27+
} else {
28+
// 겹치지 않는 경우 결과 배열에 추가
29+
result.push(curr);
30+
}
31+
}
32+
33+
return result;
34+
};

wjsdncl/57_Insert_Interval.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/**
2+
* 32m31s 소요
3+
*
4+
* 시간복잡도 : O(n) (n: intervals의 길이)
5+
*
6+
* 구간들의 배열과 새로운 구간이 주어질 때, 구간들을 병합한 결과를 반환하는 문제입니다.
7+
*
8+
* 구간들을 순회하면서 새로운 구간과 겹치는 구간을 병합합니다.
9+
* 새로운 구간이 구간들보다 클 때까지 구간들을 병합합니다.
10+
* 새로운 구간이 구간들보다 작을 때까지 구간들을 병합합니다.
11+
* 나머지 구간들을 결과에 추가합니다.
12+
* 결과를 반환합니다.
13+
*/
14+
var insert = function (intervals, newInterval) {
15+
const result = [];
16+
let i = 0;
17+
18+
// newInterval 이전의 겹치지 않는 구간 추가
19+
while (i < intervals.length && intervals[i][1] < newInterval[0]) {
20+
result.push(intervals[i]);
21+
i++;
22+
}
23+
24+
// newInterval과 겹치는 구간 병합
25+
while (i < intervals.length && intervals[i][0] <= newInterval[1]) {
26+
newInterval[0] = Math.min(newInterval[0], intervals[i][0]);
27+
newInterval[1] = Math.max(newInterval[1], intervals[i][1]);
28+
i++;
29+
}
30+
result.push(newInterval); // 병합된 구간 추가
31+
32+
// newInterval 이후의 겹치지 않는 구간 추가
33+
while (i < intervals.length) {
34+
result.push(intervals[i]);
35+
i++;
36+
}
37+
38+
return result;
39+
};

wjsdncl/743_network_delay_time.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* 37m26s 소요
3+
*
4+
* 시간복잡도: O(n^2)
5+
*
6+
* 그래프 형태로 주어진 배열에서 k번 노드에서 모든 노드로 가는 최단 시간을 구하는 문제입니다.
7+
*
8+
* 어떻게 풀어야 할지 감이 잘 안와서 풀이랑 GPT의 도움을 받았습니다.
9+
* 다익스트라 알고리즘을 사용하면 풀 수 있다고 합니다.
10+
*
11+
* 다익스트라 알고리즘은 최단 경로를 찾는 알고리즘 중 하나입니다.
12+
* 시작 노드에서 다른 노드로 가는 최단 경로를 찾을 때 사용합니다.
13+
*
14+
* 그래프를 초기화합니다.
15+
* 다익스트라 알고리즘을 사용하여 최단 경로를 찾습니다.
16+
* 최단 경로 배열 중 최대값을 찾아 반환합니다.
17+
*/
18+
var networkDelayTime = function (times, n, k) {
19+
const graph = new Map(); // 그래프 생성
20+
21+
// 그래프 초기화
22+
for (let i = 1; i <= n; i++) {
23+
graph.set(i, []);
24+
}
25+
for (let [u, v, w] of times) {
26+
graph.get(u).push([v, w]);
27+
}
28+
29+
// 다익스트라 알고리즘
30+
const dist = Array(n + 1).fill(Infinity);
31+
dist[k] = 0;
32+
33+
const pq = new MinPriorityQueue({ priority: (x) => x[1] }); // [노드, 거리]
34+
pq.enqueue([k, 0]);
35+
36+
// 우선순위 큐에서 노드를 꺼내면서 최단 거리 갱신
37+
while (!pq.isEmpty()) {
38+
const [current, time] = pq.dequeue().element;
39+
40+
// 현재 노드의 거리가 최단 거리보다 크면 무시
41+
if (time > dist[current]) continue;
42+
43+
// 인접 노드를 순회하며 최단 거리 갱신
44+
for (let [neighbor, weight] of graph.get(current)) {
45+
const newTime = time + weight;
46+
47+
// 최단 거리 갱신
48+
if (newTime < dist[neighbor]) {
49+
dist[neighbor] = newTime;
50+
pq.enqueue([neighbor, newTime]);
51+
}
52+
}
53+
}
54+
55+
// 최종 거리 배열에서 최대값 확인
56+
const result = Math.max(...dist.slice(1)); // 1번 노드부터 n번 노드까지
57+
return result === Infinity ? -1 : result;
58+
};

wjsdncl/7_reverse_integer.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* 14m51s 소요
3+
*
4+
* 시간복잡도 : O(log n) (n: x의 길이)
5+
*
6+
* 32비트 정수 x를 뒤집어서 반환하는 문제입니다.
7+
*
8+
* 32비트 정수의 범위를 벗어나면 0을 반환합니다.
9+
* 숫자를 문자열로 변환하여 뒤집은 뒤, 다시 숫자로 변환합니다.
10+
* 32비트 정수 범위를 벗어나는지 확인합니다.
11+
* 음수인 경우 부호를 복원합니다.
12+
*/
13+
var reverse = function (x) {
14+
const isNegative = x < 0; // 음수 여부 확인
15+
const reversed = parseInt(Math.abs(x).toString().split("").reverse().join("")); // 절댓값 뒤집기
16+
17+
if (reversed > 2 ** 31 - 1) return 0; // 32비트 정수 범위 확인
18+
19+
return isNegative ? -reversed : reversed; // 부호 복원
20+
};

0 commit comments

Comments
 (0)