Skip to content
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
16 changes: 16 additions & 0 deletions best-time-to-buy-and-sell-stock/grapefruitgreentealoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
var maxProfit = function (prices) {
let minPrice = Infinity;
let maxProfit = 0;

for (let price of prices) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 const도 괜찮겠네요.

// 가장 싼 가격을 갱신
if (price < minPrice) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 price - minPrice를 전처리해서 재사용한다면 음수일 때이겠네요.

minPrice = price;
} else {
// 최대 이익을 갱신
maxProfit = Math.max(maxProfit, price - minPrice);
}
}

return maxProfit;
};
46 changes: 46 additions & 0 deletions encode-and-decode-strings/grapefruitgreentealoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 네트워크 전송을 위해서 문자열 리스트를 하나의 문자열로 안전하게 합치고
// 다시 분리하는 함수를 작성하세요.

/**
풀이 과정:
구분자를 "a,b,c"와 같이 ,로 join하면, 원래 문자열에 ,가 포함될 때 깨진다.
따라서 길이 정보를 함께 저장하거나 특수 escape 문자를 써야한다.


*/
/**
* Encodes a list of strings to a single string.
* @param {string[]} strs
* @return {string}
*/
function encode(strs) {
// 각 문자열 앞에 "길이#"를 붙임
// 예: ["abc", "de"] -> "3#abc2#de"
Comment on lines +17 to +18
Copy link
Contributor

@yhkee0404 yhkee0404 Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 반대로 문자마다 Escape Character를 붙여도 되겠군요.

return strs.map((s) => `${s.length}#${s}`).join("");
}

/**
* Decodes a single string to a list of strings.
* @param {string} s
* @return {string[]}
*/
function decode(s) {
let res = [];
let i = 0;

while (i < s.length) {
// 1. 길이 읽기
let j = i;
while (s[j] !== "#") j++;
let length = parseInt(s.slice(i, j), 10);

// 2. 길이에 맞춰 문자열 추출
let str = s.slice(j + 1, j + 1 + length);
res.push(str);

// 3. 인덱스 이동
i = j + 1 + length;
}

return res;
}
37 changes: 37 additions & 0 deletions group-anagrams/grapefruitgreentealoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* @param {string[]} strs
* @return {string[][]}
*/
var groupAnagrams = function(strs) {
const strsMap = new Map();
for(let str of strs){
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 const도 괜찮겠네요.

const strArr = str.split('').sort()
const keyName = strArr.join('-')
strsMap.set(keyName,[...(strsMap.get(keyName)
||[]),str])
Comment on lines +10 to +11
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
strsMap.set(keyName,[...(strsMap.get(keyName)
||[]),str])
strsMap.set(keyName, strsMap.get(keyName)??[]).push(str);

Destructuring을 피하면 O(n)O(1)로 줄겠습니다.
Nullish Coalescing Operator를 사용해도 좋겠습니다.

}
return Array.from(strsMap.values())
};

//시간복잡도 : O(n * klogk)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Destructuring 연산 때문에 O(n * (klogk + n)) = O(nklogk + n^2)이 되겠습니다.

// 공간복잡도 :O(n · k)

//2.문자 빈도수 기반 키 만들기
// 알파벳이 26뿐이므로 각 단어마다 알파벳 개수를 세서 카운트배열 만들어 이걸 키로 사용
var groupAnagrams = function(strs) {
const map = new Map();

for (let str of strs) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 const도 괜찮겠네요.

const count = new Array(26).fill(0);
for (let char of str) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 const도 괜찮겠네요.

count[char.charCodeAt(0) - 97]++;
}
const key = count.join('#'); // 구분자 없으면 ["1","11"]과 ["11","1"] 같은 키로 오해 가능
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 leading zeros를 넣어도 되겠군요.

map.set(key, [...(map.get(key) || []), str]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
map.set(key, [...(map.get(key) || []), str]);
map.set(key, map.get(key)??[]).push(str);

마찬가지로, Destructuring을 피하면 O(n)O(1)로 줄겠습니다.
Nullish Coalescing Operator를 사용해도 좋겠습니다.

}

return Array.from(map.values());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return Array.from(map.values());
return [...map.values()];

이때는 Destructuring을 사용해도 되겠군요.

};

//시간복잡도 : O(n * k). 정렬이 없으므로
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

마찬가지로, Destructuring 연산 때문에 O(n * (k + n)) = O(n * k + n^2)이 되겠습니다.

// 공간복잡도: O(n · k)
37 changes: 37 additions & 0 deletions implement-trie-prefix-tree/grapefruitgreentealoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
function TrieNode() {
this.children = {};
this.isEnd = false;
}

function Trie() {
this.root = new TrieNode();
}

Trie.prototype.insert = function (word) {
let node = this.root;
for (let char of word) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 const도 괜찮겠네요.

if (!node.children[char]) {
node.children[char] = new TrieNode();
}
node = node.children[char];
}
node.isEnd = true;
};

Trie.prototype.search = function (word) {
let node = this._traverse(word);
return node !== null && node.isEnd === true;
Comment on lines +22 to +23
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let node = this._traverse(word);
return node !== null && node.isEnd === true;
return this._traverse(word)?.isEnd??false;

또는 Optional Chaining과 Nullish Coalescing Operator도 괜찮겠네요.

};

Trie.prototype.startsWith = function (prefix) {
return this._traverse(prefix) !== null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return this._traverse(prefix) !== null;
return this._traverse(prefix)??false;

또는 Nullish Coalescing Operator도 괜찮겠네요.

};

Trie.prototype._traverse = function (str) {
let node = this.root;
for (let char of str) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 const도 괜찮겠네요.

if (!node.children[char]) return null;
node = node.children[char];
}
return node;
};
109 changes: 109 additions & 0 deletions word-break/grapefruitgreentealoe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@

//1. 백트레킹

/**
* @param {string} s
* @param {string[]} wordDict
* @return {boolean}
*/

function findIndexAfter(arr, startIndex, callback) {
for (let i = startIndex + 1; i < arr.length; i++) {
if (callback(arr[i], i, arr)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (callback(arr[i], i, arr)) {
if (callback(i, arr)) {

또는 Parameter 하나를 줄일 수도 있겠어요.

return i;
}
}
return -1; // 못 찾으면 -1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return -1; // 못 찾으면 -1
return arr.length;

또는 길이를 반환할 수도 있겠어요.

}
Comment on lines +10 to +17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용하지 않는 코드네요.


var wordBreak = function(s, wordDict) {
let current = '';
const dp = new Array(s.length).fill('');
for(let i=0;i<s.length;i++){
const isSegment = wordDict.find((e) => e == current+s[i] )
if(isSegment) {
dp[i] = current + s[i]
Comment on lines +23 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

또는 current + s[i]를 전처리해서 재사용해도 좋겠네요.

current = ''
Comment on lines +25 to +26
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 코드에는 ;이 많이 생략됐군요.

}else{
current += s[i]
}

if(current.length == s.length && i == s.length-1){
return dp[i] ? true:false
}

// 문자열이 저장이 되어있는 위치에 다시 돌아간다.
// 그 위치에 빈 문자열을 넣어준 후 다음 index로 돌아가게끔 한다.
if(i == s.length-1 && dp[s.length-1] == ''){
i = dp.findLastIndex(e => e!=='')
current = dp[i]
dp[i] = '';
}
}
return dp[s.length-1] ? true:false

};


// 가장 초기값으로 들어가게 되면, 또 같은일을 여러번 반복하게 되므로, 가장 큰 값으로 돌아가야하는게 맞다.
// 그런데 그만큼, 더 오래걸리는 경우가 발생한다.

/*시간복잡도: O(n² * m) (n: 문자열 길이, m: wordDict 길이)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

백트래킹 시간은 이중 반복문보다 훨씬 크게 계산됩니다. 다음과 같은 경우가 최악입니다:
s =
"aaaaaaaaaab"
wordDict =
["a"]
또한 m = wordDict.length와 다른 문자열 길이 k = wordDict[i].length를 곱해야 합니다.

공간복잡도: O(n)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dp 배열이 1차원이 아닙니다. 마찬가지로, m = wordDict.length와 다른 문자열 길이 k = wordDict[i].length를 곱해야 합니다.

*/

//2. 실패난 지점을 메모이제이션 하기 : 시간리밋이 난 이유는, 이전에 실패난 지점에 대해서 다시 돌아간다는 문제가 있었기 때문에, word의 시작기점으로 잡으면 무조건 실패가 나는 index를 메모이제이션 한다.

/**
* @param {string} s
* @param {string[]} wordDict
* @return {boolean}
*/
var wordBreak = function(s, wordDict) {
const wordSet = new Set(wordDict); //중복이 되지 않게 만든다.
const failed = new Set(); //실패한 인덱스를 기록한다.

function dfs(start){
if(start === s.length) return true; // 성공
if(failed.has(start)) return false; //여길 기점으로 하면 실패한다는 것을 기록.

for(let end = start+1; end<=s.length; end++){
const word = s.slice(start,end);
if(wordSet.has(word) && dfs(end)){ // 여기서 잘랐을 때 가능한지.
return true;
}
}
failed.add(start);
return false;
}
return dfs(0);
};

/*
시간복잡도: O(n^2) + 메모이제이션으로 최적화
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

얼마나 최적화했는지 계산할 수 있습니다. sliceO(n)이므로 총 O(n^3)입니다.

공간복잡도 : O(n) : 재귀스택, failed set
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wordSet 때문에 m = wordDict.length를 더해야 합니다: O(n + m)

*/

//3. dp를 활용하여, 이중 포문으로 j,i 사이에 가능한 부분이 있는지 확인한다.

var wordBreak = function(s, wordDict) {
const wordSet = new Set(wordDict);
const dp = new Array(s.length + 1).fill(false);
dp[0] = true; // 빈 문자열은 항상 가능

for (let i = 1; i <= s.length; i++) {
for (let j = 0; j < i; j++) {
if (dp[j] && wordSet.has(s.slice(j, i))) {
dp[i] = true;
break; // 더 이상 검사 안 해도 됨
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

가지치기(Pruning) 가능할 줄 몰랐는데 배워갑니다!

}
}
}

return dp[s.length];
};

/*
시간복잡도: O(n^2)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

마찬가지로, sliceO(n)이므로 총 O(n^3)입니다.

공간복잡도 : O(n)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

마찬가지로, wordSet 때문에 m = wordDict.length를 더해야 합니다: O(n + m)

*/