Skip to content

Commit cfbf61c

Browse files
authored
Merge pull request #820 from mmyeon/main
[mallayon] Week 4
2 parents 05ff4b2 + 8df437d commit cfbf61c

File tree

5 files changed

+206
-0
lines changed

5 files changed

+206
-0
lines changed

coin-change/mmyeon.ts

+27
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+
}

merge-two-sorted-lists/mmyeon.ts

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
class ListNode {
2+
val: number;
3+
next: ListNode | null;
4+
constructor(val?: number, next?: ListNode | null) {
5+
this.val = val === undefined ? 0 : val;
6+
this.next = next === undefined ? null : next;
7+
}
8+
}
9+
10+
/**
11+
*
12+
* 접근 방법 :
13+
* - 2개의 정렬된 링크드 리스트가 주어지니까 각 리스트 값 비교하면서 작은 값을 새로운 링크드 리스트에 추가
14+
* - 링크드 리스트 head에 접근해야하니까 더미노드와 포인터 변수 분리해서 사용
15+
* - 포인터 변수 사용해서 노드 연결하기
16+
* - 두 링크드 리스트가 있는 동안 반복하고, 한 쪽이 끝나면 나머지 노드를 그대로 새로운 링크드 리스트에 추가
17+
*
18+
* 시간복잡도 : O(n+k)
19+
* - n은 list1 길이, k는 list2 길이 => 두 리스트 모두 반복하니까 O(n+k)
20+
*
21+
* 공간복잡도 : O(1)
22+
* - 기존 노드 연결해서 재사용하니까 O(1)
23+
*/
24+
25+
function mergeTwoLists(
26+
list1: ListNode | null,
27+
list2: ListNode | null
28+
): ListNode | null {
29+
const dummyNode = new ListNode();
30+
let current = dummyNode;
31+
32+
while (list1 !== null && list2 !== null) {
33+
if (list1.val <= list2.val) {
34+
current.next = list1;
35+
list1 = list1.next;
36+
current = current.next;
37+
} else {
38+
current.next = list2;
39+
list2 = list2.next;
40+
current = current.next;
41+
}
42+
}
43+
current.next = list1 !== null ? list1 : list2;
44+
45+
return dummyNode.next;
46+
}

missing-number/mmyeon.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
*
3+
* 접근 방법 :
4+
* - 연속되는 숫자 중 빠진 숫자 찾는 거니까 배열 인덱스를 활용하자.
5+
* - 배열 요소 순회하면서 map에 요소를 키로 넣고, nums 길이만큼 순회하면서 map에 값 있는지 체크
6+
* - 없으면 해당 인덱스 리턴하고, 순회 끝나면 nums 길이 리턴
7+
*
8+
* 시간복잡도 : O(n)
9+
* - nums 길이만큼 map에 요소 넣고, map에 요소 있는지 체크하니까 O(n)
10+
*
11+
* 공간복잡도 : O(n)
12+
* - map에 nums 길이만큼 저장하니까 O(n)
13+
*/
14+
15+
function missingNumber(nums: number[]): number {
16+
const set = new Set(nums);
17+
18+
for (let i = 0; i < nums.length; i++) {
19+
if (!set.has(i)) return i;
20+
}
21+
22+
return nums.length;
23+
}
24+
25+
// 공간복잡도 O(1) 개선 방법
26+
// - 0부터 n까지의 합 구하고, 실제 nums 요소 값 빼서 빠진 숫자 구함
27+
function missingNumber(nums: number[]): number {
28+
let sum = 0;
29+
30+
for (let i = 0; i <= nums.length; i++) {
31+
sum += i;
32+
if (i < nums.length) sum -= nums[i];
33+
}
34+
35+
return sum;
36+
}

palindromic-substrings/mmyeon.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
*
3+
* 접근 방법 :
4+
* - 각 문자열에서 회문 조건 충족하는 경우 중심을 기준으로 확장해나가기 위해 투 포인터 사용
5+
* - 문자가 같고 범위 내에 있는 경우 확장해나가면서 횟수 업데이트
6+
* - 홀수 회문과 다르게 짝수 회문은 중심을 2문자에서 시작되어야 하니까 인덱스 별도 처리
7+
*
8+
* 시간복잡도 : O(n^2)
9+
* - 문자열 길이가 n일 때, for문에서 각 문자마다 최대 문자열 길이까지 비교하니까 O(n^2)
10+
*
11+
* 공간복잡도 : O(1)
12+
*
13+
*/
14+
15+
function countPalindromes(s: string, left: number, right: number): number {
16+
let count = 0;
17+
18+
while (0 <= left && right < s.length && s[left] === s[right]) {
19+
count++;
20+
left--;
21+
right++;
22+
}
23+
24+
return count;
25+
}
26+
27+
function countSubstrings(s: string): number {
28+
let count = 0;
29+
30+
for (let i = 0; i < s.length; i++) {
31+
// 홀수 회문 카운트
32+
count += countPalindromes(s, i, i);
33+
// 짝수 회문 카운트
34+
count += countPalindromes(s, i, i + 1);
35+
}
36+
return count;
37+
}

word-search/mmyeon.ts

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
*
3+
* 접근 방법 :
4+
* 1. 행렬 순회하며 word와 첫 번째 문자가 같은지 체크
5+
* 2. 같으면 DFS(재귀)로 네 방향(상하좌우)을 탐색한다.
6+
* - 현재 위치가 유효한지 체크 = 범위 안인가, 문자가 같은가
7+
* - 단어 다 찾아서 index가 단어 길이와 같은지 체크
8+
* 3. 이미 방문한 노드 제외하기 위해서 네 방향 체크하기 전에 방문 여부 표시하기
9+
* 4. 4방향으로 문자 체크하기
10+
* 5. 재귀 호출하는 동안 찾지 못한 경우 방문 여부 초기화하기 (backtracking)
11+
*
12+
* 시간복잡도 : O(N * M * 4^L)
13+
* - L는 word의 길이, word 길이만큼 네 방향 체크하니까 O(4^L)
14+
* 공간복잡도 : O(L)
15+
*
16+
* - L는 word의 길이, 찾으려는 단어 길이만큼 재귀 호출되니까 O(L)
17+
*
18+
*/
19+
20+
function exist(board: string[][], word: string): boolean {
21+
const rows = board.length;
22+
const cols = board[0].length;
23+
24+
const dfs = (x: number, y: number, index: number): boolean => {
25+
// 종료조건 : 문자를 다 찾은 경우
26+
if (index === word.length) return true;
27+
28+
// 범위를 벗어나거나 이미 방문했거나 문자가 다른 경우
29+
if (x < 0 || y < 0 || x >= rows || y >= cols || board[x][y] !== word[index])
30+
return false;
31+
32+
// 방문 표시
33+
const temp = board[x][y];
34+
board[x][y] = "#";
35+
36+
// 4 방향
37+
const directions = [
38+
[1, 0],
39+
[0, 1],
40+
[-1, 0],
41+
[0, -1],
42+
];
43+
44+
for (const [dx, dy] of directions) {
45+
if (dfs(x + dx, y + dy, index + 1)) return true;
46+
}
47+
48+
// 백트래킹
49+
board[x][y] = temp;
50+
return false;
51+
};
52+
53+
for (let i = 0; i < rows; i++) {
54+
for (let j = 0; j < cols; j++) {
55+
if (word[0] === board[i][j] && dfs(i, j, 0)) return true;
56+
}
57+
}
58+
59+
return false;
60+
}

0 commit comments

Comments
 (0)