Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions _algorithms/JS-리트코드/leet-200.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
title: "[리트코드] Number of Islands 자바스크립트 풀이"
excerpt: "알고리즘 재활훈련 - 그래프 탐색"
coverImage: "/assets/algorithms/JS-리트코드/cover.png"
date: "2026-06-01T20:00:00"
ogImage:
url: "/assets/algorithms/JS-리트코드/cover.png"
---

## 문제

m x n 크기의 2차원 이진 그리드 grid가 주어집니다. grid는 '1'(땅)과 '0'(물)로 이루어진 지도를 나타냅니다.

섬의 개수를 반환하세요.

섬은 물에 둘러싸여 있으며, 가로 또는 세로로 인접한 땅들을 연결해 형성됩니다. 그리드의 네 변은 모두 물로 둘러싸여 있다고 가정해도 됩니다.

[문제출처](https://leetcode.com/problems/number-of-islands/)

**예시 1:**

입력: grid = [
["1","1","1","1","0"],
["1","1","0","1","0"],
["1","1","0","0","0"],
["0","0","0","0","0"]
]
출력: 1

 

**예시 2:**

입력: grid = [
["1","1","0","0","0"],
["1","1","0","0","0"],
["0","0","1","0","0"],
["0","0","0","1","1"]
]
출력: 3

 

**제약 조건:**

- m == grid.length
- n == grid[i].length
- 1 <= m, n <= 300
- grid[i][j]는 '0' 또는 '1'이다.

## 내풀이

### 접근: 이중 for문 + DFS(재귀)로 연결된 땅 제거

- grid 전체를 이중 for문으로 순회
- "1"을 만나면 새로운 섬 → result += 1
- recursive로 상하좌우 탐색하며 연결된 "1"을 "0"으로 바꿈 (visited 대신 grid 자체를 수정)
- 경계 밖(row/col < 0 또는 >= end)이면 return

&nbsp;

### 코드

```javascript
/**
* @param {character[][]} grid
* @return {number}
*/
var numIslands = function (grid) {
let result = 0;
const end_row = grid.length;
const end_col = grid[0].length;
Comment on lines +70 to +72

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

입력 grid가 빈 배열이거나 null/undefined인 경우, grid[0]에 접근할 때 TypeError가 발생할 수 있습니다. 실제 서비스 환경이나 견고한 코드를 위해 예외 처리를 추가하는 것이 좋습니다.

Suggested change
let result = 0;
const end_row = grid.length;
const end_col = grid[0].length;
if (!grid || grid.length === 0 || grid[0].length === 0) {
return 0;
}
let result = 0;
const end_row = grid.length;
const end_col = grid[0].length;


const recursive = (row, col) => {
if (row < 0 || row >= end_row || col < 0 || col >= end_col) {
return;
}

// 재귀 타면서 연결된 땅은 0으로 변환 → for문에서 같은 섬을 다시 세지 않도록
if (grid[row][col] === "1") {
grid[row][col] = "0";
recursive(row - 1, col);
recursive(row, col - 1);
recursive(row + 1, col);
recursive(row, col + 1);
}
};

for (let m = 0; m < grid.length; m++) {
for (let n = 0; n < grid[0].length; n++) {
if (grid[m][n] === "1") {
recursive(m, n);
result += 1;
}
}
}

return result;
};
```

&nbsp;

### 복잡도

- 시간 복잡도: O(m × n) — 각 칸을 최대 1번 방문
- 공간 복잡도: O(m × n) — 재귀 호출 스택 (최악: 섬이 한 줄로 길게 이어질 때)
127 changes: 127 additions & 0 deletions _algorithms/JS-리트코드/leet-62.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
---
title: "[리트코드] Unique Paths 자바스크립트 풀이"
excerpt: "알고리즘 재활훈련 - 동적 계획법"
coverImage: "/assets/algorithms/JS-리트코드/cover.png"
date: "2026-06-01T19:40:00"
ogImage:
url: "/assets/algorithms/JS-리트코드/cover.png"
---

## 문제

m x n 크기의 격자가 있습니다. 로봇은 처음에 **왼쪽 위 모서리 (0, 0)** 에 있습니다. 로봇은 **오른쪽 아래 모서리 (m - 1, n - 1)** 로 이동하려고 합니다.

로봇은 한 번에 **아래** 또는 **오른쪽**으로만 이동할 수 있습니다.

정수 m, n이 주어질 때, 로봇이 오른쪽 아래 모서리에 도달할 수 있는 **서로 다른 경로의 수**를 반환하세요.

[문제출처](https://leetcode.com/problems/unique-paths/description/)

**예시 1:**

입력: m = 3, n = 7
출력: 28

&nbsp;

**예시 2:**

입력: m = 3, n = 2
출력: 3

설명: 왼쪽 위에서 오른쪽 아래까지 가는 방법은 총 3가지입니다.

1. 오른쪽 → 아래 → 아래
2. 아래 → 아래 → 오른쪽
3. 아래 → 오른쪽 → 아래

&nbsp;

**제약 조건:**

- 1 <= m, n <= 100

## 내풀이 1차

### 접근: 조합

문제를 읽고 확률과통계가 딱떠올랐다.
오랜만이라 기억이 가물가물한데 조합방식으로 풀면 문제가 해결되겠다고 생각이 들었다.
m x n 격자에서 (0,0) → (m-1, n-1)까지 가려면 총 이동 횟수는 언제나 동일하기 때문에

- 아래로 가야 하는 횟수: m - 1
- 오른쪽으로 가야 하는 횟수: n - 1
- 총 이동 횟수: m + n - 2

예시 1 (m=3, n=7)일때 **아래 2번, 오른쪽 6번**을 **어떤 순서로 섞을지**만 생각 해주면 되는 문제다.
즉 RRRRRRDD, RRRRRDRD, … 처럼 **8칸짜리 줄에서 2개의 위치를 고르는 것**과 같다.

&nbsp;

### 코드

```javascript
/**
* @param {number} m
* @param {number} n
* @return {number}
*/
var uniquePaths = function (m, n) {
const factorial = (num) => {
if (num <= 1) {
return 1;
}
return num * factorial(num - 1);
};

return factorial(m + n - 2) / (factorial(n - 1) * factorial(m - 1));
Comment on lines +70 to +77

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

제약 조건에 따르면 $m, n \le 100$이므로 $m + n - 2$는 최대 198이 될 수 있습니다. JavaScript에서 171! 이상은 Infinity로 표현되기 때문에, factorial(198) 호출 시 Infinity가 반환되어 최종 결과가 NaN이 됩니다. 또한 재귀 호출로 인해 스택 오버플로우 위험이 있습니다.\n\n조합(Combination)을 계산할 때 곱셈과 나눗셈을 번갈아 수행하는 반복문 방식을 사용하면 오버플로우를 방지하고 시간/공간 복잡도를 $O(\min(m, n))$$O(1)$로 최적화할 수 있습니다.

Suggested change
const factorial = (num) => {
if (num <= 1) {
return 1;
}
return num * factorial(num - 1);
};
return factorial(m + n - 2) / (factorial(n - 1) * factorial(m - 1));
let ans = 1;
const k = Math.min(m - 1, n - 1);
for (let i = 1; i <= k; i++) {
ans = (ans * (m + n - 2 - k + i)) / i;
}
return Math.round(ans);

};
```

&nbsp;

### 복잡도

- 시간 복잡도: O(m + n) — factorial을 3번 호출하며, 가장 큰 인자 m + n - 2 기준으로 재귀 깊이만큼 연산
- 공간 복잡도: O(m + n) — factorial 재귀 호출 스택 (최대 m + n - 2까지 쌓임)

## 내풀이 2차

### 접근: 동적 계획법 (2차원 DP)

특정 칸 (i, j)에 도달하는 경로 수는 **위에서 오는 경로 + 왼쪽에서 오는 경로**의 합이다.

- dp[i][j]: (i, j)에 도달하는 서로 다른 경로의 수
- 점화식: dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
- 초기값: 첫 행·첫 열은 오른쪽/아래만 갈 수 있으므로 모두 1
- 답: dp[m - 1][n - 1]

&nbsp;

### 코드

```javascript
/**
* @param {number} m
* @param {number} n
* @return {number}
*/
var uniquePaths = function (m, n) {
const dp = Array.from({ length: m }, () => Array(n).fill(1));

for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}

return dp[m - 1][n - 1];
};
```

&nbsp;

### 복잡도

- 시간 복잡도: O(m × n) — 격자 전체를 한 번씩 채움
- 공간 복잡도: O(m × n) — dp 2차원 배열 (1차원 배열로 줄이면 O(n)까지 가능)
Loading
Loading