Skip to content

Commit 33bca46

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents a0cc746 + bfe247c commit 33bca46

File tree

19 files changed

+787
-12
lines changed

19 files changed

+787
-12
lines changed

clone-graph/jaejeong1.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import java.util.ArrayList;
2+
import java.util.HashMap;
3+
import java.util.LinkedList;
4+
import java.util.List;
5+
import java.util.Map;
6+
import java.util.Queue;
7+
8+
// Definition for a Node.
9+
class Node {
10+
public int val;
11+
public List<Node> neighbors;
12+
public Node() {
13+
val = 0;
14+
neighbors = new ArrayList<Node>();
15+
}
16+
public Node(int _val) {
17+
val = _val;
18+
neighbors = new ArrayList<Node>();
19+
}
20+
public Node(int _val, ArrayList<Node> _neighbors) {
21+
val = _val;
22+
neighbors = _neighbors;
23+
}
24+
}
25+
26+
27+
class Solution {
28+
// 풀이: BFS 방식으로 그래프를 순회하면서 현재 노드에 연결된 노드들을 복제 여부에 따라 복제 또는 연결 처리해준다
29+
// TC: O(N)
30+
// SC: O(N)
31+
public Node cloneGraph(Node node) {
32+
if (node == null) {
33+
return null;
34+
}
35+
36+
Map<Node, Node> cloneMap = new HashMap<>();
37+
Node clone = new Node(node.val);
38+
cloneMap.put(node, clone);
39+
40+
Queue<Node> queue = new LinkedList<>();
41+
queue.add(node);
42+
43+
while (!queue.isEmpty()) {
44+
Node current = queue.poll();
45+
46+
for (Node neighbor : current.neighbors) {
47+
if (!cloneMap.containsKey(neighbor)) {
48+
cloneMap.put(neighbor, new Node(neighbor.val));
49+
queue.add(neighbor);
50+
}
51+
cloneMap.get(current).neighbors.add(cloneMap.get(neighbor));
52+
}
53+
}
54+
return clone;
55+
}
56+
}

clone-graph/kayden.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from typing import Optional
2+
from collections import deque
3+
4+
5+
class Solution:
6+
# 시간복잡도: O(N) node 개수: N
7+
# 공간복잡도: O(N)
8+
def cloneGraph(self, node: Optional['Node']) -> Optional['Node']:
9+
if node:
10+
visited = {}
11+
copy = Node(val=node.val)
12+
visited[copy.val] = copy
13+
q = deque()
14+
q.append((copy, node))
15+
16+
while q:
17+
cur, node = q.popleft()
18+
19+
for idx, next_node in enumerate(node.neighbors):
20+
if next_node.val not in visited:
21+
new = Node(val=next_node.val)
22+
visited[new.val] = new
23+
q.append((new, next_node))
24+
cur.neighbors.append(visited[next_node.val])
25+
26+
return copy
27+
28+
return node

clone-graph/wogha95.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* TC: O(V + E)
3+
* 모든 정점를 방문하게 되고
4+
* 방문한 정점에서 연결된 간선을 queue에 추가하는 반복문을 실행합니다.
5+
* 따라서 시간복잡도는 정점 + 간선에 선형적으로 비례합니다.
6+
*
7+
* SC: O(V + E)
8+
* memory, visitedNodeVal 에서 V만큼 데이터 공간을 가집니다.
9+
* 그리고 queue에서 최대 모든 간선 갯수 * 2 만큼 갖게 됩니다.
10+
* 따라서 O(V + 2E) = O(V + E)로 계산했습니다.
11+
*
12+
* V: vertex, E: edge
13+
*/
14+
15+
/**
16+
* // Definition for a _Node.
17+
* function _Node(val, neighbors) {
18+
* this.val = val === undefined ? 0 : val;
19+
* this.neighbors = neighbors === undefined ? [] : neighbors;
20+
* };
21+
*/
22+
23+
/**
24+
* @param {_Node} node
25+
* @return {_Node}
26+
*/
27+
var cloneGraph = function (node) {
28+
if (!node) {
29+
return null;
30+
}
31+
32+
const memory = new Map();
33+
const visitedNodeVal = new Set();
34+
35+
return bfsClone(node);
36+
37+
// 1. bfs로 순회하면서 deep clone한 graph의 head를 반환
38+
function bfsClone(start) {
39+
const queue = [start];
40+
const clonedHeadNode = new _Node(start.val);
41+
memory.set(start.val, clonedHeadNode);
42+
43+
while (queue.length > 0) {
44+
const current = queue.shift();
45+
if (visitedNodeVal.has(current.val)) {
46+
continue;
47+
}
48+
49+
const clonedCurrentNode = getCloneNode(current.val);
50+
51+
for (const neighbor of current.neighbors) {
52+
const clonedNeighborNode = getCloneNode(neighbor.val);
53+
clonedCurrentNode.neighbors.push(clonedNeighborNode);
54+
55+
queue.push(neighbor);
56+
}
57+
58+
visitedNodeVal.add(current.val);
59+
}
60+
61+
return clonedHeadNode;
62+
}
63+
64+
// 2. memory에 val에 해당하는 node 반환 (없을 경우 생성)
65+
function getCloneNode(val) {
66+
if (!memory.has(val)) {
67+
const node = new _Node(val);
68+
memory.set(val, node);
69+
return node;
70+
}
71+
72+
return memory.get(val);
73+
}
74+
};

longest-common-subsequence/kayden.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,33 @@
1-
# 시간복잡도: O(N)
2-
# 공간복잡도: O(N)
31
class Solution:
4-
def longestConsecutive(self, nums: List[int]) -> int:
5-
nums = set(nums)
6-
answer = 0
2+
# 시간복잡도: O(A*B)
3+
# 공간복잡도: O(A*B)
4+
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
5+
a = len(text1)
6+
b = len(text2)
77

8-
for num in nums:
9-
if num - 1 not in nums:
10-
length = 1
8+
lcs = [[0]*(b+1) for _ in range(a+1)]
119

12-
while num + length in nums:
13-
length += 1
10+
for i in range(1, a+1):
11+
for j in range(1, b+1):
12+
if text1[i-1] == text2[j-1]:
13+
lcs[i][j] = lcs[i-1][j-1] + 1
14+
lcs[i][j] = max(lcs[i][j], lcs[i-1][j], lcs[i][j-1])
1415

15-
answer = max(answer, length)
16+
return lcs[a][b]
1617

17-
return answer
18+
# 시간복잡도: O(A*B)
19+
# 공간복잡도: O(A)
20+
def longestCommonSubsequence2(self, text1: str, text2: str) -> int:
21+
n = len(text1)
22+
lcs = [0]*n
23+
longest = 0
24+
for ch in text2:
25+
cur = 0
26+
for i in range(n):
27+
if cur < lcs[i]:
28+
cur = lcs[i]
29+
elif ch == text1[i]:
30+
lcs[i] = cur + 1
31+
longest = max(longest, cur+1)
32+
33+
return longest

longest-common-subsequence/wogha95.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* 알고달레 풀이 참고해서 풀었습니다.
3+
* @see https://www.algodale.com/problems/longest-common-subsequence/
4+
*
5+
* DP + 2차원 배열을 이용한 풀이
6+
* 행은 text1, 열은 text2에 대응하고
7+
* index는 text의 처음부터 몇개 문자를 사용할건지 의미합니다.
8+
* 마지막 문자가 동일하다면 dp[index1][index2] = dp[index1 - 1][index2 - 1] + 1
9+
* 마지막 문자가 다르다면 dp[index1][index2] = Math.max(dp[index1 - 1][index2], dp[index1][index2 - 1])
10+
*
11+
* TC: O(T1 * T2)
12+
* 2차원 배열을 순회
13+
*
14+
* SC: O(T1 * T2)
15+
* 2차원 배열 생성
16+
*
17+
* T1: text1.length, T2: text2.length
18+
*/
19+
20+
/**
21+
* @param {string} text1
22+
* @param {string} text2
23+
* @return {number}
24+
*/
25+
var longestCommonSubsequence = function (text1, text2) {
26+
const LENGTH1 = text1.length;
27+
const LENGTH2 = text2.length;
28+
const memory = Array.from({ length: LENGTH1 + 1 }, () =>
29+
Array.from({ length: LENGTH2 + 1 }, () => 0)
30+
);
31+
32+
for (let index1 = 1; index1 <= LENGTH1; index1++) {
33+
for (let index2 = 1; index2 <= LENGTH2; index2++) {
34+
if (text1[index1 - 1] === text2[index2 - 1]) {
35+
memory[index1][index2] = memory[index1 - 1][index2 - 1] + 1;
36+
} else {
37+
memory[index1][index2] = Math.max(
38+
memory[index1 - 1][index2],
39+
memory[index1][index2 - 1]
40+
);
41+
}
42+
}
43+
}
44+
45+
return memory[LENGTH1][LENGTH2];
46+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# 시간복잡도: O(N)
2+
# 공간복잡도: O(N)
3+
class Solution:
4+
def longestConsecutive(self, nums: List[int]) -> int:
5+
nums = set(nums)
6+
answer = 0
7+
8+
for num in nums:
9+
if num - 1 not in nums:
10+
length = 1
11+
12+
while num + length in nums:
13+
length += 1
14+
15+
answer = max(answer, length)
16+
17+
return answer
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import java.util.Collections;
2+
import java.util.HashMap;
3+
import java.util.Map;
4+
5+
class Solution {
6+
public int characterReplacement(String s, int k) {
7+
// 풀이: 슬라이딩 윈도우를 활용해 부분 문자열을 구한다
8+
// 종료 인덱스를 증가시키고, 부분 문자열 길이에서 가장 많이 들어있는 문자의 수를 뺀 값이 k보다 큰지 비교한다.
9+
// 크다면, 시작 인덱스를 증가시킨다.
10+
// 끝까지 반복하면서 최대 길이를 저장했다가 반환한다.
11+
// TC: O(N)
12+
// SC: O(N)
13+
var maxLength = 0;
14+
var start = 0;
15+
var end = 0;
16+
Map<Character, Integer> countByChar = new HashMap<>();
17+
18+
while (end < s.length()) {
19+
countByChar.put(s.charAt(end), countByChar.getOrDefault(s.charAt(end), 0) + 1);
20+
21+
while ((end - start + 1 - Collections.max(countByChar.values())) > k) {
22+
countByChar.put(s.charAt(start), countByChar.get(s.charAt(start)) - 1);
23+
start += 1;
24+
}
25+
maxLength = Math.max(end - start + 1, maxLength);
26+
end++;
27+
}
28+
29+
return maxLength;
30+
}
31+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from collections import defaultdict
2+
3+
class Solution:
4+
# 시간복잡도: O(N)
5+
# 공간복잡도: O(N)
6+
def characterReplacement(self, s: str, k: int) -> int:
7+
8+
n = len(s)
9+
l, r = 0, 1
10+
11+
d = defaultdict(int)
12+
d[s[l]] += 1
13+
14+
longest = 1
15+
while l < r and r < n:
16+
d[s[r]] += 1
17+
if r-l+1 - max(d.values()) > k:
18+
d[s[l]] -= 1
19+
l += 1
20+
longest = max(longest, r-l+1)
21+
r += 1
22+
23+
return longest
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from collections import defaultdict
2+
3+
4+
class Solution:
5+
def characterReplacement(self, s: str, k: int) -> int:
6+
"""
7+
- Idea: 슬라이딩 윈도우를 이용해 현재 윈도우 내에서 가장 자주 나타나는 문자의 개수를 추적한다.
8+
최대 k개의 문자를 바꿨을 때, 모든 문자가 같은 부분 문자열의 최대 길이를 계산한다.
9+
윈도우가 유효하지 않으면, 왼쪽 포인터를 이동시켜 윈도우 크기를 조정한다.
10+
- Time Complexity: O(n), n은 문자열의 길이다. 각 문자를 한번씩 순회하고, 슬라이딩 윈도우를 조정한다.
11+
- Space Complexity: O(26) = O(1), 슬라이딩 윈도우 내에 포함된 문자의 개수를 세기 위한 공간으로, 최대 알파벳 문자의 개수(26개)만큼 늘어날 수 있다.
12+
"""
13+
result = 0
14+
counter = defaultdict(int)
15+
left = 0
16+
17+
for right in range(len(s)):
18+
counter[s[right]] = counter[s[right]] + 1
19+
20+
while (right - left + 1) - max(counter.values()) > k:
21+
counter[s[left]] -= 1
22+
left += 1
23+
24+
result = max(result, right - left + 1)
25+
26+
return result

0 commit comments

Comments
 (0)