Skip to content

Commit

Permalink
Merge pull request #820 from mmyeon/main
Browse files Browse the repository at this point in the history
[mallayon] Week 4
  • Loading branch information
mmyeon authored Jan 3, 2025
2 parents 05ff4b2 + 8df437d commit cfbf61c
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 0 deletions.
27 changes: 27 additions & 0 deletions coin-change/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
*
* 접근 방법 :
* - 동전 최소 개수 구하는 문제니까 DP로 풀기
* - 코인마다 순회하면서 동전 개수 최소값 구하기
* - 기존값과 코인을 뺀 값 + 1 중 작은 값으로 업데이트
*
* 시간복잡도 : O(n * m)
* - 코인 개수 n만큼 순회
* - 각 코인마다 amount 값(m) 될 때까지 순회
*
* 공간복잡도 : O(m)
* - amount 만큼 dp 배열 생성
*
*/
function coinChange(coins: number[], amount: number): number {
const dp = Array(amount + 1).fill(Number.MAX_VALUE);
dp[0] = 0;

for (const coin of coins) {
for (let i = coin; i <= amount; i++) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}

return dp[amount] === Number.MAX_VALUE ? -1 : dp[amount];
}
46 changes: 46 additions & 0 deletions merge-two-sorted-lists/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
class ListNode {
val: number;
next: ListNode | null;
constructor(val?: number, next?: ListNode | null) {
this.val = val === undefined ? 0 : val;
this.next = next === undefined ? null : next;
}
}

/**
*
* 접근 방법 :
* - 2개의 정렬된 링크드 리스트가 주어지니까 각 리스트 값 비교하면서 작은 값을 새로운 링크드 리스트에 추가
* - 링크드 리스트 head에 접근해야하니까 더미노드와 포인터 변수 분리해서 사용
* - 포인터 변수 사용해서 노드 연결하기
* - 두 링크드 리스트가 있는 동안 반복하고, 한 쪽이 끝나면 나머지 노드를 그대로 새로운 링크드 리스트에 추가
*
* 시간복잡도 : O(n+k)
* - n은 list1 길이, k는 list2 길이 => 두 리스트 모두 반복하니까 O(n+k)
*
* 공간복잡도 : O(1)
* - 기존 노드 연결해서 재사용하니까 O(1)
*/

function mergeTwoLists(
list1: ListNode | null,
list2: ListNode | null
): ListNode | null {
const dummyNode = new ListNode();
let current = dummyNode;

while (list1 !== null && list2 !== null) {
if (list1.val <= list2.val) {
current.next = list1;
list1 = list1.next;
current = current.next;
} else {
current.next = list2;
list2 = list2.next;
current = current.next;
}
}
current.next = list1 !== null ? list1 : list2;

return dummyNode.next;
}
36 changes: 36 additions & 0 deletions missing-number/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
*
* 접근 방법 :
* - 연속되는 숫자 중 빠진 숫자 찾는 거니까 배열 인덱스를 활용하자.
* - 배열 요소 순회하면서 map에 요소를 키로 넣고, nums 길이만큼 순회하면서 map에 값 있는지 체크
* - 없으면 해당 인덱스 리턴하고, 순회 끝나면 nums 길이 리턴
*
* 시간복잡도 : O(n)
* - nums 길이만큼 map에 요소 넣고, map에 요소 있는지 체크하니까 O(n)
*
* 공간복잡도 : O(n)
* - map에 nums 길이만큼 저장하니까 O(n)
*/

function missingNumber(nums: number[]): number {
const set = new Set(nums);

for (let i = 0; i < nums.length; i++) {
if (!set.has(i)) return i;
}

return nums.length;
}

// 공간복잡도 O(1) 개선 방법
// - 0부터 n까지의 합 구하고, 실제 nums 요소 값 빼서 빠진 숫자 구함
function missingNumber(nums: number[]): number {
let sum = 0;

for (let i = 0; i <= nums.length; i++) {
sum += i;
if (i < nums.length) sum -= nums[i];
}

return sum;
}
37 changes: 37 additions & 0 deletions palindromic-substrings/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
*
* 접근 방법 :
* - 각 문자열에서 회문 조건 충족하는 경우 중심을 기준으로 확장해나가기 위해 투 포인터 사용
* - 문자가 같고 범위 내에 있는 경우 확장해나가면서 횟수 업데이트
* - 홀수 회문과 다르게 짝수 회문은 중심을 2문자에서 시작되어야 하니까 인덱스 별도 처리
*
* 시간복잡도 : O(n^2)
* - 문자열 길이가 n일 때, for문에서 각 문자마다 최대 문자열 길이까지 비교하니까 O(n^2)
*
* 공간복잡도 : O(1)
*
*/

function countPalindromes(s: string, left: number, right: number): number {
let count = 0;

while (0 <= left && right < s.length && s[left] === s[right]) {
count++;
left--;
right++;
}

return count;
}

function countSubstrings(s: string): number {
let count = 0;

for (let i = 0; i < s.length; i++) {
// 홀수 회문 카운트
count += countPalindromes(s, i, i);
// 짝수 회문 카운트
count += countPalindromes(s, i, i + 1);
}
return count;
}
60 changes: 60 additions & 0 deletions word-search/mmyeon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
*
* 접근 방법 :
* 1. 행렬 순회하며 word와 첫 번째 문자가 같은지 체크
* 2. 같으면 DFS(재귀)로 네 방향(상하좌우)을 탐색한다.
* - 현재 위치가 유효한지 체크 = 범위 안인가, 문자가 같은가
* - 단어 다 찾아서 index가 단어 길이와 같은지 체크
* 3. 이미 방문한 노드 제외하기 위해서 네 방향 체크하기 전에 방문 여부 표시하기
* 4. 4방향으로 문자 체크하기
* 5. 재귀 호출하는 동안 찾지 못한 경우 방문 여부 초기화하기 (backtracking)
*
* 시간복잡도 : O(N * M * 4^L)
* - L는 word의 길이, word 길이만큼 네 방향 체크하니까 O(4^L)
* 공간복잡도 : O(L)
*
* - L는 word의 길이, 찾으려는 단어 길이만큼 재귀 호출되니까 O(L)
*
*/

function exist(board: string[][], word: string): boolean {
const rows = board.length;
const cols = board[0].length;

const dfs = (x: number, y: number, index: number): boolean => {
// 종료조건 : 문자를 다 찾은 경우
if (index === word.length) return true;

// 범위를 벗어나거나 이미 방문했거나 문자가 다른 경우
if (x < 0 || y < 0 || x >= rows || y >= cols || board[x][y] !== word[index])
return false;

// 방문 표시
const temp = board[x][y];
board[x][y] = "#";

// 4 방향
const directions = [
[1, 0],
[0, 1],
[-1, 0],
[0, -1],
];

for (const [dx, dy] of directions) {
if (dfs(x + dx, y + dy, index + 1)) return true;
}

// 백트래킹
board[x][y] = temp;
return false;
};

for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
if (word[0] === board[i][j] && dfs(i, j, 0)) return true;
}
}

return false;
}

0 comments on commit cfbf61c

Please sign in to comment.