diff --git a/citrussoda/10week/139_word-break.js b/citrussoda/10week/139_word-break.js new file mode 100644 index 0000000..d9ed302 --- /dev/null +++ b/citrussoda/10week/139_word-break.js @@ -0,0 +1,23 @@ +/** + * @param {string} s + * @param {string[]} wordDict + * @return {boolean} + */ +var wordBreak = function (s, wordDict) { + const dp = new Array(s.length + 1).fill(false); + dp[0] = true; + + for (let i = 1; i <= s.length; i++) { + for (let word of wordDict) { + if (i >= word.length && dp[i - word.length]) { + const sub = s.slice(i - word.length, i); + if (sub === word) { + dp[i] = true; + break; + } + } + } + } + + return dp[s.length]; +}; diff --git a/citrussoda/10week/1584_min-cost-to-connect-all-points.js b/citrussoda/10week/1584_min-cost-to-connect-all-points.js new file mode 100644 index 0000000..2bce5d8 --- /dev/null +++ b/citrussoda/10week/1584_min-cost-to-connect-all-points.js @@ -0,0 +1,45 @@ +/** + * @param {number[][]} points + * @return {number} + */ +// Prim's Algorithm +var minCostConnectPoints = function (points) { + const n = points.length; + + // 방문 여부를 체크하는 배열 + const visited = new Set(); + + // 각 점까지의 최소 거리를 저장하는 배열 + const distances = new Array(n).fill(Infinity); + distances[0] = 0; + + let totalCost = 0; + + for (let i = 0; i < n; i++) { + let minDist = Infinity; + let minIndex = -1; + + // 아직 방문하지 않은 점들 중에서 최소 거리를 가진 점을 찾음 + for (let j = 0; j < n; j++) { + if (!visited.has(j) && distances[j] < minDist) { + minDist = distances[j]; + minIndex = j; + } + } + + visited.add(minIndex); + totalCost += minDist; + + // 선택된 점에서 다른 모든 점까지의 거리를 업데이트 + for (let j = 0; j < n; j++) { + if (!visited.has(j)) { + const distance = + Math.abs(points[minIndex][0] - points[j][0]) + + Math.abs(points[minIndex][1] - points[j][1]); + distances[j] = Math.min(distances[j], distance); + } + } + } + + return totalCost; +}; diff --git a/citrussoda/10week/215_kth-largest-element-in-an-array.js b/citrussoda/10week/215_kth-largest-element-in-an-array.js new file mode 100644 index 0000000..44aaeae --- /dev/null +++ b/citrussoda/10week/215_kth-largest-element-in-an-array.js @@ -0,0 +1,10 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var findKthLargest = function (nums, k) { + nums.sort((a, b) => b - a); + + return nums[k - 1]; +}; diff --git a/citrussoda/10week/235_lowest-common-ancestor-of-a-binary-search-tree.js b/citrussoda/10week/235_lowest-common-ancestor-of-a-binary-search-tree.js new file mode 100644 index 0000000..b7a8977 --- /dev/null +++ b/citrussoda/10week/235_lowest-common-ancestor-of-a-binary-search-tree.js @@ -0,0 +1,29 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ + +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +var lowestCommonAncestor = function (root, p, q) { + if (root.val > p.val && root.val < q.val) { + return root; + } + + if (root.val > p.val && root.val > q.val) { + return lowestCommonAncestor(root.left, p, q); + } + + if (root.val < p.val && root.val < q.val) { + return lowestCommonAncestor(root.right, p, q); + } + + return root; +}; diff --git a/citrussoda/10week/56_merge-intervals.js b/citrussoda/10week/56_merge-intervals.js new file mode 100644 index 0000000..b64bac4 --- /dev/null +++ b/citrussoda/10week/56_merge-intervals.js @@ -0,0 +1,24 @@ +/** + * @param {number[][]} intervals + * @return {number[][]} + */ +var merge = function (intervals) { + intervals.sort((a, b) => a[0] - b[0]); + + const ans = []; + let prev = intervals[0]; + + for (let i = 1; i < intervals.length; i++) { + let interval = intervals[i]; + + if (interval[0] <= prev[1]) { + prev[1] = Math.max(prev[1], interval[1]); + } else { + ans.push(prev); + prev = interval; + } + } + + ans.push(prev); + return ans; +}; diff --git a/citrussoda/1week/121.js b/citrussoda/1week/121.js new file mode 100644 index 0000000..6d833dd --- /dev/null +++ b/citrussoda/1week/121.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function (prices) { + let maxCurrent = 0; + let maxSoFar = 0; + + for (let i = 1; i < prices.length; i++) { + maxCurrent = Math.max(0, maxCurrent + prices[i] - prices[i - 1]); + maxSoFar = Math.max(maxSoFar, maxCurrent); + } + + return maxSoFar; +}; diff --git a/citrussoda/1week/15.js b/citrussoda/1week/15.js new file mode 100644 index 0000000..73f397c --- /dev/null +++ b/citrussoda/1week/15.js @@ -0,0 +1,42 @@ +/** + * @param {number[]} nums + * @return {number[][]} + */ +var threeSum = function (nums) { + let answer = []; + + nums.sort((a, b) => a - b); + + for (let i = 0; i < nums.length - 2; i++) { + if (nums[i] === nums[i - 1]) continue; + + let target = nums[i]; + let startIndex = i + 1; + let lastIndex = nums.length - 1; + + while (startIndex < lastIndex) { + let sum = target + nums[startIndex] + nums[lastIndex]; + if (sum > 0) { + lastIndex -= 1; + } else if (sum < 0) { + startIndex += 1; + } else { + answer.push([target, nums[startIndex], nums[lastIndex]]); + while ( + startIndex < lastIndex && + nums[startIndex] === nums[startIndex + 1] + ) + startIndex += 1; + while ( + startIndex < lastIndex && + nums[lastIndex] === nums[lastIndex - 1] + ) + lastIndex -= 1; + startIndex += 1; + lastIndex -= 1; + } + } + } + + return answer; +}; diff --git a/citrussoda/1week/217.js b/citrussoda/1week/217.js new file mode 100644 index 0000000..501ee29 --- /dev/null +++ b/citrussoda/1week/217.js @@ -0,0 +1,9 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +var containsDuplicate = function (nums) { + const setNums = new Set(nums); + + return setNums.size !== nums.length; +}; diff --git a/citrussoda/1week/268.js b/citrussoda/1week/268.js new file mode 100644 index 0000000..ae890d8 --- /dev/null +++ b/citrussoda/1week/268.js @@ -0,0 +1,11 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var missingNumber = function (nums) { + nums.sort((a, b) => a - b); + + for (let i = 0; i <= nums.length; i++) { + if (nums[i] !== i) return i; + } +}; diff --git a/citrussoda/1week/meetingSchedule.js b/citrussoda/1week/meetingSchedule.js new file mode 100644 index 0000000..7016d3c --- /dev/null +++ b/citrussoda/1week/meetingSchedule.js @@ -0,0 +1,27 @@ +/** + * Definition of Interval: + * class Interval { + * constructor(start, end) { + * this.start = start; + * this.end = end; + * } + * } + */ + +class Solution { + /** + * @param {Interval[]} intervals + * @returns {boolean} + */ + canAttendMeetings(intervals) { + intervals.sort((a, b) => a.start - b.start); + + for (let i = 1; i < intervals.length; i++) { + if (intervals[i - 1].end > intervals[i].start) { + return false; + } + } + + return true; + } +} diff --git a/citrussoda/2week/100_same-tree.js b/citrussoda/2week/100_same-tree.js new file mode 100644 index 0000000..a429bab --- /dev/null +++ b/citrussoda/2week/100_same-tree.js @@ -0,0 +1,48 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} p + * @param {TreeNode} q + * @return {boolean} + */ +var isSameTree = function (p, q) { + let firstTree = []; + let secondTree = []; + + iter(p, firstTree); + iter(q, secondTree); + + if (firstTree.length !== secondTree.length) return false; + + for (let i = 0; i < firstTree.length - 1; i++) { + if (firstTree[i] !== secondTree[i]) return false; + } + + return true; +}; + +const iter = (target, tree) => { + if (!target) return tree; + + tree.push(target.val); + + if (target.left) { + iter(target.left, tree); + } else if (target.left === null) { + tree.push(null); + } + + if (target.right) { + iter(target.right, tree); + } else if (target.right === null) { + tree.push(null); + } + + return tree; +}; diff --git a/citrussoda/2week/191_number-of-1-bits.js b/citrussoda/2week/191_number-of-1-bits.js new file mode 100644 index 0000000..e9b2067 --- /dev/null +++ b/citrussoda/2week/191_number-of-1-bits.js @@ -0,0 +1,19 @@ +/** + * @param {number} n + * @return {number} + */ +var hammingWeight = function (n) { + return findBit(n, 0); +}; + +const findBit = (n, count) => { + if (n < 1) return count; + + let i = 1; + while (i <= n / 2) { + i *= 2; + } + count++; + + return findBit(n - i, count); +}; diff --git a/citrussoda/2week/238_product-of-array-except-self.js b/citrussoda/2week/238_product-of-array-except-self.js new file mode 100644 index 0000000..4facd13 --- /dev/null +++ b/citrussoda/2week/238_product-of-array-except-self.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var productExceptSelf = function (nums) { + let answer = Array.from({ length: nums.length }).fill(1); + + let left = 1; + + for (let i = 0; i < nums.length; i++) { + answer[i] *= left; + left *= nums[i]; + } + + let right = 1; + + for (let i = nums.length - 1; i >= 0; i--) { + answer[i] *= right; + right *= nums[i]; + } + + return answer; +}; diff --git a/citrussoda/2week/242_valid-anagram.js b/citrussoda/2week/242_valid-anagram.js new file mode 100644 index 0000000..3ccb581 --- /dev/null +++ b/citrussoda/2week/242_valid-anagram.js @@ -0,0 +1,22 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +var isAnagram = function (s, t) { + if (s.length !== t.length) return false; + + let firstStr = {}; + [...s].forEach((char) => (firstStr[char] = (firstStr[char] || 0) + 1)); + + let secondStr = {}; + [...t].forEach((char) => (secondStr[char] = (secondStr[char] || 0) + 1)); + + for (let char in firstStr) { + if (firstStr[char] !== secondStr[char]) { + return false; + } + } + + return true; +}; diff --git a/citrussoda/2week/746_min-cost-climbing-stairs.js b/citrussoda/2week/746_min-cost-climbing-stairs.js new file mode 100644 index 0000000..add52f2 --- /dev/null +++ b/citrussoda/2week/746_min-cost-climbing-stairs.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} cost + * @return {number} + */ +var minCostClimbingStairs = function (cost) { + let dp = Array.from({ length: cost.length + 1 }, () => 0); + + for (let i = 2; i <= cost.length; i++) { + dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); + } + + console.log(dp); + + return dp[dp.length - 1]; +}; diff --git a/citrussoda/3week/125_valid-palindrome.js b/citrussoda/3week/125_valid-palindrome.js new file mode 100644 index 0000000..58f8359 --- /dev/null +++ b/citrussoda/3week/125_valid-palindrome.js @@ -0,0 +1,28 @@ +/** + * @param {string} s + * @return {boolean} + */ +var isPalindrome = function (s) { + let targetStr = ''; + let str = [...s.trim().toLowerCase()].forEach((char) => { + if ( + (char.charCodeAt(0) <= 'z'.charCodeAt(0) && + char.charCodeAt(0) >= 'a'.charCodeAt(0)) || + (parseInt(char, 10) >= 0 && parseInt(char, 10) <= 9) + ) + targetStr += char; + }); + + let left = 0; + let right = targetStr.length - 1; + + while (left < right) { + if (targetStr[left] !== targetStr[right]) { + return false; + } + left++; + right--; + } + + return true; +}; diff --git a/citrussoda/3week/190_reverse-bits.js b/citrussoda/3week/190_reverse-bits.js new file mode 100644 index 0000000..cc9752f --- /dev/null +++ b/citrussoda/3week/190_reverse-bits.js @@ -0,0 +1,37 @@ +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +// var reverseBits = function (n) { +// let stringNumber = n.toString(2).padStart(32, '0'); +// let target = 1; +// let answer = 0; + +// for (let i = 0; i < stringNumber.length; i++) { +// console.log(stringNumber[i]); +// if (+stringNumber[i] === 1) answer += target; +// target *= 2; +// } + +// return answer; +// }; + +// 최적화 +// result는 맨 오른쪽이 1인지 아닌지 판단하고 계속 왼쪽으로 이동 +// n은 한 번 비교하면 오른쪽으로 1비트씩 이동시키돼 >>>를 이용하여 0으로 채워줌. +// 맨 마지막 result를 >>> 0을 이용하여 0으로 채워줄 수 있음 + +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +var reverseBits = function (n) { + let result = 0; + + for (let i = 0; i < 32; i++) { + result = (result << 1) | (n & 1); + n = n >>> 1; + } + + return result >>> 0; +}; diff --git a/citrussoda/3week/206_reverse-linked-list.js b/citrussoda/3week/206_reverse-linked-list.js new file mode 100644 index 0000000..d6fdbeb --- /dev/null +++ b/citrussoda/3week/206_reverse-linked-list.js @@ -0,0 +1,23 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +var reverseList = function (head) { + let node = null; + + while (head) { + const temp = head.next; + head.next = node; + node = head; + head = temp; + } + + return node; +}; diff --git a/citrussoda/3week/322_coin-change.js b/citrussoda/3week/322_coin-change.js new file mode 100644 index 0000000..313e242 --- /dev/null +++ b/citrussoda/3week/322_coin-change.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} coins + * @param {number} amount + * @return {number} + */ +var coinChange = function (coins, amount) { + // DP 배열 초기화: amount + 1로 채움 (불가능한 값으로 초기화) + let dp = new Array(amount + 1).fill(amount + 1); + + // 기본 케이스: 0원을 만드는 데 필요한 동전 개수는 0 + dp[0] = 0; + + // 각 금액에 대해 최소 동전 개수 계산 + for (let i = 1; i <= amount; i++) { + for (let coin of coins) { + if (coin <= i) { + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + + // 최종 결과 반환: amount를 만들 수 없으면 -1 반환 + return dp[amount] > amount ? -1 : dp[amount]; +}; diff --git a/citrussoda/3week/49_group-anagrams.js b/citrussoda/3week/49_group-anagrams.js new file mode 100644 index 0000000..5264774 --- /dev/null +++ b/citrussoda/3week/49_group-anagrams.js @@ -0,0 +1,71 @@ +/** + * @param {string[]} strs + * @return {string[][]} + */ +var groupAnagrams = function (strs) { + let answer = {}; + + for (let str of strs) { + let key = str.split('').sort().join(''); + if (!answer[key]) { + answer[key] = []; + } + answer[key].push(str); + } + + return Object.values(answer); +}; + +// 원래 하려던 접근 : +// 1. 각 알파벳이 들어있는 객체를 만들어서 +// 2. 객체 비교는 strinfigy로 같은 걸 체크해서 +// 3. 출력하면 되지 않을까? +// 결과 => 시간초과... + +// /** +// * @param {string[]} strs +// * @return {string[][]} +// */ +// var groupAnagrams = function(strs) { +// let strsAlpha = [] +// let flagArr = Array.from({ length: strs.length }, () => 0) + +// for(let i = 0; i < strs.length; i++) { +// let obj = {} +// let sortedObj = {} + +// strs[i].split("").forEach((char) => { +// obj[char] = (obj[char] || 0) + 1 +// }) + +// Object.keys(obj).sort().forEach((char) => { +// sortedObj[char] = obj[char] +// }) + +// strsAlpha.push(sortedObj) +// } + +// let flag = 1 + +// for(let i = 0; i < strsAlpha.length; i++) { +// if (flagArr[i] === 0) { +// flagArr[i] = flag +// for(let j = i + 1; j < strsAlpha.length; j++) { +// if (JSON.stringify(strsAlpha[i]) === JSON.stringify(strsAlpha[j])) { +// flagArr[j] = flag +// } +// } +// flag++ +// } +// } + +// let result = {} +// for(let i = 0; i < flagArr.length; i++) { +// if (!result[flagArr[i]]) { +// result[flagArr[i]] = [] +// } +// result[flagArr[i]].push(strs[i]) +// } + +// return Object.values(result) +// }; diff --git a/citrussoda/4week/104_maximum-depth-of-binary-tree.js b/citrussoda/4week/104_maximum-depth-of-binary-tree.js new file mode 100644 index 0000000..b3b9dd1 --- /dev/null +++ b/citrussoda/4week/104_maximum-depth-of-binary-tree.js @@ -0,0 +1,26 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +var maxDepth = function (root) { + if (root === null) return 0; + + return dig(root); +}; + +function dig(node) { + if (node === null) return 0; + + let leftDepth = dig(node.left); + let rightDepth = dig(node.right); + + return Math.max(leftDepth, rightDepth) + 1; +} diff --git a/citrussoda/4week/141_linked-list-cycle.js b/citrussoda/4week/141_linked-list-cycle.js new file mode 100644 index 0000000..9e30726 --- /dev/null +++ b/citrussoda/4week/141_linked-list-cycle.js @@ -0,0 +1,27 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ + +/** + * @param {ListNode} head + * @return {boolean} + */ +var hasCycle = function (head) { + if (head === null) return false; + + let slow = head; + let fast = head; + + while (fast.next && fast.next.next) { + slow = slow.next; + fast = fast.next.next; + + if (fast === slow) return true; + } + + return false; +}; diff --git a/citrussoda/4week/1_two-sum.js b/citrussoda/4week/1_two-sum.js new file mode 100644 index 0000000..9203866 --- /dev/null +++ b/citrussoda/4week/1_two-sum.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +var twoSum = function (nums, target) { + let hash = new Map(); + + for (let i = 0; i < nums.length; i++) { + if (hash.has(nums[i])) return [hash.get(nums[i]), i]; + + hash.set(target - nums[i], i); + } +}; diff --git a/citrussoda/4week/202_happy-number.js b/citrussoda/4week/202_happy-number.js new file mode 100644 index 0000000..728e4d8 --- /dev/null +++ b/citrussoda/4week/202_happy-number.js @@ -0,0 +1,22 @@ +/** + * @param {number} n + * @return {boolean} + */ +var isHappy = function (n) { + let hash = new Map(); + + while (!hash.has(n)) { + hash.set(n, 1); + + let calc = n + .toString() + .split('') + .map(Number) + .reduce((acc, i) => acc + i * i, 0); + if (calc === 1) return true; + + n = calc; + } + + return false; +}; diff --git a/citrussoda/4week/20_valid-parentheses.js b/citrussoda/4week/20_valid-parentheses.js new file mode 100644 index 0000000..b49c540 --- /dev/null +++ b/citrussoda/4week/20_valid-parentheses.js @@ -0,0 +1,23 @@ +/** + * @param {string} s + * @return {boolean} + */ +var isValid = function (s) { + let pair = { + ')': '(', + '}': '{', + ']': '[', + }; + + let stack = []; + + for (let char of s) { + if (stack.length !== 0 && stack[stack.length - 1] === pair[char]) { + stack.pop(); + } else { + stack.push(char); + } + } + + return stack.length === 0; +}; diff --git a/citrussoda/4week/cpp/104_maximum-depth-of-binary-tree.cpp b/citrussoda/4week/cpp/104_maximum-depth-of-binary-tree.cpp new file mode 100644 index 0000000..2139d66 --- /dev/null +++ b/citrussoda/4week/cpp/104_maximum-depth-of-binary-tree.cpp @@ -0,0 +1,21 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int maxDepth(TreeNode* root) { + // nullptr이 NULL보다 빠르며 NULL은 정수 0으로 인식이 되나 nullptr이 인식되지 않음. + if (root == nullptr) return 0; + + // 따로 변수를 선언하지 않고 파라미터 내부에서 직접 재귀 가능 + return max(maxDepth(root -> left) + 1, maxDepth(root -> right) + 1); + } +}; \ No newline at end of file diff --git a/citrussoda/4week/cpp/141_linked-list-cycle.cpp b/citrussoda/4week/cpp/141_linked-list-cycle.cpp new file mode 100644 index 0000000..d40ece1 --- /dev/null +++ b/citrussoda/4week/cpp/141_linked-list-cycle.cpp @@ -0,0 +1,58 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + bool hasCycle(ListNode *head) { + ListNode* fast = head; + ListNode* slow = head; + + while (fast != nullptr && fast -> next != nullptr) { + slow = slow -> next; + fast = fast -> next -> next; + + if (slow == fast) return true; + } + + return false; + } +}; + + +// 2번째 방법 + +// 다음 노드를 계속 찾아가면서 노드를 visited 됐는지 확인하며 다음으로 진행한다. +// 반복되지 않는다는 것은 언젠가는 끊긴다는 이야기이므로 while로 다음 노드가 NULL이 될 때까지 +// 찾아가 저장한다. + +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +// class Solution { +// public: +// bool hasCycle(ListNode *head) { +// unordered_set visited; +// ListNode* current_node = head; + +// while (current_node != nullptr) { +// // count가 항상 빠른 것은 아니며 큰 차이는 없음. set과 map의 차이인가? +// if (visited.count(current_node)) return true; + +// visited.insert(current_node); + +// current_node = current_node -> next; +// } + +// return false; +// } +// }; \ No newline at end of file diff --git a/citrussoda/4week/cpp/1_two-sum.cpp b/citrussoda/4week/cpp/1_two-sum.cpp new file mode 100644 index 0000000..3cf05b0 --- /dev/null +++ b/citrussoda/4week/cpp/1_two-sum.cpp @@ -0,0 +1,18 @@ +class Solution { +public: + vector twoSum(vector& nums, int target) { + unordered_map m; + + for (int i = 0; i < nums.size(); i++) { + // if (m.find(target - nums[i]) != m.end()) { + // count 가 읽기도 쉽고 더 빠르다!! <= 틀린내용 다만 큰 차이는 없음 알고리즘에 따라 다른 것 같다. 혹은 set과 map에 따라서도 다른듯. + if (m.count(target - nums[i])) { + return {m[target - nums[i]], i}; + } + + m[nums[i]] = i; + } + + return {}; + } +}; \ No newline at end of file diff --git a/citrussoda/4week/cpp/202_happy-number.cpp b/citrussoda/4week/cpp/202_happy-number.cpp new file mode 100644 index 0000000..ac3788c --- /dev/null +++ b/citrussoda/4week/cpp/202_happy-number.cpp @@ -0,0 +1,27 @@ +class Solution { +public: + int newNumber(int n) { + int newNumber = 0; + + while(n != 0) { + int num = n % 10; + newNumber += num * num; + n = n / 10; + } + + return newNumber; + } + + bool isHappy(int n) { + unordered_set s; + + while(!s.count(n)) { + s.insert(n); + cout << n << '\n'; + // split('').map or forEach가 그리웠습니다.. + n = newNumber(n); + } + + return n==1; + } +}; \ No newline at end of file diff --git a/citrussoda/4week/cpp/20_valid-parentheses.cpp b/citrussoda/4week/cpp/20_valid-parentheses.cpp new file mode 100644 index 0000000..c896a6f --- /dev/null +++ b/citrussoda/4week/cpp/20_valid-parentheses.cpp @@ -0,0 +1,50 @@ +// 벡터로 풀 수 있다면 벡터를 사용하는 것이 훨씬 빠르다. +// 메모리는 unordered_map을 if문제 직접 적는 방식으로 해결 할 수 있으나 +// stack을 이미 쓰고있어 공간복잡도는 O(n)이므로 코드를 보기 좋게 하기 위해 +// 추가하였다. + +class Solution { +public: + bool isValid(string s) { + stack st; + unordered_map um = { + {')', '('}, + {']', '['}, + {'}', '{'} + }; + + for (auto c: s) { + if (!st.empty() && um[c] == st.top()) { + st.pop(); + } + else { + st.push(c); + } + } + + return st.empty(); + } +}; + +// class Solution { +// public: +// bool isValid(string s) { +// vector v; +// unordered_map um = { +// {')', '('}, +// {']', '['}, +// {'}', '{'} +// }; + +// for (auto c: s) { +// if (!v.empty() && um[c] == v.back()) { +// v.pop_back(); +// } +// else { +// v.push_back(c); +// } +// } + +// return v.empty(); +// } +// }; \ No newline at end of file diff --git a/citrussoda/5week/1046_last_stone_weight.js b/citrussoda/5week/1046_last_stone_weight.js new file mode 100644 index 0000000..ddb2849 --- /dev/null +++ b/citrussoda/5week/1046_last_stone_weight.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} stones + * @return {number} + */ +var lastStoneWeight = function (stones) { + while (stones.length > 1) { + stones.sort((a, b) => b - a); + + if (stones[0] !== stones[1]) { + stones.push(stones[0] - stones[1]); + } + + stones = stones.slice(2); + } + + return stones[0] ? stones[0] : 0; +}; diff --git a/citrussoda/5week/21_merge_two_sorted_lists.js b/citrussoda/5week/21_merge_two_sorted_lists.js new file mode 100644 index 0000000..355240f --- /dev/null +++ b/citrussoda/5week/21_merge_two_sorted_lists.js @@ -0,0 +1,31 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} list1 + * @param {ListNode} list2 + * @return {ListNode} + */ +var mergeTwoLists = function (list1, list2) { + let ans = new ListNode(); + let ptr = ans; + + while (list1 && list2) { + if (list1.val <= list2.val) { + ptr.next = list1; + list1 = list1.next; + } else { + ptr.next = list2; + list2 = list2.next; + } + ptr = ptr.next; + } + + ptr.next = list1 || list2; + + return ans.next; +}; diff --git a/citrussoda/5week/338_counting-bits.js b/citrussoda/5week/338_counting-bits.js new file mode 100644 index 0000000..2c0729b --- /dev/null +++ b/citrussoda/5week/338_counting-bits.js @@ -0,0 +1,14 @@ +/** + * @param {number} n + * @return {number[]} + */ +var countBits = function (n) { + let ans = [0]; + + for (let i = 1; i <= n; i++) { + if (i % 2 === 0) ans[i] = ans[i / 2]; + else ans[i] = ans[i - 1] + 1; + } + + return ans; +}; diff --git a/citrussoda/5week/48_rotate_image.js b/citrussoda/5week/48_rotate_image.js new file mode 100644 index 0000000..cdb550e --- /dev/null +++ b/citrussoda/5week/48_rotate_image.js @@ -0,0 +1,21 @@ +/** + * @param {number[][]} matrix + * @return {void} Do not return anything, modify matrix in-place instead. + */ +var rotate = function (matrix) { + let ans = []; + + for (let i = 0; i < matrix.length; i++) { + let clock = []; + for (let j = matrix.length - 1; j >= 0; j--) { + clock.push(matrix[j][i]); + } + ans.push(clock); + } + + for (let i = 0; i < matrix.length; i++) { + for (let j = 0; j < matrix.length; j++) { + matrix[i][j] = ans[i][j]; + } + } +}; diff --git a/citrussoda/5week/70_climbing-stairs.js b/citrussoda/5week/70_climbing-stairs.js new file mode 100644 index 0000000..1c2a672 --- /dev/null +++ b/citrussoda/5week/70_climbing-stairs.js @@ -0,0 +1,16 @@ +/** + * @param {number} n + * @return {number} + */ +var climbStairs = function (n) { + let dp = Array.from({ length: n + 1 }, () => 0); + + dp[1] = 1; + dp[2] = 2; + + for (let i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2]; + } + + return dp[n]; +}; diff --git a/citrussoda/6week/198_house-robber.js b/citrussoda/6week/198_house-robber.js new file mode 100644 index 0000000..71710de --- /dev/null +++ b/citrussoda/6week/198_house-robber.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var rob = function (nums) { + let dp = Array.from({ length: nums.length + 1 }, () => 0); + + dp[1] = nums[0]; + if (nums.length > 1) { + dp[2] = nums[1]; + } + + for (let i = 3; i <= nums.length; i++) { + dp[i] = Math.max(nums[i - 1] + dp[i - 2], nums[i - 1] + dp[i - 3]); + } + + return Math.max(...dp); +}; diff --git a/citrussoda/6week/659_encode-and-decode-strings.js b/citrussoda/6week/659_encode-and-decode-strings.js new file mode 100644 index 0000000..71d982d --- /dev/null +++ b/citrussoda/6week/659_encode-and-decode-strings.js @@ -0,0 +1,40 @@ +class Solution { + /** + * @param {string[]} strs + * @returns {string} + */ + encode(strs) { + let res = ''; + for (let s of strs) { + res += `${s.length};${s}`; + } + + return res; + } + + /** + * @param {string} str + * @returns {string[]} + */ + decode(str) { + let ans = []; + let i = 0; + + while (i < str.length) { + let j = i; + + while (str[j] !== ';') j++; + + let length = parseInt(str.substring(i, j), 10); + + i = j + 1; + j = i + length; + + ans.push(str.substring(i, j)); + + i = j; + } + + return ans; + } +} diff --git a/citrussoda/6week/66.plus-one.js b/citrussoda/6week/66.plus-one.js new file mode 100644 index 0000000..a0a73ed --- /dev/null +++ b/citrussoda/6week/66.plus-one.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} digits + * @return {number[]} + */ +var plusOne = function (digits) { + let ans = []; + + let plusOne = BigInt(digits.toString().split(',').join('')) + 1n; + + ans = plusOne.toString().split('').map(Number); + + return ans; +}; diff --git a/citrussoda/6week/703_kth-largest-element-in-a-stream.js b/citrussoda/6week/703_kth-largest-element-in-a-stream.js new file mode 100644 index 0000000..8cbfee8 --- /dev/null +++ b/citrussoda/6week/703_kth-largest-element-in-a-stream.js @@ -0,0 +1,27 @@ +/** + * @param {number} k + * @param {number[]} nums + */ +var KthLargest = function (k, nums) { + this.k = k; + + this.minHeap = new MinPriorityQueue(); + nums.forEach((num) => this.minHeap.enqueue(num)); + while (this.minHeap.size() > k) this.minHeap.dequeue(); +}; + +/** + * @param {number} val + * @return {number} + */ +KthLargest.prototype.add = function (val) { + this.minHeap.enqueue(val); + if (this.minHeap.size() > this.k) this.minHeap.dequeue(); + return this.minHeap.front().element; +}; + +/** + * Your KthLargest object will be instantiated and called as such: + * var obj = new KthLargest(k, nums) + * var param_1 = obj.add(val) + */ diff --git a/citrussoda/6week/704.binary-search.js b/citrussoda/6week/704.binary-search.js new file mode 100644 index 0000000..a92a762 --- /dev/null +++ b/citrussoda/6week/704.binary-search.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var search = function (nums, target) { + let ans = -1; + + let left = 0; + let right = nums.length - 1; + + while (left <= right) { + let mid = left + Math.floor((right - left) / 2); + + if (nums[mid] === target) { + ans = mid; + break; + } else if (nums[mid] > target) right = mid - 1; + else left = mid + 1; + } + + return ans; +}; diff --git a/citrussoda/7week/110_balanced-binary-tree.cpp b/citrussoda/7week/110_balanced-binary-tree.cpp new file mode 100644 index 0000000..ce6fa53 --- /dev/null +++ b/citrussoda/7week/110_balanced-binary-tree.cpp @@ -0,0 +1,30 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), + * right(right) {} + * }; + */ +class Solution { + public: + int solve(TreeNode* root) { + if (!root) return 0; + + int leftHeight = solve(root->left); + if (leftHeight == -1) return -1; + + int rightHeight = solve(root->right); + if (rightHeight == -1) return -1; + + if (!(abs(leftHeight - rightHeight) <= 1)) return -1; + + return max(leftHeight, rightHeight) + 1; + } + + bool isBalanced(TreeNode* root) { return solve(root) != -1; } +}; \ No newline at end of file diff --git a/citrussoda/7week/136_sigle-number.cpp b/citrussoda/7week/136_sigle-number.cpp new file mode 100644 index 0000000..b26f4c5 --- /dev/null +++ b/citrussoda/7week/136_sigle-number.cpp @@ -0,0 +1,14 @@ +class Solution { + public: + int singleNumber(vector& nums) { + sort(nums.begin(), nums.end()); + + for (int i = 0; i < nums.size() - 1; i += 2) { + if (nums[i] != nums[i + 1]) { + return nums[i]; + } + } + + return nums[nums.size() - 1]; + } +}; \ No newline at end of file diff --git a/citrussoda/7week/155_min-stack.cpp b/citrussoda/7week/155_min-stack.cpp new file mode 100644 index 0000000..5e00cc2 --- /dev/null +++ b/citrussoda/7week/155_min-stack.cpp @@ -0,0 +1,28 @@ +class MinStack { + public: + vector> s; + + MinStack() {} + + void push(int val) { + if (s.empty()) + s.push_back({val, val}); + else + s.push_back({val, min(s.back().second, val)}); + } + + void pop() { s.pop_back(); } + + int top() { return s.back().first; } + + int getMin() { return s.back().second; } +}; + +/** + * Your MinStack object will be instantiated and called as such: + * MinStack* obj = new MinStack(); + * obj->push(val); + * obj->pop(); + * int param_3 = obj->top(); + * int param_4 = obj->getMin(); + */ \ No newline at end of file diff --git a/citrussoda/7week/54_spiral-matrix.cpp b/citrussoda/7week/54_spiral-matrix.cpp new file mode 100644 index 0000000..39d75dc --- /dev/null +++ b/citrussoda/7week/54_spiral-matrix.cpp @@ -0,0 +1,32 @@ +class Solution { + public: + vector spiralOrder(vector>& matrix) { + int rows = matrix.size(); + int cols = matrix[0].size(); + + int row = 0; + int col = -1; + + int direction = 1; + + vector result; + + while (rows > 0 && cols > 0) { + for (int i = 0; i < cols; i++) { + col += direction; + result.push_back(matrix[row][col]); + } + rows--; + + for (int i = 0; i < rows; i++) { + row += direction; + result.push_back(matrix[row][col]); + } + cols--; + + direction *= -1; + } + + return result; + } +}; \ No newline at end of file diff --git a/citrussoda/7week/973_k-closest-points-to-origin.cpp b/citrussoda/7week/973_k-closest-points-to-origin.cpp new file mode 100644 index 0000000..294e118 --- /dev/null +++ b/citrussoda/7week/973_k-closest-points-to-origin.cpp @@ -0,0 +1,12 @@ +class Solution { + public: + vector> kClosest(vector>& points, int k) { + sort(points.begin(), points.end(), [](auto& p1, auto& p2) { + return p1[0] * p1[0] + p1[1] * p1[1] < p2[0] * p2[0] + p2[1] * p2[1]; + }); + + points.resize(k); + + return points; + } +}; \ No newline at end of file diff --git a/citrussoda/8week/128_longest-consecutive-sequence.cpp b/citrussoda/8week/128_longest-consecutive-sequence.cpp new file mode 100644 index 0000000..35779da --- /dev/null +++ b/citrussoda/8week/128_longest-consecutive-sequence.cpp @@ -0,0 +1,46 @@ +// class Solution { +// public: +// int longestConsecutive(vector& nums) { +// if (nums.size() == 0) return 0; + +// int minNum = *min_element(nums.begin(), nums.end()); +// int maxNum = *max_element(nums.begin(), nums.end()); +// int answer = 0; +// int tempAnswer = 0; + +// for (int i = minNum; i <= maxNum; i++) { +// if (find(nums.begin(), nums.end(), i) != nums.end()) { +// tempAnswer++; +// answer = max(tempAnswer, answer); +// } else { +// tempAnswer = 0; +// } +// } + +// return answer; +// } +// }; + +class Solution { + public: + int longestConsecutive(vector& nums) { + unordered_set numSet(nums.begin(), nums.end()); + int answer = 0; + + for (int num : numSet) { + // 시작 기준을 해당 수의 - 1이 없으면으로 잡아 while을 돌때 중복을 막는다. + // (while은 1씩 더해서 확인하므로..) + if (numSet.find(num - 1) == numSet.end()) { + int length = 1; + + while (numSet.find(num + length) != numSet.end()) { + length++; + } + + answer = max(length, answer); + } + } + + return answer; + } +}; \ No newline at end of file diff --git a/citrussoda/8week/208_implement-trie.cpp b/citrussoda/8week/208_implement-trie.cpp new file mode 100644 index 0000000..c986d40 --- /dev/null +++ b/citrussoda/8week/208_implement-trie.cpp @@ -0,0 +1,51 @@ +class TrieNode { + public: + // 알파벳 가르킬 포인터 + TrieNode *child[26]; + // 해당 노드까지 완성된 단어인가 확인 + bool isWord; + + TrieNode() { + isWord = false; + for (auto &a : child) a = nullptr; + } +}; + +class Trie { + TrieNode *root; + + public: + Trie() { root = new TrieNode(); } + + void insert(string s) { + TrieNode *p = root; + + for (auto &a : s) { + int i = a - 'a'; + if (!p->child[i]) p->child[i] = new TrieNode(); + p = p->child[i]; + } + // 다 할당했으면 단어라고 선언, 포인터 변수기 때문에 for문에서 끝까지 할당한 + // 노드에서 isWord가 true + p->isWord = true; + } + + bool search(string key, bool prefix = false) { + TrieNode *p = root; + + for (auto &a : key) { + int i = a - 'a'; + if (!p->child[i]) return false; + p = p->child[i]; + } + + // startWith를 위한 prefix 추가, startWith가 아니면 해당 노드가 끝까지 + // 갔는지 isWord만 확인하면 된다. + if (prefix == false) return p->isWord; + + // startWith라면 해당 노드까지 모두 있는 것이므로 true + return true; + } + + bool startsWith(string prefix) { return search(prefix, true); } +}; \ No newline at end of file diff --git a/citrussoda/8week/226_invert-binary-tree.cpp b/citrussoda/8week/226_invert-binary-tree.cpp new file mode 100644 index 0000000..3050e09 --- /dev/null +++ b/citrussoda/8week/226_invert-binary-tree.cpp @@ -0,0 +1,25 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), + * right(right) {} + * }; + */ +class Solution { + public: + TreeNode* invertTree(TreeNode* root) { + if (root == nullptr) return nullptr; + + swap(root->left, root->right); + + invertTree(root->left); + invertTree(root->right); + + return root; + } +}; \ No newline at end of file diff --git a/citrussoda/8week/371_sum-of-two-integers.cpp b/citrussoda/8week/371_sum-of-two-integers.cpp new file mode 100644 index 0000000..514322c --- /dev/null +++ b/citrussoda/8week/371_sum-of-two-integers.cpp @@ -0,0 +1,26 @@ +// 크기 초과 ㅠㅠ +// class Solution { +// public: +// int getSum(int a, int b) { return log(exp(a) * exp(b)); } +// }; + +// 천재인가..? 자바스크립트도 sum을 달라... +// class Solution { +// public: +// int getSum(int a, int b) { +// vector v{a,b}; +// return accumulate(begin(v),end(v),0); +// } +// }; + +class Solution { + public: + int getSum(int a, int b) { + while (b != 0) { + unsigned int carry = a & b; // 올려줄 자리 계산 + a = a ^ b; // 각 자리 더하기 + b = carry << 1; // 올려줄 자리를 왼쪽으로 시프트 + } + return a; + } +}; \ No newline at end of file diff --git a/citrussoda/8week/543_diameter-of-binary-tree.cpp b/citrussoda/8week/543_diameter-of-binary-tree.cpp new file mode 100644 index 0000000..41c6f03 --- /dev/null +++ b/citrussoda/8week/543_diameter-of-binary-tree.cpp @@ -0,0 +1,35 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), + * right(right) {} + * }; + */ +class Solution { + public: + int diameterOfBinaryTree(TreeNode* root) { + int ans = 0; + + diameter(root, ans); + + return ans; + } + + int diameter(TreeNode* node, int& ans) { + if (!node) return 0; + + int left = diameter(node->left, ans); + int right = diameter(node->right, ans); + + // 오른쪽 왼쪽 diameter 최대치 저장 (left, right는 노드 기준 최대 높이들) + ans = max(ans, left + right); + + // 높이만 return + return max(left, right) + 1; + } +}; \ No newline at end of file diff --git a/citrussoda/9week/102_binary-tree-level-order-traversal.js b/citrussoda/9week/102_binary-tree-level-order-traversal.js new file mode 100644 index 0000000..2510aca --- /dev/null +++ b/citrussoda/9week/102_binary-tree-level-order-traversal.js @@ -0,0 +1,35 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {number[][]} + */ +var levelOrder = function (root) { + if (!root) return []; + + let q = [root]; + let ans = []; + + while (q.length !== 0) { + let tempAns = []; + let tempLength = q.length; + + for (let i = 0; i < tempLength; i++) { + let curr = q.shift(); + + tempAns.push(curr.val); + + if (curr.left) q.push(curr.left); + if (curr.right) q.push(curr.right); + } + + ans.push(tempAns); + } + return ans; +}; diff --git a/citrussoda/9week/150_evaluate-reverse-polish-notation.js b/citrussoda/9week/150_evaluate-reverse-polish-notation.js new file mode 100644 index 0000000..a95d193 --- /dev/null +++ b/citrussoda/9week/150_evaluate-reverse-polish-notation.js @@ -0,0 +1,22 @@ +/** + * @param {string[]} tokens + * @return {number} + */ +var evalRPN = function (tokens) { + let stack = []; + let op = new Set(['+', '-', '*', '/']); + + for (let i of tokens) { + if (!op.has(i)) stack.push(+i); + if (op.has(i)) { + let a = stack.pop(); + let b = stack.pop(); + if (i === '+') stack.push(a + b); + if (i === '-') stack.push(b - a); + if (i === '*') stack.push(a * b); + if (i === '/') stack.push(parseInt(b / a)); + } + } + + return stack[0]; +}; diff --git a/citrussoda/9week/207_course-schedule.js b/citrussoda/9week/207_course-schedule.js new file mode 100644 index 0000000..84c0afe --- /dev/null +++ b/citrussoda/9week/207_course-schedule.js @@ -0,0 +1,41 @@ +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {boolean} + */ +var canFinish = function (numCourses, prerequisites) { + // 인접 리스트로 그래프 만들기 + const graph = Array.from({ length: numCourses }, () => []); + for (const [course, prereq] of prerequisites) { + graph[course].push(prereq); + } + + // visited: 0 = 미방문, 1 = 현재 경로에서 방문 중, 2 = 완전히 방문 완료 + const visited = new Array(numCourses).fill(0); + + const hasCycle = (course) => { + // 현재 경로에서 방문 중인 노드를 다시 방문하면 순환이 있다는 뜻 + if (visited[course] === 1) return true; + // 이미 완전히 방문한 노드면 안전 + if (visited[course] === 2) return false; + + // 현재 노드 방문 처리 + visited[course] = 1; + + // 현재 코스의 선수과목들 확인 + for (const prereq of graph[course]) { + if (hasCycle(prereq)) return true; + } + + // 방문 완료 처리 + visited[course] = 2; + return false; + }; + + // 모든 코스에 대해 순환 확인 + for (let course = 0; course < numCourses; course++) { + if (hasCycle(course)) return false; + } + + return true; +}; diff --git a/citrussoda/9week/213_house-robber-2.js b/citrussoda/9week/213_house-robber-2.js new file mode 100644 index 0000000..15029e9 --- /dev/null +++ b/citrussoda/9week/213_house-robber-2.js @@ -0,0 +1,36 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var rob = function (nums) { + // 첫번째 포함 마직막 포함 X + let dp_first = Array.from({ length: nums.length + 1 }, () => 0); + // 첫번째 X 마지막 포함 + let dp_last = Array.from({ length: nums.length + 1 }, () => 0); + + if (nums.length <= 2) return Math.max(...nums); + + // ----------------------- 1 O L X ----------------------- + dp_first[1] = nums[0]; + dp_first[2] = nums[1]; + + for (let i = 3; i <= nums.length - 1; i++) { + dp_first[i] = Math.max( + dp_first[i - 2] + nums[i - 1], + dp_first[i - 3] + nums[i - 1] + ); + } + + // ----------------------- 1 X L O ----------------------- + dp_last[1] = 0; + dp_last[2] = nums[1]; + + for (let i = 3; i <= nums.length; i++) { + dp_last[i] = Math.max( + dp_last[i - 2] + nums[i - 1], + dp_last[i - 3] + nums[i - 1] + ); + } + + return Math.max(...dp_first, ...dp_last); +}; diff --git a/citrussoda/9week/572_subtree-of-another-tree.js b/citrussoda/9week/572_subtree-of-another-tree.js new file mode 100644 index 0000000..c2b14e9 --- /dev/null +++ b/citrussoda/9week/572_subtree-of-another-tree.js @@ -0,0 +1,32 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} subRoot + * @return {boolean} + */ +var isSubtree = function (root, subRoot) { + if (!root) return false; + + if (isSametree(root, subRoot)) return true; + + return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot); +}; + +var isSametree = function (root1, root2) { + if (!root1 && !root2) return true; + // 하나라도 null이면 false + if (!root1 || !root2) return false; + // [1] [0] 한개씩 비교할때도 고려해야 함... + if (root1.val !== root2.val) return false; + + return ( + isSametree(root1.left, root2.left) && isSametree(root1.right, root2.right) + ); +};