diff --git a/container-with-most-water/wogha95.js b/container-with-most-water/wogha95.js new file mode 100644 index 000000000..86e6672bf --- /dev/null +++ b/container-with-most-water/wogha95.js @@ -0,0 +1,33 @@ +/** + * TC: O(H) + * SC: O(1) + * H: height.length + */ + +/** + * @param {number[]} height + * @return {number} + */ +var maxArea = function (height) { + let maximumWater = 0; + let left = 0; + let right = height.length - 1; + + // 1. 투포인터를 이용하여 양끝에서 모입니다. + while (left < right) { + // 2. 최대 너비값을 갱신해주고 + const h = Math.min(height[left], height[right]); + const w = right - left; + + maximumWater = Math.max(maximumWater, w * h); + + // 3. 왼쪽과 오른쪽 높이 중 더 낮은 쪽의 pointer를 옮깁니다. + if (height[left] < height[right]) { + left += 1; + } else { + right -= 1; + } + } + + return maximumWater; +}; diff --git a/design-add-and-search-words-data-structure/wogha95.js b/design-add-and-search-words-data-structure/wogha95.js new file mode 100644 index 000000000..3023320cd --- /dev/null +++ b/design-add-and-search-words-data-structure/wogha95.js @@ -0,0 +1,83 @@ +function Node() { + // 단어의 끝을 의미 + 무슨 단어인지 저장 + this.value = null; + // 단어의 다음 문자로 연결되어 있는 노드맵 + this.wordGraph = new Map(); +} + +var WordDictionary = function () { + this.wordGraph = new Map(); +}; + +/** + * TC: O(N) + * SC: O(N) + */ + +/** + * @param {string} word + * @return {void} + */ +WordDictionary.prototype.addWord = 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(D^W) + * SC: O(D * W) + * + * W: word.length, D: count of Dictionary.wordGraph keys + * + * 풀이: Trie 자료구조 + bfs탐색 + */ + +/** + * @param {string} word + * @return {boolean} + */ +WordDictionary.prototype.search = function (word) { + const queue = [{ pointer: this, index: 0 }]; + + // 1. BFS 탐색 방법 이용 + while (queue.length > 0) { + const { pointer, index } = queue.shift(); + + // 2. 찾고자하는 단어의 끝에 도달했으면 해당 단어가 있는지 확인한다. + if (index === word.length) { + if (pointer.value !== null) { + return true; + } + continue; + } + + if (word[index] === ".") { + // 3. 찾고자하는 단어의 문자가 '.'인 경우, 현재 graph에서 이어진 문자를 모두 탐색(queue에 추가) + for (const [key, node] of pointer.wordGraph) { + queue.push({ pointer: node, index: index + 1 }); + } + } else if (pointer.wordGraph.has(word[index])) { + // 4. 찾고자하는 단어의 문자가 graph에 있는 경우 탐색(queue에 추가) + queue.push({ + pointer: pointer.wordGraph.get(word[index]), + index: index + 1, + }); + } + } + + // 5. 더이상 탐색할 것이 없다면 해당 단어 없음으로 판단 + return false; +}; + +/** + * Your WordDictionary object will be instantiated and called as such: + * var obj = new WordDictionary() + * obj.addWord(word) + * var param_2 = obj.search(word) + */ diff --git a/longest-increasing-subsequence/wogha95.js b/longest-increasing-subsequence/wogha95.js new file mode 100644 index 000000000..18d1c0103 --- /dev/null +++ b/longest-increasing-subsequence/wogha95.js @@ -0,0 +1,30 @@ +/** + * TC: O(N^2) + * SC: O(N) + * N: nums.length + */ + +/** + * @param {number[]} nums + * @return {number} + */ +var lengthOfLIS = function (nums) { + // 각자 스스로는 최소 1의 lengthOfLIS를 가짐 + const longestLength = new Array(nums.length).fill(1); + let result = 1; + + // nums배열의 right까지 원소들 중 lengthOfLIS를 저장 + for (let right = 1; right < nums.length; right++) { + for (let left = 0; left < right; left++) { + if (nums[left] < nums[right]) { + longestLength[right] = Math.max( + longestLength[right], + longestLength[left] + 1 + ); + result = Math.max(result, longestLength[right]); + } + } + } + + return result; +}; diff --git a/spiral-matrix/wogha95.js b/spiral-matrix/wogha95.js new file mode 100644 index 000000000..487260c76 --- /dev/null +++ b/spiral-matrix/wogha95.js @@ -0,0 +1,140 @@ +/** + * 2차 풀이: 기존 matrix 변경 없도록 개선 + * + * TC: O(ROW * COLUMN) + * matrix 전체 순회 1회 + * + * SC: O(ROW * COLUMN) + * 정답 제출을 위한 result 공간복잡도 + */ + +/** + * @param {number[][]} matrix + * @return {number[]} + */ +var spiralOrder = function (matrix) { + const ROW = matrix.length; + const COLUMN = matrix[0].length; + // 1. 상하좌우 시작끝 index를 저장함 + const boundary = { + top: 0, + bottom: ROW - 1, + left: 0, + right: COLUMN - 1, + }; + const result = []; + + while (result.length < ROW * COLUMN) { + // 2. 오른쪽으로 순회 + for (let column = boundary.left; column <= boundary.right; column++) { + result.push(matrix[boundary.top][column]); + } + boundary.top += 1; + + // 3. 아래로 순회 + for (let row = boundary.top; row <= boundary.bottom; row++) { + result.push(matrix[row][boundary.right]); + } + boundary.right -= 1; + + // 4. 모두 순회했는데 왔던길 되돌아가는 경우를 막기위해 중간 조건문 추가 + if (result.length === ROW * COLUMN) { + break; + } + + // 5. 왼쪽으로 순회 + for (let column = boundary.right; column >= boundary.left; column--) { + result.push(matrix[boundary.bottom][column]); + } + boundary.bottom -= 1; + + // 6. 위쪽으로 순회 + for (let row = boundary.bottom; row >= boundary.top; row--) { + result.push(matrix[row][boundary.left]); + } + boundary.left += 1; + } + + return result; +}; + +/** + * 1차 풀이 + * + * TC: O(ROW * COLUMN) + * matrix 전체 순회 1회 + * + * SC: O(ROW * COLUMN) + * 정답 제출을 위한 result 공간복잡도 + */ + +/** + * @param {number[][]} matrix + * @return {number[]} + */ +var spiralOrder = function (matrix) { + const ROW = matrix.length; + const COLUMN = matrix[0].length; + // 우하좌상 순서 + const DIRECTION = [ + { + row: 0, + column: 1, + }, + { + row: 1, + column: 0, + }, + { + row: 0, + column: -1, + }, + { + row: -1, + column: 0, + }, + ]; + + // 1. 첫 시작점 방문표시 + const result = [matrix[0][0]]; + matrix[0][0] = "#"; + + let current = { + row: 0, + column: 0, + }; + let directionIndex = 0; + + // 2. 총 갯수만큼 채워질때까지 순회 + while (result.length < ROW * COLUMN) { + const next = { + row: current.row + DIRECTION[directionIndex].row, + column: current.column + DIRECTION[directionIndex].column, + }; + // 3. 다음 순회할 곳이 유효한 좌표인지 방문한 곳인지 확인 + if ( + !isValidPosition(next.row, next.column) || + matrix[next.row][next.column] === "#" + ) { + // 4. 방향 전환 + directionIndex = (directionIndex + 1) % 4; + } else { + // 5. 방문 표시 후 다음 좌표로 이동 + result.push(matrix[next.row][next.column]); + matrix[next.row][next.column] = "#"; + current = next; + } + } + + return result; + + function isValidPosition(row, column) { + if (row < 0 || ROW <= row) { + return false; + } + if (column < 0 || COLUMN <= column) { + return false; + } + return true; + } +}; diff --git a/valid-parentheses/wogha95.js b/valid-parentheses/wogha95.js new file mode 100644 index 000000000..75a677dd2 --- /dev/null +++ b/valid-parentheses/wogha95.js @@ -0,0 +1,44 @@ +/** + * TC: O(S) + * s 매개변수의 길이만큼 순회 1번 + * + * SC: O(S) + * 최악의 경우 S의 길이만큼 stack 배열에 모두 push 할 수 있기 때문에 + * + * S: s.length + */ + +/** + * @param {string} s + * @return {boolean} + */ +var isValid = function (s) { + const map = { + "(": ")", + "{": "}", + "[": "]", + }; + const stack = []; + + // 1. s의 길이만큼 순회를 하면서 + for (const char of s) { + // 2. 열린 괄호라면 stack에 짝지어진 닫힌 괄호를 저장 + // 3. 닫힌 괄호라면 stack에서 꺼낸 것과 동일한지 확인 + switch (char) { + case "(": + case "{": + case "[": + stack.push(map[char]); + break; + case "}": + case ")": + case "]": + if (stack.pop() !== char) { + return false; + } + } + } + + // 4. 남은 괄호가 없는지 확인 + return stack.length === 0; +};