From a48ed05be2e12a27505c67a24b07b6e9c34d60a5 Mon Sep 17 00:00:00 2001 From: Hyejin Date: Mon, 28 Apr 2025 23:33:22 +0900 Subject: [PATCH 1/7] Best Time to Buy and Sell Stock solution --- best-time-to-buy-and-sell-stock/clara-shin.js | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 best-time-to-buy-and-sell-stock/clara-shin.js diff --git a/best-time-to-buy-and-sell-stock/clara-shin.js b/best-time-to-buy-and-sell-stock/clara-shin.js new file mode 100644 index 000000000..05c0df2a8 --- /dev/null +++ b/best-time-to-buy-and-sell-stock/clara-shin.js @@ -0,0 +1,33 @@ +/** + * 시간 복잡도 O(n) + * 공간 복잡도 O(1) + * + * 그리디 알고리즘 + * 현재까지의 최저 가격을 기억하고, 그 가격에 샀을 때의 이익을 계속 계산하여 최대 이익을 구함 + */ + +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function (prices) { + let minPrice = prices[0]; // 최저 가격 초기화 (첫 날 가격) + let maxProfit = 0; // 최대 이익 초기화 (아직 이익 없음) + + // 두 번째 날부터 + for (let i = 1; i < prices.length; i++) { + // 현재 가격이 최저 가격보다 낮으면 최저 가격 업데이트 + if (prices[i] < minPrice) { + minPrice = prices[i]; + } + // 현재 가능한 이익 계산 (현재 가격 - 최저 가격) + const currentProfit = prices[i] - minPrice; + + // 최대 이익 업데이트 + if (currentProfit > maxProfit) { + maxProfit = currentProfit; + } + } + + return maxProfit; +}; From a01fdcffdb702d216dbcf270e05707ab455ddafe Mon Sep 17 00:00:00 2001 From: Hyejin Date: Tue, 29 Apr 2025 19:01:44 +0900 Subject: [PATCH 2/7] update Best Time to Buy and Sell Stock solution --- best-time-to-buy-and-sell-stock/clara-shin.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/best-time-to-buy-and-sell-stock/clara-shin.js b/best-time-to-buy-and-sell-stock/clara-shin.js index 05c0df2a8..6ca8c13af 100644 --- a/best-time-to-buy-and-sell-stock/clara-shin.js +++ b/best-time-to-buy-and-sell-stock/clara-shin.js @@ -16,17 +16,8 @@ var maxProfit = function (prices) { // 두 번째 날부터 for (let i = 1; i < prices.length; i++) { - // 현재 가격이 최저 가격보다 낮으면 최저 가격 업데이트 - if (prices[i] < minPrice) { - minPrice = prices[i]; - } - // 현재 가능한 이익 계산 (현재 가격 - 최저 가격) - const currentProfit = prices[i] - minPrice; - - // 최대 이익 업데이트 - if (currentProfit > maxProfit) { - maxProfit = currentProfit; - } + minPrice = Math.min(minPrice, prices[i]); // 최저 가격 갱신 + maxProfit = Math.max(maxProfit, prices[i] - minPrice); // 최대 이익 갱신 } return maxProfit; From 830a03edc65a5dc7fecf2ee7d9b3db140c593a54 Mon Sep 17 00:00:00 2001 From: Hyejin Date: Wed, 30 Apr 2025 17:13:52 +0900 Subject: [PATCH 3/7] Group Anagrams solution --- group-anagrams/clara-shin.js | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 group-anagrams/clara-shin.js diff --git a/group-anagrams/clara-shin.js b/group-anagrams/clara-shin.js new file mode 100644 index 000000000..d6c1baad5 --- /dev/null +++ b/group-anagrams/clara-shin.js @@ -0,0 +1,35 @@ +/** + * 문자열 배열 strs가 주어졌을 때, 애너그램끼리 그룹화하는 문제 + * 애너그램: 같은 문자를 재배열하여 만들 수 있는 단어들 + * + * 접근 방법: 각 문자 출현빈도를 카운팅하는 방식 + * 1. 각 문자열을 알파벳 개수로 변환하여 키를 생성 + * 2. Map을 사용하여 키를 기준으로 문자열을 그룹화 + * 3. Map의 값들을 배열로 변환하여 반환 + * + * 시간복잡도: O(n * k) (n: 문자열 개수, k: 문자열 길이) -> 단순 카운팅 + * 공간복잡도: O(n * k) -> 모든 문자열을 저장해야 하므로 + */ + +/** + * @param {string[]} strs + * @return {string[][]} + */ +var groupAnagrams = function (strs) { + const map = new Map(); + + for (let str of strs) { + const count = new Array(26).fill(0); // 알파벳 개수 초기화 + for (let i = 0; i < str.length; i++) { + const index = str.charCodeAt(i) - 'a'.charCodeAt(0); // 알파벳 인덱스 계산 + count[index]++; // 해당 알파벳 개수 증가 + } + const key = count.join('#'); // 알파벳 개수를 문자열로 변환하여 키 생성 + if (!map.has(key)) { + map.set(key, []); // 키가 없으면 새로운 배열 생성 + } + map.get(key).push(str); // 해당 키에 문자열 추가 + } + + return Array.from(map.values()); // Map의 값들을 배열로 변환하여 반환 +}; From aeabb3dbaa4af524006a19fc2b1f196a9318dcce Mon Sep 17 00:00:00 2001 From: Hyejin Date: Wed, 30 Apr 2025 17:23:37 +0900 Subject: [PATCH 4/7] Word Search solution --- word-search/clara-shin.js | 68 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 word-search/clara-shin.js diff --git a/word-search/clara-shin.js b/word-search/clara-shin.js new file mode 100644 index 000000000..2e13920f4 --- /dev/null +++ b/word-search/clara-shin.js @@ -0,0 +1,68 @@ +/** + * 주어진 격자(board)에서 특정 단어(word)가 존재하는지 확인하는 함수 + * + * 접근 방식:DFS(깊이 우선 탐색) + 백트래킹 + * 시간 복잡도: O(m * n * 4^k) (m: 행, n: 열, k: 단어 길이) + * 공간 복잡도: O(m * n) (최대 깊이 m*n) + * + */ + +/** + * @param {character[][]} board + * @param {string} word + * @return {boolean} + */ +var exist = function (board, word) { + const m = board.length; + const n = board[0].length; + + const directions = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ]; + + function dfs(row, col, index) { + if (index === word.length) { + return true; + } + + if (row < 0 || row >= m || col < 0 || col >= n || board[row][col] !== word[index]) { + return false; + } + + // 현재 셀 방문 표시 (임시로 변경) + const temp = board[row][col]; + board[row][col] = '#'; // 방문한 셀을 특수 문자로 표시 + + // 네 방향 탐색 + for (const [dx, dy] of directions) { + const newRow = row + dx; + const newCol = col + dy; + + if (dfs(newRow, newCol, index + 1)) { + // 단어를 찾았으면 원래 값 롤백 후 true 반환 + board[row][col] = temp; + return true; + } + } + + // 백트래킹(현재 셀의 원래 값 롤백) + board[row][col] = temp; + + return false; + } + + // 격자의 모든 셀에서 시작점으로 시도 + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (board[i][j] === word[0] && dfs(i, j, 0)) { + return true; + } + } + } + + // 모든 시작점에서 실패하면 + return false; +}; From 653035410481de33ee938c45208e9aa72d1a5138 Mon Sep 17 00:00:00 2001 From: Hyejin Date: Thu, 1 May 2025 20:36:26 +0900 Subject: [PATCH 5/7] Encode and Decode Strings solution --- encode-and-decode-strings/clara-shin.js | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 encode-and-decode-strings/clara-shin.js diff --git a/encode-and-decode-strings/clara-shin.js b/encode-and-decode-strings/clara-shin.js new file mode 100644 index 000000000..56d33795c --- /dev/null +++ b/encode-and-decode-strings/clara-shin.js @@ -0,0 +1,38 @@ +/** + * 문자열 리스트를 하나의 문자열로 인코딩하고, 다시 디코딩 하기 + * + * 접근 방법: + * 길이 기반 인코딩 => 각 문자열마다 "길이#문자열" 형식으로 인코딩 + * "#"을 기준으로 문자열을 나누고, 길이를 이용해 원래 문자열을 복원하여 디코딩 + */ + +/** + * @param {string[]} strs - 인코딩할 문자열 리스트 + * @return {string} - 인코딩된 문자열 + */ +var encode = function (strs) { + if (!strs || strs.length === 0) return ''; + return strs.map((str) => str.length + '#' + str).join(''); +}; + +/** + * @param {string} s - 디코딩할 인코딩된 문자열 + * @return {string[]} - 원래의 문자열 리스트 + */ +var decode = function (s) { + if (!s || s.length === 0) return []; + + const result = []; + let i = 0; + + while (i < s.length) { + const delimiterIndex = s.indexOf('#', i); // '#'의 위치 찾기 + const length = parseInt(s.slice(i, delimiterIndex)); // 길이 추출 + + const start = delimiterIndex + 1; // 문자열 시작 위치 + result.push(s.slice(start, start + length)); // 알아낸 길이만큼 문자열 추출 후 결과에 추가 + i = start + length; // 다음 문자열 시작 위치로 포인터 이동 + } + + return result; +}; From 2c6c1d724e898df9241400b40cffd7f9c8769e70 Mon Sep 17 00:00:00 2001 From: Hyejin Date: Thu, 1 May 2025 21:06:52 +0900 Subject: [PATCH 6/7] Implement Trie (Prefix Tree) solution --- implement-trie-prefix-tree/clara-shin.js | 79 ++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 implement-trie-prefix-tree/clara-shin.js diff --git a/implement-trie-prefix-tree/clara-shin.js b/implement-trie-prefix-tree/clara-shin.js new file mode 100644 index 000000000..98965f53e --- /dev/null +++ b/implement-trie-prefix-tree/clara-shin.js @@ -0,0 +1,79 @@ +// TrieNode 클래스 정의: 트라이의 각 노드를 표현 +var TrieNode = function () { + this.children = new Map(); // 자식 노드를 Map으로 저장 + this.isEnd = false; // 단어의 끝을 표시하는 플래그 +}; + +// Trie 클래스 정의: 트라이 자료구조를 표현 +var Trie = function () { + this.root = new TrieNode(); // 루트 노드 +}; + +/** + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function (word) { + let node = this.root; // 현재 노드를 루트로 초기화 + + for (let i = 0; i < word.length; i++) { + const char = word[i]; // 현재 문자 + + // 현재 문자에 대한 자식 노드가 없으면 새로 생성 + if (!node.children.has(char)) { + node.children.set(char, new TrieNode()); + } + + // 다음 자식 노드로 이동 + node = node.children.get(char); + } + node.isEnd = true; // 단어의 끝을 표시 +}; + +/** + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function (word) { + const node = this._searchPrefix(word); // 주어진 단어의 노드를 찾음 + return node !== null && node.isEnd === true; // 경로가 존재하고, 마지막 노드가 단어의 끝인지 확인 +}; + +/** + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function (prefix) { + return this._searchPrefix(prefix) !== null; // 경로가 존재하는지만 확인 +}; + +/** + * 헬퍼 메서드: 주어진 접두사에 대한 경로를 찾는 메서드 + * @param {string} str + * @return {TrieNode|null} 경로의 마지막 노드 또는 null + * @private + */ +Trie.prototype._searchPrefix = function (str) { + let node = this.root; // 현재 노드를 루트로 초기화 + + // 주어진 문자열의 각 문자에 대해 노드 탐색 + for (let i = 0; i < str.length; i++) { + const char = str[i]; // 현재 문자 + + // 현재 문자에 대한 자식 노드가 없으면 null 리턴 + if (!node.children.has(char)) { + return null; + } + + // 다음 자식 노드로 이동 + node = node.children.get(char); + } + return node; // 경로의 마지막 노드 반환 +}; +/** + * 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) + */ From aaeb0b1be3b500cda5563ec2b475c6d70a5deac9 Mon Sep 17 00:00:00 2001 From: Hyejin Date: Thu, 1 May 2025 22:11:25 +0900 Subject: [PATCH 7/7] Word Break solution --- word-break/clara-shin.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 word-break/clara-shin.js diff --git a/word-break/clara-shin.js b/word-break/clara-shin.js new file mode 100644 index 000000000..54d49768b --- /dev/null +++ b/word-break/clara-shin.js @@ -0,0 +1,34 @@ +/** + * 문자열 s가 주어진 단어 사전 wordDict의 단어들로 분리될 수 있는지 확인하는 문제 + * 다이나믹 프로그래밍(DP) + * 시간 복잡도: O(n * k) (k: 최대 단어 길이) + * 공간 복잡도: O(n) (DP 배열 + 단어 집합) + */ + +/** + * @param {string} s + * @param {string[]} wordDict + * @return {boolean} + */ +var wordBreak = function (s, wordDict) { + const n = s.length; + const dp = new Array(n + 1).fill(false); // DP 배열 초기화 + dp[0] = true; // 빈 문자열은 항상 분리 가능 + + const wordSet = new Set(wordDict); // 단어 사전을 Set으로 변환: 검색시간 O(1) + + const maxWordLength = Math.max(...wordDict.map((word) => word.length)); // 단어의 최대 길이 찾기 + + for (let i = 0; i <= n; i++) { + // 가능한 단어 길이만 검사 + for (let j = Math.max(0, i - maxWordLength); j < i; j++) { + if (dp[j] && wordSet.has(s.substring(j, i))) { + // dp[j]가 true이고, j부터 i까지의 부분 문자열이 단어 사전에 존재하는 경우 + dp[i] = true; + break; + } + } + } + + return dp[n]; +};