From ed2c4c44974b5808a5127d8adfc2286fd27f6fc5 Mon Sep 17 00:00:00 2001 From: hi-rachel Date: Thu, 1 May 2025 12:27:23 +0900 Subject: [PATCH 1/5] best-time-to-buy-and-sell-stock solution (py, ts) --- best-time-to-buy-and-sell-stock/hi-rachel.py | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 best-time-to-buy-and-sell-stock/hi-rachel.py diff --git a/best-time-to-buy-and-sell-stock/hi-rachel.py b/best-time-to-buy-and-sell-stock/hi-rachel.py new file mode 100644 index 000000000..e58cb6791 --- /dev/null +++ b/best-time-to-buy-and-sell-stock/hi-rachel.py @@ -0,0 +1,26 @@ +# TC: O(N), SC: O(1) + +class Solution: + def maxProfit(self, prices: List[int]) -> int: + max_profit = 0 + min_price = prices[0] + + for price in prices: + max_profit = max(price - min_price, max_profit) + min_price = min(price, min_price) + return max_profit + +# TS 풀이 +# 배열 요소(숫자값)을 직접 순회하려면 for ... of 사용 혹은 forEach +# for ... in -> 인덱스를 가져옴 + +# function maxProfit(prices: number[]): number { +# let max_profit: number = 0; +# let min_price: number = prices[0]; + +# for (let price of prices) { +# max_profit = Math.max(max_profit, price - min_price); +# min_price = Math.min(min_price, price); +# } +# return max_profit; +# }; From 5e0b8c04e4779e60d16ee49ba4137d5cab5a2f2f Mon Sep 17 00:00:00 2001 From: hi-rachel Date: Thu, 1 May 2025 14:15:35 +0900 Subject: [PATCH 2/5] grounp-anagram solution (py, ts) --- group-anagrams/hi-rachel.py | 14 ++++++++++ group-anagrams/hi-rachel.ts | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 group-anagrams/hi-rachel.py create mode 100644 group-anagrams/hi-rachel.ts diff --git a/group-anagrams/hi-rachel.py b/group-anagrams/hi-rachel.py new file mode 100644 index 000000000..cfe743e93 --- /dev/null +++ b/group-anagrams/hi-rachel.py @@ -0,0 +1,14 @@ +# TC O(N * K log K), SC O(N * K) + +from collections import defaultdict + +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + anagram_map = defaultdict(list) + + for word in strs: + key = ''.join(sorted(word)) + anagram_map[key].append(word) + + return list(anagram_map.values()) + diff --git a/group-anagrams/hi-rachel.ts b/group-anagrams/hi-rachel.ts new file mode 100644 index 000000000..8ad337cf9 --- /dev/null +++ b/group-anagrams/hi-rachel.ts @@ -0,0 +1,51 @@ +// TC O(N * K log K), N: 단어 수, K: 평균 단어 길이, 각 단어를 정렬 +// SC O(N * K) + +/** + * Array.from() => 이터러블 -> 일반 배열로 변환 + */ +function groupAnagrams(strs: string[]): string[][] { + const anagramMap: Map = new Map(); + + for (const word of strs) { + const key = word.split("").sort().join(""); + const group = anagramMap.get(key) || []; + group.push(word); + anagramMap.set(key, group); + } + return Array.from(anagramMap.values()); +} + +/** + * reduce 풀이 + */ +// function groupAnagrams(strs: string[]): string[][] { +// const anagramMap = strs.reduce((map, word) => { +// const key = word.split("").sort().join(""); +// if (!map.has(key)) { +// map.set(key, []); +// } +// map.get(key).push(word); +// return map; +// }, new Map()); + +// return Array.from(anagramMap.values()); +// } + +/** 간결한 버전 + * x ||= y (ES2021) + * x가 falsy 값이면 y를 할당 + * JS에서 falsy 값 = false, 0, '', null, undefined, NaN + * + * Object.values() => 객체의 값들만 배열로 추출할때 사용 + */ +// function groupAnagrams(strs: string[]): string[][] { +// const anagramMap: {[key: string]: string[]} = {}; + +// strs.forEach((word) => { +// const key = word.split('').sort().join(''); +// (anagramMap[key] ||= []).push(word); +// }); + +// return Object.values(anagramMap); +// } From 73872616aacc2331e31a4f7028a09bf838a87383 Mon Sep 17 00:00:00 2001 From: hi-rachel Date: Fri, 2 May 2025 17:03:01 +0900 Subject: [PATCH 3/5] word-break solutions (ts, py) --- word-break/hi-rachel.ts | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 word-break/hi-rachel.ts diff --git a/word-break/hi-rachel.ts b/word-break/hi-rachel.ts new file mode 100644 index 000000000..08f0399ce --- /dev/null +++ b/word-break/hi-rachel.ts @@ -0,0 +1,33 @@ +// wordDict 조합으로 s를 만들 수 있는지 반환해라 +// TC: O(n^2) SC: O(n + m * k) => s의 길이 + (단어 수 * 평균 단어 길이) +// .has(word) => O(1) + +function wordBreak(s: string, wordDict: string[]): boolean { + const wordSet = new Set(wordDict); + const dp: boolean[] = 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; + } + } + } + return dp[s.length]; +} + +// PY 풀이 +// class Solution: +// def wordBreak(self, s: str, wordDict: List[str]) -> bool: +// wordSet = set(wordDict) +// dp = [False] * (len(s)+1) +// dp[0] = True + +// for i in range(1, len(s)+1): +// for j in range(0, i): +// if dp[j] and s[j:i] in wordSet: +// dp[i] = True + +// return dp[len(s)] From 97b06078cc187da5f1f7d0a4c5714ce288a07d63 Mon Sep 17 00:00:00 2001 From: hi-rachel Date: Sat, 3 May 2025 16:09:57 +0900 Subject: [PATCH 4/5] encode-and-decode-strings solution (py) --- encode-and-decode-strings/hi-rachel.py | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 encode-and-decode-strings/hi-rachel.py diff --git a/encode-and-decode-strings/hi-rachel.py b/encode-and-decode-strings/hi-rachel.py new file mode 100644 index 000000000..218f764b4 --- /dev/null +++ b/encode-and-decode-strings/hi-rachel.py @@ -0,0 +1,30 @@ +# 문제: https://neetcode.io/problems/string-encode-and-decode +# TC: O(N), SC: O(1) +# ASCII 문자열이 아닌 이모티콘으로 구분자 선택 + +class Solution: + def encode(self, strs: List[str]) -> str: + return '🤍'.join(strs) + + def decode(self, s: str) -> List[str]: + return s.split('🤍') + +# ASCII 문자열에 포함된 기호로 구분자를 써야할 때 +# -> 글자 수 표시 +class Solution: + def encode(self, strs: List[str]) -> str: + text = "" + for str in strs: + text += f"{len(str)}:{str}" + return text + + def decode(self, s: str) -> List[str]: + ls, start = [], 0 + while start < len(s): + mid = s.find(":", start) + length = int(s[start : mid]) + word = s[mid + 1 : mid + 1 + length] + ls.append(word) + start = mid + 1 + length + return ls + From 110cc370fe5551ace5910ef3c969cbefe542ca39 Mon Sep 17 00:00:00 2001 From: hi-rachel Date: Sat, 3 May 2025 16:40:33 +0900 Subject: [PATCH 5/5] implement-trie-prefix-tree solution (py, ts) --- implement-trie-prefix-tree/hi-rachel.py | 45 +++++++++++++++++++++ implement-trie-prefix-tree/hi-rachel.ts | 54 +++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 implement-trie-prefix-tree/hi-rachel.py create mode 100644 implement-trie-prefix-tree/hi-rachel.ts diff --git a/implement-trie-prefix-tree/hi-rachel.py b/implement-trie-prefix-tree/hi-rachel.py new file mode 100644 index 000000000..37d22700c --- /dev/null +++ b/implement-trie-prefix-tree/hi-rachel.py @@ -0,0 +1,45 @@ +# Trie Data Structure 구현 +# TC: O(n), SC: O(N) +# autocomplete and spellchecker 등에 사용 + +class Node: + def __init__(self, ending=False): + self.children = {} + self.ending = ending + +class Trie: + def __init__(self): + self.root = Node(ending=True) # 노드 객체 생성 + + def insert(self, word: str) -> None: + node = self.root #Trie의 최상위 노드부터 시작 + for ch in word: + if ch not in node.children: + node.children[ch] = Node() # 새로운 노드 생성 + node = node.children[ch] + node.ending = True + + def search(self, word: str) -> bool: + node = self.root + + for ch in word: + if ch not in node.children: + return False + node = node.children[ch] + return node.ending + + def startsWith(self, prefix: str) -> bool: + node = self.root + + for ch in prefix: + if ch not in node.children: + return False + node = node.children[ch] + return True + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) diff --git a/implement-trie-prefix-tree/hi-rachel.ts b/implement-trie-prefix-tree/hi-rachel.ts new file mode 100644 index 000000000..2fb909d1e --- /dev/null +++ b/implement-trie-prefix-tree/hi-rachel.ts @@ -0,0 +1,54 @@ +class TrieNode { + children: Map; + ending: boolean; + + constructor(ending = false) { + this.children = new Map(); + this.ending = ending; + } +} + +class Trie { + private root: TrieNode; + + constructor() { + this.root = new TrieNode(true); + } + + insert(word: string): void { + let node = this.root; + for (const ch of word) { + if (!node.children.has(ch)) { + node.children.set(ch, new TrieNode()); + } + node = node.children.get(ch)!; // 노드 포인터를 ch로 이동 + } + node.ending = true; + } + + search(word: string): boolean { + let node = this.root; + for (const ch of word) { + if (!node.children.has(ch)) return false; + node = node.children.get(ch)!; + } + return node.ending; + } + + startsWith(prefix: string): boolean { + let node = this.root; + for (const ch of prefix) { + if (!node.children.has(ch)) return false; + node = node.children.get(ch)!; + } + 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) + */