diff --git a/container-with-most-water/JANGSEYEONG.js b/container-with-most-water/JANGSEYEONG.js new file mode 100644 index 000000000..479ec2064 --- /dev/null +++ b/container-with-most-water/JANGSEYEONG.js @@ -0,0 +1,49 @@ +/** 첫번째 풀이: 재귀 + * 시간복잡도: O(2^n) + */ +/** + * +var maxArea = function(height) { + let maxWater = (height.length - 1) * Math.min(height[0], height[height.length-1]); + function recursion(start, end){ + if(start >= end){ + // start와 end가 같거나 start가 end보다 커진 경우 + return; + } + maxWater = Math.max(maxWater, (end-start)*(Math.min(height[start], height[end]))); + recursion(start+1, end); // 왼쪽 늘려보고 + recursion(start, end-1); // 우측 늘려보기 + } + recursion(0, height.length-1); + return maxWater; +}; + +/** + * 두번째 풀이: 투포인터 + * 시간 복잡도: O(n) + */ +/** + * @param {number[]} height + * @return {number} + */ +var maxArea = function (height) { + let left = 0; + let right = height.length - 1; + let maxWater = 0; + + while (left < right) { + // 현재 포인터 위치에서 물의 양 계산 + const water = (right - left) * Math.min(height[left], height[right]); + maxWater = Math.max(maxWater, water); + + // 더 작은 높이를 가진 쪽의 포인터를 이동 + // 물의 양은 더 작은 높이에 의해 제한되기 때문에 작은 높이를 가리키던 포인터를 이동 + if (height[left] < height[right]) { + left++; + } else { + right--; + } + } + + return maxWater; +}; diff --git a/design-add-and-search-words-data-structure/JANGSEYEONG.js b/design-add-and-search-words-data-structure/JANGSEYEONG.js new file mode 100644 index 000000000..c5b99bcea --- /dev/null +++ b/design-add-and-search-words-data-structure/JANGSEYEONG.js @@ -0,0 +1,54 @@ +var WordDictionary = function () { + this.root = {}; +}; + +/** + * @param {string} word + * @return {void} + */ +WordDictionary.prototype.addWord = function (word) { + let node = this.root; + for (const char of word) { + if (!node[char]) { + // 현재 문자에 해당하는 노드가 없으면 새로 생성 + node[char] = { isEnd: false }; + } + node = node[char]; // 다음 노드로 이동 + } + node.isEnd = true; // 단어 끝 표시 +}; + +/** + * @param {string} word + * @return {boolean} + */ +WordDictionary.prototype.search = function (word) { + function dfs(node, index) { + // 단어의 끝에 도달했으면 isEnd 값 반환 + if (index === word.length) return node.isEnd; + + const char = word[index]; + + if (node[char]) { + // 현재 문자가 노드에 존재하면 해당 노드로 이동하여 계속 검색 + return dfs(node[char], index + 1); + } + + if (char === ".") { + // "."인 경우: 모든 가능한 문자에 대해 검색 시도 + return Object.keys(node) + .filter((key) => key !== "isEnd") + .some((key) => dfs(node[key], index + 1)); // 하나라도 true를 반환하면 true + } + + return false; + } + return dfs(this.root, 0); +}; + +/** + * 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/JANGSEYEONG.js b/longest-increasing-subsequence/JANGSEYEONG.js new file mode 100644 index 000000000..2812446e2 --- /dev/null +++ b/longest-increasing-subsequence/JANGSEYEONG.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var lengthOfLIS = function (nums) { + let sub = [nums[0]]; // 가장 첫번째 원소 일단 넣고 보기 + for (const num of nums.slice(1)) { + if (num > sub[sub.length - 1]) { + // 수열의 마지막값보다 크면 무조건 추가 + sub.push(num); + } else { + // 수열의 마지막값보다 작다면 이 숫자보다 큰 숫자들 중 가장 작은 숫자를 찾아서 교체 + let i = 0; + while (sub[i] < num) { + i++; + } + sub[i] = num; + } + } + return sub.length; +}; diff --git a/spiral-matrix/JANGSEYEONG.js b/spiral-matrix/JANGSEYEONG.js new file mode 100644 index 000000000..d7625727f --- /dev/null +++ b/spiral-matrix/JANGSEYEONG.js @@ -0,0 +1,48 @@ +/** + * @param {number[][]} matrix + * @return {number[]} + */ +var spiralOrder = function (matrix) { + let top = 0; // 상단 행 인덱스 + let bottom = matrix.length - 1; // 하단 행 인덱스 + let left = 0; // 좌측 열 인덱스 + let right = matrix[0].length - 1; // 우측 열 인덱스 + + const answer = []; + + // 상단, 우측, 하단, 좌측 경계를 차례로 순회하며 값을 수집 + // 각 반복마다 경계가 안쪽으로 줄어듦 + while (top <= bottom && left <= right) { + // 1. 상단 행 순회 + for (let col = left; col <= right; col++) { + answer.push(matrix[top][col]); + } + top++; // 상단 경계를 아래로 한칸 이동 + // 상단 경계가 하단 경계를 넘어가면 중단 + if (top > bottom) { + break; + } + // 2. 우측 열 순회 + for (let row = top; row <= bottom; row++) { + answer.push(matrix[row][right]); + } + right--; // 우측 경계를 왼쪽으로 한칸 이동 + // 우측 경계가 좌측 경계를 넘어가면 중단 + if (left > right) { + break; + } + // 3. 하단 행 순회 + for (let col = right; col >= left; col--) { + answer.push(matrix[bottom][col]); + } + bottom--; // 하단 경계를 위쪽으로 한칸 이동 + + // 4. 좌측 열 순회 + for (let row = bottom; row >= top; row--) { + answer.push(matrix[row][left]); + } + left++; // 좌측 경계를 우측으로 한칸 이동 + } + + return answer; +}; diff --git a/valid-parentheses/JANGSEYEONG.js b/valid-parentheses/JANGSEYEONG.js new file mode 100644 index 000000000..da3472c35 --- /dev/null +++ b/valid-parentheses/JANGSEYEONG.js @@ -0,0 +1,24 @@ +/** + * 시간복잡도: O(n) - 문자열의 각 문자를 한 번씩만 순회 + * 공간복잡도: O(n) - 최악의 경우 모든 문자가 여는 괄호일 때 스택에 n개 저장 + * @param {string} s + * @return {boolean} + */ +var isValid = function (s) { + const length = s.length; + if (length % 2 === 1) return false; // 홀수일 경우 바로 return false + + const MATCHES = { "(": ")", "{": "}", "[": "]" }; + + // 여는 괄호가 나오면 스택에 저장, 닫는 괄호가 나오면 스택의 마지막 여는 괄호와 비교 + const stack = []; + for (let char of s) { + if (char in MATCHES) { + stack.push(char); + } else if (MATCHES[stack.pop()] !== char) { + return false; + } + } + // 짝이 맞으면 size 0 + return stack.length === 0; +};