diff --git a/clone-graph/forest000014.java b/clone-graph/forest000014.java index 60c0a2b25..99fc4e4fe 100644 --- a/clone-graph/forest000014.java +++ b/clone-graph/forest000014.java @@ -70,7 +70,7 @@ public void dfs(Node oldNode) { Node newNeighbor = createNode(oldNeighbor.val); newNode.neighbors.add(newNeighbor); newNeighbor.neighbors.add(newNode); - dfs(oldNeighbor, newNeighbor); + dfs(oldNeighbor); } } } diff --git a/find-minimum-in-rotated-sorted-array/forest000014.java b/find-minimum-in-rotated-sorted-array/forest000014.java new file mode 100644 index 000000000..7f03d0312 --- /dev/null +++ b/find-minimum-in-rotated-sorted-array/forest000014.java @@ -0,0 +1,38 @@ +/* +# Time Complexity: O(logn) +# Space Complexity: O(1) + +binary search를 사용해 접근했습니다. +sorted array인 경우는 while문 시작 전, 예외 체크를 했습니다. +binary search를 진행하면, 각각의 loop의 mid 원소는 아래 4가지 경우 중 하나입니다. +maximum / minimum / 앞쪽 수열의 원소 중 하나 / 뒤쪽 수열의 원소 중 하나 +maximum이거나 minimum인 경우는 더 이상 탐색할 필요 없이 종료합니다. +앞쪽 수열인 경우, 우리가 원하는 minimum은 왼쪽에는 없으므로, left 포인터를 mid의 오른쪽으로 옮기고 다음 loop를 진행하고, +뒤쪽 수열인 경우, 우리가 원하는 minimum은 오른쪽에는 없으므로, rigth 포인터를 mid의 왼쪽으로 옮기고 다음 loop를 진행합니다. + + */ +class Solution { + public int findMin(int[] nums) { + int l = 0; + int r = nums.length - 1; + + if (nums[l] <= nums[r]) { // sorted array인 경우 (size가 1인 경우도 포함) + return nums[l]; + } + + while (l <= r) { + int m = (r - l) / 2 + l; // 만약 문제 조건상 l, r의 합이 int 범위를 넘어가서 overflow가 생길 수 있는 경우에, 이런 식으로 overflow를 방지할 수 있다고 알고 있습니다. 이 문제는 overflow 걱정은 없지만, 나중에 실전에서 나오면 잊지 않으려고 이렇게 구현해보았습니다. + if (m > 0 && nums[m - 1] > nums[m]) { + return nums[m]; + } else if (m < nums.length - 1 && nums[m] > nums[m + 1]) { + return nums[m + 1]; + } else if (nums[m] > nums[l]) { + l = m + 1; + } else { + r = m - 1; + } + } + + return -1; + } +} diff --git a/linked-list-cycle/forest000014.java b/linked-list-cycle/forest000014.java new file mode 100644 index 000000000..57b672067 --- /dev/null +++ b/linked-list-cycle/forest000014.java @@ -0,0 +1,29 @@ +/** + # Time Complexity : O(n) + # Space Complexity: O(1) + + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class Solution { + private final int VISITED = -999999; + public boolean hasCycle(ListNode head) { + while (head != null) { + if (head.val == VISITED) { + return true; + } + + head.val = VISITED; + head = head.next; + } + + return false; + } +} diff --git a/maximum-product-subarray/forest000014.java b/maximum-product-subarray/forest000014.java new file mode 100644 index 000000000..db31e28c1 --- /dev/null +++ b/maximum-product-subarray/forest000014.java @@ -0,0 +1,89 @@ +/* +# Time Complexity: O(n) + +# Space Complexity: O(1) + +# Solution +1. array에 0이 존재하는 경우 + +(observation: 정답이 음수가 될 가능성이 있는가? Yes. 다만, 원소 개수가 1개이고, 그 원소가 음수인 경우에만 그렇다. 음수인 원소가 2개 이상인 경우는 subarray를 잘 선택하면 그 곱을 항상 0 이상으로 만들 수 있다. 즉, 원소 개수가 1개이고 음수인 경우만 예외 처리를 해주면, 그 외의 경우는 정답이 0이거나 양수이다.) + +subarray에 0이 포함되는 순간 곱은 0이 되므로, 0보다 큰 곱을 찾기 위해서는 0을 제외하고 판단한다. +즉, 0을 기준으로 slice해서, 각각의 segment만 독립적으로 검토하면 된다. (0으로 slice한 각 segment가 아래 2번 케이스로 환원된다.) + +2. (sub)array에 0이 존재하지 않는 경우 +음수의 개수에 따라 접근을 다르게 한다. + +2-1. 짝수개 +고민할 것 없이, 전체 subarray의 원소를 곱하면 그 subarray에서 얻을 수 있는 곱의 최대값이다. + +2-2. 홀수개 +subarray 양 끝에서 각각 출발하여 최초의 마이너스(즉 가장 바깥쪽의 마이너스)를 만날 때까지, 원소들을 누적해서 곱하며 이동. +두 값 중 절대값이 작은 쪽을 subarray에서 제외. 남은 부분의 곱을 구하면, 최대값이다. +*/ + +class Solution { + public int maxProduct(int[] nums) { + if (nums.length == 1) { + return nums[0]; + } + + int ans = 0; + int start = 0; + for (int i = 0; i < nums.length; i++) { + if (nums[i] != 0) { + continue; + } + + if (i > 0) { + int res = calculateMaxProduct(start, i - 1, nums); + ans = Math.max(ans, res); + } + start = i + 1; + } + + if (start <= nums.length - 1) { + int res = calculateMaxProduct(start, nums.length - 1, nums); + ans = Math.max(ans, res); + } + + return ans; + } + + private int calculateMaxProduct(int l, int r, int[] nums) { + if (l == r) { + return nums[l]; + } + + int minusCount = 0; + int product = 1; + for (int i = l; i <= r; i++) { + if (nums[i] < 0) { + minusCount++; + } + product *= nums[i]; + } + + if (minusCount % 2 == 0) { + return product; + } else { + int leftProduct = 1; + for (int i = l; i <= r; i++) { + leftProduct *= nums[i]; + if (nums[i] < 0) { + break; + } + } + + int rightProduct = 1; + for (int i = r; i >= l; i--) { + rightProduct *= nums[i]; + if (nums[i] < 0) { + break; + } + } + + return product / Math.max(leftProduct, rightProduct); + } + } +}