Skip to content

Commit b840ada

Browse files
authored
Merge pull request #438 from wogha95/main
[재호] WEEK 05 Solutions
2 parents 3550e26 + 8cf6255 commit b840ada

File tree

5 files changed

+296
-0
lines changed

5 files changed

+296
-0
lines changed

3sum/wogha95.js

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* TC: O(N^2)
3+
* SC: O(N)
4+
*
5+
* 풀이
6+
* 2sum의 확장 문제 (nums[i] == nums[j] + nums[k])
7+
* 2sum은 투포인터로 시간복잡도 O(N)을 만들기 위해 투포인터를 활용한다.
8+
*/
9+
10+
/**
11+
* @param {number[]} nums
12+
* @return {number[][]}
13+
*/
14+
var threeSum = function (nums) {
15+
const result = [];
16+
const sortedNums = nums.sort((a, b) => a - b);
17+
18+
// 3개 항의 합이 0이 될 수 없는 경우
19+
if (sortedNums[0] > 0 || sortedNums[sortedNums.length - 1] < 0) {
20+
return [];
21+
}
22+
23+
// 1. 순회를 하며 2sum의 target 값을 지정함
24+
for (let index = 0; index < sortedNums.length - 2; ) {
25+
twoSum(index + 1, sortedNums[index]);
26+
// 3. 동일한 숫자를 제외하기 위해 순회
27+
while (sortedNums[index] === sortedNums[index + 1]) {
28+
index += 1;
29+
}
30+
index += 1;
31+
}
32+
33+
return result;
34+
35+
function twoSum(startIndex, target) {
36+
let left = startIndex;
37+
let right = sortedNums.length - 1;
38+
39+
// 2. 투포인터로 2sum이 target이 되는 경우를 찾기 위해 순회
40+
while (left < right) {
41+
const sum = sortedNums[left] + sortedNums[right];
42+
43+
if (sum + target === 0) {
44+
result.push([target, sortedNums[left], sortedNums[right]]);
45+
}
46+
47+
if (sum + target < 0) {
48+
while (sortedNums[left] === sortedNums[left + 1]) {
49+
left += 1;
50+
}
51+
left += 1;
52+
} else {
53+
while (sortedNums[right] === sortedNums[right - 1]) {
54+
right -= 1;
55+
}
56+
right -= 1;
57+
}
58+
}
59+
}
60+
};
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* TC: O(N)
3+
* SC: O(1)
4+
*/
5+
6+
/**
7+
* @param {number[]} prices
8+
* @return {number}
9+
*/
10+
var maxProfit = function (prices) {
11+
let maximumProfit = 0;
12+
let minimumPrice = prices[0];
13+
14+
for (const price of prices) {
15+
// 매일 (그날까지의) 최소 구매가를 기록합니다.
16+
minimumPrice = Math.min(minimumPrice, price);
17+
// 최대 이익을 갱신합니다.
18+
maximumProfit = Math.max(maximumProfit, price - minimumPrice);
19+
}
20+
21+
return maximumProfit;
22+
};

group-anagrams/wogha95.js

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* TC: O(N * S)
3+
* SC: O(N)
4+
* N: strs.length, S: Max(strs[i].length)
5+
*
6+
* 풀이
7+
* 주어진 배열 strs의 각 원소의 키를 구해서 같은 원소끼리 묶어 정답을 찾는다.
8+
* 키 구하는 방법은 주어진 문자열의 사용된 알파벳 갯수이다.
9+
*/
10+
11+
/**
12+
* @param {string[]} strs
13+
* @return {string[][]}
14+
*/
15+
var groupAnagrams = function (strs) {
16+
// 1. 키를 저장할 Map
17+
const keyMap = new Map();
18+
19+
for (const str of strs) {
20+
// 2. 키를 구해서 동일한 키면 같은 값(배열)에 추가한다.
21+
const key = generateKey(str);
22+
23+
if (keyMap.has(key)) {
24+
keyMap.get(key).push(str);
25+
} else {
26+
keyMap.set(key, [str]);
27+
}
28+
}
29+
30+
// 3. 키를 저장한 Map의 값들을 모아 정답을 반환한다.
31+
const result = [];
32+
33+
for (const v of keyMap.values()) {
34+
result.push(v);
35+
}
36+
37+
return result;
38+
39+
// 키 구하는 함수
40+
function generateKey(str) {
41+
// 각 알파벳이 몇개 등장했는지 기록할 배열
42+
const usedCount = new Array(26).fill(0);
43+
44+
for (const s of str) {
45+
// 아스키코드로 변환하여 index를 구한다.
46+
usedCount[s.charCodeAt() - 97] += 1;
47+
}
48+
49+
return usedCount.join(",");
50+
}
51+
};

implement-trie-prefix-tree/wogha95.js

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
function Node() {
2+
this.value = null;
3+
this.wordGraph = new Map();
4+
}
5+
6+
var Trie = function () {
7+
this.wordGraph = new Map();
8+
};
9+
10+
/**
11+
* TC: O(W)
12+
* SC: O(W)
13+
* W: word.length
14+
*/
15+
16+
/**
17+
* @param {string} word
18+
* @return {void}
19+
*/
20+
Trie.prototype.insert = function (word) {
21+
let pointer = this;
22+
for (const w of word) {
23+
if (!pointer.wordGraph.has(w)) {
24+
pointer.wordGraph.set(w, new Node());
25+
}
26+
pointer = pointer.wordGraph.get(w);
27+
}
28+
pointer.value = word;
29+
};
30+
31+
/**
32+
* TC: O(W)
33+
* SC: O(1)
34+
* W: word.length
35+
*/
36+
37+
/**
38+
* @param {string} word
39+
* @return {boolean}
40+
*/
41+
Trie.prototype.search = function (word) {
42+
let pointer = this;
43+
for (const w of word) {
44+
if (!pointer.wordGraph.has(w)) {
45+
return false;
46+
} else {
47+
pointer = pointer.wordGraph.get(w);
48+
}
49+
}
50+
return pointer.value === word;
51+
};
52+
53+
/**
54+
* TC: O(P)
55+
* SC: O(1)
56+
* P:prefix.length
57+
*/
58+
59+
/**
60+
* @param {string} prefix
61+
* @return {boolean}
62+
*/
63+
Trie.prototype.startsWith = function (prefix) {
64+
let pointer = this;
65+
for (const p of prefix) {
66+
if (!pointer.wordGraph.has(p)) {
67+
return false;
68+
} else {
69+
pointer = pointer.wordGraph.get(p);
70+
}
71+
}
72+
return true;
73+
};
74+
75+
/**
76+
* Your Trie object will be instantiated and called as such:
77+
* var obj = new Trie()
78+
* obj.insert(word)
79+
* var param_2 = obj.search(word)
80+
* var param_3 = obj.startsWith(prefix)
81+
*/

word-break/wogha95.js

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* TC: O(W * S)
3+
* 4번에서 W만큼 순회 * 메모이제이션 S
4+
*
5+
* SC: O(S)
6+
* queue 최대 S + visited 최대 S
7+
*
8+
* S: s.length, W: wordDict.length
9+
*/
10+
11+
/**
12+
* @param {string} s
13+
* @param {string[]} wordDict
14+
* @return {boolean}
15+
*/
16+
var wordBreak = function (s, wordDict) {
17+
const queue = [0];
18+
const visited = new Set();
19+
20+
while (queue.length) {
21+
const start = queue.shift();
22+
// 1. 도착했다면 정답 반환
23+
if (start === s.length) {
24+
return true;
25+
}
26+
// 2. 이미 방문한 경우 순회 방지
27+
if (visited.has(start)) {
28+
continue;
29+
}
30+
31+
// 3. 방문 표시 남기고
32+
visited.add(start);
33+
// 4. wordDict의 word를 이용할 있는 경우
34+
for (const word of wordDict) {
35+
if (s.slice(start, start + word.length) === word) {
36+
queue.push(start + word.length);
37+
}
38+
}
39+
}
40+
41+
return false;
42+
};
43+
44+
/**
45+
* TC: O(W * S)
46+
* 2번에서 W만큼 순회 * 메모이제이션 S
47+
*
48+
* SC: O(S)
49+
* possibleS의 길이 S + dfs의 깊이는 최대 S
50+
*
51+
* S: s.length, W: wordDict.length
52+
*/
53+
54+
/**
55+
* @param {string} s
56+
* @param {string[]} wordDict
57+
* @return {boolean}
58+
*/
59+
var wordBreak = function (s, wordDict) {
60+
// 1. S의 index번째 글자까지 wordDict 조합이 가능한지 표시하는 배열
61+
const possibleS = new Array(s.length + 1).fill(false);
62+
63+
dfs(0);
64+
65+
return possibleS[s.length];
66+
67+
function dfs(start) {
68+
// 2. wordDict의 word를 이용할 있는 경우
69+
for (const word of wordDict) {
70+
if (s.slice(start, start + word.length) === word) {
71+
// 3. 이미 조합 가능 표시가 있는 index의 경우 백트래킹
72+
if (possibleS[start + word.length]) {
73+
return;
74+
}
75+
76+
// 4. 조합 가능하다는 표시를 하고 다음 index로 재귀
77+
possibleS[start + word.length] = true;
78+
dfs(start + word.length);
79+
}
80+
}
81+
}
82+
};

0 commit comments

Comments
 (0)