Skip to content

Commit

Permalink
Merge pull request #438 from wogha95/main
Browse files Browse the repository at this point in the history
[재호] WEEK 05 Solutions
  • Loading branch information
wogha95 authored Sep 15, 2024
2 parents 3550e26 + 8cf6255 commit b840ada
Show file tree
Hide file tree
Showing 5 changed files with 296 additions and 0 deletions.
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);
}
}
}
};

0 comments on commit b840ada

Please sign in to comment.