diff --git a/longest-substring-without-repeating-characters/byol-han.js b/longest-substring-without-repeating-characters/byol-han.js new file mode 100644 index 000000000..9bf45a63d --- /dev/null +++ b/longest-substring-without-repeating-characters/byol-han.js @@ -0,0 +1,47 @@ +/** + * https://leetcode.com/problems/longest-substring-without-repeating-characters/description/ + * @param {string} s + * @return {number} + */ +var lengthOfLongestSubstring = function (s) { + let longestS = []; + let result = 0; + for (let char of s) { + if (!longestS.includes(char)) { + longestS.push(char); + } else { + result = Math.max(result, longestS.length); + longestS = longestS.slice(longestS.indexOf(char) + 1); + longestS.push(char); + } + } + return Math.max(result, longestS.length); +}; + +/* +Sliding Window +Sliding Window는 문자열이나 배열에서 연속된 부분(subarray/substring)을 다룰 때 아주 유용한 알고리즘 기법 +고정되거나 유동적인 “창(window)”을 좌우로 움직이며 문제를 해결하는 방식 + +슬라이딩 윈도우 핵심 아이디어 +1. 두 포인터 사용: left, right +2. 조건을 만족하는 윈도우 유지 +3. 조건이 깨지면 left를 이동 +4. 조건을 만족하면 결과 업데이트 +*/ +var lengthOfLongestSubstring = function (s) { + let set = new Set(); + let left = 0; + let maxLen = 0; + + for (let right = 0; right < s.length; right++) { + while (set.has(s[right])) { + set.delete(s[left]); // 중복 문자 제거 + left++; // 왼쪽 포인터 이동 + } + set.add(s[right]); // 현재 문자 추가 + maxLen = Math.max(maxLen, right - left + 1); // 최대 길이 업데이트 + } + + return maxLen; +}; diff --git a/number-of-islands/byol-han.js b/number-of-islands/byol-han.js new file mode 100644 index 000000000..20677d11f --- /dev/null +++ b/number-of-islands/byol-han.js @@ -0,0 +1,39 @@ +/** + * https://leetcode.com/problems/number-of-islands/ + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function (grid) { + if (!grid || grid.length === 0) return 0; + + const rows = grid.length; + const cols = grid[0].length; + let count = 0; + + const dfs = (r, c) => { + // 경계 밖이거나 물인 경우 리턴 + if (r < 0 || c < 0 || r >= rows || c >= cols || grid[r][c] === "0") { + return; + } + + // 방문 표시 (육지를 물로 바꿈) + grid[r][c] = "0"; + + // 상하좌우 탐색 + dfs(r - 1, c); // 위 + dfs(r + 1, c); // 아래 + dfs(r, c - 1); // 왼쪽 + dfs(r, c + 1); // 오른쪽 + }; + + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (grid[r][c] === "1") { + count++; + dfs(r, c); // 해당 섬 전체 방문 처리 + } + } + } + + return count; +}; diff --git a/reverse-linked-list/byol-han.js b/reverse-linked-list/byol-han.js new file mode 100644 index 000000000..5d7bf3583 --- /dev/null +++ b/reverse-linked-list/byol-han.js @@ -0,0 +1,37 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * https://leetcode.com/problems/reverse-linked-list/ + * @param {ListNode} head + * @return {ListNode} + */ +var reverseList = function (head) { + let prev = null; + let current = head; + + while (current) { + const next = current.next; // 다음 노드 기억 + current.next = prev; // 현재 노드가 이전 노드를 가리키도록 변경 + prev = current; // prev를 현재 노드로 이동 + current = next; // current를 다음 노드로 이동 + } + + return prev; // prev는 새로운 head +}; + +/* +*** linked list *** +리스트의 각 노드가 다음 노드를 가리키는 포인터를 가지고 있는 자료구조 + +리스트의 첫 번째 노드를 head라고 하고, head.next는 두 번째 노드, head.next.next는 세 번째 노드... +이런식으로 노드들을 순차적으로 접근할 수 있는 자료구조를 '연결 리스트(linked list)'라고 함 + +reverseList(head)에서 head는 리스트 전체의 진입점. +head 하나만 알고 있어도, .next를 따라가면서 전체 노드들을 순차적으로 접근할 수 있기 때문에 리스트 전체를 다룰 수 있음 + + */ diff --git a/set-matrix-zeroes/byol-han.js b/set-matrix-zeroes/byol-han.js new file mode 100644 index 000000000..c8dfd6a39 --- /dev/null +++ b/set-matrix-zeroes/byol-han.js @@ -0,0 +1,61 @@ +/** + * https://leetcode.com/problems/set-matrix-zeroes/ + * @param {number[][]} matrix + * @return {void} Do not return anything, modify matrix in-place instead. + */ +var setZeroes = function (matrix) { + const m = matrix.length; + const n = matrix[0].length; + + let firstRowHasZero = false; + let firstColHasZero = false; + + // 1. 첫 번째 열에 0이 있는지 확인 + for (let i = 0; i < m; i++) { + if (matrix[i][0] === 0) { + firstColHasZero = true; + break; + } + } + + // 2. 첫 번째 행에 0이 있는지 확인 + for (let j = 0; j < n; j++) { + if (matrix[0][j] === 0) { + firstRowHasZero = true; + break; + } + } + + // 3. 나머지 matrix에서 0을 찾고, 첫 행/열에 마킹 + for (let i = 1; i < m; i++) { + for (let j = 1; j < n; j++) { + if (matrix[i][j] === 0) { + matrix[i][0] = 0; // i번째 행에 0 마킹 + matrix[0][j] = 0; // j번째 열에 0 마킹 + } + } + } + + // 4. 마킹을 기준으로 행과 열을 0으로 변경 + for (let i = 1; i < m; i++) { + for (let j = 1; j < n; j++) { + if (matrix[i][0] === 0 || matrix[0][j] === 0) { + matrix[i][j] = 0; + } + } + } + + // 5. 첫 번째 행을 0으로 설정 + if (firstRowHasZero) { + for (let j = 0; j < n; j++) { + matrix[0][j] = 0; + } + } + + // 6. 첫 번째 열을 0으로 설정 + if (firstColHasZero) { + for (let i = 0; i < m; i++) { + matrix[i][0] = 0; + } + } +}; diff --git a/unique-paths/byol-han.js b/unique-paths/byol-han.js new file mode 100644 index 000000000..8364287f9 --- /dev/null +++ b/unique-paths/byol-han.js @@ -0,0 +1,20 @@ +/** + * https://leetcode.com/problems/unique-paths/ + * @param {number} m + * @param {number} n + * @return {number} + */ +var uniquePaths = function (m, n) { + // 2차원 배열 생성 (m행 n열), 모든 값을 1로 초기화 + const dp = Array.from({ length: m }, () => Array(n).fill(1)); + + // (1,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]; +};