diff --git a/coin-change/dohyeon2.java b/coin-change/dohyeon2.java new file mode 100644 index 000000000..9991e9e15 --- /dev/null +++ b/coin-change/dohyeon2.java @@ -0,0 +1,93 @@ +import java.util.Arrays; + +class Solution { + // TC: O(amount * coins.length) + // SC: O(amount) + public int coinChange(int[] coins, int amount) { + int[] dp = new int[amount + 1]; + // Maximum depth = amount + // amount + 1 means undefined; set to use Math.min + Arrays.fill(dp, amount + 1); + + dp[0] = 0; + + for(int i = 1; i <= amount; i++){ + for(int coin : coins){ + if(i - coin >= 0){ + // depth without the coin + with the coin(1) + dp[i] = Math.min(dp[i], dp[i - coin] + 1); + } + } + } + + return dp[amount] > amount ? -1 : dp[amount]; + } +} + +// DFS + Memoization +// class Solution { +// public int coinChange(int[] coins, int amount) { +// int[] memo = new int[amount + 1]; +// Arrays.fill(memo, -2); // -2 = 아직 계산 안함 +// return dfs(0, coins, amount, memo); +// } + +// private int dfs(int depth, int[] coins, int amount, int[] memo){ +// if(amount < 0){ +// return -1; +// } +// if(amount == 0){ +// return depth; +// } + +// if(memo[amount] != -2) return memo[amount]; + +// int min = -1; +// for(int i = 0; i < coins.length; i++){ +// int descended = coins[coins.length - i - 1]; +// int d = dfs(depth + 1, coins, amount - descended, memo); +// if(d >= 0 && (d < min || min == -1)){ +// min = d; +// } +// } + +// if(memo[amount] == -2) memo[amount] = min; // 계산한 적 없는 경우에만 저장 +// return min; +// } +// } + +// BFS : 문제 서술과 가장 어울리는 풀이지만, Bottom-Up DP가 더 빠른 결과. +// class Solution { +// public int coinChange(int[] coins, int amount) { +// Queue queue = new LinkedList<>(); +// boolean[] visited = new boolean[amount + 1]; + +// queue.offer(amount); +// visited[amount] = true; + +// int level = 0; + +// while (!queue.isEmpty()) { +// int size = queue.size(); + +// for (int i = 0; i < size; i++) { +// int cur = queue.poll(); + +// if (cur == 0) return level; + +// for (int coin : coins) { +// int next = cur - coin; + +// if (next >= 0 && !visited[next]) { +// visited[next] = true; +// queue.offer(next); +// } +// } +// } + +// level++; +// } + +// return -1; +// } +// } diff --git a/find-minimum-in-rotated-sorted-array/dohyeon2.java b/find-minimum-in-rotated-sorted-array/dohyeon2.java new file mode 100644 index 000000000..c769780fb --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/dohyeon2.java @@ -0,0 +1,47 @@ +public class Solution { + // TC : O(log n) + // SC : O(1) + public int findMin(int[] nums) { + // You must write an algorithm that runs in O(log n) time. => this means the solution is binary search + int left = 0; + int right = nums.length - 1; + + while(left < right){ + int mid = left + ((right - left) / 2); + + if(nums[right] > nums[mid]){ + right = mid; + }else{ + left = mid + 1; + } + } + + return nums[left]; + } +} + +// First attempt : the algorithm is correct but the condition is wrong. +// class Solution { +// public int findMin(int[] nums) { +// // You must write an algorithm that runs in O(log n) time. => this means the solution is binary search +// int cursor = (nums.length - 1) / 2; +// int left = 0; +// int right = nums.length - 1; + +// // 이전 값이 현재 값보다 커지는 경우가 종료 +// while(cursor - 1 >= 0 && nums[cursor - 1] < nums[cursor]){ +// int n = nums[cursor]; +// int rn = nums[right]; + +// if(rn > n){ +// right = cursor; +// }else{ +// left = cursor; +// } + +// cursor = left + ((right - left) / 2); +// } + +// return nums[cursor]; +// } +// } diff --git a/maximum-depth-of-binary-tree/dohyeon2.java b/maximum-depth-of-binary-tree/dohyeon2.java new file mode 100644 index 000000000..820bdaa87 --- /dev/null +++ b/maximum-depth-of-binary-tree/dohyeon2.java @@ -0,0 +1,40 @@ +/** + * 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; + * } + * } + */ + +// Good solution from Leetcode +// class Solution{ +// public int maxDepth(TreeNode root){ +// if (root==null) return 0; +// return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1; +// } +// } + +class Solution { + // TC : O(n) + // SC : O(h) height of tree(DFS), width of tree(BFS) + public int maxDepth(TreeNode root) { + return dfs(root, 0); + } + + private int dfs(TreeNode cursor, int depth) { + if (cursor == null) { + return depth; + } + return Math.max( + dfs(cursor.left, depth + 1), + dfs(cursor.right, depth + 1)); + } +} diff --git a/merge-two-sorted-lists/dohyeon2.java b/merge-two-sorted-lists/dohyeon2.java new file mode 100644 index 000000000..d90a36016 --- /dev/null +++ b/merge-two-sorted-lists/dohyeon2.java @@ -0,0 +1,38 @@ +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +class Solution { + // TC : O(n) + // SC : O(n) + public ListNode mergeTwoLists(ListNode list1, ListNode list2) { + // Initialize anonymous head for result + ListNode result = new ListNode(0); + // Initialize cursor to track list + ListNode cursor = result; + + // If any list remains + while(list1 != null || list2 != null){ + // Choose the smaller node + if(list2 == null + || (list1 != null && list1.val <= list2.val)){ + cursor.next = list1; + list1 = list1.next; + }else{ + cursor.next = list2; + list2 = list2.next; + } + //Set the cursor to the next + cursor = cursor.next; + } + + // Skip dummy head and return the actual merged list + return result.next; + } +} diff --git a/word-search/dohyeon2.java b/word-search/dohyeon2.java new file mode 100644 index 000000000..9b74bd290 --- /dev/null +++ b/word-search/dohyeon2.java @@ -0,0 +1,41 @@ +class Solution { + // TC : O(n*4^L); n = the number of the characters, L = the length of the word + // SC : O(m*n + L) m = a row of the board, n = a cell of the board, L = the length of the word + public boolean exist(char[][] board, String word) { + for (int y = 0; y < board.length; y++) { + for (int x = 0; x < board[0].length; x++) { + if(board[y][x] != word.charAt(0)){ + continue; + } + boolean[][] visited = new boolean[board.length][board[0].length]; + if (backtrack(x, y, 0, board, visited, word)) { + return true; + } + } + } + return false; + } + + private boolean backtrack(int x, int y, int index, char[][] board, boolean[][] visited, String word) { + if (index == word.length()) + return true; + + if (y < 0 || y >= board.length || x < 0 || x >= board[0].length) + return false; + + if (visited[y][x] || board[y][x] != word.charAt(index)) + return false; + + visited[y][x] = true; + + boolean found = backtrack(x + 1, y, index + 1, board, visited, word) || + backtrack(x - 1, y, index + 1, board, visited, word) || + backtrack(x, y + 1, index + 1, board, visited, word) || + backtrack(x, y - 1, index + 1, board, visited, word); + + visited[y][x] = false; // It failed on the first attempt because this line was missing. + + return found; + } + +}