diff --git a/3sum/samcho0608.java b/3sum/samcho0608.java new file mode 100644 index 0000000000..a020fa18f9 --- /dev/null +++ b/3sum/samcho0608.java @@ -0,0 +1,66 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +// link: https://leetcode.com/problems/3sum/ +// difficulty: Medium +class Solution { + // Problem: + // * return: all triplets of elements in nums such that the sum == 0 (indices must differ) + // Solution: + // * Time Complexity: O(N^2) + // * Space Complexity: O(1) + public List> threeSum(int[] nums) { + // sort for simplicity + // Time Complexity: O(N log N) + Arrays.sort(nums); + + List> answers = new ArrayList<>(); + + // if there are only positive or only negative numbers, there exist no solution + if(nums[0] > 0 || nums[nums.length-1] < 0) return answers; + + + + // Time Complexity: O(N^2) + // * for loop * inner while loop = O(N) * O(N) = O(N^2) + + // nums[i]: first of the triplet + // * skip positive because the other two will also be positive + for(int i = 0; i < nums.length && nums[i] <= 0; i++) { + // skip if same first of the triplet met + if(i != 0 && nums[i] == nums[i-1]) continue; + + int numI = nums[i]; + + int left = i + 1; + int right = nums.length - 1; + + // Time Complexity: O(N) + while(left < right) { + int numLeft = nums[left]; + int numRight = nums[right]; + + int sum = numI + numLeft + numRight; + + if(sum == 0) { + answers.add(Arrays.asList(numI, numLeft, numRight)); + + // skip same lefts and rights two prevent duplicate + // * must update both left and right + // * e.g. if only left is moved, newNumLeft = 0 - (numI + numRight) and that can only be numLeft that's already visited + // * Time Complexity: O(1) because there is no actual operation other than skipping + while(left < nums.length && nums[left] == numLeft) left++; + + while(right > left && nums[right] == numRight) right--; + } else if(sum > 0) { + right--; + } else { + left++; + } + } + } + + return answers; + } +} diff --git a/climbing-stairs/samcho0608.java b/climbing-stairs/samcho0608.java new file mode 100644 index 0000000000..207a56e27a --- /dev/null +++ b/climbing-stairs/samcho0608.java @@ -0,0 +1,21 @@ +class Solution { + // Problem: + // * can take 1 or 2 steps + // * return: how many distinct ways to climb to the top(n) + // Solution: + // * Time Complexity: O(N) + // * due to memoization(DP) + // * Space Complexity: O(N) + public int climbStairs(int n) { + // memo[i] = distinct steps to reach ith step + int[] memo = new int[n + 1]; + memo[0] = 1; + memo[1] = 1; + + for(int i = 2; i < n+1; i++) { + memo[i] = memo[i-1] + memo[i-2]; + } + + return memo[n]; + } +} diff --git a/product-of-array-except-self/samcho0608.java b/product-of-array-except-self/samcho0608.java new file mode 100644 index 0000000000..f6b20fbb1a --- /dev/null +++ b/product-of-array-except-self/samcho0608.java @@ -0,0 +1,75 @@ +// link: https://leetcode.com/problems/product-of-array-except-self/submissions/1831301674/ +// difficulty: Medium +class Solution1 { + // Problem: + // * return: array where answer[i] = product of all elements except nums[i] + // Solution: + // * Time Complexity: O(N) + // * Space Complexity: O(N) + public int[] productExceptSelf(int[] nums) { + int n = nums.length; + + // prefixProds[i] = prod of all elements upto i (exclusive) + int[] prefixProds = new int[n]; + for(int i = 0; i < n; i++) { + if(i == 0) { + prefixProds[i] = 1; + continue; + } + + prefixProds[i] = prefixProds[i-1] * nums[i-1]; + } + + // suffixProds[i] = prod of all elements from end to i (exclusive) + int[] suffixProds = new int[n]; + for(int i = n - 1; i >= 0; i--) { + if(i == n - 1) { + suffixProds[i] = 1; + continue; + } + + suffixProds[i] = suffixProds[i+1] * nums[i+1]; + } + + // multiply prefix and suffix prods to find answers + int[] answers = new int[n]; + for(int i = 0; i< n;i++) { + answers[i] = prefixProds[i] * suffixProds[i]; + } + + return answers; + } +} + +// uses only 1 array whereas solution 1 uses 3 +class Solution2 { + // Problem: + // * return: array where answer[i] = product of all elements except nums[i] + // Solution: + // * Time Complexity: O(N) + // * Space Complexity: O(N) + public int[] productExceptSelf(int[] nums) { + int n = nums.length; + + // prefixProds[i] = prod of all elements upto i (exclusive) + int[] answers = new int[n]; + for(int i = 0; i < n; i++) { + if(i == 0) { + answers[i] = 1; + continue; + } + + answers[i] = answers[i-1] * nums[i-1]; + } + + // use a single variable for suffix product + int suffixProd = 1; + for(int i = n - 2; i >= 0; i--) { + suffixProd *= nums[i+1]; + answers[i] *= suffixProd; + } + + return answers; + } +} + diff --git a/valid-anagram/samcho0608.java b/valid-anagram/samcho0608.java new file mode 100644 index 0000000000..0b7a02ab05 --- /dev/null +++ b/valid-anagram/samcho0608.java @@ -0,0 +1,64 @@ +import java.util.HashMap; + +// link: https://leetcode.com/problems/valid-anagram/ +// difficulty: Easy +class Solution1 { + // Problem: + // * return: is t an anagram of s + public boolean isAnagram(String s, String t) { + if(s.length() != t.length()) return false; + + int n = s.length(); + + // Space Complexity: O(N) + HashMap freqS = new HashMap<>(); + HashMap freqT = new HashMap<>(); + + // Time Complexity: O(N) + for(int i = 0; i < n; i++) { + char charS = s.charAt(i); + freqS.put(charS, freqS.getOrDefault(charS, 0) + 1); + + char charT = t.charAt(i); + freqT.put(charT, freqT.getOrDefault(charT, 0) + 1); + } + + // Time Complexity: O(N) + for(var entryS: freqS.entrySet()) { + int cntT = freqT.getOrDefault(entryS.getKey(), 0); + if(cntT != entryS.getValue()) return false; + } + + return true; + } +} + +// Map 하나만 사용하는 개선된 방식 +class Solution2 { + // Problem: + // * return: is t an anagram of s + public boolean isAnagram(String s, String t) { + if(s.length() != t.length()) return false; + + int n = s.length(); + + // Space Complexity: O(N) + HashMap freq = new HashMap<>(); + + // Time Complexity: O(N) + for(int i = 0; i < n; i++) { + char charS = s.charAt(i); + freq.put(charS, freq.getOrDefault(charS, 0) + 1); + + char charT = t.charAt(i); + freq.put(charT, freq.getOrDefault(charT, 0) - 1); + } + + // Time Complexity: O(N) + for(int count: freq.values()) { + if(count != 0) return false; + } + + return true; + } +} diff --git a/validate-binary-search-tree/samcho0608.java b/validate-binary-search-tree/samcho0608.java new file mode 100644 index 0000000000..fb97523e9e --- /dev/null +++ b/validate-binary-search-tree/samcho0608.java @@ -0,0 +1,80 @@ +// link: https://leetcode.com/problems/validate-binary-search-tree/description/ +// difficulty: Medium +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution1 { + // Problem: + // * return: check if tree is a valid BST + // * left subtree contains keys strictly less than node's key + // * right subtree contains keys strictly greater than node's key + // * recursive structure + // Solution: + // * Time Complexity: O(N) + // * Space Complexity(in terms of call stack): + // * O(N) if skewed + // * O(log N) if not skewed + public boolean isValidBST(TreeNode root) { + // checklist: + // * is subtree a valid bst + // * left subtree : is max value of subtree less than node + // * right subtree : is min value of subtree greater than node + return isValid(root, null, null); + } + + private boolean isValid(TreeNode node, Integer min, Integer max) { + if(node == null) return true; + + int val = node.val; + + if(min != null && val <= min) return false; + if(max != null && val >= max) return false; + + if(!isValid(node.left, min, val)) return false; + if(!isValid(node.right, val, max)) return false; + + return true; + } +} + +// in-order traversal approach +// * reads from left-most to right (strictly increasing val order expected) +class Solution2 { + private Integer prev; + + // Solution: + // * Time Complexity: O(N) + // * Space Complexity(in terms of call stack): + // * O(N) if skewed + // * O(log N) if not skewed + public boolean isValidBST(TreeNode root) { + prev = null; + return inorder(root); + } + + private boolean inorder(TreeNode node) { + // reached end without failure + if(node == null) return true; + + // inorder so travel left first + if(!inorder(node.left)) return false; + + // if node value is not greater than prev, it isn't a BST in in-order + if(prev != null && node.val <= prev) return false; + prev = node.val; + + return inorder(node.right); + } +}