diff --git a/container-with-most-water/radiantchoi.ts b/container-with-most-water/radiantchoi.ts new file mode 100644 index 000000000..d61c74e8a --- /dev/null +++ b/container-with-most-water/radiantchoi.ts @@ -0,0 +1,27 @@ +function maxArea(height: number[]): number { + let result = 0; + let left = 0; + let right = height.length - 1; + + // 입력 원소의 갯수가 10만개까지이므로, O(n^2)은 시간초과 + // Two Pointer 활용 + while (left < right) { + const leftPillar = height[left]; + const rightPillar = height[right]; + + // "면적"은 둘의 높이 중 적은 쪽과, 인덱스 차이를 곱한 값 + const area = (right - left) * Math.min(leftPillar, rightPillar); + + result = Math.max(result, area); + + // 투 포인터 이동 기준 - 무엇을 버리고, 무엇을 남길까? + // 둘 중 높이가 더 낮은 쪽을 버리는 것이 더 많은 면적을 만들기 위한 합리적 선택 + if (leftPillar > rightPillar) { + right--; + } else { + left++; + } + } + + return result; +}; diff --git a/design-add-and-search-words-data-structure/radiantchoi.swift b/design-add-and-search-words-data-structure/radiantchoi.swift new file mode 100644 index 000000000..da9cfd451 --- /dev/null +++ b/design-add-and-search-words-data-structure/radiantchoi.swift @@ -0,0 +1,86 @@ +// 단어 검색을 위한 자료구조: Trie +class WordDictionary { + // 루트 노드 + let root: TrieNode + + init() { + root = TrieNode() + } + + func addWord(_ word: String) { + // Array({String}) initializer의 반환 타입은 [Character] + let spread = Array(word) + var node = root + + // 한 글자씩 순회하며 자식 노드 추가 혹은 방문 + for letter in spread { + if let child = node.children[letter] { + node = child + } else { + let newNode = TrieNode() + node.children[letter] = newNode + node = newNode + } + } + + // 추가하고자 하는 단어의 마지막 글자에 해당하는 노드까지 순회했으므로, 해당 노드를 종료 노드로 설정 + node.isTerminating = true + } + + func search(_ word: String) -> Bool { + return traverse(root, Array(word), 0) + } + + private func traverse(_ node: TrieNode, _ quote: [Character], _ starting: Int) -> Bool { + // Trie의 0번째 인덱스는 아무 글자도 나타내지 않으므로, 첫 번째 글자가 곧 깊이 1의 노드에 저장 + // 따라서 starting이 quote.count와 같다면, 모든 글자를 체크한 것이므로 종료 노드인지 확인할 수 있음 + // quote.count까지 incrementing하고 바로 체크하므로, 이 이상 숫자가 커질 수 없음 + if starting == quote.count { + return node.isTerminating + } + + let letter = quote[starting] + + // 현재 글자가 와일드카드 문자인지 아닌지 체크하고, DFS 방식의 순회 + if letter == "." { + var result = false + + // 와일드카드 문자라면 모든 자식 노드를 순회하여 결과 반환 + for key in node.children.keys { + if let child = node.children[key] { + result = result || traverse(child, quote, starting + 1) + } + } + + return result + } else { + // 와일드카드 문자가 아니라면, 일단 자식 노드에 포함되어있는지 확인 + guard let child = node.children[letter] else { + return false + } + + // 포함되어있다면, 다음 글자를 순회하여 결과 반환 + return traverse(child, quote, starting + 1) + } + } +} + +// 각각의 트라이 노드 +class TrieNode { + // 현재 글자에서 끝나는 단어가 있는가? + var isTerminating: Bool + // 자식 노드 - Character 형태로 다음 글자를 저장하므로, 노드에는 별도로 글자를 저장하지 않는다 + var children: [Character: TrieNode] + + init(isTerminating: Bool = false, children: [Character: TrieNode] = [:]) { + self.isTerminating = isTerminating + self.children = children + } +} + +/** + * Your WordDictionary object will be instantiated and called as such: + * let obj = WordDictionary() + * obj.addWord(word) + * let ret_2: Bool = obj.search(word) + */ diff --git a/spiral-matrix/radiantchoi.ts b/spiral-matrix/radiantchoi.ts new file mode 100644 index 000000000..6615da27b --- /dev/null +++ b/spiral-matrix/radiantchoi.ts @@ -0,0 +1,40 @@ +function spiralOrder(matrix: number[][]): number[] { + let x = 0; + let y = 0; + + let result: number[] = []; + const threshold = matrix.length * matrix[0].length + + let direction = 0; + const dx = [0, 1, 0, -1]; + const dy = [1, 0, -1, 0]; + let visited = Array.from({ length: matrix.length }, () => Array(matrix[0].length).fill(false)) + + while (true) { + if (result.length >= threshold) { + break; + } + + result.push(matrix[x][y]); + visited[x][y] = true + + const nx = x + dx[direction] + const ny = y + dy[direction] + + if (nx < 0 || nx >= matrix.length || ny < 0 || ny >= matrix[0].length || visited[nx][ny]) { + direction++; + + if (direction > 3) { + direction = 0; + } + + x += dx[direction]; + y += dy[direction]; + } else { + x = nx; + y = ny; + } + } + + return result; +}; diff --git a/valid-parentheses/radiantchoi.ts b/valid-parentheses/radiantchoi.ts new file mode 100644 index 000000000..8f9199ad7 --- /dev/null +++ b/valid-parentheses/radiantchoi.ts @@ -0,0 +1,25 @@ +function isValid(s: string): boolean { + let stack: string[] = []; + + // 스택에 대응하는 문자가 있다면 제거, 없다면 현재 문자를 추가 + for (const letter of s) { + if (stack.length > 0) { + const top = stack[stack.length - 1]; + + if (top === "(" && letter === ")") { + stack.pop(); + } else if (top === "{" && letter === "}") { + stack.pop(); + } else if (top === "[" && letter === "]") { + stack.pop(); + } else { + stack.push(letter); + } + } else { + stack.push(letter); + } + } + + // 스택에 내용물이 있는지 없는지만으로도 "Valid"한지 판별 가능 + return stack.length === 0; +};