Skip to content

Commit ebcfa7c

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 73fb3a1 + cfbf61c commit ebcfa7c

File tree

184 files changed

+5674
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

184 files changed

+5674
-1
lines changed

3sum/Yjason-K.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* 세 수의 합이 0이 되는 모든 고유한 조합을 찾는 함수
3+
*
4+
* @param {number[]} nums - 정수 배열
5+
* @returns {number[][]} - 세 수의 합이 0이 되는 조합 배열
6+
*
7+
* 1. 입력 배열 `nums`를 오름차순으로 정렬.
8+
* 2. 이중 반복문을 사용하여 각 요소를 기준으로 `투 포인터(two-pointer)`를 이용해 조합을 탐색.
9+
* 3. 중복 조합을 방지하기 위해 `Set`을 사용하여 결과 조합의 문자열을 저장.
10+
* 4. 조건에 맞는 조합을 `result` 배열에 추가합니다.
11+
*
12+
* 시간 복잡도:
13+
* - 정렬: O(n log n)
14+
* - 이중 반복문 및 투 포인터: O(n^2)
15+
* - 전체 시간 복잡도: O(n^2)
16+
*
17+
* 공간 복잡도:
18+
* - `Set` 및 `result` 배열에 저장되는 고유 조합: O(k), k는 고유한 조합의 수
19+
* - 전체 공간 복잡도: O(n + k)
20+
*/
21+
function threeSum(nums: number[]): number[][] {
22+
const sumSet = new Set<string>();
23+
const result: number[][] = [];
24+
nums.sort((a, b) => a - b);
25+
26+
// 첫 번째 요소를 기준으로 반복문 수행
27+
for (let i = 0; i < nums.length - 2; i++) {
28+
// 정렬 된 상태이기 때문에 시작점을 기준으로 다음 값 중복 비교
29+
if (i > 0 && nums[i] === nums[i - 1]) continue;
30+
31+
let start = i + 1, end = nums.length - 1;
32+
while (start < end) {
33+
const sum = nums[i] + nums[start] + nums[end];
34+
if (sum > 0) {
35+
end--;
36+
} else if (sum < 0) {
37+
start++;
38+
} else {
39+
const triplet = [nums[i], nums[start], nums[end]];
40+
const key = triplet.toString();
41+
if (!sumSet.has(key)) {
42+
sumSet.add(key);
43+
result.push(triplet);
44+
}
45+
start++;
46+
end--;
47+
}
48+
}
49+
}
50+
51+
return result;
52+
}
53+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* Definition for a binary tree node.
3+
* public class TreeNode {
4+
* int val;
5+
* TreeNode left;
6+
* TreeNode right;
7+
* TreeNode() {}
8+
* TreeNode(int val) { this.val = val; }
9+
* TreeNode(int val, TreeNode left, TreeNode right) {
10+
* this.val = val;
11+
* this.left = left;
12+
* this.right = right;
13+
* }
14+
* }
15+
*/
16+
17+
// preorder에서 맨 왼쪽을 root
18+
// root값을 기반으로 inorder에서 인덱스를 찾는다 그리고 왼쪽 오른쪽 길이를 구한다.
19+
// 다시 buildTree 함수를 재귀하는데 이때 위에서 구한 왼쪽 길이와 오른쪽길이를 참고해서
20+
// 왼쪽 buildTree
21+
// value를 갱신
22+
// 오른쪽 buildTree를 갱신한다.
23+
24+
// 시간복잡도 : O(N^2) -> 한쪽으로 치우친 트리일 경우 O(N)(index of) + T(N-1)이 될 수 있다.
25+
// 위 식을 전개해보면 N + N-1 + N-2 + ... + 1 = N(N+1)/2 = O(N^2)
26+
// 공간복잡도 : O(N) ->리트코드 but N길이의 리스트 크기*N번의 재귀호출이 일어날 수 있다. 따라서 O(N^2)가 아닌가...?
27+
class SolutionGotprgmer {
28+
public TreeNode buildTree(int[] preorder, int[] inorder) {
29+
30+
if(preorder.length == 0 || indexOf(inorder,preorder[0]) == -1){
31+
return null;
32+
}
33+
TreeNode node = new TreeNode();
34+
35+
int root = preorder[0];
36+
int indexOfRoot = indexOf(inorder,root);
37+
int leftCnt = indexOfRoot;
38+
// 찾으면
39+
node.val = root;
40+
node.left = buildTree(Arrays.copyOfRange(preorder,1,1+leftCnt),Arrays.copyOfRange(inorder,0,leftCnt));
41+
node.right = buildTree(Arrays.copyOfRange(preorder,1+leftCnt,preorder.length),Arrays.copyOfRange(inorder,1+leftCnt,inorder.length));
42+
return node;
43+
}
44+
public int indexOf(int[] intArray,int findNum){
45+
for(int i=0;i<intArray.length;i++){
46+
if(findNum==intArray[i]){
47+
return i;
48+
}
49+
}
50+
return -1;
51+
}
52+
53+
}

coin-change/Chaedie.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
"""
2+
직접 풀지 못해 알고달레 풀이를 참고했습니다. https://www.algodale.com/problems/coin-change/
3+
4+
Solution:
5+
1) BFS를 통해 모든 동전을 한번씩 넣어보며 amount와 같아지면 return
6+
7+
(c: coins의 종류 갯수, a: amount)
8+
Time: O(ca)
9+
Space: O(a)
10+
"""
11+
12+
13+
class Solution:
14+
def coinChange(self, coins: List[int], amount: int) -> int:
15+
q = deque([(0, 0)]) # (동전 갯수, 누적 금액)
16+
visited = set()
17+
18+
while q:
19+
count, total = q.popleft()
20+
if total == amount:
21+
return count
22+
if total in visited:
23+
continue
24+
visited.add(total)
25+
for coin in coins:
26+
if total + coin <= amount:
27+
q.append((count + 1, total + coin))
28+
return -1

coin-change/jinah92.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# O(C*A) times, O(A) spaces
2+
class Solution:
3+
def coinChange(self, coins: List[int], amount: int) -> int:
4+
dp = [0] + [amount + 1] * amount
5+
6+
for coin in coins:
7+
for i in range(coin, amount + 1):
8+
dp[i] = min(dp[i], dp[i-coin]+1)
9+
10+
return dp[amount] if dp[amount] < amount + 1 else -1

coin-change/minji-go.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
Problem: https://leetcode.com/problems/coin-change/
3+
Description: return the fewest number of coins that you need to make up that amount
4+
Concept: Array, Dynamic Programming, Breadth-First Search
5+
Time Complexity: O(NM), Runtime 15ms - M is the amount
6+
Space Complexity: O(M), Memory 44.28MB
7+
*/
8+
class Solution {
9+
public int coinChange(int[] coins, int amount) {
10+
int[] dp = new int[amount+1];
11+
Arrays.fill(dp, amount+1);
12+
dp[0]=0;
13+
14+
for(int i=1; i<=amount; i++){
15+
for(int coin : coins){
16+
if(i >= coin) {
17+
dp[i] = Math.min(dp[i], dp[i-coin] +1);
18+
}
19+
}
20+
}
21+
return dp[amount]>amount? -1: dp[amount];
22+
}
23+
}

coin-change/mmyeon.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
*
3+
* 접근 방법 :
4+
* - 동전 최소 개수 구하는 문제니까 DP로 풀기
5+
* - 코인마다 순회하면서 동전 개수 최소값 구하기
6+
* - 기존값과 코인을 뺀 값 + 1 중 작은 값으로 업데이트
7+
*
8+
* 시간복잡도 : O(n * m)
9+
* - 코인 개수 n만큼 순회
10+
* - 각 코인마다 amount 값(m) 될 때까지 순회
11+
*
12+
* 공간복잡도 : O(m)
13+
* - amount 만큼 dp 배열 생성
14+
*
15+
*/
16+
function coinChange(coins: number[], amount: number): number {
17+
const dp = Array(amount + 1).fill(Number.MAX_VALUE);
18+
dp[0] = 0;
19+
20+
for (const coin of coins) {
21+
for (let i = coin; i <= amount; i++) {
22+
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
23+
}
24+
}
25+
26+
return dp[amount] === Number.MAX_VALUE ? -1 : dp[amount];
27+
}

coin-change/pmjuu.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from typing import List
2+
3+
4+
class Solution:
5+
def coinChange(self, coins: List[int], amount: int) -> int:
6+
# dp[i]: i 금액을 만들기 위해 필요한 최소 동전 개수
7+
dp = [float('inf')] * (amount + 1)
8+
dp[0] = 0
9+
10+
for i in range(1, amount + 1):
11+
for coin in coins:
12+
if coin <= i:
13+
dp[i] = min(dp[i], dp[i - coin] + 1)
14+
15+
return dp[amount] if dp[amount] != float('inf') else -1
16+
17+
18+
# 시간 복잡도:
19+
# - 외부 반복문은 금액(amount)의 범위에 비례하고 -> O(n) (n은 amount)
20+
# - 내부 반복문은 동전의 개수에 비례하므로 -> O(m) (m은 coins의 길이)
21+
# - 총 시간 복잡도: O(n * m)
22+
23+
# 공간 복잡도:
24+
# - dp 배열은 금액(amount)의 크기만큼의 공간을 사용하므로 O(n)
25+
# - 추가 공간 사용은 없으므로 총 공간 복잡도: O(n)

combination-sum/Chaedie.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Solution:
3+
최초 풀이 당시엔 단순히 dfs로 풀었으나 시간 초과로 실패했습니다.
4+
이후 풀이 설명을 통해 i 번째 숫자를 넣거나 / 안넣거나 라는 조건으로 i를 늘려가도록 진행하는 백트래킹을 하면 된다는점을 배웠습니다.
5+
이를 통해 불필요한 중복을 줄이고 효율적인 구현이 가능해집니다.
6+
7+
C: len(candidates)
8+
T: target size
9+
10+
Time: O(C^T) = 라고 설명되어 있는데 솔찍히 잘 모르겠습니다.
11+
Space: O(T) = 재귀가 가장 깊을 때 [1,1,1,1...] T 만큼이기 때문에 O(T)
12+
"""
13+
14+
15+
class Solution:
16+
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
17+
result = []
18+
sol = []
19+
n = len(candidates)
20+
21+
def backtrack(i, cur_sum):
22+
if cur_sum == target:
23+
result.append(sol.copy())
24+
return
25+
if cur_sum > target or i == n:
26+
return
27+
28+
backtrack(i + 1, cur_sum)
29+
30+
sol.append(candidates[i])
31+
backtrack(i, cur_sum + candidates[i])
32+
sol.pop()
33+
34+
backtrack(0, 0)
35+
return result

combination-sum/GangBean.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
class Solution {
2+
public List<List<Integer>> combinationSum(int[] candidates, int target) {
3+
/**
4+
1. understanding
5+
- find all combinations, which sum to target
6+
- can use same number multiple times
7+
2. strategy
8+
- dp[target]: all combination, which sum to target
9+
- dp[n + 1] = dp[n] | dp[1]
10+
- [2,3,6,7], target = 7
11+
- dp[0] = [[]]
12+
- dp[1] = [[]]
13+
- dp[2] = [[2]]
14+
- dp[3] = [[3]]
15+
- dp[4] = dp[2] | dp[2] = [[2,2]]
16+
- dp[5] = dp[2] | dp[3] = [[2,3]]
17+
- dp[6] = dp[2] | dp[4] , dp[3] | dp[3] = [[2,2,2], [3,3]]
18+
- dp[7] = dp[2] | dp[5], dp[3] | dp[4], dp[6] | dp[1], dp[7] = [[2,2,3],]
19+
3. complexity
20+
- time: O(target * N) where N is length of candidates
21+
- space: O(target * N)
22+
*/
23+
List<List<Integer>>[] dp = new List[target + 1];
24+
for (int i = 0; i <= target; i++) {
25+
dp[i] = new ArrayList<>();
26+
}
27+
28+
dp[0].add(new ArrayList<>());
29+
30+
for (int candidate : candidates) {
31+
for (int i = candidate; i <= target; i++) {
32+
for (List<Integer> combination : dp[i - candidate]) {
33+
List<Integer> newCombination = new ArrayList<>(combination);
34+
newCombination.add(candidate);
35+
dp[i].add(newCombination);
36+
}
37+
}
38+
}
39+
40+
return dp[target];
41+
}
42+
}
43+

combination-sum/HerrineKim.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// 시간 복잡도 : O(n^2)
2+
// 공간 복잡도 : O(n)
3+
4+
/**
5+
* @param {number[]} candidates
6+
* @param {number} target
7+
* @return {number[][]}
8+
*/
9+
10+
var combinationSum = function(candidates, target) {
11+
const result = [];
12+
13+
const backtrack = (remaining, combo, start) => {
14+
if (remaining === 0) {
15+
result.push([...combo]);
16+
return;
17+
}
18+
19+
for (let i = start; i < candidates.length; i++) {
20+
if (candidates[i] <= remaining) {
21+
combo.push(candidates[i]);
22+
backtrack(remaining - candidates[i], combo, i);
23+
combo.pop();
24+
}
25+
}
26+
};
27+
28+
backtrack(target, [], 0);
29+
return result;
30+
};

combination-sum/HodaeSsi.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# 시간복잡도 : O(n * m) (n: target, m: len(candidates))
2+
# 공간복잡도 : O(n * m)
3+
class Solution:
4+
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
5+
dp = [[] for _ in range(target + 1)]
6+
dp[0] = [[]]
7+
8+
for candidate in candidates:
9+
for num in range(candidate, target + 1):
10+
for combination in dp[num - candidate]:
11+
temp = combination.copy()
12+
temp.extend([candidate])
13+
dp[num].append(temp)
14+
15+
return dp[target]
16+

combination-sum/Real-Reason.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package leetcode_study
2+
3+
fun combinationSum(candidates: IntArray, target: Int): List<List<Int>> {
4+
val result = mutableListOf<List<Int>>()
5+
val nums = ArrayDeque<Int>()
6+
dfs(candidates, target, 0, 0, nums, result)
7+
8+
return result
9+
}
10+
11+
private fun dfs(candidates: IntArray, target: Int, startIdx: Int, total: Int, nums: ArrayDeque<Int>, result: MutableList<List<Int>>) {
12+
if (target < total) return
13+
if (target == total) {
14+
result.add(ArrayList(nums))
15+
return
16+
}
17+
for (i in startIdx..< candidates.size) {
18+
val num = candidates[i]
19+
nums.add(num)
20+
dfs(candidates, target, i, total + num, nums, result)
21+
nums.removeLast()
22+
}
23+
}

0 commit comments

Comments
 (0)