Skip to content

[forest000014] Week 11 #1042

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Feb 22, 2025
63 changes: 63 additions & 0 deletions 3sum/forest000014.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
# Time Complexity: O(n^2)
# Space Complexity: O(1)
*/

class Solution {
public List<List<Integer>> threeSum1(int[] nums) { // solution 1
int n = nums.length;
Arrays.sort(nums);
Set<List<Integer>> ans = new HashSet<>();

for (int i = 0; i < n - 2; i++) {
for (int j = i + 1; j < n - 1; j++) {
int target = -nums[i] - nums[j]; // nums[i], nums[j]와 더해서 합이 0이 되기 위해 nums[k]가 가져야하는 값
int k = -1;
int l = j + 1;
int r = n - 1;
while (l <= r) {
int m = (r - l) / 2 + l;
if (nums[m] == target) {
k = m;
break;
} else if (nums[m] < target) {
l = m + 1;
} else {
r = m - 1;
}
}
if (k != -1) { // binary search에서 target을 찾은 경우
ans.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[k])));
}
}
}

return new ArrayList<>(ans);
}

public List<List<Integer>> threeSum(int[] nums) { // solution 2
int n = nums.length;
Arrays.sort(nums);
Set<List<Integer>> ans = new HashSet<>();

for (int i = 0; i < n - 2; i++) {
int l = i + 1;
int r = n - 1;
int target = -nums[i];
while (l < r) {
int sum = nums[l] + nums[r];
if (sum == target) {
ans.add(new ArrayList<>(Arrays.asList(nums[i], nums[l], nums[r])));
l++;
r--; // 또 다른 (l, r) 조합이 있을 수 있으므로, loop를 계속 이어간다.
} else if (sum < target) {
l++;
} else {
r--;
}
}
}

return new ArrayList<>(ans);
}
}
50 changes: 50 additions & 0 deletions binary-tree-maximum-path-sum/forest000014.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
# Time Complexity: O(n)
# Space Complexity: O(n)
- 재귀 호출 내부에서 left, right 변수를 사용하고, 재귀 호출 최대 깊이는 n이므로
# Solution
전체 문제를 각 subtree에 대한 문제로 쪼개어 생각할 수 있습니다.
임의의 노드 x에 대해, x의 왼쪽 자식을 x_l, x의 오른쪽 자식을 x_r, x의 값을 x.val이라고 정의하겠습니다.
x를 root로 하는 subtree에서 'x를 path의 한쪽 끝으로 하는 path sum 중 최대값'을 dp[x]라고 정의하겠습니다.
그러면 dp[x] = max(max(0, dp[x_l]) + x.val, max(0, dp[x_r]) + x.val) 로 구할 수 있습니다. (subtree의 dp 값이 음수인 경우는 버리면 되기 때문에.)
이제 root로부터 출발해서 DFS로 전체 노드를 순회하며 이 점화식을 적용하면, 전체 tree에 대해 dp값을 구할 수 있습니다.
단, 문제에서 원하는 답은 root를 반드시 path의 한쪽 끝으로 원하는 것은 아니고, 심지어 root가 path에 포함되지 않아도 되기 때문에,
어중간한(?) (= root를 path에 포함하지 않는) path도 고려할 필요가 있는데요.
이를 고려하기 위해, 각 재귀 함수 호출마다 max(0, dp[x_l]) + root.val + max(0, dp[x_r]) 값이 정답이 될 수 있는지 체크하는 과정이 필요합니다.
*/
/**
* 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 Solution {
public int ans = -30_000_001;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int 에서 최솟값을 초기화 하는거라면 Integer.MIN_VALUE를 사용하면 어떨까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아아 넵 그런 방법이 있었군요! 다음 번 풀이부터는 사용해보겠습니다 :)

public int maxPathSum(TreeNode root) {
maxInTree(root);

return ans;
}

public int maxInTree(TreeNode root) {
if (root == null) {
return 0;
}

int left = Math.max(0, maxInTree(root.left));
int right = Math.max(0, maxInTree(root.right));

ans = Math.max(ans, left + root.val + right);

return root.val + Math.max(left, right);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
이 문제는 힌트의 도움을 받아서 풀었습니다.
- preorder의 첫 원소는 항상 root node임
- inorder에서 root node의 왼쪽의 원소들은 root node의 왼쪽 subtree, 오른쪽 원소들은 오른쪽 subtree임
- 왼쪽 subtree와 오른쪽 subtree는 각각 preorder에서 연속하게 있음. (root, 왼쪽 subtree, 오른쪽 subtree 순)

시간 복잡도 : O(n)
공간 복잡도 : O(n^2)
(skewed tree의 경우, 최악의 공간 복잡도를 가짐)
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder.length == 0) {
return null;
}
if (preorder.length == 1) {
return new TreeNode(preorder[0]);
}
int currIdx;
for (currIdx = 0; currIdx < inorder.length; currIdx++) {
if (inorder[currIdx] == preorder[0]) {
break;
}
}

int[] lp = new int[currIdx];
int[] li = new int[currIdx];
int[] rp = new int[inorder.length - currIdx - 1];
int[] ri = new int[inorder.length - currIdx - 1];
for (int i = 0; i < currIdx; i++) {
lp[i] = preorder[i + 1];
li[i] = inorder[i];
}
for (int i = currIdx + 1; i < inorder.length; i++) {
rp[i - currIdx - 1] = preorder[i];
ri[i - currIdx - 1] = inorder[i];
}

TreeNode lc = buildTree(lp, li);
TreeNode rc = buildTree(rp, ri);

TreeNode curr = new TreeNode(preorder[0], lc, rc);

return curr;
}
}
55 changes: 55 additions & 0 deletions decode-ways/forest000014.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
# Time Complexity: O(n)
# Space Complexity: O(n)
*/
class Solution {

private boolean check12(char ch) {
return (ch == '1' || ch == '2');
}

private boolean check1(char ch) {
return ch == '1';
}

private boolean check2(char ch) {
return ch == '2';
}

private boolean check0(char ch) {
return ch == '0';
}

private boolean check6(char ch) {
return ch <= '6';
}

public int numDecodings(String s) {
int n = s.length();

if (n == 0)
return 0;

int[] dp = new int[n + 1];

if (check0(s.charAt(0)))
return 0;

dp[0] = 1;
dp[1] = 1;
if (n == 1)
return dp[1];

for (int i = 1; i < n; i++) {
if (check0(s.charAt(i)) && !check12(s.charAt(i - 1)))
return 0;

if (!check0(s.charAt(i)))
dp[i + 1] = dp[i];

if (check1(s.charAt(i - 1)) || (check6(s.charAt(i)) && check2(s.charAt(i - 1))))
dp[i + 1] += dp[i - 1];
}
return dp[n];
}
}
65 changes: 65 additions & 0 deletions graph-valid-tree/forest000014.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
# Time Complexity: O(n)
# Space Complexity: O(n + m)
- m은 edges.length

# Solution
edges[0][0]에서 출발하여 인접한 모든 edge를 DFS로 순회한다.
- cycle이 있는 경우 (이미 방문한 적이 있는 node를 재방문)
- 순회를 마쳤는데 방문하지 않은 node가 있는 경우
위 2경우는 invalid tree이고, 그렇지 않으면 valid tree이다.
*/
class Solution {
public ArrayList<ArrayList<Integer>> adj = new ArrayList<>();
public boolean[] visited;
public boolean validTree(int n, int[][] edges) {
if (edges.length == 0) {
return n == 1;
}

visited = new boolean[n];

for (int i = 0; i < n; i++) {
adj.add(new ArrayList<Integer>());
}

for (int i = 0; i < edges.length; i++) {
int a = edges[i][0];
int b = edges[i][1];
adj.get(a).add(b);
adj.get(b).add(a);
}

if (!dfs(-1, edges[0][0])) {
return false;
}

for (int i = 0; i < n; i++) {
if (!visited[i]) {
return false;
}
}

return true;
}

public boolean dfs(int prev, int curr) {
visited[curr] = true;

for (Integer next : adj.get(curr)) {
if (next == prev) {
continue;
}

if (visited[next]) {
return false;
}

if (!dfs(curr, next)) {
return false;
}
}

return true;
}
}
24 changes: 24 additions & 0 deletions jump-game/forest000014.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
# Time Complexity: O(n)
# Space Complexity: O(n)
*/

class Solution {
public boolean canJump(int[] nums) {
int n = nums.length;
boolean[] dp = new boolean[n];

dp[0] = true;

for (int i = 0; i < n; i++) {
if (!dp[i]) return false;
int j = Math.min(n - 1, i + nums[i]);
for (; j >= i + 1; j--) {
if (dp[j]) break;
dp[j] = true;
}
}

return true;
}
}
28 changes: 28 additions & 0 deletions maximum-depth-of-binary-tree/forest000014.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
# Time Complexity: O(n)
# Space Complexity: O(1)
*/
/**
* 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 Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}

return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
29 changes: 29 additions & 0 deletions merge-intervals/forest000014.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
# Time Complexity: O(nlogn)
# Space Complexity: O(n)
*/

class Solution {
public int[][] merge(int[][] intervals) {
int n = intervals.length;

Arrays.sort(intervals, (a, b) -> a[0] - b[0]);

ArrayList<int[]> ans = new ArrayList<>();
ans.add(new int[2]);
ans.get(0)[0] = intervals[0][0];
ans.get(0)[1] = intervals[0][1];

for (int i = 1; i < n; i++) {
if (ans.get(ans.size() - 1)[1] < intervals[i][0]) {
ans.add(new int[2]);
ans.get(ans.size() - 1)[0] = intervals[i][0];
ans.get(ans.size() - 1)[1] = intervals[i][1];
} else {
ans.get(ans.size() - 1)[1] = Math.max(ans.get(ans.size() - 1)[1], intervals[i][1]);
}
}

return ans.toArray(new int[ans.size()][]);
}
}
Loading