diff --git a/linked-list-cycle/uraflower.js b/linked-list-cycle/uraflower.js new file mode 100644 index 000000000..d4452f97e --- /dev/null +++ b/linked-list-cycle/uraflower.js @@ -0,0 +1,50 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ + +/** + * 연결 리스트의 사이클 여부를 반환하는 함수 + * 시간복잡도: O(n) + * 공간복잡도: O(1) + * @param {ListNode} head + * @return {boolean} + */ +const hasCycle = function(head) { + let node = head; + + while (node?.next) { + if (node.val === null) { + return true; + } + node.val = null; + node = node.next; + } + + return false; +}; + +// 거북이와 토끼 알고리즘 +// 시간복잡도: O(n) +// 공간복잡도: O(1) +const hasCycle = function(head) { + let slow = head; // 한 번에 한 노드씩 + let fast = head; // 한 번에 두 노드씩 + + while (fast?.next) { + slow = slow.next; + fast = fast.next.next; + + // 한 번에 두 노드씩 가는 fast가 + // 자신보다 느린 slow랑 같은 경우가 생긴다면 + // 사이클이 있다는 뜻 + if (slow === fast) { + return true; + } + } + + return false; +}; diff --git a/maximum-product-subarray/uraflower.js b/maximum-product-subarray/uraflower.js new file mode 100644 index 000000000..f3c10dae8 --- /dev/null +++ b/maximum-product-subarray/uraflower.js @@ -0,0 +1,23 @@ +/** + * 주어진 배열에서 가장 큰 부분 배열의 곱을 반환하는 함수 + * @param {number[]} nums + * @return {number} + */ +const maxProduct = function (nums) { + let min = nums[0]; + let max = nums[0]; + let result = nums[0]; // 현재까지 가장 큰 부분 배열 곱을 저장 + + for (let i = 1; i < nums.length; i++) { + let tempMin = Math.min(nums[i], min * nums[i], max * nums[i]); + let tempMax = Math.max(nums[i], min * nums[i], max * nums[i]); + min = tempMin; + max = tempMax; + result = Math.max(result, max); + } + + return result; +} + +// 시간복잡도: O(n) +// 공간복잡도: O(1) diff --git a/minimum-window-substring/uraflower.js b/minimum-window-substring/uraflower.js new file mode 100644 index 000000000..5bdca731a --- /dev/null +++ b/minimum-window-substring/uraflower.js @@ -0,0 +1,52 @@ +/** + * @param {string} s + * @param {string} t + * @return {string} + */ +const minWindow = function (s, t) { + const counter = Array.from(t).reduce((obj, char) => { + obj[char] = (obj[char] || 0) + 1; + return obj; + }, {}); + + let lettersToSatisfy = Object.keys(counter).length; + let minStart = 0; + let minEnd = Infinity; + + let start = 0; + for (let end = 0; end < s.length; end++) { + // s[end]가 t에 포함된 문자인 경우 + if (s[end] in counter) { + counter[s[end]]--; + + // 해당 문자가 범위 안에 모두 포함된 경우 + if (counter[s[end]] === 0) { + lettersToSatisfy--; + } + } + + // 현재 범위에 t 내 모든 문자가 포함된 경우 + while (lettersToSatisfy === 0) { + // 더 작은 범위로 정답 갱신 + if (end - start < minEnd - minStart) { + minStart = start; + minEnd = end; + } + + // start 늘리기 + if (s[start] in counter) { + counter[s[start]]++; + if (counter[s[start]] > 0) { + lettersToSatisfy++; + } + } + + start++; + } + } + + return minEnd === Infinity ? '' : s.slice(minStart, minEnd + 1); +}; + +// 시간복잡도: O(m) (m: s.length) +// 공간복잡도: O(1) diff --git a/pacific-atlantic-water-flow/uraflower.js b/pacific-atlantic-water-flow/uraflower.js new file mode 100644 index 000000000..15c228464 --- /dev/null +++ b/pacific-atlantic-water-flow/uraflower.js @@ -0,0 +1,70 @@ +/** + * @param {number[][]} heights + * @return {number[][]} + */ +const pacificAtlantic = function (heights) { + // 각 cell에서 시작해서 바다로 뻗어나가는 것 말고 + // 바다에서 시작해서 각 cell이 바다로 흘러올 수 있는지 확인한 후 + // 두 바다에 모두 흘러갈 수 있는 cell만 filter + + const rows = heights.length; + const cols = heights[0].length; + + // 각 바다에 도달 가능한지 여부를 담는 visited를 만듦 + const pacific = Array.from({ length: rows }, () => Array(cols).fill(false)); + const atlantic = Array.from({ length: rows }, () => Array(cols).fill(false)); + + const direction = [[0, 1], [0, -1], [1, 0], [-1, 0]]; + + // 순회 + function bfs(r, c, visited) { + visited[r][c] = true; + + const queue = [[r, c]]; + + while (queue.length) { + const [r, c] = queue.shift(); + + for (const [dr, dc] of direction) { + const nr = r + dr; + const nc = c + dc; + + // 나보다 height가 크고, 방문한 적 없으면, 큐에 담기 + if (0 <= nr && nr < rows && 0 <= nc && nc < cols + && !visited[nr][nc] + && heights[nr][nc] >= heights[r][c] + ) { + queue.push([nr, nc]); + visited[nr][nc] = true; + } + } + } + } + + // 바다에서 시작해서 거꾸로 탐색 + for (let r = 0; r < rows; r++) { + bfs(r, 0, pacific); // left + bfs(r, cols - 1, atlantic); // right + } + + for (let c = 0; c < cols; c++) { + bfs(0, c, pacific); // top + bfs(rows - 1, c, atlantic); // bottom + } + + // 태평양, 대서양으로 모두 flow할 수 있는 cell 찾기 + const result = []; + + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + if (pacific[r][c] && atlantic[r][c]) { + result.push([r, c]); + } + } + } + + return result; +}; + +// 시간복잡도: O(m*n) +// 공간복잡도: O(m*n) diff --git a/sum-of-two-integers/uraflower.js b/sum-of-two-integers/uraflower.js new file mode 100644 index 000000000..d2585961e --- /dev/null +++ b/sum-of-two-integers/uraflower.js @@ -0,0 +1,16 @@ +/** + * +, - 연산자를 사용하지 않고 a, b를 더하는 함수 + * @param {number} a + * @param {number} b + * @return {number} + */ +const getSum = function (a, b) { + while (b !== 0) { + [a, b] = [a ^ b, (a & b) << 1] + } + + return a; +}; + +// 시간복잡도: O(1) +// 공간복잡도: O(1)