From 491d9e47a2cce983ea66e7ca9d5a94ea3a17a4f8 Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:29:43 -0500 Subject: [PATCH 01/15] Add solution #635 --- README.md | 1 + solutions/0635-design-log-storage-system.js | 63 +++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 solutions/0635-design-log-storage-system.js diff --git a/README.md b/README.md index 049db06..40d56d7 100644 --- a/README.md +++ b/README.md @@ -590,6 +590,7 @@ 632|[Smallest Range Covering Elements from K Lists](./solutions/0632-smallest-range-covering-elements-from-k-lists.js)|Hard| 633|[Sum of Square Numbers](./solutions/0633-sum-of-square-numbers.js)|Medium| 634|[Find the Derangement of An Array](./solutions/0634-find-the-derangement-of-an-array.js)|Medium| +635|[Design Log Storage System](./solutions/0635-design-log-storage-system.js)|Medium| 636|[Exclusive Time of Functions](./solutions/0636-exclusive-time-of-functions.js)|Medium| 637|[Average of Levels in Binary Tree](./solutions/0637-average-of-levels-in-binary-tree.js)|Easy| 638|[Shopping Offers](./solutions/0638-shopping-offers.js)|Medium| diff --git a/solutions/0635-design-log-storage-system.js b/solutions/0635-design-log-storage-system.js new file mode 100644 index 0000000..50a8b30 --- /dev/null +++ b/solutions/0635-design-log-storage-system.js @@ -0,0 +1,63 @@ +/** + * 635. Design Log Storage System + * https://leetcode.com/problems/design-log-storage-system/ + * Difficulty: Medium + * + * You are given several logs, where each log contains a unique ID and timestamp. Timestamp is a + * string that has the following format: Year:Month:Day:Hour:Minute:Second, for example, + * 2017:01:01:23:59:59. All domains are zero-padded decimal numbers. + * + * Implement the LogSystem class: + * - LogSystem() Initializes the LogSystem object. + * - void put(int id, string timestamp) Stores the given log (id, timestamp) in your storage system. + * - int[] retrieve(string start, string end, string granularity) Returns the IDs of the logs whose + * timestamps are within the range from start to end inclusive. start and end all have the same + * format as timestamp, and granularity means how precise the range should be (i.e. to the exact + * Day, Minute, etc.). For example, start = "2017:01:01:23:59:59", end = "2017:01:02:23:59:59", + * and granularity = "Day" means that we need to find the logs within the inclusive range from + * Jan. 1st 2017 to Jan. 2nd 2017, and the Hour, Minute, and Second for each log entry can be + * ignored. + */ + +var LogSystem = function() { + this.logs = []; + this.granularities = { + Year: 4, + Month: 7, + Day: 10, + Hour: 13, + Minute: 16, + Second: 19 + }; +}; + +/** + * @param {number} id + * @param {string} timestamp + * @return {void} + */ +LogSystem.prototype.put = function(id, timestamp) { + this.logs.push([timestamp, id]); +}; + +/** + * @param {string} start + * @param {string} end + * @param {string} granularity + * @return {number[]} + */ +LogSystem.prototype.retrieve = function(start, end, granularity) { + const precision = this.granularities[granularity]; + const startKey = start.slice(0, precision).padEnd(19, '0'); + const endKey = end.slice(0, precision).padEnd(19, '9'); + + const result = []; + for (const [timestamp, id] of this.logs) { + const key = timestamp.slice(0, precision).padEnd(19, '0'); + if (key >= startKey && key <= endKey) { + result.push(id); + } + } + + return result.sort((a, b) => a - b); +}; From 8ff463893b4cdedf22242ea624a6fa7902f5d4f4 Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:32:42 -0500 Subject: [PATCH 02/15] Add solution #642 --- README.md | 1 + .../0642-design-search-autocomplete-system.js | 97 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 solutions/0642-design-search-autocomplete-system.js diff --git a/README.md b/README.md index 40d56d7..52c6c2c 100644 --- a/README.md +++ b/README.md @@ -597,6 +597,7 @@ 639|[Decode Ways II](./solutions/0639-decode-ways-ii.js)|Hard| 640|[Solve the Equation](./solutions/0640-solve-the-equation.js)|Medium| 641|[Design Circular Deque](./solutions/0641-design-circular-deque.js)|Medium| +642|[Design Search Autocomplete System](./solutions/0642-design-search-autocomplete-system.js)|Hard| 643|[Maximum Average Subarray I](./solutions/0643-maximum-average-subarray-i.js)|Easy| 645|[Set Mismatch](./solutions/0645-set-mismatch.js)|Medium| 646|[Maximum Length of Pair Chain](./solutions/0646-maximum-length-of-pair-chain.js)|Medium| diff --git a/solutions/0642-design-search-autocomplete-system.js b/solutions/0642-design-search-autocomplete-system.js new file mode 100644 index 0000000..d6e6385 --- /dev/null +++ b/solutions/0642-design-search-autocomplete-system.js @@ -0,0 +1,97 @@ +/** + * 642. Design Search Autocomplete System + * https://leetcode.com/problems/design-search-autocomplete-system/ + * Difficulty: Hard + * + * Design a search autocomplete system for a search engine. Users may input a sentence (at + * least one word and end with a special character '#'). + * + * You are given a string array sentences and an integer array times both of length n where + * sentences[i] is a previously typed sentence and times[i] is the corresponding number of + * times the sentence was typed. For each input character except '#', return the top 3 + * historical hot sentences that have the same prefix as the part of the sentence already typed. + * + * Here are the specific rules: + * - The hot degree for a sentence is defined as the number of times a user typed the exactly + * same sentence before. + * - The returned top 3 hot sentences should be sorted by hot degree (The first is the hottest + * one). If several sentences have the same hot degree, use ASCII-code order (smaller one + * appears first). + * - If less than 3 hot sentences exist, return as many as you can. + * - When the input is a special character, it means the sentence ends, and in this case, you + * need to return an empty list. + * + * Implement the AutocompleteSystem class: + * - AutocompleteSystem(String[] sentences, int[] times) Initializes the object with the + * sentences and times arrays. + * - List input(char c) This indicates that the user typed the character c. + * - Returns an empty array [] if c == '#' and stores the inputted sentence in the system. + * - Returns the top 3 historical hot sentences that have the same prefix as the part of the + * sentence already typed. If there are fewer than 3 matches, return them all. + */ + +/** + * @param {string[]} sentences + * @param {number[]} times + */ +var AutocompleteSystem = function(sentences, times) { + this.trie = {}; + this.current = ''; + this.root = this.trie; + + for (let i = 0; i < sentences.length; i++) { + this.insert(sentences[i], times[i]); + } +}; + +/** + * @param {character} c + * @return {string[]} + */ +AutocompleteSystem.prototype.input = function(c) { + if (c === '#') { + this.insert(this.current, 1); + this.current = ''; + this.root = this.trie; + return []; + } + + this.current += c; + if (!this.root[c]) { + this.root[c] = {}; + this.root = this.root[c]; + return []; + } + + this.root = this.root[c]; + const candidates = []; + this.search(this.root, this.current, candidates); + + candidates.sort((a, b) => { + if (a.count !== b.count) return b.count - a.count; + return a.sentence < b.sentence ? -1 : 1; + }); + + return candidates.slice(0, 3).map(item => item.sentence); +}; + +AutocompleteSystem.prototype.insert = function(sentence, count) { + let node = this.trie; + for (const char of sentence) { + if (!node[char]) node[char] = {}; + node = node[char]; + } + node.isEnd = (node.isEnd || 0) + count; +}; + +AutocompleteSystem.prototype.search = function(node, prefix, candidates) { + if (node.isEnd) { + candidates.push({ sentence: prefix, count: node.isEnd }); + } + + for (const char in node) { + if (char !== 'isEnd') { + this.search(node[char], prefix + char, candidates); + } + } +}; From 4bb7c2d210df92e46f3fb89629c0871ad8730256 Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:33:56 -0500 Subject: [PATCH 03/15] Add solution #644 --- README.md | 1 + solutions/0644-maximum-average-subarray-ii.js | 54 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 solutions/0644-maximum-average-subarray-ii.js diff --git a/README.md b/README.md index 52c6c2c..2df1153 100644 --- a/README.md +++ b/README.md @@ -599,6 +599,7 @@ 641|[Design Circular Deque](./solutions/0641-design-circular-deque.js)|Medium| 642|[Design Search Autocomplete System](./solutions/0642-design-search-autocomplete-system.js)|Hard| 643|[Maximum Average Subarray I](./solutions/0643-maximum-average-subarray-i.js)|Easy| +644|[Maximum Average Subarray II](./solutions/0644-maximum-average-subarray-ii.js)|Hard| 645|[Set Mismatch](./solutions/0645-set-mismatch.js)|Medium| 646|[Maximum Length of Pair Chain](./solutions/0646-maximum-length-of-pair-chain.js)|Medium| 647|[Palindromic Substrings](./solutions/0647-palindromic-substrings.js)|Medium| diff --git a/solutions/0644-maximum-average-subarray-ii.js b/solutions/0644-maximum-average-subarray-ii.js new file mode 100644 index 0000000..b2f7549 --- /dev/null +++ b/solutions/0644-maximum-average-subarray-ii.js @@ -0,0 +1,54 @@ +/** + * 644. Maximum Average Subarray II + * https://leetcode.com/problems/maximum-average-subarray-ii/ + * Difficulty: Hard + * + * You are given an integer array nums consisting of n elements, and an integer k. + * + * Find a contiguous subarray whose length is greater than or equal to k that has the maximum + * average value and return this value. Any answer with a calculation error less than 10-5 will + * be accepted. + */ + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var findMaxAverage = function(nums, k) { + const n = nums.length; + let minVal = Math.min(...nums); + let maxVal = Math.max(...nums); + + while (maxVal - minVal > 1e-5) { + const mid = (minVal + maxVal) / 2; + if (canFindLargerAverage(nums, k, mid)) { + minVal = mid; + } else { + maxVal = mid; + } + } + + return minVal; +}; + +function canFindLargerAverage(nums, k, target) { + let sum = 0; + let prevSum = 0; + let minPrevSum = 0; + + for (let i = 0; i < k; i++) { + sum += nums[i] - target; + } + + if (sum >= 0) return true; + + for (let i = k; i < nums.length; i++) { + sum += nums[i] - target; + prevSum += nums[i - k] - target; + minPrevSum = Math.min(minPrevSum, prevSum); + if (sum - minPrevSum >= 0) return true; + } + + return false; +} From 394ffe8c5f621f5cb83c6796b4580af4cf994711 Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:38:49 -0500 Subject: [PATCH 04/15] Add solution #651 --- README.md | 1 + solutions/0651-4-keys-keyboard.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 solutions/0651-4-keys-keyboard.js diff --git a/README.md b/README.md index 2df1153..3931d59 100644 --- a/README.md +++ b/README.md @@ -606,6 +606,7 @@ 648|[Replace Words](./solutions/0648-replace-words.js)|Medium| 649|[Dota2 Senate](./solutions/0649-dota2-senate.js)|Medium| 650|[2 Keys Keyboard](./solutions/0650-2-keys-keyboard.js)|Medium| +651|[4 Keys Keyboard](./solutions/0651-4-keys-keyboard.js)|Medium| 652|[Find Duplicate Subtrees](./solutions/0652-find-duplicate-subtrees.js)|Medium| 653|[Two Sum IV - Input is a BST](./solutions/0653-two-sum-iv-input-is-a-bst.js)|Easy| 654|[Maximum Binary Tree](./solutions/0654-maximum-binary-tree.js)|Medium| diff --git a/solutions/0651-4-keys-keyboard.js b/solutions/0651-4-keys-keyboard.js new file mode 100644 index 0000000..5420a8c --- /dev/null +++ b/solutions/0651-4-keys-keyboard.js @@ -0,0 +1,31 @@ +/** + * 651. 4 Keys Keyboard + * https://leetcode.com/problems/4-keys-keyboard/ + * Difficulty: Medium + * + * Imagine you have a special keyboard with the following keys: + * - A: Print one 'A' on the screen. + * - Ctrl-A: Select the whole screen. + * - Ctrl-C: Copy selection to buffer. + * - Ctrl-V: Print buffer on screen appending it after what has already been printed. + * + * Given an integer n, return the maximum number of 'A' you can print on the screen with at + * most n presses on the keys. + */ + +/** + * @param {number} n + * @return {number} + */ +var maxA = function(n) { + const dp = new Array(n + 1).fill(0); + + for (let i = 1; i <= n; i++) { + dp[i] = dp[i - 1] + 1; + for (let j = 2; j < i; j++) { + dp[i] = Math.max(dp[i], dp[j - 2] * (i - j + 1)); + } + } + + return dp[n]; +}; From b77f3a40f098dfcce776a56cff357f3f268be32b Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:48:13 -0500 Subject: [PATCH 05/15] Add solution #656 --- README.md | 1 + solutions/0656-coin-path.js | 88 +++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 solutions/0656-coin-path.js diff --git a/README.md b/README.md index 3931d59..24748fc 100644 --- a/README.md +++ b/README.md @@ -611,6 +611,7 @@ 653|[Two Sum IV - Input is a BST](./solutions/0653-two-sum-iv-input-is-a-bst.js)|Easy| 654|[Maximum Binary Tree](./solutions/0654-maximum-binary-tree.js)|Medium| 655|[Print Binary Tree](./solutions/0655-print-binary-tree.js)|Medium| +656|[Coin Path](./solutions/0656-coin-path.js)|Hard| 657|[Robot Return to Origin](./solutions/0657-robot-return-to-origin.js)|Easy| 658|[Find K Closest Elements](./solutions/0658-find-k-closest-elements.js)|Medium| 659|[Split Array into Consecutive Subsequences](./solutions/0659-split-array-into-consecutive-subsequences.js)|Medium| diff --git a/solutions/0656-coin-path.js b/solutions/0656-coin-path.js new file mode 100644 index 0000000..f5c3e9e --- /dev/null +++ b/solutions/0656-coin-path.js @@ -0,0 +1,88 @@ +/** + * 656. Coin Path + * https://leetcode.com/problems/coin-path/ + * Difficulty: Hard + * + * You are given an integer array coins (1-indexed) of length n and an integer maxJump. You can + * jump to any index i of the array coins if coins[i] != -1 and you have to pay coins[i] when you + * visit index i. In addition to that, if you are currently at index i, you can only jump to any + * index i + k where i + k <= n and k is a value in the range [1, maxJump]. + * + * You are initially positioned at index 1 (coins[1] is not -1). You want to find the path that + * reaches index n with the minimum cost. + * + * Return an integer array of the indices that you will visit in order so that you can reach + * index n with the minimum cost. If there are multiple paths with the same cost, return the + * lexicographically smallest such path. If it is not possible to reach index n, return an + * empty array. + * + * A path p1 = [Pa1, Pa2, ..., Pax] of length x is lexicographically smaller than + * p2 = [Pb1, Pb2, ..., Pbx] of length y, if and only if at the first j where Paj and Pbj + * differ, Paj < Pbj; when no such j exists, then x < y. + */ + +/** + * @param {number[]} coins + * @param {number} maxJump + * @return {number[]} + */ +var cheapestJump = function(coins, maxJump) { + const n = coins.length; + const minCost = new Array(n + 1).fill(Infinity); + const parent = new Array(n + 1).fill(-1); + + minCost[1] = coins[0]; + + for (let i = 1; i <= n; i++) { + if (coins[i - 1] === -1 || minCost[i] === Infinity) continue; + + for (let j = i + 1; j <= Math.min(i + maxJump, n); j++) { + if (coins[j - 1] === -1) continue; + + const newCost = minCost[i] + coins[j - 1]; + if (newCost < minCost[j]) { + minCost[j] = newCost; + parent[j] = i; + } else if (newCost === minCost[j] && parent[j] !== -1) { + const currentPath = buildPath(parent, j); + const newPath = buildPath(parent, j, i); + if (compare(newPath, currentPath)) { + parent[j] = i; + } + } + } + } + + if (minCost[n] === Infinity) return []; + + const result = []; + let current = n; + while (current !== -1) { + result.unshift(current); + current = parent[current]; + } + + return result; +}; + +function buildPath(parent, end, newParent = null) { + const path = []; + let current = end; + if (newParent !== null) { + path.unshift(current); + current = newParent; + } + while (current !== -1) { + path.unshift(current); + current = parent[current]; + } + return path; +} + +function compare(path1, path2) { + for (let i = 0; i < Math.min(path1.length, path2.length); i++) { + if (path1[i] < path2[i]) return true; + if (path1[i] > path2[i]) return false; + } + return path1.length < path2.length; +} From 7ac24b114c0c4ca465868a3e5b22c49ca83264a0 Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:50:25 -0500 Subject: [PATCH 06/15] Add solution #660 --- README.md | 1 + solutions/0660-remove-9.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 solutions/0660-remove-9.js diff --git a/README.md b/README.md index 24748fc..b2f77ba 100644 --- a/README.md +++ b/README.md @@ -615,6 +615,7 @@ 657|[Robot Return to Origin](./solutions/0657-robot-return-to-origin.js)|Easy| 658|[Find K Closest Elements](./solutions/0658-find-k-closest-elements.js)|Medium| 659|[Split Array into Consecutive Subsequences](./solutions/0659-split-array-into-consecutive-subsequences.js)|Medium| +660|[Remove 9](./solutions/0660-remove-9.js)|Hard| 661|[Image Smoother](./solutions/0661-image-smoother.js)|Easy| 662|[Maximum Width of Binary Tree](./solutions/0662-maximum-width-of-binary-tree.js)|Medium| 664|[Strange Printer](./solutions/0664-strange-printer.js)|Hard| diff --git a/solutions/0660-remove-9.js b/solutions/0660-remove-9.js new file mode 100644 index 0000000..02b239a --- /dev/null +++ b/solutions/0660-remove-9.js @@ -0,0 +1,28 @@ +/** + * 660. Remove 9 + * https://leetcode.com/problems/remove-9/ + * Difficulty: Hard + * + * Start from integer 1, remove any integer that contains 9 such as 9, 19, 29... + * + * Now, you will have a new integer sequence [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, ...]. + * + * Given an integer n, return the nth (1-indexed) integer in the new sequence. + */ + +/** + * @param {number} n + * @return {number} + */ +var newInteger = function(n) { + let result = 0; + let base = 1; + + while (n > 0) { + result += (n % 9) * base; + n = Math.floor(n / 9); + base *= 10; + } + + return result; +}; From 8dbd9c7f4b33d4b265aa3c2de52c45cda01780ac Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:51:47 -0500 Subject: [PATCH 07/15] Add solution #663 --- README.md | 1 + solutions/0663-equal-tree-partition.js | 41 ++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 solutions/0663-equal-tree-partition.js diff --git a/README.md b/README.md index b2f77ba..a6e86f2 100644 --- a/README.md +++ b/README.md @@ -618,6 +618,7 @@ 660|[Remove 9](./solutions/0660-remove-9.js)|Hard| 661|[Image Smoother](./solutions/0661-image-smoother.js)|Easy| 662|[Maximum Width of Binary Tree](./solutions/0662-maximum-width-of-binary-tree.js)|Medium| +663|[Equal Tree Partition](./solutions/0663-equal-tree-partition.js)|Medium| 664|[Strange Printer](./solutions/0664-strange-printer.js)|Hard| 665|[Non-decreasing Array](./solutions/0665-non-decreasing-array.js)|Medium| 667|[Beautiful Arrangement II](./solutions/0667-beautiful-arrangement-ii.js)|Medium| diff --git a/solutions/0663-equal-tree-partition.js b/solutions/0663-equal-tree-partition.js new file mode 100644 index 0000000..7c93c6e --- /dev/null +++ b/solutions/0663-equal-tree-partition.js @@ -0,0 +1,41 @@ +/** + * 663. Equal Tree Partition + * https://leetcode.com/problems/equal-tree-partition/ + * Difficulty: Medium + * + * Given the root of a binary tree, return true if you can partition the tree into two trees + * with equal sums of values after removing exactly one edge on the original tree. + */ + +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {boolean} + */ +var checkEqualTree = function(root) { + const subtreeSums = new Set(); + const totalSum = calculateSum(root); + + return totalSum % 2 === 0 && subtreeSums.has(totalSum / 2); + + function calculateSum(node) { + if (!node) return 0; + + const leftSum = calculateSum(node.left); + const rightSum = calculateSum(node.right); + const currentSum = node.val + leftSum + rightSum; + + if (node !== root) { + subtreeSums.add(currentSum); + } + + return currentSum; + } +}; From b5b4de8c6396b8605090a82705fbe277258a63b2 Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:53:46 -0500 Subject: [PATCH 08/15] Add solution #666 --- README.md | 1 + solutions/0666-path-sum-iv.js | 52 +++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 solutions/0666-path-sum-iv.js diff --git a/README.md b/README.md index a6e86f2..6ebe50e 100644 --- a/README.md +++ b/README.md @@ -621,6 +621,7 @@ 663|[Equal Tree Partition](./solutions/0663-equal-tree-partition.js)|Medium| 664|[Strange Printer](./solutions/0664-strange-printer.js)|Hard| 665|[Non-decreasing Array](./solutions/0665-non-decreasing-array.js)|Medium| +666|[Path Sum IV](./solutions/0666-path-sum-iv.js)|Medium| 667|[Beautiful Arrangement II](./solutions/0667-beautiful-arrangement-ii.js)|Medium| 668|[Kth Smallest Number in Multiplication Table](./solutions/0668-kth-smallest-number-in-multiplication-table.js)|Hard| 669|[Trim a Binary Search Tree](./solutions/0669-trim-a-binary-search-tree.js)|Medium| diff --git a/solutions/0666-path-sum-iv.js b/solutions/0666-path-sum-iv.js new file mode 100644 index 0000000..b3f637a --- /dev/null +++ b/solutions/0666-path-sum-iv.js @@ -0,0 +1,52 @@ +/** + * 666. Path Sum IV + * https://leetcode.com/problems/path-sum-iv/ + * Difficulty: Medium + * + * If the depth of a tree is smaller than 5, then this tree can be represented by an array + * of three-digit integers. You are given an ascending array nums consisting of three-digit + * integers representing a binary tree with a depth smaller than 5, where for each integer: + * - The hundreds digit represents the depth d of this node, where 1 <= d <= 4. + * - The tens digit represents the position p of this node within its level, where 1 <= p <= 8, + * corresponding to its position in a full binary tree. + * - The units digit represents the value v of this node, where 0 <= v <= 9. + * + * Return the sum of all paths from the root towards the leaves. + * + * It is guaranteed that the given array represents a valid connected binary tree. + */ + +/** + * @param {number[]} nums + * @return {number} + */ +var pathSum = function(nums) { + const nodeMap = new Map(); + + for (const num of nums) { + const depth = Math.floor(num / 100); + const position = Math.floor((num % 100) / 10); + const value = num % 10; + nodeMap.set(`${depth}-${position}`, value); + } + + return dfs(1, 1, 0); + + function dfs(depth, position, currentSum) { + const key = `${depth}-${position}`; + if (!nodeMap.has(key)) return 0; + + const nodeValue = nodeMap.get(key); + const pathSum = currentSum + nodeValue; + + const leftChild = `${depth + 1}-${position * 2 - 1}`; + const rightChild = `${depth + 1}-${position * 2}`; + + if (!nodeMap.has(leftChild) && !nodeMap.has(rightChild)) { + return pathSum; + } + + return dfs(depth + 1, position * 2 - 1, pathSum) + + dfs(depth + 1, position * 2, pathSum); + } +}; From 4298b0074a0a114954ca0e9c448d82ec49e27bb7 Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:54:54 -0500 Subject: [PATCH 09/15] Add solution #681 --- README.md | 1 + solutions/0681-next-closest-time.js | 50 +++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 solutions/0681-next-closest-time.js diff --git a/README.md b/README.md index 6ebe50e..9753391 100644 --- a/README.md +++ b/README.md @@ -636,6 +636,7 @@ 678|[Valid Parenthesis String](./solutions/0678-valid-parenthesis-string.js)|Medium| 679|[24 Game](./solutions/0679-24-game.js)|Hard| 680|[Valid Palindrome II](./solutions/0680-valid-palindrome-ii.js)|Easy| +681|[Next Closest Time](./solutions/0681-next-closest-time.js)|Medium| 682|[Baseball Game](./solutions/0682-baseball-game.js)|Easy| 684|[Redundant Connection](./solutions/0684-redundant-connection.js)|Medium| 685|[Redundant Connection II](./solutions/0685-redundant-connection-ii.js)|Hard| diff --git a/solutions/0681-next-closest-time.js b/solutions/0681-next-closest-time.js new file mode 100644 index 0000000..78d0631 --- /dev/null +++ b/solutions/0681-next-closest-time.js @@ -0,0 +1,50 @@ +/** + * 681. Next Closest Time + * https://leetcode.com/problems/next-closest-time/ + * Difficulty: Medium + * + * Given a time represented in the format "HH:MM", form the next closest time by reusing the + * current digits. There is no limit on how many times a digit can be reused. + * + * You may assume the given input string is always valid. For example, "01:34", "12:09" are + * all valid. "1:34", "12:9" are all invalid. + */ + +/** + * @param {string} time + * @return {string} + */ +var nextClosestTime = function(time) { + const digits = new Set(time.replace(':', '')); + const sortedDigits = [...digits].sort(); + + return generateNextTime(time); + + function isValidTime(h, m) { + return h < 24 && m < 60; + } + + function generateNextTime(timeStr) { + const [hours, minutes] = timeStr.split(':'); + + for (let i = 3; i >= 0; i--) { + const pos = i < 2 ? i : i + 1; + const currentDigit = timeStr[pos]; + + for (const digit of sortedDigits) { + if (digit > currentDigit) { + const newTime = timeStr.substring(0, pos) + digit + timeStr.substring(pos + 1); + const [h, m] = newTime.split(':').map(Number); + if (isValidTime(h, m)) { + return newTime; + } + } + } + + const newTime = timeStr.substring(0, pos) + sortedDigits[0] + timeStr.substring(pos + 1); + timeStr = newTime; + } + + return sortedDigits[0].repeat(2) + ':' + sortedDigits[0].repeat(2); + } +}; From bd9d33a5d08153fb03703bbbedbcc426bb5a55cb Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 17:56:13 -0500 Subject: [PATCH 10/15] Add solution #683 --- README.md | 1 + solutions/0683-k-empty-slots.js | 55 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 solutions/0683-k-empty-slots.js diff --git a/README.md b/README.md index 9753391..41351d4 100644 --- a/README.md +++ b/README.md @@ -638,6 +638,7 @@ 680|[Valid Palindrome II](./solutions/0680-valid-palindrome-ii.js)|Easy| 681|[Next Closest Time](./solutions/0681-next-closest-time.js)|Medium| 682|[Baseball Game](./solutions/0682-baseball-game.js)|Easy| +683|[K Empty Slots](./solutions/0683-k-empty-slots.js)|Hard| 684|[Redundant Connection](./solutions/0684-redundant-connection.js)|Medium| 685|[Redundant Connection II](./solutions/0685-redundant-connection-ii.js)|Hard| 686|[Repeated String Match](./solutions/0686-repeated-string-match.js)|Easy| diff --git a/solutions/0683-k-empty-slots.js b/solutions/0683-k-empty-slots.js new file mode 100644 index 0000000..f3b2318 --- /dev/null +++ b/solutions/0683-k-empty-slots.js @@ -0,0 +1,55 @@ +/** + * 683. K Empty Slots + * https://leetcode.com/problems/k-empty-slots/ + * Difficulty: Hard + * + * You have n bulbs in a row numbered from 1 to n. Initially, all the bulbs are turned off. + * We turn on exactly one bulb every day until all bulbs are on after n days. + * + * You are given an array bulbs of length n where bulbs[i] = x means that on the (i+1)th day, + * we will turn on the bulb at position x where i is 0-indexed and x is 1-indexed. + * + * Given an integer k, return the minimum day number such that there exists two turned on + * bulbs that have exactly k bulbs between them that are all turned off. If there isn't + * such day, return -1. + */ + +/** + * @param {number[]} bulbs + * @param {number} k + * @return {number} + */ +var kEmptySlots = function(bulbs, k) { + const days = new Array(bulbs.length + 1); + + for (let i = 0; i < bulbs.length; i++) { + days[bulbs[i]] = i + 1; + } + + let left = 1; + let right = k + 2; + let minDay = Infinity; + + while (right <= bulbs.length) { + let mid = left + 1; + let isValid = true; + + while (mid < right) { + if (days[mid] < Math.max(days[left], days[right])) { + isValid = false; + left = mid; + right = mid + k + 1; + break; + } + mid++; + } + + if (isValid) { + minDay = Math.min(minDay, Math.max(days[left], days[right])); + left++; + right++; + } + } + + return minDay === Infinity ? -1 : minDay; +}; From ca5baf405900cf1f266ee0f7bb85a41a69d1e3f4 Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 18:42:08 -0500 Subject: [PATCH 11/15] Add solution #694 --- README.md | 1 + solutions/0694-number-of-distinct-islands.js | 52 ++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 solutions/0694-number-of-distinct-islands.js diff --git a/README.md b/README.md index 41351d4..a85fa6c 100644 --- a/README.md +++ b/README.md @@ -649,6 +649,7 @@ 691|[Stickers to Spell Word](./solutions/0691-stickers-to-spell-word.js)|Hard| 692|[Top K Frequent Words](./solutions/0692-top-k-frequent-words.js)|Medium| 693|[Binary Number with Alternating Bits](./solutions/0693-binary-number-with-alternating-bits.js)|Easy| +694|[Number of Distinct Islands](./solutions/0694-number-of-distinct-islands.js)|Medium| 695|[Max Area of Island](./solutions/0695-max-area-of-island.js)|Medium| 696|[Count Binary Substrings](./solutions/0696-count-binary-substrings.js)|Easy| 697|[Degree of an Array](./solutions/0697-degree-of-an-array.js)|Easy| diff --git a/solutions/0694-number-of-distinct-islands.js b/solutions/0694-number-of-distinct-islands.js new file mode 100644 index 0000000..cd7baca --- /dev/null +++ b/solutions/0694-number-of-distinct-islands.js @@ -0,0 +1,52 @@ +/** + * 694. Number of Distinct Islands + * https://leetcode.com/problems/number-of-distinct-islands/ + * Difficulty: Medium + * + * You are given an m x n binary matrix grid. An island is a group of 1's (representing land) + * connected 4-directionally (horizontal or vertical.) You may assume all four edges of the + * grid are surrounded by water. + * + * An island is considered to be the same as another if and only if one island can be translated + * (and not rotated or reflected) to equal the other. + * + * Return the number of distinct islands. + */ + +/** + * @param {number[][]} grid + * @return {number} + */ +var numDistinctIslands = function(grid) { + const rows = grid.length; + const cols = grid[0].length; + const visited = Array.from({ length: rows }, () => new Array(cols).fill(false)); + const islandShapes = new Set(); + + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (grid[i][j] === 1 && !visited[i][j]) { + const shape = []; + dfs(i, j, i, j, shape); + islandShapes.add(shape.join('|')); + } + } + } + + return islandShapes.size; + + function dfs(row, col, baseRow, baseCol, shape) { + if (row < 0 || row >= rows || col < 0 || col >= cols + || visited[row][col] || grid[row][col] === 0) { + return; + } + + visited[row][col] = true; + shape.push(`${row - baseRow},${col - baseCol}`); + + dfs(row + 1, col, baseRow, baseCol, shape); + dfs(row - 1, col, baseRow, baseCol, shape); + dfs(row, col + 1, baseRow, baseCol, shape); + dfs(row, col - 1, baseRow, baseCol, shape); + } +}; From 685fc369d8563105dcadb7e1b7d85164262bca1b Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 18:43:26 -0500 Subject: [PATCH 12/15] Add solution #702 --- README.md | 1 + ...earch-in-a-sorted-array-of-unknown-size.js | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 solutions/0702-search-in-a-sorted-array-of-unknown-size.js diff --git a/README.md b/README.md index a85fa6c..14eb02f 100644 --- a/README.md +++ b/README.md @@ -657,6 +657,7 @@ 699|[Falling Squares](./solutions/0699-falling-squares.js)|Hard| 700|[Search in a Binary Search Tree](./solutions/0700-search-in-a-binary-search-tree.js)|Easy| 701|[Insert into a Binary Search Tree](./solutions/0701-insert-into-a-binary-search-tree.js)|Medium| +702|[Search in a Sorted Array of Unknown Size](./solutions/0702-search-in-a-sorted-array-of-unknown-size.js)|Medium| 703|[Kth Largest Element in a Stream](./solutions/0703-kth-largest-element-in-a-stream.js)|Easy| 704|[Binary Search](./solutions/0704-binary-search.js)|Easy| 705|[Design HashSet](./solutions/0705-design-hashset.js)|Easy| diff --git a/solutions/0702-search-in-a-sorted-array-of-unknown-size.js b/solutions/0702-search-in-a-sorted-array-of-unknown-size.js new file mode 100644 index 0000000..865bda1 --- /dev/null +++ b/solutions/0702-search-in-a-sorted-array-of-unknown-size.js @@ -0,0 +1,49 @@ +/** + * 702. Search in a Sorted Array of Unknown Size + * https://leetcode.com/problems/search-in-a-sorted-array-of-unknown-size/ + * Difficulty: Medium + * + * This is an interactive problem. + * + * You have a sorted array of unique elements and an unknown size. You do not have an access + * to the array but you can use the ArrayReader interface to access it. You can call + * ArrayReader.get(i) that: + * - returns the value at the ith index (0-indexed) of the secret array (i.e., secret[i]), or + * - returns 231 - 1 if the i is out of the boundary of the array. + * + * You are also given an integer target. + * + * Return the index k of the hidden array where secret[k] == target or return -1 otherwise. + * + * You must write an algorithm with O(log n) runtime complexity. + */ + +/** + * @param {ArrayReader} reader + * @param {number} target + * @return {number} + */ +var search = function(reader, target) { + let left = 0; + let right = 1; + + while (reader.get(right) < target) { + left = right; + right *= 2; + } + + while (left <= right) { + const mid = Math.floor((left + right) / 2); + const value = reader.get(mid); + + if (value === target) { + return mid; + } else if (value < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + return -1; +}; From 9650be71ac68c161e779e9c8501f4884801df31e Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 18:45:13 -0500 Subject: [PATCH 13/15] Add solution #708 --- README.md | 1 + ...sert-into-a-sorted-circular-linked-list.js | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 solutions/0708-insert-into-a-sorted-circular-linked-list.js diff --git a/README.md b/README.md index 14eb02f..67f86d7 100644 --- a/README.md +++ b/README.md @@ -663,6 +663,7 @@ 705|[Design HashSet](./solutions/0705-design-hashset.js)|Easy| 706|[Design HashMap](./solutions/0706-design-hashmap.js)|Easy| 707|[Design Linked List](./solutions/0707-design-linked-list.js)|Medium| +708|[Insert into a Sorted Circular Linked List](./solutions/0708-insert-into-a-sorted-circular-linked-list.js)|Medium| 709|[To Lower Case](./solutions/0709-to-lower-case.js)|Easy| 710|[Random Pick with Blacklist](./solutions/0710-random-pick-with-blacklist.js)|Hard| 712|[Minimum ASCII Delete Sum for Two Strings](./solutions/0712-minimum-ascii-delete-sum-for-two-strings.js)|Medium| diff --git a/solutions/0708-insert-into-a-sorted-circular-linked-list.js b/solutions/0708-insert-into-a-sorted-circular-linked-list.js new file mode 100644 index 0000000..ff17f2d --- /dev/null +++ b/solutions/0708-insert-into-a-sorted-circular-linked-list.js @@ -0,0 +1,53 @@ +/** + * 708. Insert into a Sorted Circular Linked List + * https://leetcode.com/problems/insert-into-a-sorted-circular-linked-list/ + * Difficulty: Medium + * + * Given a Circular Linked List node, which is sorted in non-descending order, write a + * function to insert a value insertVal into the list such that it remains a sorted + * circular list. The given node can be a reference to any single node in the list and + * may not necessarily be the smallest value in the circular list. + * + * If there are multiple suitable places for insertion, you may choose any place to + * insert the new value. After the insertion, the circular list should remain sorted. + * + * If the list is empty (i.e., the given node is null), you should create a new single + * circular list and return the reference to that single node. Otherwise, you should + * return the originally given node. + */ + +/** + * @param {_Node} head + * @param {number} insertVal + * @return {_Node} + */ +var insert = function(head, insertVal) { + const newNode = new _Node(insertVal, null); + + if (!head) { + newNode.next = newNode; + return newNode; + } + + if (head.next === head) { + newNode.next = head; + head.next = newNode; + return head; + } + + let prev = head; + let curr = head.next; + do { + if ((prev.val <= insertVal && insertVal <= curr.val) + || (prev.val > curr.val && (insertVal >= prev.val || insertVal <= curr.val))) { + break; + } + prev = curr; + curr = curr.next; + } while (prev !== head); + + prev.next = newNode; + newNode.next = curr; + + return head; +}; From 35667500efa7859bf43e15c96c255db01c23f2bb Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 18:46:55 -0500 Subject: [PATCH 14/15] Add solution #711 --- README.md | 1 + .../0711-number-of-distinct-islands-ii.js | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 solutions/0711-number-of-distinct-islands-ii.js diff --git a/README.md b/README.md index 67f86d7..9617eac 100644 --- a/README.md +++ b/README.md @@ -666,6 +666,7 @@ 708|[Insert into a Sorted Circular Linked List](./solutions/0708-insert-into-a-sorted-circular-linked-list.js)|Medium| 709|[To Lower Case](./solutions/0709-to-lower-case.js)|Easy| 710|[Random Pick with Blacklist](./solutions/0710-random-pick-with-blacklist.js)|Hard| +711|[Number of Distinct Islands II](./solutions/0711-number-of-distinct-islands-ii.js)|Hard| 712|[Minimum ASCII Delete Sum for Two Strings](./solutions/0712-minimum-ascii-delete-sum-for-two-strings.js)|Medium| 713|[Subarray Product Less Than K](./solutions/0713-subarray-product-less-than-k.js)|Medium| 714|[Best Time to Buy and Sell Stock with Transaction Fee](./solutions/0714-best-time-to-buy-and-sell-stock-with-transaction-fee.js)|Medium| diff --git a/solutions/0711-number-of-distinct-islands-ii.js b/solutions/0711-number-of-distinct-islands-ii.js new file mode 100644 index 0000000..309f9d5 --- /dev/null +++ b/solutions/0711-number-of-distinct-islands-ii.js @@ -0,0 +1,82 @@ +/** + * 711. Number of Distinct Islands II + * https://leetcode.com/problems/number-of-distinct-islands-ii/ + * Difficulty: Hard + * + * You are given an m x n binary matrix grid. An island is a group of 1's (representing land) + * connected 4-directionally (horizontal or vertical.) You may assume all four edges of the + * grid are surrounded by water. + * + * An island is considered to be the same as another if they have the same shape, or have + * the same shape after rotation (90, 180, or 270 degrees only) or reflection (left/right + * direction or up/down direction). + * + * Return the number of distinct islands. + */ + +/** + * @param {number[][]} grid + * @return {number} + */ +var numDistinctIslands2 = function(grid) { + const rows = grid.length; + const cols = grid[0].length; + const visited = Array.from({ length: rows }, () => new Array(cols).fill(false)); + const uniqueShapes = new Set(); + + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (grid[i][j] === 1 && !visited[i][j]) { + const cells = []; + dfs(i, j, cells); + const canonical = normalize(cells); + uniqueShapes.add(canonical); + } + } + } + + return uniqueShapes.size; + + function dfs(row, col, cells) { + if (row < 0 || row >= rows || col < 0 || col >= cols + || visited[row][col] || grid[row][col] === 0) { + return; + } + + visited[row][col] = true; + cells.push([row, col]); + + dfs(row + 1, col, cells); + dfs(row - 1, col, cells); + dfs(row, col + 1, cells); + dfs(row, col - 1, cells); + } + + function normalize(cells) { + const transformations = [ + (r, c) => [r, c], + (r, c) => [r, -c], + (r, c) => [-r, c], + (r, c) => [-r, -c], + (r, c) => [c, r], + (r, c) => [c, -r], + (r, c) => [-c, r], + (r, c) => [-c, -r] + ]; + + const shapes = []; + + for (const transform of transformations) { + const transformed = cells.map(([r, c]) => transform(r, c)); + transformed.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]); + + const minR = transformed[0][0]; + const minC = transformed[0][1]; + const normalized = transformed.map(([r, c]) => [r - minR, c - minC]); + + shapes.push(normalized.map(([r, c]) => `${r},${c}`).join('|')); + } + + return shapes.sort()[0]; + } +}; From 460838a4bd2467afaafd6ce1f6b70b21130ea56f Mon Sep 17 00:00:00 2001 From: Josh Crozier <5490537+JoshCrozier@users.noreply.github.com> Date: Sat, 21 Jun 2025 18:55:39 -0500 Subject: [PATCH 15/15] Add solution #716 --- README.md | 1 + solutions/0716-max-stack.js | 92 +++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 solutions/0716-max-stack.js diff --git a/README.md b/README.md index 9617eac..cf74cc2 100644 --- a/README.md +++ b/README.md @@ -671,6 +671,7 @@ 713|[Subarray Product Less Than K](./solutions/0713-subarray-product-less-than-k.js)|Medium| 714|[Best Time to Buy and Sell Stock with Transaction Fee](./solutions/0714-best-time-to-buy-and-sell-stock-with-transaction-fee.js)|Medium| 715|[Range Module](./solutions/0715-range-module.js)|Hard| +716|[Max Stack](./solutions/0716-max-stack.js)|Hard| 717|[1-bit and 2-bit Characters](./solutions/0717-1-bit-and-2-bit-characters.js)|Easy| 718|[Maximum Length of Repeated Subarray](./solutions/0718-maximum-length-of-repeated-subarray.js)|Medium| 719|[Find K-th Smallest Pair Distance](./solutions/0719-find-k-th-smallest-pair-distance.js)|Hard| diff --git a/solutions/0716-max-stack.js b/solutions/0716-max-stack.js new file mode 100644 index 0000000..f12bdc5 --- /dev/null +++ b/solutions/0716-max-stack.js @@ -0,0 +1,92 @@ +/** + * 716. Max Stack + * https://leetcode.com/problems/max-stack/ + * Difficulty: Hard + * + * Design a max stack data structure that supports the stack operations and supports finding + * the stack's maximum element. + * + * Implement the MaxStack class: + * - MaxStack() Initializes the stack object. + * - void push(int x) Pushes element x onto the stack. + * - int pop() Removes the element on top of the stack and returns it. + * - int top() Gets the element on the top of the stack without removing it. + * - int peekMax() Retrieves the maximum element in the stack without removing it. + * - int popMax() Retrieves the maximum element in the stack and removes it. If there is more + * than one maximum element, only remove the top-most one. + * + * You must come up with a solution that supports O(1) for each top call and O(logn) for each + * other call. + */ + +var MaxStack = function() { + this.stack = []; + this.maxHeap = new PriorityQueue((a, b) => a.val === b.val ? b.id - a.id : b.val - a.val); + this.nodeId = 0; + this.deleted = new Set(); +}; + +/** +* @param {number} x +* @return {void} +*/ +MaxStack.prototype.push = function(x) { + const id = this.nodeId++; + const node = { val: x, id }; + this.stack.push(node); + this.maxHeap.enqueue(node); +}; + +/** +* @return {number} +*/ +MaxStack.prototype.pop = function() { + this.cleanStack(); + const node = this.stack.pop(); + this.deleted.add(node.id); + return node.val; +}; + +/** +* @return {number} +*/ +MaxStack.prototype.top = function() { + this.cleanStack(); + return this.stack[this.stack.length - 1].val; +}; + +/** +* @return {number} +*/ +MaxStack.prototype.peekMax = function() { + this.cleanMaxHeap(); + return this.maxHeap.front().val; +}; + +/** +* @return {number} +*/ +MaxStack.prototype.popMax = function() { + this.cleanMaxHeap(); + const maxNode = this.maxHeap.dequeue(); + this.deleted.add(maxNode.id); + return maxNode.val; +}; + +/** +* @return {void} +*/ +MaxStack.prototype.cleanStack = function() { + while (this.stack.length && this.deleted.has(this.stack[this.stack.length - 1].id)) { + this.stack.pop(); + } +}; + +/** +* @return {void} +*/ +MaxStack.prototype.cleanMaxHeap = function() { + while (this.maxHeap.size() && this.deleted.has(this.maxHeap.front().id)) { + this.maxHeap.dequeue(); + } +};