Skip to content

Commit f527385

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 8712bec + 552db31 commit f527385

File tree

18 files changed

+657
-0
lines changed

18 files changed

+657
-0
lines changed

.github/workflows/automation.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,28 @@ jobs:
2424
- uses: actions/labeler@v5
2525
with:
2626
repo-token: ${{ github.token }}
27+
28+
assign-reviewer:
29+
runs-on: ubuntu-latest
30+
steps:
31+
- name: Get previous PR author and assign as reviewer
32+
env:
33+
GITHUB_TOKEN: ${{ github.token }}
34+
run: |
35+
current_repo=${{ github.repository }}
36+
current_pr_num=${{ github.event.number }}
37+
38+
# 이전 PR 중에서 현재 PR 작성자와 다른 작성자 찾기
39+
previous_pr_author=$(gh pr list --repo $current_repo \
40+
--state all \
41+
--search "created:<${{ github.event.pull_request.created_at }} sort:created-desc -author:${{ github.actor }}" \
42+
--limit 3 \
43+
--json number,author \
44+
--jq "map(select(.number < $current_pr_num))[0].author.login")
45+
46+
if [ -n "$previous_pr_author" ]; then
47+
gh pr edit $current_pr_num --repo $current_repo --add-reviewer $previous_pr_author
48+
else
49+
echo "❌ No previous PR author found to assign as reviewer"
50+
exit 1
51+
fi

find-median-from-data-stream/flynn.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
풀이
3+
- 이진탐색을 이용합니다
4+
Big O
5+
- N: 현재 MedianFinder.nums의 크기
6+
- AddNum
7+
- Time complexity: O(N)
8+
- bisect -> O(logN)
9+
- slices.Insert -> O(N)
10+
- Space complexity: O(1)
11+
- FindMedian
12+
- Time complexity: O(1)
13+
- Space complexity: O(1)
14+
*/
15+
16+
import "slices"
17+
18+
type MedianFinder struct {
19+
nums []int
20+
}
21+
22+
func Constructor() MedianFinder {
23+
mf := MedianFinder{}
24+
mf.nums = make([]int, 0)
25+
return mf
26+
}
27+
28+
func (this *MedianFinder) AddNum(num int) {
29+
n := len(this.nums)
30+
if n == 0 {
31+
this.nums = append(this.nums, num)
32+
} else {
33+
idx := bisectLeft(this.nums, num)
34+
this.nums = slices.Insert(this.nums, idx, num)
35+
}
36+
}
37+
38+
func (this *MedianFinder) FindMedian() float64 {
39+
n := len(this.nums)
40+
if n%2 == 0 {
41+
return (float64(this.nums[n/2-1]) + float64(this.nums[n/2])) / 2
42+
} else {
43+
return float64(this.nums[n/2])
44+
}
45+
}
46+
47+
// ----- Helper -----
48+
func bisectLeft(arr []int, x int) int {
49+
lo := 0
50+
hi := len(arr)
51+
for lo < hi {
52+
mid := lo + (hi-lo)/2
53+
if arr[mid] < x {
54+
lo = mid + 1
55+
} else {
56+
hi = mid
57+
}
58+
}
59+
return lo
60+
}
61+
62+
/**
63+
* Your MedianFinder object will be instantiated and called as such:
64+
* obj := Constructor();
65+
* obj.AddNum(num);
66+
* param_2 := obj.FindMedian();
67+
*/

house-robber/flynn.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
풀이 1
3+
- DP를 이용하여 풀이합니다
4+
아래 배열 두 개를 이용합니다
5+
robbed[i]: i번째 집을 털면서 구한 rob(nums[:i+1])의 최대값
6+
unrobbed[i]: i번째 집을 안 털면서 구한 rob(nums[:i+1])의 최대값
7+
두 배열을 이용하여 아래와 같은 점화식을 세울 수 있습니다
8+
robbed[i] = nums[i] + max(robbed[i-2], unrobbed[i-1])
9+
unrobbed[i] = max(robbed[i-1], unrobbed[i-1])
10+
Big O
11+
- N: nums의 길이
12+
- Time complexity: O(N)
13+
- Space complexity: O(N)
14+
*/
15+
16+
func rob(nums []int) int {
17+
n := len(nums)
18+
19+
if n == 1 {
20+
return nums[0]
21+
}
22+
23+
robbed := make([]int, n)
24+
robbed[0] = nums[0]
25+
robbed[1] = nums[1]
26+
27+
unrobbed := make([]int, n)
28+
unrobbed[1] = nums[0]
29+
30+
for i := 2; i < n; i++ {
31+
robbed[i] = nums[i] + max(robbed[i-2], unrobbed[i-1])
32+
unrobbed[i] = max(robbed[i-1], unrobbed[i-1])
33+
}
34+
35+
return max(robbed[n-1], unrobbed[n-1])
36+
}
37+
38+
/*
39+
풀이 2
40+
- 풀이 1과 동일한데, memoization을 위해 배열을 사용하지 않습니다
41+
robbed[i], unrobbed[i] 계산에는 robbed[i-2], robbed[i-1], unrobbed[i-1]만 있어도 충분하기 때문입니다
42+
Big O
43+
- N: nums의 길이
44+
- Time complexity: O(N)
45+
- Space complexity: O(1)
46+
*/
47+
48+
func rob(nums []int) int {
49+
n := len(nums)
50+
51+
if n == 1 {
52+
return nums[0]
53+
}
54+
55+
ppRobbed := nums[0] // robbed[i-2]에 해당
56+
pRobbed := nums[1] // robbed[i-1]에 해당
57+
pUnrobbed := nums[0] // unrobbed[i-1]에 해당
58+
59+
for i := 2; i < n; i++ {
60+
ppRobbed, pRobbed, pUnrobbed = pRobbed, nums[i]+max(ppRobbed, pUnrobbed), max(pRobbed, pUnrobbed)
61+
}
62+
63+
return max(pRobbed, pUnrobbed)
64+
}
65+
66+
func max(a, b int) int {
67+
if a > b {
68+
return a
69+
} else {
70+
return b
71+
}
72+
}

house-robber/jaejeong1.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class Solution {
2+
public int rob(int[] nums) {
3+
// 인접한 경우는 제외한 최대 합
4+
// 풀이: dp로 풀이한다. dp[i] = max(dp[i-1], dp[i-2] + nums[i])
5+
// TC: O(N), SC: O(N)
6+
if (nums.length == 1) {
7+
return nums[0];
8+
}
9+
10+
var dp = new int[nums.length];
11+
dp[0] = nums[0];
12+
dp[1] = Math.max(nums[0], nums[1]);
13+
14+
for (int i=2; i<nums.length; i++) {
15+
dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]);
16+
}
17+
18+
return dp[nums.length-1];
19+
}
20+
}

house-robber/jdalma.kt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
import kotlin.math.max
6+
7+
class `house-robber` {
8+
9+
fun rob(nums: IntArray): Int {
10+
return usingDP(nums)
11+
}
12+
13+
/**
14+
* TC: O(n), SC: O(n)
15+
*/
16+
private fun usingDP(nums: IntArray): Int {
17+
val dp = IntArray(nums.size + 1).apply {
18+
this[0] = 0
19+
this[1] = nums[0]
20+
}
21+
for (index in 1 until nums.size) {
22+
dp[index + 1] = max(nums[index] + dp[index - 1], dp[index])
23+
}
24+
25+
return dp[nums.size]
26+
}
27+
28+
/**
29+
* TC: O(n), SC: O(n)
30+
*/
31+
private fun usingMemoization(nums: IntArray): Int {
32+
val memo = IntArray(nums.size) { -1 }
33+
fun recursive(index: Int): Int {
34+
return if (index > nums.size - 1) 0
35+
else if (memo[index] != -1) memo[index]
36+
else {
37+
memo[index] = max(nums[index] + recursive(index + 2), recursive(index + 1))
38+
memo[index]
39+
}
40+
}
41+
42+
return recursive(0)
43+
}
44+
45+
/**
46+
* 시간초과
47+
* TC: O(2^n), SC: O(n)
48+
*/
49+
private fun usingRecursive(nums:IntArray): Int {
50+
fun recursive(index: Int, depth: Int): Int {
51+
if (index > nums.size - 1) return 0
52+
println("${"-".repeat(depth)} : max($index + ${index + 2}, ${index + 1})")
53+
return max(nums[index] + recursive(index + 2, depth + 1), recursive(index + 1, depth + 1))
54+
}
55+
56+
return recursive(0, 0)
57+
}
58+
59+
@Test
60+
fun `인접하지 않은 원소를 선택하여 최대의 합을 반환한다`() {
61+
rob(intArrayOf(1,2,3,1)) shouldBe 4
62+
rob(intArrayOf(2,7,9,3,1)) shouldBe 12
63+
rob(intArrayOf(8,7,9,11,1)) shouldBe 19
64+
}
65+
}

house-robber/kayden.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class Solution:
2+
# 시간복잡도: O(N)
3+
# 공간복잡도: O(1)
4+
def rob(self, nums: List[int]) -> int:
5+
one, two = 0, 0
6+
7+
for num in nums:
8+
temp = max(two+num, one)
9+
two, one = one, temp
10+
11+
return one

house-robber/mangodm-web.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from typing import List
2+
3+
4+
class Solution:
5+
def rob(self, nums: List[int]) -> int:
6+
"""
7+
- Idea: i번째 집까지의 최대 금액은 두 가지 중 더 큰 값으로 결정된다.
8+
1. (i-2번째 집까지의 최대 금액) + i번째 집의 금액
9+
2. (i-1번째 집까지의 최대 금액)
10+
이를 이용해 동적 프로그래밍으로 각 집까지의 최대 금액을 계산한다.
11+
중간 결과를 저장할 배열을 만들고 순차적으로 값을 채우면, 맨 마지막 값이 전체 최대 금액이 된다.
12+
- Time Complexity: O(n). n은 집의 개수.
13+
모든 집을 한번씩 순회해야 하므로 O(n) 시간이 걸린다.
14+
- Space Complexity: O(n). n은 집의 개수.
15+
각 집까지의 최대 금액을 저장하기 위해 배열을 사용하므로 O(n) 만큼의 메모리가 필요하다.
16+
"""
17+
if len(nums) == 1:
18+
return nums[0]
19+
20+
dp = [0] * len(nums)
21+
dp[0] = nums[0]
22+
dp[1] = max(nums[0], nums[1])
23+
24+
for i in range(2, len(nums)):
25+
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])
26+
27+
return dp[-1]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
풀이
3+
- common ancestor라는 조건에 맞는 node를 찾아냅니다
4+
for common ancestor C, left subtree of C includes p (p.Val <= C.Val)
5+
and right subtree of C includes q (C.Val <= q.Val)
6+
이러한 조건을 만족하는 common ancestor는 BST에 하나만 존재합니다
7+
따라서 common ancestor를 찾으면 그게 곧 lowest common ancestor입니다
8+
Big O
9+
- N: 노드의 개수
10+
- H: 트리의 높이 (avg: logN, worst: N)
11+
- Time complexity: O(H)
12+
- Space complexity: O(H)
13+
*/
14+
15+
/**
16+
* Definition for a binary tree node.
17+
* type TreeNode struct {
18+
* Val int
19+
* Left *TreeNode
20+
* Right *TreeNode
21+
* }
22+
*/
23+
24+
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
25+
if p.Val > q.Val { // p < q가 되도록 함
26+
return lowestCommonAncestor(root, q, p)
27+
}
28+
if p.Val <= root.Val && root.Val <= q.Val { // common ancestor를 찾음
29+
return root
30+
} else if q.Val < root.Val { // left subtree 탐색
31+
return lowestCommonAncestor(root.Left, p, q)
32+
} else { // right subtree 탐색
33+
return lowestCommonAncestor(root.Right, p, q)
34+
}
35+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
// Definition for a binary tree node.
3+
class TreeNode {
4+
int val;
5+
TreeNode left;
6+
TreeNode right;
7+
8+
TreeNode(int x) {
9+
val = x;
10+
}
11+
}
12+
13+
14+
class Solution {
15+
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
16+
// 플이: p,q 둘다 root 보다 값이 적으면 왼쪽 서브트리를, 둘다 크면 오른쪽 서브트리를 탐색해야한다.
17+
// 그렇지 않으면 해당 root가 최저 공통 조상이 된다.
18+
// TC: O(H), H: 트리의 높이
19+
// SC: O(1)
20+
var node = root;
21+
while (node != null) {
22+
if (p.val < node.val && q.val < node.val) {
23+
node = node.left;
24+
} else if (p.val > node.val && q.val > node.val) {
25+
node = node.right;
26+
} else {
27+
break;
28+
}
29+
}
30+
31+
return node;
32+
}
33+
}

0 commit comments

Comments
 (0)