Skip to content

[재호] WEEK 05 Solutions #438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 15, 2024
Merged
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
60 changes: 60 additions & 0 deletions 3sum/wogha95.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* TC: O(N^2)
* SC: O(N)
*
* 풀이
* 2sum의 확장 문제 (nums[i] == nums[j] + nums[k])
* 2sum은 투포인터로 시간복잡도 O(N)을 만들기 위해 투포인터를 활용한다.
*/

/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function (nums) {
const result = [];
const sortedNums = nums.sort((a, b) => a - b);

// 3개 항의 합이 0이 될 수 없는 경우
if (sortedNums[0] > 0 || sortedNums[sortedNums.length - 1] < 0) {
return [];
}

// 1. 순회를 하며 2sum의 target 값을 지정함
for (let index = 0; index < sortedNums.length - 2; ) {
twoSum(index + 1, sortedNums[index]);
// 3. 동일한 숫자를 제외하기 위해 순회
while (sortedNums[index] === sortedNums[index + 1]) {
index += 1;
}
index += 1;
}

return result;

function twoSum(startIndex, target) {
let left = startIndex;
let right = sortedNums.length - 1;

// 2. 투포인터로 2sum이 target이 되는 경우를 찾기 위해 순회
while (left < right) {
const sum = sortedNums[left] + sortedNums[right];

if (sum + target === 0) {
result.push([target, sortedNums[left], sortedNums[right]]);
}

if (sum + target < 0) {
while (sortedNums[left] === sortedNums[left + 1]) {
left += 1;
}
left += 1;
} else {
while (sortedNums[right] === sortedNums[right - 1]) {
right -= 1;
}
right -= 1;
}
}
}
};
22 changes: 22 additions & 0 deletions best-time-to-buy-and-sell-stock/wogha95.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* TC: O(N)
* SC: O(1)
*/

/**
* @param {number[]} prices
* @return {number}
*/
var maxProfit = function (prices) {
let maximumProfit = 0;
let minimumPrice = prices[0];

for (const price of prices) {
// 매일 (그날까지의) 최소 구매가를 기록합니다.
minimumPrice = Math.min(minimumPrice, price);
// 최대 이익을 갱신합니다.
maximumProfit = Math.max(maximumProfit, price - minimumPrice);
}

return maximumProfit;
};
51 changes: 51 additions & 0 deletions group-anagrams/wogha95.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* TC: O(N * S)
* SC: O(N)
* N: strs.length, S: Max(strs[i].length)
*
* 풀이
* 주어진 배열 strs의 각 원소의 키를 구해서 같은 원소끼리 묶어 정답을 찾는다.
* 키 구하는 방법은 주어진 문자열의 사용된 알파벳 갯수이다.
*/

/**
* @param {string[]} strs
* @return {string[][]}
*/
var groupAnagrams = function (strs) {
// 1. 키를 저장할 Map
const keyMap = new Map();

for (const str of strs) {
// 2. 키를 구해서 동일한 키면 같은 값(배열)에 추가한다.
const key = generateKey(str);

if (keyMap.has(key)) {
keyMap.get(key).push(str);
} else {
keyMap.set(key, [str]);
}
}

// 3. 키를 저장한 Map의 값들을 모아 정답을 반환한다.
const result = [];

for (const v of keyMap.values()) {
result.push(v);
}

return result;

// 키 구하는 함수
function generateKey(str) {
// 각 알파벳이 몇개 등장했는지 기록할 배열
const usedCount = new Array(26).fill(0);

for (const s of str) {
// 아스키코드로 변환하여 index를 구한다.
usedCount[s.charCodeAt() - 97] += 1;
}

return usedCount.join(",");
}
};
81 changes: 81 additions & 0 deletions implement-trie-prefix-tree/wogha95.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
function Node() {
this.value = null;
this.wordGraph = new Map();
}

var Trie = function () {
this.wordGraph = new Map();
};

/**
* TC: O(W)
* SC: O(W)
* W: word.length
*/

/**
* @param {string} word
* @return {void}
*/
Trie.prototype.insert = function (word) {
let pointer = this;
for (const w of word) {
if (!pointer.wordGraph.has(w)) {
pointer.wordGraph.set(w, new Node());
}
pointer = pointer.wordGraph.get(w);
}
pointer.value = word;
};

/**
* TC: O(W)
* SC: O(1)
* W: word.length
*/

/**
* @param {string} word
* @return {boolean}
*/
Trie.prototype.search = function (word) {
let pointer = this;
for (const w of word) {
if (!pointer.wordGraph.has(w)) {
return false;
} else {
pointer = pointer.wordGraph.get(w);
}
}
return pointer.value === word;
};

/**
* TC: O(P)
* SC: O(1)
* P:prefix.length
*/

/**
* @param {string} prefix
* @return {boolean}
*/
Trie.prototype.startsWith = function (prefix) {
let pointer = this;
for (const p of prefix) {
if (!pointer.wordGraph.has(p)) {
return false;
} else {
pointer = pointer.wordGraph.get(p);
}
}
return true;
};

/**
* Your Trie object will be instantiated and called as such:
* var obj = new Trie()
* obj.insert(word)
* var param_2 = obj.search(word)
* var param_3 = obj.startsWith(prefix)
*/
82 changes: 82 additions & 0 deletions word-break/wogha95.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* TC: O(W * S)
* 4번에서 W만큼 순회 * 메모이제이션 S
*
* SC: O(S)
* queue 최대 S + visited 최대 S
*
* S: s.length, W: wordDict.length
*/

/**
* @param {string} s
* @param {string[]} wordDict
* @return {boolean}
*/
var wordBreak = function (s, wordDict) {
const queue = [0];
const visited = new Set();

while (queue.length) {
const start = queue.shift();
// 1. 도착했다면 정답 반환
if (start === s.length) {
return true;
}
// 2. 이미 방문한 경우 순회 방지
if (visited.has(start)) {
continue;
}

// 3. 방문 표시 남기고
visited.add(start);
// 4. wordDict의 word를 이용할 있는 경우
for (const word of wordDict) {
if (s.slice(start, start + word.length) === word) {
queue.push(start + word.length);
}
}
}

return false;
};

/**
* TC: O(W * S)
* 2번에서 W만큼 순회 * 메모이제이션 S
*
* SC: O(S)
* possibleS의 길이 S + dfs의 깊이는 최대 S
*
* S: s.length, W: wordDict.length
*/

/**
* @param {string} s
* @param {string[]} wordDict
* @return {boolean}
*/
var wordBreak = function (s, wordDict) {
// 1. S의 index번째 글자까지 wordDict 조합이 가능한지 표시하는 배열
const possibleS = new Array(s.length + 1).fill(false);

dfs(0);

return possibleS[s.length];

function dfs(start) {
// 2. wordDict의 word를 이용할 있는 경우
for (const word of wordDict) {
if (s.slice(start, start + word.length) === word) {
// 3. 이미 조합 가능 표시가 있는 index의 경우 백트래킹
if (possibleS[start + word.length]) {
return;
}

// 4. 조합 가능하다는 표시를 하고 다음 index로 재귀
possibleS[start + word.length] = true;
dfs(start + word.length);
}
}
}
};