diff --git a/1.two-sum.js b/1-two-sum.js similarity index 100% rename from 1.two-sum.js rename to 1-two-sum.js diff --git a/100-same-tree.js b/100-same-tree.js index 27b1830d..6cdcd4b5 100755 --- a/100-same-tree.js +++ b/100-same-tree.js @@ -1,8 +1,9 @@ /** * Definition for a binary tree node. - * function TreeNode(val) { - * this.val = val; - * this.left = this.right = null; + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) * } */ /** @@ -11,15 +12,28 @@ * @return {boolean} */ const isSameTree = function(p, q) { - return isSame(p, q); + if(p == null && q == null) return true + if(p == null || q == null || p.val !== q.val) return false + return isSameTree(p.left, q.left) && isSameTree(p.right, q.right) }; -const isSame = (p, q) => { - if (p === null && q === null) return true; +// another - if ((p !== null && q === null) || (p === null && q !== null)) return false; - - if (p.val !== q.val) return false; - - return isSame(p.left, q.left) && isSame(p.right, q.right); +/** + * 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} p + * @param {TreeNode} q + * @return {boolean} + */ +const isSameTree = function(p, q) { + if(p == null || q == null) return p === q + if(p.val !== q.val) return false + return isSameTree(p.left, q.left) && isSameTree(p.right, q.right) }; diff --git a/1001-grid-illumination.js b/1001-grid-illumination.js new file mode 100644 index 00000000..2275a29d --- /dev/null +++ b/1001-grid-illumination.js @@ -0,0 +1,67 @@ +/** + * @param {number} N + * @param {number[][]} lamps + * @param {number[][]} queries + * @return {number[]} + */ +const gridIllumination = function (N, lamps, queries) { + const rowMap = new Map() + const colMap = new Map() + const hillMap = new Map() + const daleMap = new Map() + const litMap = new Map() + const direction = [ + [0, 0], + [0, 1], + [1, 0], + [-1, 0], + [0, -1], + [-1, -1], + [1, 1], + ] + //map what areas are lit + for (let [x, y] of lamps) { + insert(rowMap, x) + insert(colMap, y) + insert(hillMap, x + y) + insert(daleMap, x - y) + litMap.set(N * x + y, true) + } + const result = new Array(queries.length).fill(0) + let count = 0 + for (let [x, y] of queries) { + if ( + rowMap.get(x) > 0 || + colMap.get(y) > 0 || + hillMap.get(x + y) > 0 || + daleMap.get(x - y) > 0 + ) { + result[count] = 1 + } + for (let [i, j] of direction) { + let newX = x + i + let newY = y + j + if (litMap.has(N * newX + newY)) { + decrease(rowMap, newX) + decrease(colMap, newY) + decrease(hillMap, newX + newY) + decrease(daleMap, N * newX + newY) + litMap.delete(N * newX + newY) + } + } + count++ + } + return result +} +const insert = (map, value) => { + if (map.has(value)) { + map.set(value, map.get(value) + 1) + } else { + map.set(value, 1) + } +} +const decrease = (map, value) => { + if (map.has(value)) { + map.set(value, map.get(value) - 1) + } +} diff --git a/10035-maximum-area-of-longest-diagonal-rectangle.js b/10035-maximum-area-of-longest-diagonal-rectangle.js new file mode 100644 index 00000000..42991b15 --- /dev/null +++ b/10035-maximum-area-of-longest-diagonal-rectangle.js @@ -0,0 +1,11 @@ +/** + * @param {number[][]} dimensions + * @return {number} + */ +var areaOfMaxDiagonal = function(dimensions) { + let res = 0 + const n = dimensions + const arr = dimensions.map(([l,w]) => [l ** 2 + w ** 2, l * w]) + arr.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : b[0] - a[0]) + return arr[0][1] +}; diff --git a/10036-minimum-moves-to-capture-the-queen.js b/10036-minimum-moves-to-capture-the-queen.js new file mode 100644 index 00000000..57cd9d85 --- /dev/null +++ b/10036-minimum-moves-to-capture-the-queen.js @@ -0,0 +1,80 @@ +/** + * @param {number} a + * @param {number} b + * @param {number} c + * @param {number} d + * @param {number} e + * @param {number} f + * @return {number} + */ +var minMovesToCaptureTheQueen = function(a, b, c, d, e, f) { + if(rook() || bishop()) return 1 + + return 2 + + function rook() { + if(a === e) { + const min = Math.min(b,f), max = Math.max(b,f) + if(c !== a) return true + else if(d < min || d > max) return true + else return false + } + if(b === f) { + const min = Math.min(a,e), max = Math.max(a,e) + if(d !== b) return true + else if(c < min || c > max) return true + else return false + } + + return false + } + function bishop() { + // c,d,e,f + + const dirs = [[-1, -1], [-1, 1], [1, -1], [1, 1]] + const visited = new Set() + const target = `${e},${f}` + const key = (x, y) => `${x},${y}` + + const ss = new Set() + // top-left + let x = c, y = d + let dd = dirs[0] + while(x + dd[0]>= 1 && x + dd[0]<= 8 && y+ dd[1] >= 1 && y+dd[1] <= 8 && (!(x + dd[0] === a && y +dd[1] === b))) { + ss.add(key(x +dd[0], y +dd[1])) + x += dd[0] + y += dd[1] + } + + // top-right + x = c, y = d + dd = dirs[1] + while(x + dd[0]>= 1 && x + dd[0]<= 8 && y+ dd[1] >= 1 && y+dd[1] <= 8 && (!(x + dd[0] === a && y +dd[1] === b))) { + ss.add(key(x +dd[0], y +dd[1])) + x += dd[0] + y += dd[1] + } + + // bottom-left + x = c, y = d + dd = dirs[2] + while(x + dd[0]>= 1 && x + dd[0]<= 8 && y+ dd[1] >= 1 && y+dd[1] <= 8 && (!(x + dd[0] === a && y +dd[1] === b))) { + ss.add(key(x +dd[0], y +dd[1])) + x += dd[0] + y += dd[1] + } + + // bottom-right + x = c, y = d + dd = dirs[3] + while(x + dd[0]>= 1 && x + dd[0]<= 8 && y+ dd[1] >= 1 && y+dd[1] <= 8 && (!(x + dd[0] === a && y +dd[1] === b))) { + ss.add(key(x +dd[0], y +dd[1])) + x += dd[0] + y += dd[1] + } + if(ss.has(target)) return true + + + return false + } +}; diff --git a/10037-maximum-size-of-a-set-after-removals.js b/10037-maximum-size-of-a-set-after-removals.js new file mode 100644 index 00000000..29bbdb66 --- /dev/null +++ b/10037-maximum-size-of-a-set-after-removals.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const maximumSetSize = function(nums1, nums2) { + const n = nums1.length, {min} = Math + const s1 = new Set(nums1), s2 = new Set(nums2) + const common = new Set() + for(const e of s1) { + if(s2.has(e)) common.add(e) + } + const n1 = s1.size, n2 = s2.size, c = common.size + return min(n, min(n1 - c, n / 2) + min(n2 - c, n / 2) + c) +}; diff --git a/1004-max-consecutive-ones-iii.js b/1004-max-consecutive-ones-iii.js new file mode 100644 index 00000000..65ca7c85 --- /dev/null +++ b/1004-max-consecutive-ones-iii.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} A + * @param {number} K + * @return {number} + */ +const longestOnes = function (A, K) { + let i = 0 + let j = 0 + const len = A.length + while (j < len) { + if (A[j] === 0) K-- + if (K < 0) { + if (A[i] === 0) K++ + i++ + } + j++ + } + return j - i +} diff --git a/1009-complement-of-base-10-integer.js b/1009-complement-of-base-10-integer.js new file mode 100644 index 00000000..f88696bd --- /dev/null +++ b/1009-complement-of-base-10-integer.js @@ -0,0 +1,44 @@ +/** + * @param {number} N + * @return {number} + */ +const bitwiseComplement = function (N) { + if (N === 0) return 1 + // bitmask has the same length as N and contains only ones 1...1 + let bitmask = N + bitmask |= bitmask >> 1 + bitmask |= bitmask >> 2 + bitmask |= bitmask >> 4 + bitmask |= bitmask >> 8 + bitmask |= bitmask >> 16 + // flip all bits + return bitmask ^ N +} + +// another + +/** + * @param {number} N + * @return {number} + */ +const bitwiseComplement = function (N) { + let X = 1; + while (N > X) X = X * 2 + 1; + return N ^ X; +} + +// another + +/** + * @param {number} N + * @return {number} + */ +const bitwiseComplement = function (N) { + if (N === 0) return 1 + // l is a length of N in binary representation + const l = Math.floor(Math.log(N) / Math.log(2)) + 1 + // bitmask has the same length as num and contains only ones 1...1 + const bitmask = (1 << l) - 1 + // flip all bits + return bitmask ^ N +} diff --git a/1011-capacity-to-ship-packages-within-d-days.js b/1011-capacity-to-ship-packages-within-d-days.js new file mode 100644 index 00000000..86b274e7 --- /dev/null +++ b/1011-capacity-to-ship-packages-within-d-days.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} weights + * @param {number} days + * @return {number} + */ +const shipWithinDays = function(weights, days) { + let l = Math.max(...weights) + let r = weights.reduce((ac, e) => ac + e, 0) + while(l < r) { + const mid = Math.floor((l + r) / 2) + if(valid(mid)) { + r = mid + } else l = mid + 1 + } + + return l + + function valid(mid) { + let res = 1, cur = 0 + for(let w of weights) { + if(cur + w > mid) { + cur = 0 + res++ + } + cur += w + } + return res <= days + } +}; diff --git a/1012-numbers-with-repeated-digits.js b/1012-numbers-with-repeated-digits.js new file mode 100644 index 00000000..b9c88524 --- /dev/null +++ b/1012-numbers-with-repeated-digits.js @@ -0,0 +1,145 @@ +/** + * @param {number} n + * @return {number} + */ +function numDupDigitsAtMostN(n) { + let numNoDupDigits = 0; // the number of positive integers less than or equal to n with no repeated digits + + let lst = Array.from(String(n), Number); + let n_digits = lst.length; + + // if n = 8765, lst = [8,7,6,5], + // the number without repeated digit can the the following format: + // XXX + // XX + // X + for (let i = 1; i < n_digits; i++) { + // the number of i digits without repeated digit + // the leading digit cannot be 0 + numNoDupDigits += 9 * perm(9, i - 1); + } + + // and + // 1XXX ~ 7XXX + // 80XX ~ 86XX + // 870X ~ 875X + // 8760 ~ 8764 + let seen = new Set(); + for (let i = 0; i < lst.length; i++) { + let x = lst[i]; + for (let y = (i === 0 ? 1 : 0); y < x; y++) { + if (!seen.has(y)) { + // the leading digit used - y + // for the remaining positions we cannot use digits in set seen and y + numNoDupDigits += perm(9 - i, n_digits - i - 1); + } + } + if (seen.has(x)) { + break; + } + seen.add(x); + } + + // and + // 8765 + if (n_digits === new Set(lst).size) { + numNoDupDigits += 1; + } + + return n - numNoDupDigits; +} + +function perm(m, n) { + let res = 1 + for(let i = 0; i < n; i++) { + res *= m + m-- + } + + return res +} + +// another + + +/** + * @param {number} n + * @return {number} + */ +var numDupDigitsAtMostN = function(n) { + const digits = [], {floor} = Math + let tmp = n + 1 + while(tmp) { + digits.push(tmp % 10) + tmp = floor(tmp / 10) + } + let res = 0 + const len = digits.length + let cur = 9 + for(let i = 0; i < len - 1; i++) { + res += cur + cur *= (9 - i) + } + cur = floor(cur / 9) + const seen = Array(10).fill(false) + for(let i = 0; i < len; i++) { + const d = digits[len - i - 1] + for(let j = (i === 0 ? 1 : 0); j < d; j++) { + if(!seen[j]) res += cur + } + cur = floor(cur / (9 - i)) + if(seen[d]) break + seen[d] = true + } + + return n - res +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +var numDupDigitsAtMostN = function(n) { + return n - helper(n) + function helper(num) { + let res = 0 + const s = `${num}` + const slen = s.length + for(let len = 1; len < slen; len++) { + res += perm(10, len) - perm(9, len - 1) + } + const visited = Array(10).fill(null) + dfs(s, 0, visited) + + return res + function dfs(s, i, visited) { + const n = s.length + if(i === n) { + res++ + return + } + for(let d = 0; d <= 9; d++) { + if(d === 0 && i === 0) continue + if(visited[d]) continue + if(d < +s[i]) { + res += perm(10 - i - 1, n - i - 1) + } else if(d === +s[i]) { + visited[d] = 1 + dfs(s, i + 1, visited) + visited[d] = 0 + } + } + } + } + + function perm(m, n) { + if(n === 0) return 1 + let res = 1 + for(let i = 0; i < n; i++) { + res *= m - i + } + return res + } +}; diff --git a/1024-video-stitching.js b/1024-video-stitching.js index 3c0452f4..2ce978c9 100644 --- a/1024-video-stitching.js +++ b/1024-video-stitching.js @@ -1,29 +1,97 @@ +/** + * @param {number[][]} clips + * @param {number} time + * @return {number} + */ +const videoStitching = function(clips, time) { + const n = clips.length + if(time === 0) return 0 + clips.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]) + let res = 0, start = 0, end = 0, nextEnd = 0, idx = 0 + + while(idx < n) { + nextEnd = end + while(idx < n && clips[idx][0] <= end) { + nextEnd = Math.max(nextEnd, clips[idx][1]) + idx++ + } + res++ + if(nextEnd >= time) return res + else if(nextEnd === end) return -1 + else { + end = nextEnd + } + } + + return -1 + +}; + +// anonther + /** * @param {number[][]} clips * @param {number} T * @return {number} */ -const videoStitching = function(clips, T) { +const videoStitching = function (clips, T) { clips.sort((a, b) => a[0] - b[0]) + if(T === 0) return 0 let laststart = -1, curend = 0, count = 0 for (let i = 0; i < clips.length; ) { - if (clips[i][0] > curend) { - return -1 - } + if (clips[i][0] > curend) return -1 let maxend = curend // while one clip's start is before or equal to current end while (i < clips.length && clips[i][0] <= curend) { - // find out the one with the max possible end maxend = Math.max(maxend, clips[i][1]) i++ } count++ curend = maxend - if (curend >= T) { - return count - } + if (curend >= T) return count } return -1 } + +// another + +/** + * @param {number[][]} clips + * @param {number} T + * @return {number} + */ +const videoStitching = function (clips, T) { + clips.sort((a, b) => a[0] - b[0]) + let res = 0 + for(let i = 0, start = 0, end = 0, len = clips.length; start < T; start = end, res++) { + for(; i < len && clips[i][0] <= start; i++) { + end = Math.max(end, clips[i][1]) + } + if(start === end) return -1 + } + return res +} + + +// another + +/** + * @param {number[][]} clips + * @param {number} T + * @return {number} + */ +const videoStitching = function (clips, T) { + const dp = Array(T + 1).fill( T + 1 ) + dp[0] = 0 + for(let i = 0; i <= T; i++) { + for(let c of clips) { + if(i >= c[0] && i <= c[1]) dp[i] = Math.min(dp[i], dp[c[0]] + 1) + } + if(dp[i] === T + 1) return -1 + } + return dp[T] +} + + diff --git a/1029-two-city-scheduling.js b/1029-two-city-scheduling.js index b6fb76e4..d973fd13 100644 --- a/1029-two-city-scheduling.js +++ b/1029-two-city-scheduling.js @@ -24,6 +24,27 @@ const twoCitySchedCost = function(costs) { // another +/** + * @param {number[][]} costs + * @return {number} + */ +const twoCitySchedCost = function(costs) { + const N = costs.length + let res = 0 + const refund = [] + for(let i = 0; i < N; i++) { + refund[i] = costs[i][1] - costs[i][0] + res += costs[i][0] + } + refund.sort((a, b) => a - b) + for(let i = 0; i < N / 2; i++) { + res += refund[i] + } + return res +}; + +// another + /** * @param {number[][]} costs * @return {number} diff --git a/103-binary-tree-zigzag-level-order-traversal.js b/103-binary-tree-zigzag-level-order-traversal.js index 9cd1f0f0..54ff515f 100644 --- a/103-binary-tree-zigzag-level-order-traversal.js +++ b/103-binary-tree-zigzag-level-order-traversal.js @@ -38,3 +38,71 @@ function bfs(row, res) { } bfs(next, res) } + +// another + +/** + * 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 {number[][]} + */ +const zigzagLevelOrder = function (root) { + if (!root) return []; + const queue = [root]; + const zigzag = []; + let numLevels = 1; + while (queue.length > 0) { + const width = queue.length; + const levelTraversal = []; + for (let i = 0; i < width; i++) { + const currentNode = queue.shift(); + if (currentNode.right) queue.push(currentNode.right); + if (currentNode.left) queue.push(currentNode.left); + numLevels % 2 === 0 + ? levelTraversal.push(currentNode.val) + : levelTraversal.unshift(currentNode.val); + } + zigzag.push(levelTraversal); + numLevels++; + } + + return zigzag; +}; + +// another + +/** + * 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 {number[][]} + */ +const zigzagLevelOrder = function (root) { + const res = [] + dfs(root, res, 0) + return res + + function dfs(node, res, level) { + if(node == null) return + if(res.length <= level) res.push([]) + const tmp = res[level] + if(level % 2 === 0) tmp.push(node.val) + else tmp.unshift(node.val) + + dfs(node.left, res, level + 1) + dfs(node.right, res, level + 1) + } +}; diff --git a/1041-robot-bounded-in-circle.js b/1041-robot-bounded-in-circle.js index e268c8c4..65146881 100644 --- a/1041-robot-bounded-in-circle.js +++ b/1041-robot-bounded-in-circle.js @@ -12,3 +12,48 @@ const isRobotBounded = function(instructions) { } return x == 0 && y == 0 || i > 0; }; + +// another + +/** + * @param {string} instructions + * @return {boolean} + */ +const isRobotBounded = function(instructions) { + let x = 0, y = 0, i = 0 + const dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]] // U, R, D, L + for(let e of instructions) { + if(e === 'R') { + i = (i + 1) % 4 + } else if(e === 'L') { + i = (i + 3) % 4 + } else { + x += dirs[i][0] + y += dirs[i][1] + } + } + return x === 0 && y === 0 || i > 0 +}; + +// another + +/** + * @param {string} instructions + * @return {boolean} + */ +const isRobotBounded = function(instructions) { + const dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]] + let x = 0, y = 0, i = 0 + for(let ins of instructions) { + if(ins === 'G') { + const dir = dirs[i] + x += dir[0] + y += dir[1] + } else if(ins === 'L') { + i = i - 1 < 0 ? 3 : i - 1 + } else if(ins === 'R') { + i = i + 1 > 3 ? 0 : i + 1 + } + } + return x === 0 && y === 0 || i !== 0 +}; diff --git a/1042-flower-planting-with-no-adjacent.js b/1042-flower-planting-with-no-adjacent.js new file mode 100644 index 00000000..8dd0b263 --- /dev/null +++ b/1042-flower-planting-with-no-adjacent.js @@ -0,0 +1,33 @@ +/** + * @param {number} N + * @param {number[][]} paths + * @return {number[]} + */ +const gardenNoAdj = function(N, paths) { + const map = {}; + for (let i = 0; i < N; i++) { + map[i] = []; + } + for (let path of paths) { + let l = path[0] - 1; + let r = path[1] - 1; + map[l].push(r); + map[r].push(l); + } + const result = new Array(N).fill(-1); + for (let i = 0; i < N; i++) { + let colors = new Array(4).fill(false); + for (let neighbor of map[i]) { + if (result[neighbor] !== -1) { + colors[result[neighbor]] = true; + } + } + for (let j = 0; j < colors.length; j++) { + if (!colors[j]) { + result[i] = j; + break; + } + } + } + return result.map(i => ++i); +}; diff --git a/1043-partition-array-for-maximum-sum.js b/1043-partition-array-for-maximum-sum.js index c98797e8..adec52a9 100644 --- a/1043-partition-array-for-maximum-sum.js +++ b/1043-partition-array-for-maximum-sum.js @@ -15,3 +15,29 @@ const maxSumAfterPartitioning = function(A, K) { } return dp[N - 1]; }; + +// another + +/** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ +const maxSumAfterPartitioning = function(arr, k) { + const n = arr.length, memo = Array(n + 1) + memo[0] = 0 + return dp(n) + + function dp(i) { + if(i === 0) return 0 + if(memo[i] != null) return memo[i] + + let sum = 0, max = 0, res = 0 + for(let j = i; j > 0 && i - j < k; j--) { + max = Math.max(max, arr[j - 1]) + sum = (i - j + 1) * max + res = Math.max(res, dp(j - 1) + sum) + } + return memo[i] = res + } +}; diff --git a/1044-longest-duplicate-substring.js b/1044-longest-duplicate-substring.js index e1bf941a..9403a04b 100644 --- a/1044-longest-duplicate-substring.js +++ b/1044-longest-duplicate-substring.js @@ -1,16 +1,49 @@ +/** + * @param {string} s + * @return {string} + */ +const longestDupSubstring = function(s) { + const n = s.length + let l = 0, r = n, res = '' + while(l < r) { + const mid = (l + r + 1) >> 1 + const [chk, str] = valid(s, mid) + if(chk) { + l = mid + res = str + } else { + r = mid - 1 + } + } + return res +}; + +function valid(s, len) { + const set = new Set() + for(let i = 0, n = s.length; i <= n - len; i++) { + const tmp = s.substr(i, len) + if(set.has(tmp)) return [true, tmp] + set.add(tmp) + } + + return [false, ''] +} + +// another + /** * @param {string} S * @return {string} */ const longestDupSubstring = function(S) { - let R = 26, + const R = 26, MOD = 1e9 + 7 let lo = 0, hi = S.length - 1, res = '' while (lo < hi) { - let len = Math.ceil((lo + hi) / 2) - let sub = rabinKarp(S, len) + const len = Math.ceil((lo + hi) / 2) + const sub = rabinKarp(S, len) if (sub !== '') { lo = len res = sub @@ -28,23 +61,23 @@ const longestDupSubstring = function(S) { for (let i = 1; i < len; i++) { RM = (RM * R) % MOD } - let map = new Map() + const map = new Map() let num = 0 // 计算前len个字符串的散列值 for (let i = 0; i < len; i++) { - let code = str.charCodeAt(i) - aCode + const code = str.charCodeAt(i) - aCode num = (num * R + code) % MOD } map.set(num, 0) // 后续计算散列值 for (let i = 0; i < str.length - len; i++) { - let preCode = str.charCodeAt(i) - aCode, + const preCode = str.charCodeAt(i) - aCode, curCode = str.charCodeAt(i + len) - aCode num = (num + MOD - ((preCode * RM) % MOD)) % MOD num = (num * R + curCode) % MOD if (map.has(num)) { - let sub = str.substring(i + 1, i + 1 + len) - let preId = map.get(num), + const sub = str.substring(i + 1, i + 1 + len) + const preId = map.get(num), preSub = str.substring(preId, preId + len) if (sub === preSub) return sub } diff --git a/1046-last-stone-weight.js b/1046-last-stone-weight.js new file mode 100644 index 00000000..978dbd30 --- /dev/null +++ b/1046-last-stone-weight.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} stones + * @return {number} + */ +const lastStoneWeight = function(stones) { + stones.sort((a, b) => a - b) + while (stones.length > 1) { + const num = Math.abs(stones.pop() - stones.pop()) + stones.splice(stones.findIndex(item => item >= num), 0, num) + } + return stones[0] +}; diff --git a/105-construct-binary-tree-from-preorder-and-inorder-traversal.js b/105-construct-binary-tree-from-preorder-and-inorder-traversal.js index a7c58a06..beebb4af 100644 --- a/105-construct-binary-tree-from-preorder-and-inorder-traversal.js +++ b/105-construct-binary-tree-from-preorder-and-inorder-traversal.js @@ -1,3 +1,36 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {number[]} preorder + * @param {number[]} inorder + * @return {TreeNode} + */ +const buildTree = function(preorder, inorder) { + if(preorder.length === 0 && inorder.length === 0) return null + const val = preorder[0] + const node = new TreeNode(val) + const inIdx = inorder.indexOf(val) + const leftIn = inorder.slice(0, inIdx) + const rightIn = inorder.slice(inIdx + 1) + + const leftPre = preorder.slice(1, leftIn.length + 1) + const rightPre = preorder.slice(leftIn.length + 1) + + // console.log(leftIn, rightIn, leftPre, rightPre) + node.left = buildTree(leftPre, leftIn) + node.right = buildTree(rightPre, rightIn) + return node +}; + + +// another + + /** * Definition for a binary tree node. * function TreeNode(val) { diff --git a/1050-actors-and-directors-who-cooperated-at-least-three-times.sql b/1050-actors-and-directors-who-cooperated-at-least-three-times.sql new file mode 100644 index 00000000..13ea8e07 --- /dev/null +++ b/1050-actors-and-directors-who-cooperated-at-least-three-times.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +SELECT actor_id, director_id +FROM ActorDirector +GROUP BY actor_id, director_id +HAVING COUNT(1) >= 3 diff --git a/1052-grumpy-bookstore-owner.js b/1052-grumpy-bookstore-owner.js index 4aae8d95..977d6c8b 100644 --- a/1052-grumpy-bookstore-owner.js +++ b/1052-grumpy-bookstore-owner.js @@ -24,3 +24,28 @@ const maxSatisfied = function(customers, grumpy, X) { return totalSatisfiedCustomers + max } + +// another + +/** + * @param {number[]} customers + * @param {number[]} grumpy + * @param {number} X + * @return {number} + */ +const maxSatisfied = function (customers, grumpy, X) { + let satisfied = 0, + maxMakeSatisfied = 0 + for (let i = 0, winOfMakeSatisfied = 0; i < grumpy.length; ++i) { + if (grumpy[i] === 0) { + satisfied += customers[i] + } else { + winOfMakeSatisfied += customers[i] + } + if (i >= X) { + winOfMakeSatisfied -= grumpy[i - X] * customers[i - X] + } + maxMakeSatisfied = Math.max(winOfMakeSatisfied, maxMakeSatisfied) + } + return satisfied + maxMakeSatisfied +} diff --git a/1054-distant-barcodes.js b/1054-distant-barcodes.js index 452c9d04..c0930553 100644 --- a/1054-distant-barcodes.js +++ b/1054-distant-barcodes.js @@ -1,3 +1,42 @@ +/** + * @param {number[]} barcodes + * @return {number[]} + */ +const rearrangeBarcodes = function(barcodes) { + const hash = {} + let maxFreq = 0, max = 0 + for(const e of barcodes) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + if(hash[e] > maxFreq) { + maxFreq = hash[e] + max = e + } + } + const n = barcodes.length + const entries = Object.entries(hash) + const res = Array(n) + let idx = 0 + while(maxFreq) { + res[idx] = max + idx += 2 + maxFreq-- + } + for(let [v, f] of entries) { + if(+v === max) continue + while(f) { + if(idx >= n) idx = 1 + res[idx] = +v + idx += 2 + f-- + } + } + + return res +}; + +// another + /** * @param {number[]} barcodes * @return {number[]} @@ -20,3 +59,48 @@ const rearrangeBarcodes = function(barcodes) { return barcodes; }; + +// another + +/** + * @param {number[]} barcodes + * @return {number[]} + */ +const rearrangeBarcodes = function(barcodes) { + const hash = {}, n = barcodes.length + for(let e of barcodes) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + const res = Array(n) + let max = 0, idx = -1 + for(let k in hash) { + if(hash[k] > max) { + max = hash[k] + idx = +k + } + } + let i = 0 + // max freq first + while(max > 0) { + res[i] = idx + max-- + i += 2 + } + // the rest + const keys = Object.keys(hash).map(e => +e) + for(let j = 0, len = keys.length; j < len; j++) { + if(keys[j] !== idx) { + const k = keys[j] + let freq = hash[k] + while(freq > 0) { + if(i >= n) i = 1 + res[i] = k + freq-- + i += 2 + } + } + } + + return res +}; diff --git a/1055-shortest-way-to-form-string,js b/1055-shortest-way-to-form-string,js new file mode 100644 index 00000000..886c670c --- /dev/null +++ b/1055-shortest-way-to-form-string,js @@ -0,0 +1,53 @@ +/** + * @param {string} source + * @param {string} target + * @return {number} + */ +const shortestWay = function(source, target) { + const a = 'a'.charCodeAt(0), arr = Array(26).fill(0) + for(const ch of source) arr[ch.charCodeAt(0) - a] = 1 + let res = 0, j = 0 + for(let i = 0, n = source.length; i < n; i++) { + if(arr[target[j].charCodeAt(0) - a] === 0) return -1 + if(source[i] === target[j]) j++ + if(j === target.length) { + res++ + break + } + if(i === n - 1) { + res++ + i = -1 + } + } + + return res +}; + +// another + +/** + * @param {string} source + * @param {string} target + * @return {number} + */ +const shortestWay = function(source, target) { + const a = 'a'.charCodeAt(0), map = Array(26).fill(0) + for(let ch of source) { + map[ch.charCodeAt(0) - a] = 1 + } + let j = 0, res = 1 + for(let i = 0, n = target.length; i < n; i++, j++) { + const cur = target[i] + if(map[cur.charCodeAt(0) - a] === 0) return -1 + while(j < source.length && source[j] !== cur) { + j++ + } + if(j === source.length) { + res++ + j = -1 + i-- + } + } + + return res +}; diff --git a/1056-confusing-number.js b/1056-confusing-number.js new file mode 100644 index 00000000..66bb7319 --- /dev/null +++ b/1056-confusing-number.js @@ -0,0 +1,19 @@ +/** + * @param {number} n + * @return {boolean} + */ +const confusingNumber = function(n) { + // 0, 1, 6, 8, 9 + const invalid = new Set(['2', '3', '4', '5', '7']) + const valid = new Set(['6', '9']) + const arr = ('' + n).split('') + let num = 0 + for(let i = 0; i < arr.length; i++) { + const ch = arr[i] + if(invalid.has(ch)) return false + if(ch === '6') arr[i] = '9' + else if(ch === '9') arr[i] = '6' + } + arr.reverse() + return arr.join('') !== '' + n +}; diff --git a/1059-all-paths-from-source-lead-to-destination.js b/1059-all-paths-from-source-lead-to-destination.js new file mode 100644 index 00000000..46512113 --- /dev/null +++ b/1059-all-paths-from-source-lead-to-destination.js @@ -0,0 +1,37 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} source + * @param {number} destination + * @return {boolean} + */ +const leadsToDestination = function(n, edges, source, destination) { + const inm = new Map(), outm = new Map() + for(let k = 0, len = edges.length; k < len; k++) { + const [o, i] = edges[k] + if(!inm.has(i)) inm.set(i, new Set()) + if(!outm.has(o)) outm.set(o, new Set()) + inm.get(i).add(o) + outm.get(o).add(i) + } + const visited = new Set() + const obj = { res: true } + dfs(source) + return obj.res + function dfs(node) { + if((outm.get(node) == null || outm.get(node).size === 0) && node !== destination) { + obj.res = false + return + } + if(visited.has(node)) { + obj.res = false + return + } + if(outm.get(node) == null) return + visited.add(node) + for(let e of outm.get(node)) { + if(obj.res) dfs(e) + } + visited.delete(node) + } +}; diff --git a/106-construct-binary-tree-from-inorder-and-postorder-traversal.js b/106-construct-binary-tree-from-inorder-and-postorder-traversal.js index e94dade1..19c5a701 100644 --- a/106-construct-binary-tree-from-inorder-and-postorder-traversal.js +++ b/106-construct-binary-tree-from-inorder-and-postorder-traversal.js @@ -30,3 +30,39 @@ const buildTree = function(inorder, postorder) { return root; } }; + +// another + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {number[]} inorder + * @param {number[]} postorder + * @return {TreeNode} + */ + +const buildTree = function (inorder, postorder) { + let pInorder = inorder.length - 1 + let pPostorder = postorder.length - 1 + return helper(inorder, postorder, null) + function helper(inorder, postorder, end) { + if (pPostorder < 0) return null + // create root node + const n = new TreeNode(postorder[pPostorder--]) + // if right node exist, create right subtree + if (inorder[pInorder] != n.val) { + n.right = helper(inorder, postorder, n) + } + pInorder-- + // if left node exist, create left subtree + if (end === null || inorder[pInorder] !== end.val) { + n.left = helper(inorder, postorder, end) + } + return n + } +} diff --git a/1060-missing-element-in-sorted-array.js b/1060-missing-element-in-sorted-array.js new file mode 100644 index 00000000..a151e66f --- /dev/null +++ b/1060-missing-element-in-sorted-array.js @@ -0,0 +1,101 @@ +/** + +Given a sorted array A of unique numbers, find the K-th missing number +starting from the leftmost number of the array. + +Example 1: + +Input: A = [4,7,9,10], K = 1 +Output: 5 +Explanation: +The first missing number is 5. +Example 2: + +Input: A = [4,7,9,10], K = 3 +Output: 8 +Explanation: +The missing numbers are [5,6,8,...], hence the third missing number is 8. +Example 3: + +Input: A = [1,2,4], K = 3 +Output: 6 +Explanation: +The missing numbers are [3,5,6,7,...], hence the third missing number is 6. + +Note: + +1 <= A.length <= 50000 +1 <= A[i] <= 1e7 +1 <= K <= 1e8 + +*/ + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const missingElement = function(nums, k) { + for (let i = 1, len = nums.length; i < len; i++) { + const dif = nums[i] - nums[i - 1] - 1 + if (dif >= k) { + return nums[i - 1] + k + } + k -= dif + } + return nums[nums.length - 1] + k +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const missingElement = function(nums, k) { + const n = nums.length + let l = 0 + let h = n - 1 + const missingNum = nums[n - 1] - nums[0] + 1 - n + if (missingNum < k) { + return nums[n - 1] + k - missingNum + } + while (l < h - 1) { + const m = l + ((h - l) >> 1) + const missing = nums[m] - nums[l] - (m - l) + if (missing >= k) { + h = m + } else { + k -= missing + l = m + } + } + return nums[l] + k +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const missingElement = function(nums, k) { + const n = nums.length + if (k > missing(nums, n - 1)) return nums[n - 1] + k - missing(nums, n - 1) + let left = 0, + right = n - 1, + pivot + while (left < right) { + pivot = left + Math.floor((right - left) / 2) + if (missing(nums, pivot) < k) left = pivot + 1 + else right = pivot + } + return nums[left - 1] + k - missing(nums, left - 1) +} +function missing(arr, idx) { + return arr[idx] - arr[0] - idx +} + diff --git a/1061-lexicographically-smallest-equivalent-string.js b/1061-lexicographically-smallest-equivalent-string.js new file mode 100644 index 00000000..8672746c --- /dev/null +++ b/1061-lexicographically-smallest-equivalent-string.js @@ -0,0 +1,47 @@ +/** + * @param {string} s1 + * @param {string} s2 + * @param {string} baseStr + * @return {string} + */ +var smallestEquivalentString = function (s1, s2, baseStr) { + if (s1.length === 0 || s2.length === 0) return '' + const uf = new UnionFind() + for (let i = 0; i < s1.length; i++) { + uf.union(s1[i], s2[i]) + } + let res = '' + for (const ch of baseStr) { + res += uf.find(ch) || ch // some letters don't have connected component + } + return res +} +class UnionFind { + constructor() { + this.parents = new Map() + } + find(x) { + if (this.parents.get(x) === x) return x + this.parents.set(x, this.find(this.parents.get(x))) // path compression + return this.parents.get(x) + } + union(u, v) { + // init + if (!this.parents.has(u)) { + this.parents.set(u, u) + } + if (!this.parents.has(v)) { + this.parents.set(v, v) + } + // find root + const rootU = this.find(u) + const rootV = this.find(v) + if (rootU === rootV) return // connected already + // set smallest lex as the root + if (rootU > rootV) { + this.parents.set(rootU, rootV) + } else { + this.parents.set(rootV, rootU) + } + } +} diff --git a/1062-longest-repeating-substring.js b/1062-longest-repeating-substring.js new file mode 100644 index 00000000..ee57fe13 --- /dev/null +++ b/1062-longest-repeating-substring.js @@ -0,0 +1,116 @@ +/** + * @param {string} s + * @return {number} + */ +const longestRepeatingSubstring = function(s) { + let left = 0; + let right = s.length - 1; + while(left < right) { + let pivot = Math.floor((left + right + 1) / 2); + if (hasRepeat(s, pivot)) { + left = pivot; + } else { + right = pivot - 1; + } + } + return left; +}; + +const hasRepeat = (s, l) => { + const strings = new Set(); + for (let i = 0; i < s.length - l + 1; i++) { + const sub = s.substr(i, l); + if (strings.has(sub)) { + return true; + } + strings.add(sub); + } + return false; +} + +// another + +/** + * @param {string} s + * @return {number} + */ +const longestRepeatingSubstring = function(s) { + const n = s.length; + // dp[i][j] means # of repeated chars for substrings ending at i and j + const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0)); + let res = 0; + for (let i = 1; i <= n; i++) { + for (let j = i + 1; j <= n; j++) { + if (s.charAt(i - 1) === s.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1] + 1; + res = Math.max(res, dp[i][j]); + } + } + } + return res; +}; + +// non-overlap version +// http://nriverwang.blogspot.com/2013/04/longest-repeated-substring.html + +/* +You are to find the longest repeated substring in a given text. +Repeated substrings may not overlap. If more than one substring is +repeated with the same length, print the first one you find.(starting +from the beginning of the text). NOTE: The substrings can't be all spaces. + +Input Sample: +Your program should accept as its first argument a path to a filename. +The input file contains several lines. Each line is one test case. +Each line contains a test string. eg. + +banana +abc + +Output Sample: +For each set of input produce a single line of output which is the +longest repeated substring. If there is none, print out the string NONE. eg. +an +NONE + +std::string repeated_substring(std::string &str) { + int len = str.length(); + + int **c = new int*[len + 1]; + for (int i = 0; i <= len; ++i) + c[i] = new int[len + 1]; + for (int i = 0; i <= len; ++i) { + c[i][0] = 0; + c[0][i] = 0; + } + + int max_len = 0, index = len + 1; + for (int i = 1; i <= len; ++i) { + for (int j = 1; j <= len; ++j) { + if (str[i-1] == str[j-1] && abs(i-j) > c[i-1][j-1]) { + c[i][j] = c[i-1][j-1] + 1; + if (c[i][j] > max_len) { + max_len = c[i][j]; + index = std::min(i, j); + } + } else { + c[i][j] = 0; + } + } + } + + for (int i = 0; i <= len; ++i) + delete[] c[i]; + delete[] c; + + if (max_len > 0) { + std::string ret = str.substr(index - max_len, max_len); + for (int i = 0; i < max_len; ++i) + if(ret[i] != ' ') + return ret; + } + + return "NONE"; +} + +*/ diff --git a/1064-fixed-point.js b/1064-fixed-point.js new file mode 100644 index 00000000..39a1113d --- /dev/null +++ b/1064-fixed-point.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const fixedPoint = function(arr) { + const n = arr.length + let l = 0, r = n - 1 + while(l < r) { + const mid = l + ((r - l) >> 1) + if(arr[mid] < mid) l = mid + 1 + else if(arr[mid] > mid) r = mid - 1 + else r = mid + } + return arr[l] === l ? l : -1 +}; diff --git a/1065-index-pairs-of-a-string.js b/1065-index-pairs-of-a-string.js new file mode 100644 index 00000000..90eca7b8 --- /dev/null +++ b/1065-index-pairs-of-a-string.js @@ -0,0 +1,41 @@ +/** + * @param {string} text + * @param {string[]} words + * @return {number[][]} + */ +const indexPairs = function(text, words) { + const res = [], trie = buildTrie(words) + const n = text.length + for(let i = 0; i < n; i++) { + let node = trie + for(let j = i; j < n; j++) { + if(node.children[text[j]] == null) break + node = node.children[text[j]] + if(node.isWord) res.push([i, j]) + } + } + + return res +}; + +function buildTrie(words) { + const root = new Trie() + + for(let word of words) { + let node = root + for(let c of word) { + if(node.children[c] == null) node.children[c] = new Trie() + node = node.children[c] + } + node.isWord = true + } + + return root +} + +class Trie { + constructor() { + this.children = {} + this.isWord = false + } +} diff --git a/1066-campus-bikes-ii.js b/1066-campus-bikes-ii.js new file mode 100644 index 00000000..8b536b6d --- /dev/null +++ b/1066-campus-bikes-ii.js @@ -0,0 +1,141 @@ +/** + * @param {number[][]} workers + * @param {number[][]} bikes + * @return {number} + */ +const assignBikes = function(workers, bikes) { + const { abs, min } = Math + const n = workers.length, m = bikes.length + + const limit = 1 << m + const dp = Array(limit).fill(Infinity) + dp[0] = 0 + let res = Infinity + for(let mask = 1; mask < limit; mask++) { + if(bitCnt(mask) > n) continue + for(let i = 0; i < m; i++) { + if((mask >> i) & 1) { + dp[mask] = min( + dp[mask], + dp[mask ^ (1 << i)] + distance(bitCnt(mask) - 1, i) + ) + } + } + if(bitCnt(mask) === n) { + res = min(res, dp[mask]) + } + } + + return res + + function bitCnt(num) { + let res = 0 + while(num) { + num = num & (num - 1) + res++ + } + + return res + } + + // worker, bike + function distance(i, j) { + return abs(workers[i][0] - bikes[j][0]) + abs(workers[i][1] - bikes[j][1]) + } +}; + +// another + +/** + * @param {number[][]} workers + * @param {number[][]} bikes + * @return {number} + */ +const assignBikes = function(workers, bikes) { + const n = workers.length, m = bikes.length + let res = Infinity + dfs(0, 0, 0) + return res + function dfs(i, mask, cur) { + if(i === n) { + res = Math.min(res, cur) + return + } + for(let j = 0; j < m; j++) { + if((mask & (1 << j)) === 0) { + dfs(i + 1, mask | (1 << j), cur + calc(i, j)) + } + } + } + + function calc(i, j) { + const a = workers[i], b = bikes[j] + return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]) + } + +}; + +// another + +/** + * @param {number[][]} workers + * @param {number[][]} bikes + * @return {number} + */ +const assignBikes = function(workers, bikes) { + const n = workers.length, m = bikes.length + const dp = Array(1 << m).fill(Infinity) + return dfs(0, 0) + + function dfs(i, mask) { + if(i >= workers.length) return 0 + if(dp[mask] !== Infinity) return dp[mask] + for(let j = 0; j < bikes.length; j++) { + if((mask & (1 << j)) === 0) { + dp[mask] = Math.min(dp[mask], dist(i, j) + dfs(i + 1, mask + (1 << j))) + } + } + + return dp[mask] + } + + function dist(j, i) { + return Math.abs(bikes[i][0] - workers[j][0]) + Math.abs(bikes[i][1] - workers[j][1]) + } +}; + +// another + +/** + * @param {number[][]} workers + * @param {number[][]} bikes + * @return {number} + */ +const assignBikes = function (workers, bikes) { + const n = workers.length + const m = bikes.length + const dp = Array.from({ length: n + 1 }, () => + Array(1 << m).fill(Number.MAX_VALUE / 2) + ) + + dp[0][0] = 0 + let min = Number.MAX_VALUE + for (let i = 1; i <= n; i++) { + for (let s = 1; s < 1 << m; s++) { + for (let j = 0; j < m; j++) { + if ((s & (1 << j)) === 0) continue + let prev = s ^ (1 << j) + dp[i][s] = Math.min( + dp[i - 1][prev] + dis(workers[i - 1], bikes[j]), + dp[i][s] + ) + if (i === n) min = Math.min(min, dp[i][s]) + } + } + } + return min +} + +function dis(p1, p2) { + return Math.abs(p1[0] - p2[0]) + Math.abs(p1[1] - p2[1]) +} diff --git a/1067-digit-count-in-range.js b/1067-digit-count-in-range.js new file mode 100644 index 00000000..7b75d18d --- /dev/null +++ b/1067-digit-count-in-range.js @@ -0,0 +1,80 @@ +/** + * @param {number} d + * @param {number} low + * @param {number} high + * @return {number} + */ +const digitsCount = function(d, low, high) { + return countDigit(high, d) - countDigit(low - 1, d) +}; +function countDigit(limit, d) { + let res = 0 + const str = `${limit}` + const len = str.length + const { pow } = Math + if(d === 0) { + for(let i = 1; i < len; i++) { + const pre = ~~(limit / pow(10, i)) + const post = pow(10, i - 1) + res += (pre - 1) * post + const e = +str[len - i] + if(e > d) { + res += post + } else if(e === d) { + res += (limit % post) + 1 + } + } + } else { + for(let i = 1; i <= len; i++) { + const pre = ~~(limit / pow(10, i)) + const post = pow(10, i - 1) + res += pre * post + const e = +str[len - i] + if(e > d) { + res += post + } else if(e === d) { + res += (limit % post) + 1 + } + } + } + + + return res +} + + +// another + +/** + * @param {number} d + * @param {number} low + * @param {number} high + * @return {number} + */ +const digitsCount = function (d, low, high) { + return countDigit(high, d) - countDigit(low - 1, d) + + function countDigit(n, d) { + if (n < 0 || n < d) { + return 0 + } + let count = 0 + for (let i = 1; i <= n; i *= 10) { + let divider = i * 10 + count += ((n / divider) >> 0) * i + if (d > 0) { + // tailing number need to be large than d * i to qualify. + count += Math.min(Math.max((n % divider) - d * i + 1, 0), i) + } else { + if (n / divider > 0) { + if (i > 1) { + // when d == 0, we need avoid to take numbers like 0xxxx into account. + count -= i + count += Math.min((n % divider) + 1, i) + } + } + } + } + return count + } +} diff --git a/1068-product-sales-analysis-i.sql b/1068-product-sales-analysis-i.sql new file mode 100644 index 00000000..fb17c96c --- /dev/null +++ b/1068-product-sales-analysis-i.sql @@ -0,0 +1,7 @@ +# Write your MySQL query statement below +SELECT p.product_name, s.year, s.price +FROM + (SELECT DISTINCT product_id, year, price + FROM Sales) AS s +INNER JOIN Product AS p +WHERE s.product_id = p.product_id diff --git a/1069-product-sales-analysis-ii.sql b/1069-product-sales-analysis-ii.sql new file mode 100644 index 00000000..b35be6c5 --- /dev/null +++ b/1069-product-sales-analysis-ii.sql @@ -0,0 +1,2 @@ +# Write your MySQL query statement below +select product_id, sum(quantity) as total_quantity from Sales s group by product_id; diff --git a/107-binary-tree-level-order-traversal-ii.js b/107-binary-tree-level-order-traversal-ii.js new file mode 100644 index 00000000..12484e33 --- /dev/null +++ b/107-binary-tree-level-order-traversal-ii.js @@ -0,0 +1,45 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[][]} + */ +const levelOrderBottom = function(root) { + const levels = [] + postOrderTraversal(root) + return levels.reverse() + + function postOrderTraversal(node, level = 0) { + if (node) { + if (!levels[level]) levels.push([]) + postOrderTraversal(node.left, level + 1) + postOrderTraversal(node.right, level + 1) + levels[level].push(node.val) + } + } +} + +// another + +const levelOrderBottom = function(root) { + if (!root) return [] + const currentLevelNodes = [root] + const result = [] + while (currentLevelNodes.length > 0) { + const count = currentLevelNodes.length + const currentLevelValues = [] + for (let i = 0; i < count; i++) { + const node = currentLevelNodes.shift() + currentLevelValues.push(node.val) + if (node.left) currentLevelNodes.push(node.left) + if (node.right) currentLevelNodes.push(node.right) + } + result.unshift(currentLevelValues) + } + return result +} diff --git a/1070-product-sales-analysis-iii.sql b/1070-product-sales-analysis-iii.sql new file mode 100644 index 00000000..dfa5ddef --- /dev/null +++ b/1070-product-sales-analysis-iii.sql @@ -0,0 +1,12 @@ +# Write your MySQL query statement below +select sub.product_id, + sub.first_year, + S.quantity, + S.price +from (select product_id, + min(year) as first_year + from Sales + group by product_id) sub, + Sales S +where S.product_id = sub.product_id +and S.year = sub.first_year diff --git a/1075-project-employees-i.sql b/1075-project-employees-i.sql new file mode 100644 index 00000000..4384a49a --- /dev/null +++ b/1075-project-employees-i.sql @@ -0,0 +1,7 @@ +# Write your MySQL query statement below +SELECT p.project_id, +ROUND(AVG(e.experience_years), 2) AS average_years +FROM Project AS p +INNER JOIN Employee AS e +ON p.employee_id = e.employee_id +GROUP BY p.project_id; diff --git a/1076-project-employees-ii.sql b/1076-project-employees-ii.sql new file mode 100644 index 00000000..b24cd3f0 --- /dev/null +++ b/1076-project-employees-ii.sql @@ -0,0 +1,11 @@ +# Write your MySQL query statement below +SELECT project_id +FROM project +GROUP BY project_id +HAVING COUNT(*) = ( + SELECT COUNT(*) cnt + FROM project + GROUP BY project_id + ORDER BY cnt DESC + LIMIT 1 +); diff --git a/1077-project-employees-iii.sql b/1077-project-employees-iii.sql new file mode 100644 index 00000000..254561ee --- /dev/null +++ b/1077-project-employees-iii.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +SELECT P.project_id, E.employee_id +FROM Project as P +INNER JOIN Employee as E On E.employee_id = P.employee_id +WHERE (P.project_id , E.experience_years) in ( +SELECT P.project_id, MAX(E.experience_years) +FROM Project as P +INNER JOIN Employee as E On E.employee_id = P.employee_id +GROUP BY P.project_id); diff --git a/1081-smallest-subsequence-of-distinct-characters.js b/1081-smallest-subsequence-of-distinct-characters.js index f27ff2d9..2b5e37c8 100644 --- a/1081-smallest-subsequence-of-distinct-characters.js +++ b/1081-smallest-subsequence-of-distinct-characters.js @@ -56,3 +56,26 @@ const smallestSubsequence = function(s) { return res.join('') }; +// anoother + + +/** + * @param {string} text + * @return {string} + */ +const smallestSubsequence = function(text) { + const n = text.length, stack = [], last = {}, visited = {} + for(let i = 0; i < n; i++) last[text[i]] = i + for(let i = 0; i < n; i++) { + const ch = text[i] + if (visited[ch]) continue + while(stack.length && stack[stack.length - 1] > ch && last[stack[stack.length - 1]] > i) { + visited[stack[stack.length - 1]] = 0 + stack.pop() + } + visited[ch] = 1 + stack.push(ch) + } + + return stack.join('') +}; diff --git a/1082-sales-analysis-i.sql b/1082-sales-analysis-i.sql new file mode 100644 index 00000000..39fb6d3e --- /dev/null +++ b/1082-sales-analysis-i.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +select seller_id from Sales +group by seller_id +having sum(price) = +(select sum(price) as sm +from Sales +group by seller_id +order by sm desc +limit 1); diff --git a/1083-sales-analysis-ii.sql b/1083-sales-analysis-ii.sql new file mode 100644 index 00000000..b4d215c8 --- /dev/null +++ b/1083-sales-analysis-ii.sql @@ -0,0 +1,10 @@ +# Write your MySQL query statement below +select distinct buyer_id from sales s +join product p +on p.product_id = s.product_id +where buyer_id not in ( + select distinct buyer_id from sales s + join product p on + s.product_id = p.product_id + where product_name = 'iPhone' +) and product_name='S8'; diff --git a/1084-sales-analysis-iii.sql b/1084-sales-analysis-iii.sql new file mode 100644 index 00000000..a58724c0 --- /dev/null +++ b/1084-sales-analysis-iii.sql @@ -0,0 +1,7 @@ +# Write your MySQL query statement below +SELECT product_id, product_name +FROM Sales +JOIN Product +Using(product_id) +GROUP BY product_id +HAVING MIN(sale_date) >= '2019-01-01' AND MAX(sale_date) <= '2019-03-31' diff --git a/1085-sum-of-digits-in-the-minimum-number.js b/1085-sum-of-digits-in-the-minimum-number.js new file mode 100644 index 00000000..13032caf --- /dev/null +++ b/1085-sum-of-digits-in-the-minimum-number.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const sumOfDigits = function(nums) { + let min = Math.min(...nums); + let ans = 0; + while (min > 0) { + ans += min % 10; + min = ~~(min / 10); + } + return 1 - ans % 2; +}; diff --git a/1086-high-five.js b/1086-high-five.js new file mode 100644 index 00000000..28a31f5c --- /dev/null +++ b/1086-high-five.js @@ -0,0 +1,67 @@ +/** + +Given a list of scores of different students, return the average score +of each student's top five scores in the order of each student's id. + +Each entry items[i] has items[i][0] the student's id, and items[i][1] +the student's score. The average score is calculated using integer division. + +Example 1: + +Input: [[1,91],[1,92],[2,93],[2,97],[1,60],[2,77],[1,65],[1,87],[1,100],[2,100],[2,76]] +Output: [[1,87],[2,88]] +Explanation: +The average of the student with id = 1 is 87. +The average of the student with id = 2 is 88.6. But with integer division +their average converts to 88. + +Note: + +1 <= items.length <= 1000 +items[i].length == 2 +The IDs of the students is between 1 to 1000 +The score of the students is between 1 to 100 +For each student, there are at least 5 scores + +*/ + +/** + * @param {number[][]} items + * @return {number[][]} + */ +const highFive = function(items) { + const m = {} + for(let el of items) { + const key = '' + el[0] + if(!m.hasOwnProperty(key)) m[key] = [] + add(m[key], el[1]) + } + const res = [] + Object.entries(m).forEach(el => { + res.push([+el[0], div(el[1])]) + }) + return res.sort((a, b) => a[0] - b[0]) +}; + +function div(arr) { + let sum = 0 + arr.forEach(el => sum += el) + return sum / 5 >> 0 +} + +function add(arr, val) { + if(arr.length < 5) arr.push(val) + else { + let min = Number.MAX_VALUE + let idx = -1 + for(let i = 0, len = arr.length; i < len; i++) { + if(arr[i] < min) { + min = arr[i] + idx = i + } + } + if(val > min && idx !== -1) { + arr.splice(idx, 1, val) + } + } +} diff --git a/1087-brace-expansion.js b/1087-brace-expansion.js new file mode 100644 index 00000000..5f1039d5 --- /dev/null +++ b/1087-brace-expansion.js @@ -0,0 +1,46 @@ +/** + * @param {string} S + * @return {string[]} + */ +const expand = function(S) { + const arr = [] + let cur = '' + for (let i = 0, len = S.length; i < len; i++) { + const ch = S.charAt(i) + if (ch === '{') { + if (cur) arr.push(cur) + cur = [] + } else if (ch === '}') { + arr.push(cur.sort()) + cur = '' + } else if (ch === ',') { + } else { + if (typeof cur === 'string' || cur === '') { + cur += ch + } else { + cur.push(ch) + } + } + } + arr.push(cur) + const res = [] + bt(arr, 0, '', res) + return res +} +function bt(arr, i, cur, res) { + if (i === arr.length) { + res.push(cur) + return + } + if (typeof arr[i] === 'string') { + cur += arr[i] + bt(arr, i + 1, cur, res) + } else { + for (let j = 0, len = arr[i].length; j < len; j++) { + let bak = cur + cur += arr[i][j] + bt(arr, i + 1, cur, res) + cur = bak + } + } +} diff --git a/1088-confusing-number-ii.js b/1088-confusing-number-ii.js new file mode 100644 index 00000000..756294f2 --- /dev/null +++ b/1088-confusing-number-ii.js @@ -0,0 +1,24 @@ +/** + * @param {number} N + * @return {number} + */ +const confusingNumberII = function (N) { + const valid = [ + [0, 0], + [1, 1], + [6, 9], + [8, 8], + [9, 6], + ] + function dfs(num, rotated, order) { + let count = 0 + if (num !== rotated) count++ + for (const [dig, rot] of valid) { + if (num === 0 && dig === 0) continue + if (num * 10 + dig > N) break + count += dfs(num * 10 + dig, rot * order + rotated, order * 10) + } + return count + } + return dfs(0, 0, 1) +} diff --git a/1091-shortest-path-in-binary-matrix.js b/1091-shortest-path-in-binary-matrix.js index 85741715..110137e1 100644 --- a/1091-shortest-path-in-binary-matrix.js +++ b/1091-shortest-path-in-binary-matrix.js @@ -3,32 +3,78 @@ * @return {number} */ const shortestPathBinaryMatrix = function(grid) { - let N = grid.length, - qu = [[0, 0]], - path = 1 + if(grid == null || grid.length === 0 || grid[0][0] === 1) return -1 + let res = 1 + const n = grid.length const dirs = [ - [-1, 0], [1, 0], + [-1, 0], + [0, 1], [0, -1], + [-1, -1], + [-1, 1], + [1, 1], + [1, -1], + ] + let q = [[0, 0]] + while(q.length) { + const tmp = q + q = [] + for(let [x, y] of tmp) { + if (x < 0 || x >= n || y < 0 || y >= n || grid[x][y] !== 0) continue + if(x === n - 1 && y === n - 1) return res + grid[x][y] = 1 + for(let [dx, dy] of dirs) { + q.push([x + dx, y + dy]) + } + } + res++ + } + return -1 +}; + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const shortestPathBinaryMatrix = function(grid) { + if(grid == null || grid.length === 0 || grid[0][0] === 1) return -1 + let res = 1 + const n = grid.length + const dirs = [ + [1, 0], + [-1, 0], [0, 1], + [0, -1], [-1, -1], [-1, 1], + [1, 1], [1, -1], - [1, 1] ] - while (qu.length !== 0) { - let cop = qu - qu = [] - for (let [r, c] of cop) { - if (r < 0 || r >= grid.length || c < 0 || c >= grid[0].length) continue - if (grid[r][c] === 1) continue - grid[r][c] = 1 - if (r === N - 1 && c === N - 1) return path - for (let dir of dirs) { - qu.push([r + dir[0], c + dir[1]]) + let q = [[0, 0]] + while(q.length) { + let ref = q + q = [] + for(let [x, y] of ref) { + if(x === n - 1 && y === n - 1) return res + grid[x][y] = 1 + for(let [dx, dy] of dirs) { + const nx = x + dx, ny = y + dy + if(helper(grid, nx, ny)) { + q.push([nx, ny]) + grid[nx][ny] = 1 // very important + } } } - path++ + res++ } return -1 +}; + +function helper(grid, i, j) { + const n = grid.length + if(i < 0 || i >= n || j < 0 || j >= n || grid[i][j] !== 0) return false + return true } diff --git a/1094-car-pooling.js b/1094-car-pooling.js index 9b82dc84..a37547cf 100644 --- a/1094-car-pooling.js +++ b/1094-car-pooling.js @@ -1,3 +1,26 @@ +/** + * @param {number[][]} trips + * @param {number} capacity + * @return {boolean} + */ +const carPooling = function(trips, capacity) { + const arr = Array(1001).fill(0) + for(const [num, s, e] of trips) { + arr[s] += num + arr[e] -= num + } + for(let i = 1; i < 1001; i++) { + arr[i] += arr[i - 1] + } + + for(let e of arr) { + if(e > capacity) return false + } + return true +}; + +// another + /** * @param {number[][]} trips * @param {number} capacity @@ -12,3 +35,27 @@ const carPooling = function(trips, capacity) { for (let i = 0; capacity >= 0 && i < 1001; ++i) capacity -= stops[i] return capacity >= 0 } + +// another + +/** + * @param {number[][]} trips + * @param {number} capacity + * @return {boolean} + */ +const carPooling = function(trips, capacity) { + const arr = Array(1001).fill(0) + for(let el of trips) { + const [num, s, e] = el + arr[s] += num + arr[e] -= num + } + for(let i = 1; i < 1001; i++) { + if(arr[i] !== 0) arr[i] += arr[i - 1] + else arr[i] = arr[i - 1] + } + for(let e of arr) { + if(e > capacity) return false + } + return true +}; diff --git a/1096-brace-expansion-ii.js b/1096-brace-expansion-ii.js new file mode 100644 index 00000000..d8df4332 --- /dev/null +++ b/1096-brace-expansion-ii.js @@ -0,0 +1,52 @@ +/** + * @param {string} expression + * @return {string[]} + */ +const braceExpansionII = function (expression) { + expression = expression.replace(/([a-z]){1}/g, '{$1}') + const stk = new Array() + for (let char of expression) { + if (char !== '}') { + stk.push(char) + } else { + let str = '', + prev = '', + temp = '' + while (stk[stk.length - 1] != '{') { + prev = temp + temp = stk.pop() + if (temp == ',' || prev == ',' || str == '') str = temp + str + else { + str = str + .split(',') + .map((item) => { + let ar = new Array() + for (let ch of temp.split(',')) ar.push(ch + item) + return ar.join(',') + }) + .join(',') + } + } + stk.pop() + while ( + stk.length > 0 && + stk[stk.length - 1] != ',' && + stk[stk.length - 1] != '{' + ) { + temp = stk.pop() + str = str + .split(',') + .map((item) => { + let ar = new Array() + for (let ch of temp.split(',')) ar.push(ch + item) + return ar.join(',') + }) + .join(',') + } + + if (str.length > 0) stk.push(str) + } + } + + return [...new Set(stk[0].split(','))].sort() +} diff --git a/1099-two-sum-less-than-k.js b/1099-two-sum-less-than-k.js new file mode 100644 index 00000000..87166250 --- /dev/null +++ b/1099-two-sum-less-than-k.js @@ -0,0 +1,49 @@ +/** + +Given an array A of integers and integer K, +return the maximum S such that there exists i < j with A[i] + A[j] = S and S < K. +If no i, j exist satisfying this equation, return -1. + +Example 1: + +Input: A = [34,23,1,24,75,33,54,8], K = 60 +Output: 58 +Explanation: +We can use 34 and 24 to sum 58 which is less than 60. + +Example 2: + +Input: A = [10,20,30], K = 15 +Output: -1 +Explanation: +In this case it's not possible to get a pair sum less that 15. + +Note: + +1 <= A.length <= 100 +1 <= A[i] <= 1000 +1 <= K <= 2000 + +*/ + +/** + * @param {number[]} A + * @param {number} K + * @return {number} + */ +const twoSumLessThanK = function(A, K) { + A.sort((a, b) => a - b) + let max = -1, + i = 0, + j = A.length - 1 + while (i < j) { + const sum = A[i] + A[j] + if (sum < K) { + max = Math.max(max, sum) + i++ + } else { + j-- + } + } + return max +} diff --git a/11-container-with-most-water.js b/11-container-with-most-water.js index 623b971b..763f29d5 100755 --- a/11-container-with-most-water.js +++ b/11-container-with-most-water.js @@ -3,16 +3,36 @@ * @return {number} */ const maxArea = function(height) { - const arr = []; - const arr_len = height.length; - for (let i = 0, j = arr_len - 1; i < j; ) { - arr.push(Math.abs(j - i) * Math.min(height[i], height[j])); - if (height[i] < height[j]) { - i++; + let res = 0, l = 0, r = height.length - 1 + while(l < r) { + const tmp = (r - l) * Math.min(height[l], height[r]) + if(tmp > res) res = tmp + if(height[l] < height[r]) l++ + else r-- + } + return res +}; + +// another + +/** + * @param {number[]} height + * @return {number} + */ +const maxArea = function(height) { + const n = height.length, {min,max} = Math + let i = 0, j = n - 1, leftMax = height[i], rightMax = height[j] + let res = 0 + while(i < j) { + res = max(res, (j - i) * min(leftMax, rightMax)) + if(leftMax <= rightMax) { + i++ + leftMax = max(leftMax, height[i]) } else { - j--; + j-- + rightMax = max(rightMax, height[j]) } } - - return Math.max.apply(Math, arr); + + return res }; diff --git a/1102-path-with-maximum-minimum-value.js b/1102-path-with-maximum-minimum-value.js new file mode 100644 index 00000000..ef6b6ca6 --- /dev/null +++ b/1102-path-with-maximum-minimum-value.js @@ -0,0 +1,65 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const maximumMinimumPath = function (grid) { + const m = grid.length, + n = grid[0].length + const dirs = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + + const set = new Set() + + let ceil = Math.min(grid[0][0], grid[m - 1][n - 1]) + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] <= ceil) { + set.add(grid[i][j]) + } + } + } + const arr = Array.from(set) + arr.sort((a, b) => a - b) + let l = 0, + r = arr.length - 1 + while (l < r) { + const mid = r - ((r - l) >> 1) + if (valid(arr[mid])) { + l = mid + } else { + r = mid - 1 + } + } + + return arr[l] + + function valid(v) { + const memo = Array.from({ length: m }, () => Array(n).fill(0)) + + function dfs(x, y) { + if (x === m - 1 && y === n - 1) return true + memo[x][y] = 1 + for (const [dx, dy] of dirs) { + const nx = x + dx, + ny = y + dy + if ( + nx >= 0 && + nx < m && + ny >= 0 && + ny < n && + memo[nx][ny] === 0 && + grid[nx][ny] >= v && + dfs(nx, ny) + ) + return true + } + return false + } + + return dfs(0, 0) + } +} diff --git a/1103-distribute-candies-to-people.js b/1103-distribute-candies-to-people.js new file mode 100644 index 00000000..309ef1a2 --- /dev/null +++ b/1103-distribute-candies-to-people.js @@ -0,0 +1,18 @@ +/** + * @param {number} candies + * @param {number} num_people + * @return {number[]} + */ +const distributeCandies = function(candies, num_people) { + const n = num_people + const res = Array(n).fill(0) + let idx = 0, cur = 0 + while(candies > 0) { + cur++ + res[idx] += Math.min(cur, candies) + idx++ + candies -= cur + if(idx === n) idx = 0 + } + return res +}; diff --git a/1104.path-in-zigzag-labelled-binary-tree.js b/1104.path-in-zigzag-labelled-binary-tree.js new file mode 100644 index 00000000..7f5f3c54 --- /dev/null +++ b/1104.path-in-zigzag-labelled-binary-tree.js @@ -0,0 +1,61 @@ +/** + * @param {number} label + * @return {number[]} + */ +const pathInZigZagTree = function(label) { + const res = [], { log2, floor, ceil } = Math + const level = floor(log2(label)) + let compl = 2 ** (level + 1) - 1 + 2 ** level - label + + while(label) { + res.push(label) + label = floor(label / 2) + compl = floor(compl / 2) + ;[label, compl] = [compl, label] + } + + res.reverse() + + return res +}; + +// another + + +/** + * @param {number} label + * @return {number[]} + */ +const pathInZigZagTree = function(label) { + const res = [], { log2, floor, ceil } = Math + + res.push(label) + + // check last row + const lev = ceil(log2(label + 1)) + const reverse = lev % 2 === 0 ? true : false + // console.log(reverse, lev) + if(reverse) { + const idx = 2 ** lev - 1 - label + label = 2 ** (lev - 1) + idx + } + // console.log(label) + + while(label > 1) { + const level = floor(log2(label)) + const parent = floor(label / 2) + const parentLevelNum = 2 ** (level - 1) + const parentReverse = level % 2 === 0 ? true : false + const parentStart = 2 ** (level - 1) + const parentEnd = 2 ** level - 1 + // console.log(parentStart, parentEnd, parent) + const idx = parent - parentStart + res.push(parentReverse ? parentEnd - idx : parentStart + idx) + + label = parent + } + + + res.reverse() + return res +}; diff --git a/1105-filling-bookcase-shelves.js b/1105-filling-bookcase-shelves.js index 712581f4..26f71c83 100644 --- a/1105-filling-bookcase-shelves.js +++ b/1105-filling-bookcase-shelves.js @@ -18,3 +18,48 @@ const minHeightShelves = function(books, shelf_width) { } return dp[books.length] }; + +// another + +/** + * @param {number[][]} books + * @param {number} shelf_width + * @return {number} + */ +const minHeightShelves = function(books, shelf_width) { + const n = books.length, dp = Array(1001).fill(Infinity) + dp[0] = 0 + for(let i = 0; i < n; i++) { + let sum = 0, mx = 0 + for(let j = i; j >= 0 && sum + books[j][0] <= shelf_width; j--) { + sum += books[j][0] + mx = Math.max(mx, books[j][1]) + dp[i + 1] = Math.min(dp[i + 1], dp[j] + mx) + } + } + return dp[n] +}; + +// another + +/** + * @param {number[][]} books + * @param {number} shelf_width + * @return {number} + */ + const minHeightShelves = function(books, shelf_width) { + const n = books.length, dp = Array(1001) + dp[0] = 0 + + for(let i = 0; i < n; i++) { + let [w, h] = books[i] + dp[i + 1] = dp[i] + h + for(let j = i - 1; j >= 0 && w + books[j][0] <= shelf_width; j--) { + h = Math.max(h, books[j][1]) + w += books[j][0] + dp[i + 1] = Math.min(dp[i + 1], dp[j] + h) + } + } + + return dp[n] +}; diff --git a/1109-corporate-flight-bookings.js b/1109-corporate-flight-bookings.js index d326526c..8fe83d1c 100644 --- a/1109-corporate-flight-bookings.js +++ b/1109-corporate-flight-bookings.js @@ -1,3 +1,24 @@ +/** + * @param {number[][]} bookings + * @param {number} n + * @return {number[]} + */ +const corpFlightBookings = function(bookings, n) { + const arr = Array(n + 2).fill(0) + for(const [s, e, num] of bookings) { + arr[s] += num + arr[e + 1] -= num + } + for(let i = 1; i < n + 2; i++) { + arr[i] += arr[i - 1] + } + arr.pop() + arr.shift() + return arr +}; + +// another + /** * @param {number[][]} bookings * @param {number} n @@ -12,3 +33,23 @@ const corpFlightBookings = function(bookings, n) { for (let i = 1; i < n; ++i) res[i] += res[i - 1] return res } + +// another + +/** + * @param {number[][]} bookings + * @param {number} n + * @return {number[]} + */ +const corpFlightBookings = function(bookings, n) { + const arr = Array(n + 2).fill(0) + for(let [s, e, num] of bookings) { + arr[s] += num + arr[e + 1] -= num + } + for(let i = 1; i <= n; i++) { + if(arr[i] !== 0) arr[i] += arr[i - 1] + else arr[i] = arr[i - 1] + } + return arr.slice(1, n + 1) +}; diff --git a/1111-maximum-nesting-depth-of-two-valid-parentheses-strings.js b/1111-maximum-nesting-depth-of-two-valid-parentheses-strings.js new file mode 100644 index 00000000..436fbc27 --- /dev/null +++ b/1111-maximum-nesting-depth-of-two-valid-parentheses-strings.js @@ -0,0 +1,18 @@ +/** + * @param {string} seq + * @return {number[]} + */ +const maxDepthAfterSplit = function(seq) { + const n = seq.length + const res = Array(n).fill(0) + let depth = 0 + for(let i = 0; i < n; i++) { + const ch = seq[i] + if(ch === '(') { + depth++ + } + res[i] = depth % 2 + if(ch === ')') depth-- + } + return res +}; diff --git a/1113-reported-posts.sql b/1113-reported-posts.sql new file mode 100644 index 00000000..5322b458 --- /dev/null +++ b/1113-reported-posts.sql @@ -0,0 +1,8 @@ +# Write your MySQL query statement below +select + extra as report_reason + ,count(distinct post_id) as report_count +from Actions +where action_date = '2019-07-04' + and action = 'report' +group by extra; diff --git a/1114-print-in-order.cpp b/1114-print-in-order.cpp new file mode 100644 index 00000000..48110120 --- /dev/null +++ b/1114-print-in-order.cpp @@ -0,0 +1,33 @@ +class Foo { +public: + int count = 0; + mutex mtx; + condition_variable cv; + Foo() { + count = 1; + } + + void first(function printFirst) { + unique_lock lck(mtx); + // printFirst() outputs "first". Do not change or remove this line. + printFirst(); + count = 2; + cv.notify_all(); + } + + void second(function printSecond) { + unique_lock lck(mtx); + cv.wait(lck, [this]() { return count == 2;}); + // printSecond() outputs "second". Do not change or remove this line. + printSecond(); + count = 3; + cv.notify_all(); + } + + void third(function printThird) { + unique_lock lck(mtx); + cv.wait(lck, [this]() { return count == 3;}); + // printThird() outputs "third". Do not change or remove this line. + printThird(); + } +}; diff --git a/1118-number-of-days-in-a-month.js b/1118-number-of-days-in-a-month.js new file mode 100644 index 00000000..f9a90c14 --- /dev/null +++ b/1118-number-of-days-in-a-month.js @@ -0,0 +1,66 @@ +/** + +Given a year Y and a month M, return how many days there are in that month. + +Example 1: + +Input: Y = 1992, M = 7 +Output: 31 +Example 2: + +Input: Y = 2000, M = 2 +Output: 29 +Example 3: + +Input: Y = 1900, M = 2 +Output: 28 + +Note: + +1583 <= Y <= 2100 +1 <= M <= 12 + +*/ + +/** + * @param {number} Y + * @param {number} M + * @return {number} + */ +function numberOfDays(Y, M) { + switch (M) { + case 2: + return Y % 400 === 0 || (Y % 4 === 0 && Y % 100 !== 0) ? 29 : 28; + case 4: + case 6: + case 9: + case 11: + return 30; + default: + return 31; + } +} + +// another + +const numberOfDays = function(Y, M) { + return new Date(Y,M,0).getDate(); +}; + +// another + +/** + * @param {number} Y + * @param {number} M + * @return {number} + */ +const numberOfDays = function(Y, M) { + const d = new Date(Y, M - 1) + let num = 0 + while(d.getMonth() === M - 1) { + num++ + const n = d.getDate() + d.setDate(n + 1) + } + return num +}; diff --git a/1119-remove-vowels-from-a-string.js b/1119-remove-vowels-from-a-string.js new file mode 100644 index 00000000..b0ccfd23 --- /dev/null +++ b/1119-remove-vowels-from-a-string.js @@ -0,0 +1,7 @@ +/** + * @param {string} s + * @return {string} + */ +const removeVowels = function(s) { + return s.replace(/[aeiou]/g, '') +}; diff --git a/1120-maximum-average-subtree.js b/1120-maximum-average-subtree.js new file mode 100644 index 00000000..4d02b632 --- /dev/null +++ b/1120-maximum-average-subtree.js @@ -0,0 +1,47 @@ +/** + +Given the root of a binary tree, find the maximum average value of any subtree of that tree. +(A subtree of a tree is any node of that tree plus all its descendants. +The average value of a tree is the sum of its values, divided by the number of nodes.) + +Example 1: + +Input: [5,6,1] +Output: 6.00000 +Explanation: +For the node with value = 5 we have an average of (5 + 6 + 1) / 3 = 4. +For the node with value = 6 we have an average of 6 / 1 = 6. +For the node with value = 1 we have an average of 1 / 1 = 1. +So the answer is 6 which is the maximum. + +Note: + +The number of nodes in the tree is between 1 and 5000. +Each node will have a value between 0 and 100000. +Answers will be accepted as correct if they are within 10^-5 of the correct answer. + +*/ + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const maximumAverageSubtree = function(root) { + let max = -Number.MIN_VALUE; + function helper(root) { + if (!root) return [0, 0]; // [value, number of nodes] + const [lTotal, lNum] = helper(root.left); + const [rTotal, rNum] = helper(root.right); + max = Math.max(max, (rTotal + lTotal + root.val) / (rNum + lNum + 1)); + return [lTotal + rTotal + root.val, lNum + rNum + 1]; + } + helper(root); + return max; +}; diff --git a/1121-divide-array-into-increasing-sequences.js b/1121-divide-array-into-increasing-sequences.js new file mode 100644 index 00000000..7dc7937b --- /dev/null +++ b/1121-divide-array-into-increasing-sequences.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @param {number} K + * @return {boolean} + */ +const canDivideIntoSubsequences = function (nums, K) { + let cur = 1, + groups = 1, + n = nums.length + for (let i = 1; i < n; ++i) { + cur = nums[i - 1] < nums[i] ? 1 : cur + 1 + groups = Math.max(groups, cur) + } + return n >= K * groups +} diff --git a/1123-lowest-common-ancestor-of-deepest-leaves.js b/1123-lowest-common-ancestor-of-deepest-leaves.js index 36148413..ef42ddea 100644 --- a/1123-lowest-common-ancestor-of-deepest-leaves.js +++ b/1123-lowest-common-ancestor-of-deepest-leaves.js @@ -1,3 +1,36 @@ +/** + * 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 {TreeNode} + */ +const lcaDeepestLeaves = function(root) { + let maxDepth = 0, lcaNode = null + + function lca(node, depth) { + if(node == null) return depth - 1 + maxDepth = Math.max(depth, maxDepth) + const left = lca(node.left, depth + 1) + const right = lca(node.right, depth + 1) + if(left === maxDepth && right === maxDepth) { + lcaNode = node + } + return Math.max(left, right) + } + + lca(root, 0) + return lcaNode +}; + + +// another + /** * Definition for a binary tree node. * function TreeNode(val) { diff --git a/1125-smallest-sufficient-team.js b/1125-smallest-sufficient-team.js index 561385d6..2e8e9754 100644 --- a/1125-smallest-sufficient-team.js +++ b/1125-smallest-sufficient-team.js @@ -1,3 +1,132 @@ +/** + * @param {string[]} req_skills + * @param {string[][]} people + * @return {number[]} + */ +var smallestSufficientTeam = function(req_skills, people) { + const n = req_skills.length, m = people.length + const limit = 1 << n + const reqSet = new Set(req_skills) + const si = {} + for(let i = 0; i < n; i++) si[req_skills[i]] = i + const ps = {} + for(let i = 0; i < m; i++) { + const p = people[i] + let mask = 0 + for(const s of p) { + if(!reqSet.has(s)) continue + mask |= (1 << si[s]) + } + ps[i] = mask + } + const res = Array.from({ length: limit }, () => new Array()) + let dp = Array(limit).fill(Infinity) + dp[0] = 0 + for(let i = 0; i < m; i++) { + const pMask = ps[i] + // const dp2 = [...dp] + for(let mask = 0; mask < limit; mask++) { + const newMask = mask | pMask + if(dp[newMask] > dp[mask] + 1) { + dp[newMask] = dp[mask] + 1 + res[newMask] = [...res[mask]] + res[newMask].push(i) + } + } + // dp = dp2 + } + + return res[limit - 1] +}; + +// another + +/** + * @param {string[]} req_skills + * @param {string[][]} people + * @return {number[]} + */ +var smallestSufficientTeam = function(req_skills, people) { + const n = req_skills.length, m = people.length + const limit = 1 << n + const reqSet = new Set(req_skills) + const si = {} + for(let i = 0; i < n; i++) si[req_skills[i]] = i + const ps = {} + for(let i = 0; i < m; i++) { + const p = people[i] + let mask = 0 + for(const s of p) { + if(!reqSet.has(s)) continue + mask |= (1 << si[s]) + } + ps[i] = mask + } + const res = Array.from({ length: limit }, () => new Array()) + let dp = Array(limit).fill(Infinity) + dp[0] = 0 + for(let i = 0; i < m; i++) { + const pMask = ps[i] + const dp2 = [...dp] + for(let mask = 0; mask < limit; mask++) { + const newMask = mask | pMask + if(dp2[newMask] > dp[mask] + 1) { + dp2[newMask] = dp[mask] + 1 + res[newMask] = [...res[mask]] + res[newMask].push(i) + } + } + dp = dp2 + } + + return res[limit - 1] +}; + +// another + + +/** + * @param {string[]} req_skills + * @param {string[][]} people + * @return {number[]} + */ +const smallestSufficientTeam = function (req_skills, people) { + const m = req_skills.length, + n = people.length, + limit = 1 << m + const skillIdxMap = {} + for(let i = 0; i < m; i++) { + skillIdxMap[req_skills[i]] = i + } + const dp = Array(limit) + + dp[0] = [] + + for(let i = 0; i < n; i++) { + let skillMask = 0 + for(let j = 0; j < people[i].length; j++) { + skillMask |= (1 << skillIdxMap[people[i][j]]) + } + + for(let j = 0; j < dp.length; j++) { + if(dp[j] == null) continue + const prev = j + const comb = prev | skillMask + + if(dp[comb] == null || dp[comb].length > dp[prev].length + 1) { + + dp[comb] = dp[prev].slice() + dp[comb].push(i) + } + } + } + + return dp[limit - 1] +} + +// another + + /** * @param {string[]} req_skills * @param {string[][]} people diff --git a/1127-user-purchase-platform.sql b/1127-user-purchase-platform.sql new file mode 100644 index 00000000..54ef060e --- /dev/null +++ b/1127-user-purchase-platform.sql @@ -0,0 +1,32 @@ +# Write your MySQL query statement below +SELECT + p.spend_date, + p.platform, + IFNULL(SUM(amount), 0) total_amount, + COUNT(user_id) total_users +FROM +( + SELECT DISTINCT(spend_date), 'desktop' platform FROM Spending + UNION + SELECT DISTINCT(spend_date), 'mobile' platform FROM Spending + UNION + SELECT DISTINCT(spend_date), 'both' platform FROM Spending +) p +LEFT JOIN ( + SELECT + spend_date, + user_id, + IF(mobile_amount > 0, IF(desktop_amount > 0, 'both', 'mobile'), 'desktop') platform, + (mobile_amount + desktop_amount) amount + FROM ( + SELECT + spend_date, + user_id, + SUM(CASE platform WHEN 'mobile' THEN amount ELSE 0 END) mobile_amount, + SUM(CASE platform WHEN 'desktop' THEN amount ELSE 0 END) desktop_amount + FROM Spending + GROUP BY spend_date, user_id + ) o +) t +ON p.platform=t.platform AND p.spend_date=t.spend_date +GROUP BY spend_date, platform; diff --git a/1128-number-of-equivalent-domino-pairsnumber-of-equivalent-domino-pairs.js b/1128-number-of-equivalent-domino-pairsnumber-of-equivalent-domino-pairs.js new file mode 100644 index 00000000..eebd4674 --- /dev/null +++ b/1128-number-of-equivalent-domino-pairsnumber-of-equivalent-domino-pairs.js @@ -0,0 +1,34 @@ +/** + * @param {number[][]} dominoes + * @return {number} + */ +const numEquivDominoPairs = function(dominoes) { + const hash = {} + for (let dom of dominoes) { + const [a, b] = dom + const key = `${a},${b}`, alterKey = `${b},${a}` + if (hash[key] == null && hash[alterKey] == null) { + hash[key] = 1 + } else { + if(hash[key] != null) hash[key] += 1 + else hash[alterKey] += 1 + } + } + + let res = 0 + + Object.keys(hash).forEach(k => { + if(hash[k] > 1) res += sum(hash[k]) + }) + + return res +}; + +function sum(n) { + let res = 0 + while(n > 1) { + res += n - 1 + n-- + } + return res +} diff --git a/1131-maximum-of-absolute-value-expression.js b/1131-maximum-of-absolute-value-expression.js new file mode 100644 index 00000000..ca0c1470 --- /dev/null +++ b/1131-maximum-of-absolute-value-expression.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number} + */ +var maxAbsValExpr = function(arr1, arr2) { + let n = arr1.length; + let combs = [ + [1,1],[1,-1],[-1,1],[-1,-1] + ]; + let result = -Infinity; + for(let [p,q] of combs) { + let max = -Infinity, min = Infinity; + for(let i=0; i < n; i++) { + let value = (p * arr1[i]) + (q * arr2[i]) + i; + max = Math.max(max,value); + min = Math.min(min,value); + }; + result = Math.max(result, max-min); + }; + return result; +}; + diff --git a/1133-largest-unique-number.js b/1133-largest-unique-number.js new file mode 100644 index 00000000..8e9ec0ca --- /dev/null +++ b/1133-largest-unique-number.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const largestUniqueNumber = function(nums) { + const hash = {} + for(let e of nums) { + hash[e] = (hash[e] || 0) + 1 + } + let res = -Infinity + Object.keys(hash).forEach(k => { + if(hash[k] === 1) { + if(+k > res) { + res = +k + } + } + }) + return res === -Infinity ? -1 : res +}; diff --git a/1134-armstrong-number.js b/1134-armstrong-number.js new file mode 100644 index 00000000..5884e3f4 --- /dev/null +++ b/1134-armstrong-number.js @@ -0,0 +1,20 @@ +/** + * @param {number} n + * @return {boolean} + */ +const isArmstrong = function(n) { + //number of digits in N + let k = ~~(Math.log10(n) + 1); + //temporary variable (so we dont modify N) + let x = n; + //to hold sum + let sum = 0; + //get each digit + while (x !== 0) { + //add this digit^k to sum + sum += Math.pow(x % 10, k); + //get next digit + x = ~~(x/10); + } + return sum == n; +}; diff --git a/1136-parallel-courses.js b/1136-parallel-courses.js new file mode 100644 index 00000000..6f727b6e --- /dev/null +++ b/1136-parallel-courses.js @@ -0,0 +1,82 @@ +/** + * @param {number} n + * @param {number[][]} relations + * @return {number} + */ +const minimumSemesters = function (n, relations) { + const inDegree = Array(n + 1).fill(0) + const graph = {} + for(const [prev, nxt] of relations) { + if(graph[prev] == null) graph[prev] = [] + graph[prev].push(nxt) + + inDegree[nxt]++ + } + + let q = [] + for(let i = 1; i <= n; i++) { + if(inDegree[i] === 0) q.push(i) + } + +// console.log(inDegree) + let res = 0, cnt = 0 + while(q.length) { + const size = q.length, nxt = [] + + for(let i = 0; i < size; i++) { + const cur = q[i] + for(const e of (graph[cur] || [])) { + inDegree[e]-- + if(inDegree[e] === 0) { + nxt.push(e) + } + } + } + res++ + cnt += size + q = nxt + // console.log(nxt) + } +// console.log(cnt, res) + + return cnt === n ? res : -1 +} + + +// another + +/** + * @param {number} N + * @param {number[][]} relations + * @return {number} + */ +const minimumSemesters = function (N, relations) { + const g = new Map() // key: prerequisite, value: course list. + const inDegree = new Array(N + 1).fill(0) // inDegree[i]: number of prerequisites for i. + for (let r of relations) { + if (!g.has(r[0])) g.set(r[0], []) + g.get(r[0]).push(r[1]) // construct graph. + ++inDegree[r[1]] // count prerequisites for r[1]. + } + const q = [] // save current 0 in-degree vertices. + for (let i = 1; i <= N; ++i) if (inDegree[i] === 0) q.push(i) + let semester = 0 + while (q.length) { + // BFS traverse all currently 0 in degree vertices. + for (let sz = q.length; sz > 0; --sz) { + // sz is the search breadth. + const c = q.shift() + --N + // c's in-degree is currently 0, but it is not a prerequisite of anyone else. + if (!g.has(c)) continue + const tmp = g.get(c) + g.delete(c) + for (let course of tmp) + if (--inDegree[course] === 0) + // decrease the in-degree of course's neighbors. + q.push(course) // add current 0 in-degree vertex into Queue. + } + ++semester // need one more semester. + } + return N === 0 ? semester : -1 +} diff --git a/1141-user-activity-for-the-past-30-days-i.sql b/1141-user-activity-for-the-past-30-days-i.sql new file mode 100644 index 00000000..8b46b0d9 --- /dev/null +++ b/1141-user-activity-for-the-past-30-days-i.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +select activity_date as day, count(distinct user_id) as active_users +from Activity +where datediff('2019-07-27', activity_date) < 30 +group by activity_date; diff --git a/1142-user-activity-for-the-past-30-days-ii.sql b/1142-user-activity-for-the-past-30-days-ii.sql new file mode 100644 index 00000000..d2b3aad1 --- /dev/null +++ b/1142-user-activity-for-the-past-30-days-ii.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +SELECT ifnull(ROUND(COUNT(DISTINCT session_id)/COUNT(DISTINCT user_id), 2),0.00) +AS average_sessions_per_user +FROM Activity +WHERE activity_date >= '2019-06-28' and activity_date <= '2019-07-27'; diff --git a/1143-longest-common-subsequence.js b/1143-longest-common-subsequence.js index afa76a1f..9e856a67 100644 --- a/1143-longest-common-subsequence.js +++ b/1143-longest-common-subsequence.js @@ -15,3 +15,29 @@ const longestCommonSubsequence = function(text1, text2) { } return dp[dp.length - 1].pop() } + +// another + +/** + * @param {string} text1 + * @param {string} text2 + * @return {number} + */ +const longestCommonSubsequence = function(text1, text2) { + const len1 = text1.length + const len2 = text2.length + if(len1 === 0 || len2 === 0) return 0 + const dp = Array(len2 + 1).fill(0) + for(let i = 1; i <= len1; i++) { + let prev = 0 + for(let j = 1; j <= len2; j++) { + const tmp = dp[j] + if(text1[i - 1] === text2[j - 1]) dp[j] = Math.max(dp[j], prev + 1) + else { + dp[j] = Math.max(dp[j - 1], dp[j]) + } + prev = tmp + } + } + return dp[len2] +}; diff --git a/1146-snapshot-array.js b/1146-snapshot-array.js index 356b41dd..28e93963 100644 --- a/1146-snapshot-array.js +++ b/1146-snapshot-array.js @@ -1,3 +1,130 @@ +/** + * @param {number} length + */ +const SnapshotArray = function(length) { + this.snaps = Array(length) + this.snapId = 0 +}; + +/** + * @param {number} index + * @param {number} val + * @return {void} + */ +SnapshotArray.prototype.set = function(index, val) { + if(this.snaps[index] == null) { + this.snaps[index] = {} + } + this.snaps[index][this.snapId] = val +}; + +/** + * @return {number} + */ +SnapshotArray.prototype.snap = function() { + return this.snapId++ +}; + +/** + * @param {number} index + * @param {number} snap_id + * @return {number} + */ +SnapshotArray.prototype.get = function(index, snap_id) { + let res = 0 + let id = snap_id + while(id >= 0) { + if(this.snaps[index] == null || this.snaps[index][id] == null) id-- + else { + res = this.snaps[index][id] + break + } + } + + return res +}; + +/** + * Your SnapshotArray object will be instantiated and called as such: + * var obj = new SnapshotArray(length) + * obj.set(index,val) + * var param_2 = obj.snap() + * var param_3 = obj.get(index,snap_id) + */ + +// another + +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const binarySearch = function (nums, target, comparator) { + let low = 0; + let high = nums.length - 1; + while (low <= high) { + let mid = low + ((high - low) >>> 1); + let midValue = nums[mid]; + let cmp = comparator(midValue, target); + if (cmp < 0) low = mid + 1; + else if (cmp > 0) high = mid - 1; + else return mid; + } + return -(low + 1); +}; + +/** + * @param {number} length + */ +const SnapshotArray = function (length) { + this.count = 0; + this.arr = Array.from({ length: length }, () => [[0, 0]]); +}; + +/** + * @param {number} index + * @param {number} val + * @return {void} + */ +SnapshotArray.prototype.set = function (index, val) { + const arr = this.arr, + count = this.count; + if (arr[index][arr[index].length - 1][0] === count) { + arr[index][arr[index].length - 1][1] = val; + } else { + arr[index].push([count, val]); + } +}; + +/** + * @return {number} + */ +SnapshotArray.prototype.snap = function () { + return this.count++; +}; + +/** + * @param {number} index + * @param {number} snap_id + * @return {number} + */ +SnapshotArray.prototype.get = function (index, snap_id) { + let idx = binarySearch(this.arr[index], [snap_id, 0], (a, b) => a[0] - b[0]); + if (idx < 0) idx = -idx - 2; + return this.arr[index][idx][1]; +}; + +/** + * Your SnapshotArray object will be instantiated and called as such: + * var obj = new SnapshotArray(length) + * obj.set(index,val) + * var param_2 = obj.snap() + * var param_3 = obj.get(index,snap_id) + */ + + +// another + /** * @param {number} length */ diff --git a/1148-article-views-i.sql b/1148-article-views-i.sql new file mode 100644 index 00000000..47b0221c --- /dev/null +++ b/1148-article-views-i.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +SELECT DISTINCT author_id AS id FROM Views +where author_id = viewer_id +ORDER BY id; diff --git a/1150-check-if-a-number-is-majority-element-in-a-sorted-array.js b/1150-check-if-a-number-is-majority-element-in-a-sorted-array.js new file mode 100644 index 00000000..53b5b874 --- /dev/null +++ b/1150-check-if-a-number-is-majority-element-in-a-sorted-array.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {boolean} + */ +function isMajorityElement(nums, target) { + let firstIdx = bs(nums, target) + let endIdx = firstIdx + (~~(nums.length / 2)) + if(endIdx < nums.length && nums[endIdx] === target) return true + return false +} + +function bs(arr, target) { + let l = 0, h = arr.length - 1 + while(l < h) { + const mid = l + ((h - l) >> 1) + if (arr[mid] < target) l = mid + 1 + else h = mid + } + return l +} diff --git a/1151-minimum-swaps-to-group-all-1s-together.js b/1151-minimum-swaps-to-group-all-1s-together.js new file mode 100644 index 00000000..392f6012 --- /dev/null +++ b/1151-minimum-swaps-to-group-all-1s-together.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} data + * @return {number} + */ +const minSwaps = function(data) { + let num = 0, n = data.length + const arr = Array(n).fill(0) + for(let i = 0; i < n; i++) { + const e = data[i] + if(e === 1) { + num++ + } + arr[i] = num + } + if(num === 0) return 0 + let res = num - arr[num - 1] + for(let i = num; i < n; i++) { + res = Math.min(res, num - (arr[i] - arr[i - num])) + } + return res +}; diff --git a/1153-string-transforms-into-another-string.js b/1153-string-transforms-into-another-string.js new file mode 100644 index 00000000..2d35d4f4 --- /dev/null +++ b/1153-string-transforms-into-another-string.js @@ -0,0 +1,45 @@ +/** + +Given two strings str1 and str2 of the same length, +determine whether you can transform str1 into str2 by doing zero or more conversions. +In one conversion you can convert all occurrences of one character +in str1 to any other lowercase English character. +Return true if and only if you can transform str1 into str2. + +Example 1: + +Input: str1 = "aabcc", str2 = "ccdee" +Output: true +Explanation: Convert 'c' to 'e' then 'b' to 'd' then 'a' to 'c'. +Note that the order of conversions matter. + +Example 2: + +Input: str1 = "leetcode", str2 = "codeleet" +Output: false +Explanation: There is no way to transform str1 to str2. + +Note: + +1 <= str1.length == str2.length <= 10^4 +Both str1 and str2 contain only lowercase English letters. + +*/ + +/** + * @param {string} str1 + * @param {string} str2 + * @return {boolean} + */ +const canConvert = function(str1, str2) { + if (str1 === str2) return true + const map = new Map() + for (let i = 0; i < str1.length; i++) { + if (map.has(str1[i]) && map.get(str1[i]) !== str2[i]) { + return false + } + map.set(str1[i], str2[i]) + } + const set = new Set(map.values()) + return set.size < 26 +} diff --git a/1157-online-majority-element-in-subarray.js b/1157-online-majority-element-in-subarray.js index 72a30cfb..54f72984 100644 --- a/1157-online-majority-element-in-subarray.js +++ b/1157-online-majority-element-in-subarray.js @@ -1,3 +1,141 @@ +function Bisect() { + return { insort_right, insort_left, bisect_left, bisect_right } + function insort_right(a, x, lo = 0, hi = null) { + lo = bisect_right(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_right(a, x, lo = 0, hi = null) { + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = (lo + hi) >> 1 + x < a[mid] ? (hi = mid) : (lo = mid + 1) + } + return lo + } + function insort_left(a, x, lo = 0, hi = null) { + lo = bisect_left(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_left(a, x, lo = 0, hi = null) { + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = (lo + hi) >> 1 + a[mid] < x ? (lo = mid + 1) : (hi = mid) + } + return lo + } +} + +function SegmentTreeRQ(m, A, n) { + let bisect = new Bisect() + let h = Math.ceil(Math.log2(n)) + const MAX = 2 * 2 ** h - 1 + let tree = Array(MAX).fill(-1) + let a = [...A] + build(1, 0, n - 1) + return { + query, + } + + function build(vi, tl, tr) { + if (tl == tr) { + tree[vi] = a[tl] + return + } + let mid = getMid(tl, tr) + build(vi * 2, tl, mid) + build(vi * 2 + 1, mid + 1, tr) + if ( + tree[vi * 2] != -1 && + get_occurrence(tree[vi * 2], tl, tr) * 2 > tr - tl + 1 + ) { + tree[vi] = tree[vi * 2] + } else if ( + tree[vi * 2 + 1] != -1 && + get_occurrence(tree[vi * 2 + 1], tl, tr) * 2 > tr - tl + 1 + ) { + tree[vi] = tree[vi * 2 + 1] + } + } + + function query(vi, l, r, tl, tr) { + if (l > tr || r < tl) { + return { + first: -1, + second: -1, + } + } + if (tl <= l && r <= tr) { + if (tree[vi] == -1) + return { + first: -1, + second: -1, + } + let occ = get_occurrence(tree[vi], tl, tr) + if (occ * 2 > tr - tl + 1) { + return { + first: tree[vi], + second: occ, + } + } else { + return { + first: -1, + second: -1, + } + } + } + let mid = getMid(l, r) + let resL = query(vi * 2, l, mid, tl, tr) + if (resL.first > -1) return resL + let resR = query(vi * 2 + 1, mid + 1, r, tl, tr) + if (resR.first > -1) return resR + return { + first: -1, + second: -1, + } + } + + function get_occurrence(num, l, r) { + // only difference + if (!m.has(num)) return 0 + let a = m.get(num) + let lbv = bisect.bisect_left(a, l) //lower_bound + if (lbv == a.length) return 0 + let ubv = bisect.bisect_right(a, r) // upper_bound + return ubv - lbv + } + + function getMid(low, high) { + return low + ((high - low) >> 1) + } +} + +function MajorityChecker(a) { + let m = new Map() + let n = a.length + for (let i = 0; i < n; i++) { + if (!m.has(a[i])) m.set(a[i], []) + m.get(a[i]).push(i) + } + let st = new SegmentTreeRQ(m, a, n) + return { + query, + } + + function query(left, right, threshold) { + let res = st.query(1, 0, n - 1, left, right) + if (res.second >= threshold) { + return res.first + } + return -1 + } +} + +// another + + /** * @param {number[]} arr */ diff --git a/116-populating-next-right-pointers-in-each-node.js b/116-populating-next-right-pointers-in-each-node.js new file mode 100644 index 00000000..3461fb0c --- /dev/null +++ b/116-populating-next-right-pointers-in-each-node.js @@ -0,0 +1,42 @@ +/** + * // Definition for a Node. + * function Node(val,left,right,next) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * }; + */ +/** + * @param {Node} root + * @return {Node} + */ +const connect = function(root) { + if (root == null) return null + const cur = [root] + while (cur.length) { + let len = cur.length + for (let i = 0; i < len; i++) { + let el = cur.shift() + if (i === len - 1) el.next = null + else el.next = cur[0] + + if (el.left) cur.push(el.left) + if (el.right) cur.push(el.right) + } + } + return root +} + +// another + +const connect = function(root) { + if (!root) return null + if (root.left && root.right) { + root.left.next = root.right + root.right.next = root.next ? root.next.left : null + } + connect(root.left) + connect(root.right) + return root +} diff --git a/1165-single-row-keyboard.js b/1165-single-row-keyboard.js new file mode 100644 index 00000000..6a8039f2 --- /dev/null +++ b/1165-single-row-keyboard.js @@ -0,0 +1,17 @@ +/** + * @param {string} keyboard + * @param {string} word + * @return {number} + */ +const calculateTime = function(keyboard, word) { + const hash = {}, { abs } = Math + for(let i = 0; i < 26; i++) { + hash[keyboard[i]] = i + } + let pre = 0, sum = 0 + for(const ch of word) { + sum += abs(hash[ch] - pre) + pre = hash[ch] + } + return sum +}; diff --git a/1166-design-file-system.js b/1166-design-file-system.js new file mode 100644 index 00000000..8378b6d1 --- /dev/null +++ b/1166-design-file-system.js @@ -0,0 +1,85 @@ + +const FileSystem = function() { + this.m = new Map() + this.m.set('', 1) +}; + +/** + * @param {string} path + * @param {number} value + * @return {boolean} + */ +FileSystem.prototype.createPath = function(path, value) { + if(this.m.has(path)) return false + const p = path.slice(0, path.lastIndexOf('/')) + if(!this.m.has(p)) return false + this.m.set(path, value) + return true +}; + +/** + * @param {string} path + * @return {number} + */ +FileSystem.prototype.get = function(path) { + if(!this.m.has(path)) return -1 + return this.m.get(path) +}; + +/** + * Your FileSystem object will be instantiated and called as such: + * var obj = new FileSystem() + * var param_1 = obj.createPath(path,value) + * var param_2 = obj.get(path) + */ + +// another + +class Node { + constructor(v) { + this.val = v + this.children = new Map() + } +} +const FileSystem = function() { + this.r = new Node(null) +}; + +/** + * @param {string} path + * @param {number} value + * @return {boolean} + */ +FileSystem.prototype.createPath = function(path, value) { + if(path == null || path === '') return + const arr = path.split('/').filter(e => e !== '/' && e !== '') + let cur = this.r + for(let i = 0, len = arr.length; i < len; i++) { + if(i !== len - 1 && !cur.children.has(arr[i])) return false + if(i === len - 1 && cur.children.has(arr[i])) return false + if(i !== len - 1) cur = cur.children.get(arr[i]) + } + cur.children.set(arr[arr.length - 1], new Node(value)) + return true +}; + +/** + * @param {string} path + * @return {number} + */ +FileSystem.prototype.get = function(path) { + const arr = path.split('/').filter(e => e !== '/' && e !== '') + let cur = this.r + for(let i = 0, len = arr.length; i < len; i++) { + if(!cur.children.has(arr[i])) return -1 + cur = cur.children.get(arr[i]) + } + return cur.val +}; + +/** + * Your FileSystem object will be instantiated and called as such: + * var obj = new FileSystem() + * var param_1 = obj.createPath(path,value) + * var param_2 = obj.get(path) + */ diff --git a/1167-minimum-cost-to-connect-sticks.js b/1167-minimum-cost-to-connect-sticks.js new file mode 100644 index 00000000..6eeb60c6 --- /dev/null +++ b/1167-minimum-cost-to-connect-sticks.js @@ -0,0 +1,213 @@ +/** + +You have some sticks with positive integer lengths. + +You can connect any two sticks of lengths X and Y into +one stick by paying a cost of X + Y. You perform this action until there is one stick remaining. + +Return the minimum cost of connecting all the given sticks into one stick in this way. + +Example 1: + +Input: sticks = [2,4,3] +Output: 14 +Example 2: + +Input: sticks = [1,8,3,5] +Output: 30 + +Constraints: + +1 <= sticks.length <= 10^4 +1 <= sticks[i] <= 10^4 + +*/ + +/** + * @param {number[]} sticks + * @return {number} + */ +const connectSticks = function(sticks) { + if (sticks.length < 1) return 0 + let size = sticks.length - 1 + let i = Math.floor(sticks.length / 2) + for (; i >= 0; i--) { + heapify(sticks, i, size) + } + let cost = 0 + while (size >= 1) { + const temp = sticks[0] + sticks[0] = sticks[size--] + heapify(sticks, 0, size) + sticks[0] = sticks[0] + temp + cost += sticks[0] + heapify(sticks, 0, size) + } + return cost +} +const heapify = (arr, index, size) => { + let smallest = index + let l = index * 2 + 1 + let r = index * 2 + 2 + if (l <= size && arr[l] < arr[smallest]) { + smallest = l + } + if (r <= size && arr[r] < arr[smallest]) { + smallest = r + } + if (smallest != index) { + swap(arr, index, smallest) + heapify(arr, smallest, size) + } +} +const swap = (arr, i, j) => { + const temp = arr[i] + arr[i] = arr[j] + arr[j] = temp +} + +// another + +/** + * @param {number[]} sticks + * @return {number} + */ +const connectSticks = function(sticks) { + if (sticks.length === 1) return 0 + sticks.sort((a, b) => a - b) + let sum = [], + result = 0 + while (sticks.length || sum.length > 1) { + let cur = 0 + for (let i = 0; i < 2; i++) { + if (sticks[0] && (sum[0] === undefined || sticks[0] < sum[0])) { + cur += sticks[0] + sticks.shift() + } else { + cur += sum[0] + sum.shift() + } + } + sum.push(cur) + result += cur + } + return result +} + +// another + +/** + * @param {number[]} sticks + * @return {number} + */ +const connectSticks = function(sticks) { + sticks.sort((a, b) => a - b) + const sums = [] + let result = 0 + if (sticks.length < 2) return result + const getMin = () => { + const stick = sticks.length ? sticks[0] : Infinity + const sum = sums.length ? sums[0] : Infinity + if (sum < stick) { + return sums.shift() + } else { + return sticks.shift() + } + } + while (sticks.length || sums.length > 1) { + const tmp1 = getMin() + const tmp2 = getMin() + const curr = tmp1 + tmp2 + result += curr + sums.push(curr) + } + return result +} + +// another + +/** + * @param {number[]} sticks + * @return {number} + */ +const connectSticks = function(sticks) { + const pq = new PriorityQueue((a, b) => a < b) + for(let e of sticks) pq.push(e) + let res = 0 + while(pq.size() > 1) { + const e1 = pq.pop() + const e2 = pq.pop() + pq.push(e1 + e2) + res += e1 + e2 + } + + return res +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1168-optimize-water-distribution-in-a-village.js b/1168-optimize-water-distribution-in-a-village.js new file mode 100644 index 00000000..443506da --- /dev/null +++ b/1168-optimize-water-distribution-in-a-village.js @@ -0,0 +1,33 @@ +/** + * @param {number} n + * @param {number[]} wells + * @param {number[][]} pipes + * @return {number} + */ +const minCostToSupplyWater = function(n, wells, pipes) { + const uf = Array(n + 1).fill(0) + const edges = [] + for(let i = 0; i < n; i++) { + uf[i + 1] = i + 1 + edges.push([0, i + 1, wells[i]]) + } + for(let p of pipes) { + edges.push(p) + } + edges.sort((a, b) => a[2] - b[2]) + let res = 0 + for(let e of edges) { + const x = find(e[0]), y = find(e[1]) + if(x !== y) { + res += e[2] + uf[x] = y + n-- + } + } + return res + + function find(x) { + if(x !== uf[x]) uf[x] = find(uf[x]) + return uf[x] + } +}; diff --git a/117-populating-next-right-pointers-in-each-node-ii.js b/117-populating-next-right-pointers-in-each-node-ii.js new file mode 100644 index 00000000..f0f83654 --- /dev/null +++ b/117-populating-next-right-pointers-in-each-node-ii.js @@ -0,0 +1,28 @@ +/** + * // Definition for a Node. + * function Node(val,left,right,next) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * }; + */ +/** + * @param {Node} root + * @return {Node} + */ +const connect = function(root) { + if (root == null) return null + const cur = [root] + while (cur.length) { + const len = cur.length + for (let i = 0; i < len; i++) { + const el = cur.shift() + if (i === len - 1) el.next = null + else el.next = cur[0] + if (el.left) cur.push(el.left) + if (el.right) cur.push(el.right) + } + } + return root +} diff --git a/1172-dinner-plate-stacks.js b/1172-dinner-plate-stacks.js new file mode 100644 index 00000000..72f8a9bd --- /dev/null +++ b/1172-dinner-plate-stacks.js @@ -0,0 +1,214 @@ +/** + * @param {number} capacity + */ +const DinnerPlates = function (capacity) { + this.capacity = capacity + this.stacks = [] + this.pq = new PriorityQueue() +} + +/** + * @param {number} val + * @return {void} + */ +DinnerPlates.prototype.push = function (val) { + if (this.pq.isEmpty()) { + if ( + this.stacks.length > 0 && + this.stacks[this.stacks.length - 1].length < this.capacity + ) { + this.stacks[this.stacks.length - 1].push(val) + } else { + this.stacks.push([]) + this.stacks[this.stacks.length - 1].push(val) + } + } else { + const num = this.pq.pop() + this.stacks[num].push(val) + } +} + +/** + * @return {number} + */ +DinnerPlates.prototype.pop = function () { + while ( + this.stacks.length > 0 && + this.stacks[this.stacks.length - 1].length === 0 + ) { + const len = this.stacks.length - 1 + while (!this.pq.isEmpty() && this.pq.peek() >= len) { + this.pq.pop() + } + this.stacks.pop() + } + if (this.stacks.length === 0) { + return -1 + } else { + return this.stacks[this.stacks.length - 1].pop() + } +} + +/** + * @param {number} index + * @return {number} + */ +DinnerPlates.prototype.popAtStack = function (index) { + const st = this.stacks[index] + + if (st && st.length > 0) { + this.pq.push(index) + return st.pop() + } + + return -1 +} + +/** + * Your DinnerPlates object will be instantiated and called as such: + * var obj = new DinnerPlates(capacity) + * obj.push(val) + * var param_2 = obj.pop() + * var param_3 = obj.popAtStack(index) + */ +class PriorityQueue { + constructor(len, compare) { + this.compare = (a, b) => { + return a < b + } + this.last = 0 + this.arr = [] + } + push(val) { + this.last++ + this.arr[this.last] = val + this.up(this.last) + } + pop() { + if (this.isEmpty()) { + return null + } + const res = this.arr[1] + this.swap(1, this.last) + this.last-- + this.down(1) + return res + } + up(lo) { + while (lo > 1) { + const currEl = this.arr[lo] + const parent = Math.floor(lo / 2) + const parentEl = this.arr[parent] + if (this.compare(currEl, parentEl)) { + this.swap(lo, parent) + } else { + break + } + lo = parent + } + } + down(hi) { + while (hi * 2 <= this.last) { + const currEl = this.arr[hi] + let nextEl = this.arr[hi * 2] + let nextIndex = hi * 2 + if ( + hi * 2 + 1 <= this.last && + this.compare(this.arr[hi * 2 + 1], nextEl) + ) { + nextIndex = hi * 2 + 1 + nextEl = this.arr[nextIndex] + } + if (this.compare(nextEl, currEl)) { + this.swap(hi, nextIndex) + } else { + break + } + hi = nextIndex + } + } + swap(i, j) { + const temp = this.arr[i] + this.arr[i] = this.arr[j] + this.arr[j] = temp + } + peek() { + if (this.isEmpty()) { + return null + } + return this.arr[1] + } + isEmpty() { + return this.last < 1 + } +} + +// another + +/** + * @param {number} capacity + */ +const DinnerPlates = function (capacity) { + this.pushIndex = 0 + this.popIndex = 0 + this.capacity = capacity + this.stacks = [[]] +} + +/** + * @param {number} val + * @return {void} + */ +DinnerPlates.prototype.push = function (val) { + while ( + this.pushIndex < this.stacks.length && + this.stacks[this.pushIndex].length === this.capacity + ) { + this.pushIndex++ + } + if (this.stacks.length === this.pushIndex) { + this.stacks[this.pushIndex] = [val] + } else { + this.stacks[this.pushIndex].push(val) + } + if (this.popIndex < this.pushIndex) { + this.popIndex = this.pushIndex + } +} + +/** + * @return {number} + */ +DinnerPlates.prototype.pop = function () { + while (this.stacks[this.popIndex].length === 0) { + if (this.popIndex > 0) { + this.popIndex-- + } else { + return -1 + } + } + const valueAtIndex = this.stacks[this.popIndex].pop() + if (this.pushIndex > this.popIndex) { + this.pushIndex = this.popIndex + } + return valueAtIndex +} + +/** + * @param {number} index + * @return {number} + */ +DinnerPlates.prototype.popAtStack = function (index) { + if (index >= this.stacks.length) return -1 + if (index < this.pushIndex) this.pushIndex = index + return this.stacks[index].length > 0 ? this.stacks[index].pop() : -1 +} + +/** + * Your DinnerPlates object will be instantiated and called as such: + * var obj = new DinnerPlates(capacity) + * obj.push(val) + * var param_2 = obj.pop() + * var param_3 = obj.popAtStack(index) + */ + diff --git a/1173-immediate-food-delivery-i.sql b/1173-immediate-food-delivery-i.sql new file mode 100644 index 00000000..03068217 --- /dev/null +++ b/1173-immediate-food-delivery-i.sql @@ -0,0 +1,3 @@ +# Write your MySQL query statement below +select round(100 * sum(order_date = customer_pref_delivery_date) / count(*), 2) +as immediate_percentage from Delivery; diff --git a/1174-immediate-food-delivery-ii.sql b/1174-immediate-food-delivery-ii.sql new file mode 100644 index 00000000..12308311 --- /dev/null +++ b/1174-immediate-food-delivery-ii.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +select +round(100*sum(case when b.min_order_date = b.min_delivery_date then 1 else 0 end)/count(*), 2) +as immediate_percentage +from ( + select min(order_date) as min_order_date, min(customer_pref_delivery_date) as min_delivery_date + from delivery + group by customer_id +) b; diff --git a/1176-diet-plan-performance.js b/1176-diet-plan-performance.js new file mode 100644 index 00000000..4930160b --- /dev/null +++ b/1176-diet-plan-performance.js @@ -0,0 +1,44 @@ +/** + * @param {number[]} calories + * @param {number} k + * @param {number} lower + * @param {number} upper + * @return {number} + */ +var dietPlanPerformance = function(calories, k, lower, upper) { + let res = 0 + for(let i = 0, n = calories.length, tmp = 0; i < n; i++) { + tmp += calories[i] + if(i >= k - 1) { + if(i >= k) { + tmp -= calories[i - k] + } + if(tmp < lower) res-- + else if(tmp > upper) res++ + } + + } + return res +}; + +// another + +/** + * @param {number[]} calories + * @param {number} k + * @param {number} lower + * @param {number} upper + * @return {number} + */ +var dietPlanPerformance = function(calories, k, lower, upper) { + let res = 0 + for(let i = 0, n = calories.length; i < n - k + 1; i++) { + let tmp = 0 + for(let j = 0; j < k && i + j < n; j++) { + tmp += calories[i + j] + } + if(tmp < lower) res-- + else if(tmp > upper) res++ + } + return res +}; diff --git a/1179-reformat-department-table.sql b/1179-reformat-department-table.sql new file mode 100644 index 00000000..a36706c3 --- /dev/null +++ b/1179-reformat-department-table.sql @@ -0,0 +1,17 @@ +# Write your MySQL query statement below +select id, + sum(case when month = 'jan' then revenue else null end) as Jan_Revenue, + sum(case when month = 'feb' then revenue else null end) as Feb_Revenue, + sum(case when month = 'mar' then revenue else null end) as Mar_Revenue, + sum(case when month = 'apr' then revenue else null end) as Apr_Revenue, + sum(case when month = 'may' then revenue else null end) as May_Revenue, + sum(case when month = 'jun' then revenue else null end) as Jun_Revenue, + sum(case when month = 'jul' then revenue else null end) as Jul_Revenue, + sum(case when month = 'aug' then revenue else null end) as Aug_Revenue, + sum(case when month = 'sep' then revenue else null end) as Sep_Revenue, + sum(case when month = 'oct' then revenue else null end) as Oct_Revenue, + sum(case when month = 'nov' then revenue else null end) as Nov_Revenue, + sum(case when month = 'dec' then revenue else null end) as Dec_Revenue +from department +group by id +order by id diff --git a/1180-count-substrings-with-only-one-distinct-letter.js b/1180-count-substrings-with-only-one-distinct-letter.js new file mode 100644 index 00000000..bf5b3bec --- /dev/null +++ b/1180-count-substrings-with-only-one-distinct-letter.js @@ -0,0 +1,14 @@ +/** + * @param {string} s + * @return {number} + */ +const countLetters = function(s) { + const str = ` ${s} ` + let res = 0, cnt = 0 + for(let i = 1; i < str.length - 1; i++) { + if(str[i] !== str[i - 1]) cnt = 1 + else cnt += 1 + res += cnt + } + return res +}; diff --git a/1181-before-and-after-puzzle.js b/1181-before-and-after-puzzle.js new file mode 100644 index 00000000..211eeef9 --- /dev/null +++ b/1181-before-and-after-puzzle.js @@ -0,0 +1,71 @@ +/** + +Given a list of phrases, generate a list of Before and After puzzles. + +A phrase is a string that consists of lowercase English letters and spaces only. +No space appears in the start or the end of a phrase. There are no consecutive spaces in a phrase. +Before and After puzzles are phrases that are formed by merging two phrases where the last word of +the first phrase is the same as the first word of the second phrase. +Return the Before and After puzzles that can be formed by every two phrases phrases[i] and +phrases[j] where i != j. Note that the order of matching two phrases matters, +we want to consider both orders. + +You should return a list of distinct strings sorted lexicographically. + +Example 1: + +Input: phrases = ["writing code","code rocks"] +Output: ["writing code rocks"] +Example 2: + +Input: phrases = ["mission statement", + "a quick bite to eat", + "a chip off the old block", + "chocolate bar", + "mission impossible", + "a man on a mission", + "block party", + "eat my words", + "bar of soap"] +Output: ["a chip off the old block party", + "a man on a mission impossible", + "a man on a mission statement", + "a quick bite to eat my words", + "chocolate bar of soap"] +Example 3: + +Input: phrases = ["a","b","a"] +Output: ["a"] + +Constraints: + +1 <= phrases.length <= 100 +1 <= phrases[i].length <= 100 + +*/ + +/** + * @param {string[]} phrases + * @return {string[]} + */ +const beforeAndAfterPuzzles = function(phrases) { + const ret = new Set() + const start = {} + const splitArr = phrases.map(el => el.split(' ')) + for (let i = 0; i < splitArr.length; i++) { + const firstWord = splitArr[i][0] + start[firstWord] = start[firstWord] || [] + start[firstWord].push(i) + } + for (let i = 0; i < splitArr.length; i++) { + const lastWord = splitArr[i][splitArr[i].length - 1] + if (start[lastWord]) { + for (let idx of start[lastWord]) { + if (idx !== i) { + ret.add(splitArr[i].concat(splitArr[idx].slice(1)).join(' ')) + } + } + } + } + return [...ret].sort() +} diff --git a/1183-maximum-number-of-ones.js b/1183-maximum-number-of-ones.js new file mode 100644 index 00000000..59126327 --- /dev/null +++ b/1183-maximum-number-of-ones.js @@ -0,0 +1,26 @@ +/** + * @param {number} width + * @param {number} height + * @param {number} sideLength + * @param {number} maxOnes + * @return {number} + */ +const maximumNumberOfOnes = function (width, height, sideLength, maxOnes) { + const n1 = (height / sideLength) >> 0, + h = height % sideLength, + n2 = (width / sideLength) >> 0, + w = width % sideLength + if (maxOnes <= w * h) return n1 * n2 * maxOnes + (n1 + n2 + 1) * maxOnes + else { + const a = h * w, + B = (sideLength - w) * h, + C = (sideLength - h) * w + let b = Math.min(B, maxOnes - a) + let c = Math.min(maxOnes - a - b, C) + const res1 = n1 * (a + c) + n2 * (a + b) + c = Math.min(C, maxOnes - a) + b = Math.min(maxOnes - a - c, B) + const res2 = n1 * (a + c) + n2 * (a + b) + return n1 * n2 * maxOnes + Math.max(res1, res2) + a + } +} diff --git a/1186-maximum-subarray-sum-with-one-deletion.js b/1186-maximum-subarray-sum-with-one-deletion.js new file mode 100644 index 00000000..6938f589 --- /dev/null +++ b/1186-maximum-subarray-sum-with-one-deletion.js @@ -0,0 +1,42 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const maximumSum = function (arr) { + const n = arr.length + let oneDel = 0, noDel = arr[0], res = arr[0] + + for(let i = 1; i < n; i++) { + oneDel = Math.max(noDel, oneDel + arr[i]) + noDel = Math.max(arr[i], noDel + arr[i]) + res = Math.max(res, oneDel, noDel) + } + + return res +} + +// another + +/** + * @param {number[]} arr + * @return {number} + */ +const maximumSum = function (arr) { + const n = arr.length + let max = arr[0] + const maxEndAt = Array(n), maxStartAt = Array(n) + maxEndAt[0] = arr[0] + for(let i = 1; i < n; i++) { + maxEndAt[i] = Math.max(arr[i], maxEndAt[i - 1] + arr[i]) + max = Math.max(max, maxEndAt[i]) + } + maxStartAt[n - 1] = arr[n - 1] + for(let i = n - 2; i >= 0; i--) { + maxStartAt[i] = Math.max(arr[i], maxStartAt[i + 1] + arr[i]) + } + let res = Math.max(maxStartAt[0], maxEndAt[n - 1]) + for(let i = 1; i < n - 1; i++) { + res = Math.max(max, res, maxEndAt[i - 1] + maxStartAt[i + 1]) + } + return res +} diff --git a/1187-make-array-strictly-increasing.js b/1187-make-array-strictly-increasing.js new file mode 100644 index 00000000..0ce65c02 --- /dev/null +++ b/1187-make-array-strictly-increasing.js @@ -0,0 +1,60 @@ +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number} + */ +const makeArrayIncreasing = function(arr1, arr2) { + arr2.sort((a, b) => a - b) + let arr3 = [arr2[0]] + for (let i = 1; i < arr2.length; i++) { + if (arr2[i] > arr2[i - 1]) { + arr3.push(arr2[i]) + } + } + arr2 = arr3 + let n = arr1.length + let indexMap = new Array(n * 2 + 2) + for (let i = 0; i < n; i++) { + let ai = arr1[i] + let li = findLarger(arr2, ai) + indexMap[i * 2] = li + indexMap[i * 2 + 1] = arr2[li - 1] === ai ? li - 2 : li - 1 + } + indexMap[n * 2] = arr2.length + indexMap[n * 2 + 1] = arr2.length - 1 + let dp = new Array(n + 1) + let MaxNum = 1000000000 + 1 + dp[0] = 0 + for (let i = 1; i < n + 1; i++) { + let min = i + let ai = i === n ? MaxNum : arr1[i] + for (let j = 0; j < i; j++) { + if (dp[j] == -1 || ai <= arr1[j]) { + continue + } + if (indexMap[i * 2 + 1] - indexMap[j * 2] + 1 < i - j - 1) continue + min = Math.min(min, dp[j] + i - j - 1) + } + if (min === i) { + if (indexMap[i * 2 + 1] + 1 < i) { + min = -1 + } + } + dp[i] = min + } + return dp[n] +} +const findLarger = function(arr, a) { + if (a > arr[arr.length - 1]) return arr.length + let l = 0 + let r = arr.length - 1 + while (l < r) { + let mid = (l + r) >> 1 + if (arr[mid] <= a) { + l = mid + 1 + } else { + r = mid + } + } + return l +} diff --git a/1189-maximum-number-of-balloons.js b/1189-maximum-number-of-balloons.js new file mode 100644 index 00000000..8a268b94 --- /dev/null +++ b/1189-maximum-number-of-balloons.js @@ -0,0 +1,12 @@ +/** + * @param {string} text + * @return {number} + */ +const maxNumberOfBalloons = function(text) { + const cnt = [...text].reduce((A, ch) => { + A[ch] = (A[ch] || 0) + 1; + return A; + }, {}); + const ans = Math.min(cnt['b'], cnt['a'], cnt['l'] / 2, cnt['o'] / 2, cnt['n']); + return ans ? Math.floor(ans) : 0; +}; diff --git a/1190-reverse-substrings-between-each-pair-of-parentheses.js b/1190-reverse-substrings-between-each-pair-of-parentheses.js new file mode 100644 index 00000000..cdfe4768 --- /dev/null +++ b/1190-reverse-substrings-between-each-pair-of-parentheses.js @@ -0,0 +1,55 @@ +/** + * @param {string} s + * @return {string} + */ +const reverseParentheses = function(s) { + const res = [''] + let control = 0 + let order = 1 + for (let i = 0; i < s.length; i++) { + if (s[i] === '(') { + control++ + order = order ? 0 : 1 + res.push('') + } else if (s[i] === ')') { + if (order) res[control - 1] = res.pop() + res[control - 1] + else res[control - 1] = res[control - 1] + res.pop() + order = order ? 0 : 1 + control-- + } else { + if (order) res[control] = res[control] + s[i] + else res[control] = s[i] + res[control] + } + } + return res[0] +} + +// another + +/** + * @param {string} s + * @return {string} + */ +const reverseParentheses = function(s) { + const n = s.length + const stack = [] + const pair = [] + for(let i = 0; i < n; i++) { + if(s[i] === '(') stack.push(i) + else if(s[i] === ')') { + const tmp = stack.pop() + pair[i] = tmp + pair[tmp] = i + } + } + let res = '' + for(let i = 0, d = 1; i < n; i += d) { + if(s[i] === '(' || s[i] ===')') { + i = pair[i] + d = -d + } else { + res += s[i] + } + } + return res +} diff --git a/1191-k-concatenation-maximum-sum.js b/1191-k-concatenation-maximum-sum.js new file mode 100644 index 00000000..e73b8dbd --- /dev/null +++ b/1191-k-concatenation-maximum-sum.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ +const kConcatenationMaxSum = function(arr, k) { + const MOD = 1e9 + 7, + INF = 1e4 + 1; + const kadane = (A, sum = 0, ans = -INF) => { + for (let x of A) { + sum = Math.max(0, sum + x); + ans = Math.max(ans, sum); + } + return [sum, ans]; + }; + const [sum1, ans1] = kadane(arr); + const [sum2, ans2] = kadane(arr, sum1); + const [sum3, ans3] = kadane(arr, sum2); + const delta1 = ans2 - ans1, + delta2 = ans3 - ans2; + return k == 1 || delta1 == 0 + ? ans1 + : delta2 == 0 + ? ans2 + : ans1 + ((delta1 * (k - 1)) % MOD); +}; diff --git a/1192-critical-connections-in-a-network.js b/1192-critical-connections-in-a-network.js new file mode 100644 index 00000000..649afd14 --- /dev/null +++ b/1192-critical-connections-in-a-network.js @@ -0,0 +1,35 @@ +/** + * @param {number} n + * @param {number[][]} connections + * @return {number[][]} + */ +const criticalConnections = function(n, connections) { + const g = [], + low = Array(n), + res = [] + low.fill(0) + for (let con of connections) { + g[con[0]] = g[con[0]] || [] + g[con[1]] = g[con[1]] || [] + g[con[0]].push(con[1]) + g[con[1]].push(con[0]) + } + const dfs = function(cur, v, p) { + let dfn = cur + low[v] = cur + for (let i of g[v]) { + if (i != p) { + if (low[i] == 0) { + cur++ + dfs(cur, i, v) + if (low[i] > dfn) { + res.push([i, v]) + } + } + low[v] = Math.min(low[v], low[i]) + } + } + } + dfs(1, 0, -1) + return res +} diff --git a/1194-tournament-winners.sql b/1194-tournament-winners.sql new file mode 100644 index 00000000..99365396 --- /dev/null +++ b/1194-tournament-winners.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +select group_id, player_id from ( + select p.group_id, ps.player_id, sum(ps.score) as score from Players p, + (select first_player as player_id, first_score as score from Matches + union all + select second_player, second_score from Matches) ps + where p.player_id = ps.player_id + group by ps.player_id order by group_id, score desc, player_id) top_scores +group by group_id; diff --git a/1199-minimum-time-to-build-blocks.js b/1199-minimum-time-to-build-blocks.js new file mode 100644 index 00000000..873aa97c --- /dev/null +++ b/1199-minimum-time-to-build-blocks.js @@ -0,0 +1,58 @@ +/** + * @param {number[]} blocks + * @param {number} split + * @return {number} + */ +const minBuildTime = function (blocks, split) { + const minHeap = new MinHeap() + blocks.forEach((block) => minHeap.push(block)) + while (minHeap.size() > 1) { + minHeap.pop() + minHeap.push(minHeap.pop() + split) + } + return minHeap.pop() +} + +class MinHeap { + constructor() { + this.store = [] + } + size() { + return this.store.length + } + push(value) { + this.store.push(value) + this.heapifyUp(this.store.length - 1) + } + pop() { + if (this.store.length < 2) return this.store.pop() + let result = this.store[0] + this.store[0] = this.store.pop() + this.heapifyDown(0) + return result + } + heapifyUp(child) { + const parent = Math.floor((child - 1) / 2) + if (child && this.store[child] < this.store[parent]) { + const temp = this.store[child] + this.store[child] = this.store[parent] + this.store[parent] = temp + this.heapifyUp(parent) + } + } + heapifyDown(parent) { + const childs = [1, 2] + .map((n) => parent * 2 + n) + .filter((n) => n < this.store.length) + let child = childs[0] + if (childs[1] && this.store[childs[1]] < this.store[child]) { + child = childs[1] + } + if (child && this.store[child] < this.store[parent]) { + const temp = this.store[child] + this.store[child] = this.store[parent] + this.store[parent] = temp + this.heapifyDown(child) + } + } +} diff --git a/120-triangle.js b/120-triangle.js index 483942e8..6f809c2a 100644 --- a/120-triangle.js +++ b/120-triangle.js @@ -17,3 +17,26 @@ const minimumTotal = function(triangle) { return triangle[0][0]; }; + +// another + +/** + * @param {number[][]} triangle + * @return {number} + */ +const minimumTotal = function(triangle) { + const m = triangle.length, n = triangle.at(-1).length + const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(Infinity)) + dp[1][1] = triangle[0][0] + for(let i = 2; i <= m; i++) { + for(let j = 1; j <= triangle[i - 1].length; j++) { + if(j === 1) dp[i][j] = dp[i - 1][j] + triangle[i - 1][j - 1] + else dp[i][j] = Math.min(dp[i - 1][j], dp[i - 1][j - 1]) + triangle[i - 1][j - 1] + } + } + let res = Infinity + for (let j = 0; j <= n; j++) { + res = Math.min(res, dp[m][j]) + } + return res +}; diff --git a/1200-minimum-absolute-difference.js b/1200-minimum-absolute-difference.js new file mode 100644 index 00000000..ec62435c --- /dev/null +++ b/1200-minimum-absolute-difference.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} arr + * @return {number[][]} + */ +const minimumAbsDifference = function(arr) { + arr.sort((a, b) => a - b) + let min = Number.MAX_VALUE + for(let i = 1, len = arr.length; i < len; i++) { + if(arr[i] - arr[i - 1] < min) min = arr[i] - arr[i - 1] + } + const res = [] + for(let i = 1, len = arr.length; i < len; i++) { + if(arr[i] - arr[i - 1] === min) res.push([arr[i - 1], arr[i]]) + } + return res +}; diff --git a/1201-ugly-number-iii.js b/1201-ugly-number-iii.js new file mode 100644 index 00000000..b553502c --- /dev/null +++ b/1201-ugly-number-iii.js @@ -0,0 +1,73 @@ +/** + * @param {number} n + * @param {number} a + * @param {number} b + * @param {number} c + * @return {number} + */ +const nthUglyNumber = function(n, a, b, c) { + let lo = 1, hi = 2 * 1e9; + const { floor: f } = Math + let ab = a * b / gcd(a, b); + let bc = b * c / gcd(b, c); + let ac = a * c / gcd(a, c); + let abc = a * bc / gcd(a, bc); + while(lo < hi) { + let mid = lo + Math.floor((hi - lo) / 2); + if(valid(mid)) hi = mid; + else lo = mid + 1; + } + return lo; + + function valid(mid) { + let res = f(mid / a) + f(mid / b) + f(mid / c) - f(mid / ab) - f(mid / bc) - f(mid / ac) + f(mid / abc) + return res >= n + } + + function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) + } +}; + +// another + +/** + * @param {number} n + * @param {number} a + * @param {number} b + * @param {number} c + * @return {number} + */ +var nthUglyNumber = function (n, a, b, c) { + const {floor} = Math + let lo = 1, + hi = 2 * (1e9 | 0) + ;(a = BigInt(a)), (b = BigInt(b)), (c = BigInt(c)) + let ab = (a * b) / gcd(a, b) + let bc = (b * c) / gcd(b, c) + let ac = (a * c) / gcd(a, c) + let abc = (a * bc) / gcd(a, bc) + + while (lo < hi) { + let mid = lo + ((hi - lo) >> 1) + let cnt = + floor(mid / Number(a)) + + floor(mid / Number(b)) + + floor(mid / Number(c)) - + floor(mid / Number(ab)) - + floor(mid / Number(bc)) - + floor(mid / Number(ac)) + + floor(mid / Number(abc)) + if (cnt < n) { + lo = mid + 1 + } else { + hi = mid + } + } + + return lo + + function gcd(a, b) { + return b ? gcd(b, a % b) : a + } +} diff --git a/1202-smallest-string-with-swaps.js b/1202-smallest-string-with-swaps.js new file mode 100644 index 00000000..c02d041f --- /dev/null +++ b/1202-smallest-string-with-swaps.js @@ -0,0 +1,43 @@ +/** + * @param {string} s + * @param {number[][]} pairs + * @return {string} + */ +const smallestStringWithSwaps = function(s, pairs) { + let set = Array(s.length).fill(-1) + function union(a, b) { + let root1 = find(a) + let root2 = find(b) + if (root1 !== root2) { + set[root2] = root1 + } + } + function find(a) { + if (set[a] < 0) { + return a + } else { + return (set[a] = find(set[a])) + } + } + for (let pair of pairs) { + union(pair[0], pair[1]) + } + let groups = [] + for (let i = 0; i < s.length; i++) { + groups[i] = [] + } + for (let i = 0; i < s.length; i++) { + groups[find(i)].push(i) + } + let sArr = s.split('') + for (let i = 0; i < s.length; i++) { + if (groups[i].length > 1) { + let chars = groups[i].map(idx => s[idx]) + chars.sort() + for (let k = 0; k < groups[i].length; k++) { + sArr[groups[i][k]] = chars[k] + } + } + } + return sArr.join('') +} diff --git a/1203-sort-items-by-groups-respecting-dependencies.js b/1203-sort-items-by-groups-respecting-dependencies.js new file mode 100644 index 00000000..0894cd98 --- /dev/null +++ b/1203-sort-items-by-groups-respecting-dependencies.js @@ -0,0 +1,143 @@ +/** + * @param {number} n + * @param {number} m + * @param {number[]} group + * @param {number[][]} beforeItems + * @return {number[]} + */ +const sortItems = function (n, m, group, beforeItems) { + const graph = Array.from({ length: m + n }, () => []) + const indegree = Array(n + m).fill(0) + for (let i = 0; i < group.length; i++) { + if (group[i] == -1) continue + graph[n + group[i]].push(i) + indegree[i]++ + } + for (let i = 0; i < beforeItems.length; i++) { + for (const e of beforeItems[i]) { + const a = group[e] === -1 ? e : n + group[e] + const b = group[i] === -1 ? i : n + group[i] + if (a === b) { + // same group, ingroup order + graph[e].push(i) + indegree[i]++ + } else { + // outgoup order + graph[a].push(b) + indegree[b]++ + } + } + } + const res = [] + for (let i = 0; i < n + m; i++) { + if (indegree[i] === 0) dfs(res, graph, indegree, n, i) + } + return res.length === n ? res : [] + + function dfs(ans, graph, indegree, n, cur) { + if (cur < n) ans.push(cur) + indegree[cur] = -1 // mark it visited + for (let next of graph[cur] || []) { + indegree[next]-- + if (indegree[next] === 0) dfs(ans, graph, indegree, n, next) + } + } +} + + +// another + + +/** + * @param {number} n + * @param {number} m + * @param {number[]} group + * @param {number[][]} beforeItems + * @return {number[]} + */ +const sortItems = function (n, m, group, beforeItems) { + const vertexs = new Map() + const groupVertexs = new Map() + let groupNo = m + for (let i = 0; i < n; i++) { + vertexs.set(i, { + neighbors: new Set(), + indegree: 0, + }) + if (group[i] === -1) { + group[i] = groupNo++ + } + if (!groupVertexs.has(group[i])) { + groupVertexs.set(group[i], { + v: new Set(), + neighbors: new Set(), + indegree: 0, + }) + } + groupVertexs.get(group[i]).v.add(i) + } + + for (let i = 0; i < n; i++) { + for (const before of beforeItems[i]) { + if (!vertexs.get(before).neighbors.has(i)) { + vertexs.get(i).indegree += 1 + } + vertexs.get(before).neighbors.add(i) + + const groupOfBefore = group[before] + if (groupOfBefore === group[i]) continue + if (!groupVertexs.get(groupOfBefore).neighbors.has(group[i])) { + groupVertexs.get(group[i]).indegree += 1 + } + groupVertexs.get(groupOfBefore).neighbors.add(group[i]) + } + } + + const zeroGroup = [] + for (const group of groupVertexs) { + if (group[1].indegree === 0) { + zeroGroup.push(group[0]) + } + } + const result = [] + let cntGroup = 0 + let cntV = 0 + const groupTotal = groupVertexs.size + + while (zeroGroup.length) { + const top = zeroGroup.pop() + cntGroup += 1 + const v = groupVertexs.get(top).v + const total = v.size + const zero = [] + + for (const i of v) { + if (vertexs.get(i).indegree === 0) { + zero.push(i) + } + } + while (zero.length) { + const it = zero.pop() + result.push(it) + for (const n of vertexs.get(it).neighbors) { + vertexs.get(n).indegree -= 1 + if (v.has(n) && vertexs.get(n).indegree === 0) { + zero.push(n) + } + } + } + if (result.length - cntV !== total) { + return [] + } + cntV = result.length + + for (const groupneigbor of groupVertexs.get(top).neighbors) { + groupVertexs.get(groupneigbor).indegree -= 1 + if (groupVertexs.get(groupneigbor).indegree === 0) { + zeroGroup.push(groupneigbor) + } + } + } + + return cntGroup === groupTotal ? result : [] +} diff --git a/1206-design-skiplist.js b/1206-design-skiplist.js new file mode 100644 index 00000000..c559a289 --- /dev/null +++ b/1206-design-skiplist.js @@ -0,0 +1,145 @@ +class Skiplist { + constructor() { + this.head = { down: null, right: null, val: -Infinity } + } + search(val) { + let curr = this.head + while (curr) { + while (curr.right && curr.right.val <= val) { + curr = curr.right + } + if (curr.val == val) { + return true + } + curr = curr.down + } + return false + } + add(val) { + let curr = this.head + const insertion_positions = [] + while (curr) { + while (curr.right && curr.right.val < val) { + curr = curr.right + } + insertion_positions.push(curr) + curr = curr.down + } + let insert = true + let down = null + while (insert && insertion_positions.length) { + const position = insertion_positions.pop() + const node = { down, val, right: position.right } + position.right = node + down = node + insert = Math.random() < 0.5 + } + if (insert) { + const node = { val, down } + this.head = { val: -Infinity, right: node, down: this.head } + } + } + erase(val) { + let curr = this.head + const erase_positions = [] + while (curr) { + while (curr.right && curr.right.val < val) { + curr = curr.right + } + if (curr.right && curr.right.val == val) { + erase_positions.push(curr) + } + curr = curr.down + } + const seen = erase_positions.length > 0 + for (const position of erase_positions) { + position.right = position.right && position.right.right + } + return seen + } +} + +// another + +const Skiplist = function () { + this.maxLvl = ~~Math.log2(20000) + this.levels = [...Array(this.maxLvl)].map(() => new Node(-1)) + for (let i = this.maxLvl - 1; i > 0; i--) { + this.levels[i].down = this.levels[i - 1] + } + this.head = this.levels[this.maxLvl - 1] +} + +/** + * @param {number} target + * @return {boolean} + */ +Skiplist.prototype.search = function (target) { + const pre = this.iter(target) + return !pre[0].next ? false : pre[0].next.val === target +} + +Skiplist.prototype.iter = function (target) { + let cur = this.head + const pre = [] + for (let i = this.maxLvl - 1; i >= 0; i--) { + while (cur.next && cur.next.val < target) cur = cur.next + pre[i] = cur + cur = cur.down + } + return pre +} + +/** + * @param {number} num + * @return {void} + */ +Skiplist.prototype.add = function (num) { + const pre = this.iter(num) + const lvs = decideLevels(this.maxLvl) + for (let i = 0; i < lvs; i++) { + const next = pre[i].next + pre[i].next = new Node(num) + pre[i].next.next = next + if (i > 0) pre[i].next.down = pre[i - 1].next + } +} + +/** + * @param {number} num + * @return {boolean} + */ +Skiplist.prototype.erase = function (num) { + const pre = this.iter(num) + let ret + if (!pre[0].next || pre[0].next.val !== num) return false + for (let i = this.maxLvl - 1; i >= 0; i--) { + if (pre[i].next && pre[i].next.val === num) { + const toBeDeleted = pre[i].next + pre[i].next = toBeDeleted.next + toBeDeleted.next = null + toBeDeleted.down = null + } + } + return true +} + +/** + * Your Skiplist object will be instantiated and called as such: + * var obj = new Skiplist() + * var param_1 = obj.search(target) + * obj.add(num) + * var param_3 = obj.erase(num) + */ + +const decideLevels = (max) => { + let ans = 1 + while (Math.random() > 0.5 && ans < max) ans++ + return ans +} + +const Node = function (val) { + this.val = val + this.next = null + this.down = null +} diff --git a/1207-unique-number-of-occurrences.js b/1207-unique-number-of-occurrences.js new file mode 100644 index 00000000..d1621449 --- /dev/null +++ b/1207-unique-number-of-occurrences.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} arr + * @return {boolean} + */ +const uniqueOccurrences = function(arr) { + const hash = {} + for(let e of arr) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + const ks = new Set(Object.keys(hash)), vs = new Set(Object.values(hash)) + return ks.size === vs.size +}; diff --git a/1209-remove-all-adjacent-duplicates-in-string-ii.js b/1209-remove-all-adjacent-duplicates-in-string-ii.js new file mode 100644 index 00000000..e03e4c40 --- /dev/null +++ b/1209-remove-all-adjacent-duplicates-in-string-ii.js @@ -0,0 +1,51 @@ +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const removeDuplicates = function (s, k) { + const stack = []; + const arr = s.split('') + for(let i = 0; i < arr.length; i++) { + if(i === 0 || arr[i] !== arr[i - 1]) { + stack.push(1) + } else { + stack[stack.length - 1]++ + if(stack[stack.length - 1] === k) { + stack.pop() + arr.splice(i - k + 1, k) + i -= k + } + } + + } + return arr.join('') +}; + +// another + +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const removeDuplicates = function (s, k) { + const stack = []; + s = s.split(''); + for (let i = 0; i < s.length;) { + if (i === 0 || s[i] !== s[i - 1]) { + stack.push(1); + i++ + } else { + stack[stack.length - 1]++; + if (stack[stack.length - 1] === k) { + stack.pop(); + s.splice(i - k + 1, k); + i = i - k + 1; + } else { + i++ + } + } + } + return s.join(''); +}; diff --git a/121-best-time-to-buy-and-sell-stock.js b/121-best-time-to-buy-and-sell-stock.js index 1435def8..7a5d1899 100755 --- a/121-best-time-to-buy-and-sell-stock.js +++ b/121-best-time-to-buy-and-sell-stock.js @@ -14,3 +14,18 @@ const maxProfit = function(prices) { } return maxP; }; + +// another + +/** + * @param {number[]} prices + * @return {number} + */ +const maxProfit = function(prices) { + let res = 0, maxCur = 0 + for(let i = 1; i < prices.length; i++) { + maxCur = Math.max(0, maxCur + (prices[i] - prices[i - 1])) + res = Math.max(res, maxCur) + } + return res +}; diff --git a/1210-minimum-moves-to-reach-target-with-rotations.js b/1210-minimum-moves-to-reach-target-with-rotations.js new file mode 100644 index 00000000..6d23ef5a --- /dev/null +++ b/1210-minimum-moves-to-reach-target-with-rotations.js @@ -0,0 +1,69 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const minimumMoves = function (grid) { + const n = grid.length; + const start = [0, 0, 0, 1].join(','); + const end = [n - 1, n - 2, n - 1, n - 1].join(","); + let curr_level = new Set([start]); + let moves = 0; + const visited = new Set(); + while (curr_level.size) { + const next_level = new Set(); + for (let pos of curr_level) { + visited.add(pos); + let [r1, c1, r2, c2] = pos.split(",").map((e) => +e); + if ( + c1 + 1 < n && + grid[r1][c1 + 1] == 0 && + c2 + 1 < n && + grid[r2][c2 + 1] == 0 + ) { + const coord = [r1, c1 + 1, r2, c2 + 1].join(","); + if (!visited.has(coord)) { + next_level.add(coord); + } + } + if ( + r1 + 1 < n && + grid[r1 + 1][c1] == 0 && + r2 + 1 < n && + grid[r2 + 1][c2] == 0 + ) { + const coord = [r1 + 1, c1, r2 + 1, c2].join(","); + if (!visited.has(coord)) { + next_level.add(coord); + } + } + if ( + r1 == r2 && + c2 == c1 + 1 && + r1 + 1 < n && + grid[r1 + 1][c1] + grid[r1 + 1][c1 + 1] == 0 + ) { + const coord = [r1, c1, r1 + 1, c1].join(","); + if (!visited.has(coord)) { + next_level.add(coord); + } + } + if ( + c1 == c2 && + r2 == r1 + 1 && + c1 + 1 < n && + grid[r1][c1 + 1] + grid[r1 + 1][c1 + 1] == 0 + ) { + const coord = [r1, c1, r1, c1 + 1].join(","); + if (!visited.has(coord)) { + next_level.add(coord); + } + } + } + if (next_level.has(end)) { + return moves + 1; + } + curr_level = next_level; + moves += 1; + } + return -1; +}; diff --git a/1211-queries-quality-and-percentage.sql b/1211-queries-quality-and-percentage.sql new file mode 100644 index 00000000..904006a7 --- /dev/null +++ b/1211-queries-quality-and-percentage.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +SELECT + query_name, + ROUND(AVG(rating / position), 2) AS quality, + ROUND(AVG(rating < 3) * 100, 2) AS poor_query_percentage +FROM + Queries +GROUP BY + query_name; diff --git a/1213-intersection-of-three-sorted-arrays.js b/1213-intersection-of-three-sorted-arrays.js new file mode 100644 index 00000000..3984750c --- /dev/null +++ b/1213-intersection-of-three-sorted-arrays.js @@ -0,0 +1,52 @@ +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @param {number[]} arr3 + * @return {number[]} + */ +const arraysIntersection = function(arr1, arr2, arr3) { + const common = [], n1 = arr1.length, n2 = arr2.length, n3 = arr3.length + let p1 = 0, p2 = 0, p3 = 0 + while(p1 < n1 && p2 < n2) { + if(arr1[p1] === arr2[p2]) { + common.push(arr1[p1]) + p1++ + p2++ + } else if(arr1[p1] < arr2[p2]) p1++ + else p2++ + } + const res = [], nc = common.length + let pc = 0 + while(pc < nc && p3 < n3) { + if(common[pc] === arr3[p3]) { + res.push(arr3[p3]) + pc++ + p3++ + } else if(common[pc] < arr3[p3]) pc++ + else p3++ + } + + + return res +}; + +// another + +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @param {number[]} arr3 + * @return {number[]} + */ +const arraysIntersection = function(arr1, arr2, arr3) { + let a=0,b=0,c=0; + const res = []; + while(a new Array(n + 1).fill(0)) + for(let i = 1; i <= m; i++) { + for(let j = 1; j <= n; j++) { + if(s1[i - 1] === s2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + 1 + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + } + } + } + return dp[m][n] +} + +// another + +/** + * @param {string} s + * @param {number} k + * @return {boolean} + */ +const isValidPalindrome = function(s, k) { + const len = s.length + const cache = Array.from({ length: len }, () => new Array(len).fill(0)) + chk(s, 0, len - 1, cache) + return cache[0][len - 1] <= k +}; + +function chk(s, l, r, cache) { + if(l >= r) return 0 + if(cache[l][r]) return cache[l][r] + let num = 0 + if(s[l] === s[r]) { + num = chk(s, l + 1, r - 1, cache) + } else { + num = 1 + Math.min(chk(s, l, r - 1, cache), chk(s, l + 1, r, cache)) + } + cache[l][r] = num + return num +} + +// another + +const isValidPalindrome = function(s, k) { + const len = s.length + const dp = Array.from({ length: len }, () => new Array(len).fill(0)) + for(let i = len - 1; i >= 0; i--) { + dp[i][i] = 1 + for(let j = i + 1; j < len; j++) { + if(s[i] === s[j]) dp[i][j] = dp[i + 1][j - 1] + 2 + else dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]) + } + } + return len <= dp[0][len - 1] + k +}; + diff --git a/1217-minimum-cost-to-move-chips-to-the-same-position.js b/1217-minimum-cost-to-move-chips-to-the-same-position.js new file mode 100644 index 00000000..c9c72ba9 --- /dev/null +++ b/1217-minimum-cost-to-move-chips-to-the-same-position.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} position + * @return {number} + */ +const minCostToMoveChips = function(position) { + let oddSum = 0, evenSum = 0 + for(let i = 0; i < position.length; i++) { + if(position[i] % 2 === 0) evenSum++ + else oddSum++ + } + return Math.min(oddSum, evenSum) +}; diff --git a/1219-path-with-maximum-gold.js b/1219-path-with-maximum-gold.js new file mode 100644 index 00000000..150b85e8 --- /dev/null +++ b/1219-path-with-maximum-gold.js @@ -0,0 +1,83 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const getMaximumGold = function(grid) { + const m = grid.length, n = grid[0].length + const arr = [] + const dirs = [[-1, 0], [1, 0], [0, 1], [0, -1]] + const visited = new Set() + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] !== 0) arr.push([i, j]) + } + } + let res = 0 + + for(const [i, j] of arr) { + visited.clear() + visited.add(`${i},${j}`) + dfs(i, j, grid[i][j]) + } + + return res + + function dfs(i, j, cur) { + + res = Math.max(res, cur) + for(const [dx, dy] of dirs) { + const nx = i + dx + const ny = j + dy + const key = `${nx},${ny}` + if(nx >= 0 && nx < m && ny >= 0 && ny < n && !visited.has(key) && grid[nx][ny] !== 0) { + visited.add(key) + dfs(nx, ny, cur + grid[nx][ny]) + visited.delete(key) + } + } + } + +}; + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +var getMaximumGold = function (grid) { + const m = grid.length + const n = grid[0].length + let max = 0 + + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] != 0) { + const sum = backtrack(grid, i, j, m, n) + max = Math.max(sum, max) + } + } + } + + return max +} + +function backtrack(grid, row, col, m, n) { + if (outOfBound(row, col, m, n) || grid[row][col] === 0) return 0 + + let sum = grid[row][col] + grid[row][col] = 0 // mark as being visited already + + const top = backtrack(grid, row - 1, col, m, n) + const right = backtrack(grid, row, col + 1, m, n) + const bot = backtrack(grid, row + 1, col, m, n) + const left = backtrack(grid, row, col - 1, m, n) + + grid[row][col] = sum // backtrack to the original form + + return sum + Math.max(top, right, bot, left) +} + +function outOfBound(row, col, m, n) { + return row < 0 || col < 0 || row >= m || col >= n +} diff --git a/122-best-time-to-buy-and-sell-stock-ii.js b/122-best-time-to-buy-and-sell-stock-ii.js new file mode 100644 index 00000000..20ced781 --- /dev/null +++ b/122-best-time-to-buy-and-sell-stock-ii.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} prices + * @return {number} + */ +const maxProfit = function (prices) { + let p = 0 + for (let i = 1; i < prices.length; ++i) { + let delta = prices[i] - prices[i - 1] + if (delta > 0) { + p += delta + } + } + return p +} diff --git a/1220-count-vowels-permutation.js b/1220-count-vowels-permutation.js new file mode 100644 index 00000000..101580d6 --- /dev/null +++ b/1220-count-vowels-permutation.js @@ -0,0 +1,27 @@ +/** + * @param {number} n + * @return {number} + */ +const countVowelPermutation = function (n) { + const mod = 1e9 + 7 + const arr = [ + [0, 1, 1], // a -> e + [0, 1, 2], // e -> a, i + [0, 1, 4], // i -> a, e, o, u + [0, 1, 2], // o -> i, u + [0, 1, 1], // u -> a + ] + for (let i = 3; i <= n; i++) { + arr[0][i % 3] = arr[1][(i - 1) % 3] % mod + arr[1][i % 3] = (arr[0][(i - 1) % 3] + arr[2][(i - 1) % 3]) % mod + arr[2][i % 3] = + (arr[0][(i - 1) % 3] + + arr[1][(i - 1) % 3] + + arr[3][(i - 1) % 3] + + arr[4][(i - 1) % 3]) % + mod + arr[3][i % 3] = (arr[2][(i - 1) % 3] + arr[4][(i - 1) % 3]) % mod + arr[4][i % 3] = arr[0][(i - 1) % 3] % mod + } + return arr.reduce((sum, subArr) => sum + subArr[n % 3], 0) % mod +} diff --git a/1221-split-a-string-in-balanced-strings.js b/1221-split-a-string-in-balanced-strings.js new file mode 100644 index 00000000..fe5401de --- /dev/null +++ b/1221-split-a-string-in-balanced-strings.js @@ -0,0 +1,12 @@ +/** + * @param {string} s + * @return {number} + */ +const balancedStringSplit = function(s) { + let res = 0, num = 0 + for(let ch of s) { + num += ch === 'L' ? 1 : -1 + if(num === 0) res++ + } + return res +}; diff --git a/1223-dice-roll-simulation.js b/1223-dice-roll-simulation.js new file mode 100644 index 00000000..2a760b53 --- /dev/null +++ b/1223-dice-roll-simulation.js @@ -0,0 +1,26 @@ +/** + * @param {number} n + * @param {number[]} rollMax + * @return {number} + */ +const dieSimulator = function(n, rollMax) { + const mod = 10 ** 9 + 7 + const faces = rollMax.length + const dp = Array.from({ length: n + 1 }, () => new Array(faces + 1).fill(0)) + dp[0][faces] = 1 + for(let j = 0; j < faces; j++) { + dp[1][j] = 1 + } + dp[1][faces] = faces + for(let i = 2; i < n + 1; i++) { + for(let j = 0; j < faces; j++) { + for(let k = 1; k < rollMax[j] + 1; k++) { + if(i - k < 0) break + dp[i][j] += dp[i - k][faces] - dp[i - k][j] + dp[i][j] %= mod + } + } + dp[i][faces] = dp[i].reduce((ac, e) => ac + e, 0) + } + return dp[n][faces] % mod +}; diff --git a/1224-maximum-equal-frequency.js b/1224-maximum-equal-frequency.js new file mode 100644 index 00000000..192cc0e6 --- /dev/null +++ b/1224-maximum-equal-frequency.js @@ -0,0 +1,72 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxEqualFreq = function (nums) { + const freqCnt = {}, cnt = {}, { max } = Math + + let res = 0, maxF = 0, i = 0 + for(const e of nums) { + if(cnt[e] == null) cnt[e] = 0 + cnt[e]++ + + const f = cnt[e] + + if(freqCnt[f - 1] == null) freqCnt[f - 1] = 0 + if(freqCnt[f] == null) freqCnt[f] = 0 + + if(freqCnt[f - 1] > 0) freqCnt[f - 1]-- + freqCnt[f]++ + + maxF = max(maxF, f) + + /* + cnt records the occurence of each num, freq records the frequence of number of occurences. max_F is the largest frequence. + There are three cases which satify the condition: + + all elements appear exact once. + all elements appear max_F times, except one appears once. + all elements appear max_F-1 times, except one appears max_F. + */ + if( + maxF === 1 || + maxF * freqCnt[maxF] === i || + (maxF - 1) * (freqCnt[maxF - 1] + 1) === i + ) { + res = i + 1 + } + + i++ + } + + return res +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxEqualFreq = function (nums) { + const cnt = {}, + freq = {} + let maxF = 0, + res = 0 + nums.forEach((num, i) => { + if (cnt[num] == null) cnt[num] = 0 + cnt[num] += 1 + if (freq[cnt[num] - 1] == null) freq[cnt[num] - 1] = 0 + if (freq[cnt[num]] == null) freq[cnt[num]] = 0 + freq[cnt[num] - 1] -= 1 + freq[cnt[num]] += 1 + maxF = Math.max(maxF, cnt[num]) + if ( + maxF * freq[maxF] === i || + (maxF - 1) * (freq[maxF - 1] + 1) === i || + maxF === 1 + ) + res = i + 1 + }) + return res +} diff --git a/1228-missing-number-in-arithmetic-progression.js b/1228-missing-number-in-arithmetic-progression.js new file mode 100644 index 00000000..6bccbb36 --- /dev/null +++ b/1228-missing-number-in-arithmetic-progression.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const missingNumber = function(arr) { + const n = arr.length + + for(let i = 1 ; i < n - 1; i++) { + const d1 = arr[i] - arr[i - 1], d2 = arr[i + 1] - arr[i] + if(d1 === d2) continue + if(d1 / d2 === 2) return arr[i - 1] + d1 / 2 + if(d2 / d1 === 2) return arr[i] + d2 / 2 + } + return arr[0] +}; diff --git a/1229-meeting-scheduler.js b/1229-meeting-scheduler.js new file mode 100644 index 00000000..46d4c72e --- /dev/null +++ b/1229-meeting-scheduler.js @@ -0,0 +1,81 @@ +/** + * @param {number[][]} slots1 + * @param {number[][]} slots2 + * @param {number} duration + * @return {number[]} + */ +const minAvailableDuration = function (slots1, slots2, duration) { + const hash = {} + for(const [s, e] of slots1) { + if(hash[s] == null) hash[s] = 0 + if(hash[e] == null) hash[e] = 0 + + hash[s]++ + hash[e]-- + } + + for(const [s, e] of slots2) { + if(hash[s] == null) hash[s] = 0 + if(hash[e] == null) hash[e] = 0 + + hash[s]++ + hash[e]-- + } + + const keys = Object.keys(hash).map(e => +e) + keys.sort((a, b) => a - b) + for(let i = 1; i < keys.length; i++) { + hash[keys[i]] += hash[keys[i - 1]] + } + // console.log(keys, hash) + const n = keys.length + for(let i = 0; i < keys.length; i++) { + const k = keys[i] + if(hash[k] === 2 && i + 1 < n && valid(k, i)) { + return [k, k + duration] + } + } + + return [] + + function valid(k, idx) { + let l = k, r = k + duration + for(let i = idx + 1; i < keys.length && keys[i] < r; i++) { + const key = keys[i] + if(hash[key] !== 2) return false + } + + return true + } +} + +// another + +/** + * @param {number[][]} slots1 + * @param {number[][]} slots2 + * @param {number} duration + * @return {number[]} + */ +const minAvailableDuration = function (slots1, slots2, duration) { + slots1.sort((a, b) => a[0] - b[0]) + slots2.sort((a, b) => a[0] - b[0]) + + const m = slots1.length, n = slots2.length + let i = 0, j = 0 + + while(i < m && j < n) { + const start = Math.max(slots1[i][0], slots2[j][0]) + const end = Math.min(slots1[i][1], slots2[j][1]) + + if(end - start >= duration) { + return [start, start + duration] + } + + if(slots1[i][1] > slots2[j][1]) j++ + else i++ + + } + + return [] +} diff --git a/1231-divide-chocolate.js b/1231-divide-chocolate.js new file mode 100644 index 00000000..ea4d1768 --- /dev/null +++ b/1231-divide-chocolate.js @@ -0,0 +1,54 @@ +/** + * @param {number[]} sweetness + * @param {number} K + * @return {number} + */ +const maximizeSweetness = function (sweetness, K) { + let left = 1, + right = 1e9 / (K + 1) + while (left < right) { + let mid = (left + right + 1) >> 1 + let cur = 0, + cuts = 0 + for (let a of sweetness) { + if ((cur += a) >= mid) { + cur = 0 + if (++cuts > K) break + } + } + if (cuts > K) left = mid + else right = mid - 1 + } + return left +} + +// another + +/** + * @param {number[]} sweetness + * @param {number} K + * @return {number} + */ +const maximizeSweetness = function(sweetness, K) { + let l = 1, r = 10 ** 9 + while(l < r) { + const mid = r - Math.floor((r - l) / 2) + if(valid(mid)) l = mid + else r = mid - 1 + } + return l + + function valid(mid) { + let res = 0, cur = 0 + const n = sweetness.length + for(let i = 0; i < n; i++) { + const e = sweetness[i] + cur += e + if(cur >= mid) { + res++ + cur = 0 + } + } + return res >= K + 1 + } +}; diff --git a/1232-check-if-it-is-a-straight-line.js b/1232-check-if-it-is-a-straight-line.js new file mode 100644 index 00000000..d59a9e37 --- /dev/null +++ b/1232-check-if-it-is-a-straight-line.js @@ -0,0 +1,16 @@ +/** + * @param {number[][]} coordinates + * @return {boolean} + */ +const checkStraightLine = function(coordinates) { + const r = ratio(coordinates[0], coordinates[1]) + for(let i = 1, len = coordinates.length; i < len - 1; i++) { + if(ratio(coordinates[i], coordinates[i + 1]) !== r) return false + } + + return true +}; + +function ratio(a, b) { + return (b[1] - a[1]) / (b[0] - a[0]) +} diff --git a/1235-maximum-profit-in-job-scheduling.js b/1235-maximum-profit-in-job-scheduling.js new file mode 100644 index 00000000..a5a0fa3b --- /dev/null +++ b/1235-maximum-profit-in-job-scheduling.js @@ -0,0 +1,113 @@ +/** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ +const jobScheduling = function (startTime, endTime, profit) { + const n = startTime.length + const items = Array(n) + for(let i = 0;i < n; i++) items[i] = [startTime[i], endTime[i], profit[i]] + items.sort((a, b) => a[1] - b[1]) + const dpEndTime = [0] + const dpProfit = [0] + for(const [s, e, p] of items) { + const prevIdx = binarySearch(dpEndTime, 0, dpEndTime.length - 1, s) + const curProfit = dpProfit[prevIdx] + p, maxProfit = dpProfit[dpProfit.length - 1] + if(curProfit > maxProfit) { + dpProfit.push(curProfit) + dpEndTime.push(e) + } + } + + return dpProfit[dpProfit.length - 1] +} + +function binarySearch(arr, l, r, x) { + while (l < r) { + const mid = r - ((r - l) >> 1) + if (arr[mid] > x) r = mid - 1 + else l = mid + } + return l +} + + +// another + +/** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ +const jobScheduling = function (startTime, endTime, profit) { + const n = startTime.length + const items = Array.from({ length: startTime.length }, () => Array(3).fill(0)) + for (let i = 0; i < startTime.length; i++) { + items[i] = [startTime[i], endTime[i], profit[i]] + } + items.sort((a1, a2) => a1[1] - a2[1]) + const dpProfit = [0] + for (let i = 0; i < n; i++) { + const [s, e, p] = items[i] + let prevIdx = -1 + for(let j = i - 1; j >= 0; j--) { + if(items[j][1] <= items[i][0]) { + prevIdx = j + break + } + } + const curProfit = (prevIdx === -1 ? 0 : dpProfit[prevIdx]) + p + dpProfit[i] = Math.max(dpProfit[dpProfit.length - 1], curProfit) + } + return dpProfit[dpProfit.length - 1] +} + + +// another + + +/** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ +const jobScheduling = function (startTime, endTime, profit) { + const items = Array.from({ length: startTime.length }, () => Array(3).fill(0)) + for (let i = 0; i < startTime.length; i++) { + items[i] = [startTime[i], endTime[i], profit[i]] + } + items.sort((a1, a2) => a1[1] - a2[1]) + const dpEndTime = [] + const dpProfit = [] + dpEndTime.push(0) + dpProfit.push(0) + for (let item of items) { + const s = item[0], + e = item[1], + p = item[2] + // find previous endTime index + const prevIdx = binarySearch(dpEndTime, 0, dpEndTime.length - 1, s) + const currProfit = dpProfit[prevIdx] + p, + maxProfit = dpProfit[dpProfit.length - 1] + if (currProfit > maxProfit) { + dpProfit.push(currProfit) + dpEndTime.push(e) + } + } + return dpProfit[dpProfit.length - 1] +} + +function binarySearch(arr, l, r, x) { + while (l <= r) { + const mid = l + ((r - l) >> 1) + if (arr[mid] > x) r = mid - 1 + else { + if (mid == arr.length - 1 || arr[mid + 1] > x) return mid + l = mid + 1 + } + } + return -1 +} diff --git a/1239-maximum-length-of-a-concatenated-string-with-unique-characters.js b/1239-maximum-length-of-a-concatenated-string-with-unique-characters.js new file mode 100644 index 00000000..7572f0d6 --- /dev/null +++ b/1239-maximum-length-of-a-concatenated-string-with-unique-characters.js @@ -0,0 +1,41 @@ +/** + * @param {string[]} arr + * @return {number} + */ +const maxLength = function(arr) { + let maxLen = 0; + arr = arr.filter(isUnique); + const mem = {}; + maxLen = dfs(arr, "", 0, maxLen, mem); + + return maxLen; +}; + +function dfs(arr, path, i, maxLen, mem) { + if (mem[path]) return mem[path]; + let pathIsUnique = isUnique(path); + if (pathIsUnique) { + maxLen = Math.max(path.length, maxLen); + } + if (i === arr.length || !pathIsUnique) { + mem[path] = maxLen; + return maxLen; + } + for (let j = i; j < arr.length; j++) { + maxLen = dfs(arr, path + arr[j], j + 1, maxLen, mem); + } + + + mem[path] = maxLen; + return maxLen; +} + +function isUnique(str) { + const map = {} + for (let i = 0; i < str.length; i++) { + if (map[str[i]]) return false; + map[str[i]] = 1; + } + + return true; +} diff --git a/124-binary-tree-maximum-path-sum.js b/124-binary-tree-maximum-path-sum.js index 5f53f2dc..68e174a9 100644 --- a/124-binary-tree-maximum-path-sum.js +++ b/124-binary-tree-maximum-path-sum.js @@ -26,3 +26,35 @@ function traverse(node, obj) { return node.val + Math.max(left, right) } +// another + +/** + * 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 {number} + */ +const maxPathSum = function(root) { + let res = -Infinity + dfs(root) + return res + + function dfs(node) { + if(node == null) return 0 + let left = dfs(node.left), right = dfs(node.right) + res = Math.max( + res, + node.val, + node.val + left, + node.val + right, + node.val + left + right, + ) + return Math.max(node.val, node.val + left, node.val + right) + } +}; diff --git a/1240-tiling-a-rectangle-with-the-fewest-squares.js b/1240-tiling-a-rectangle-with-the-fewest-squares.js new file mode 100644 index 00000000..73602aab --- /dev/null +++ b/1240-tiling-a-rectangle-with-the-fewest-squares.js @@ -0,0 +1,30 @@ +/** + * @param {number} n + * @param {number} m + * @return {number} + */ +const tilingRectangle = function (n, m) { + if ((n === 11 && m === 13) || (n === 13 && m === 11)) { + return 6 + } + + const dp = Array(n + 1) + .fill() + .map((_) => Array(m + 1).fill(0)) + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= m; j++) { + if (i === j) { + dp[i][j] = 1 + continue + } + dp[i][j] = m * n + for (let k = 1; k <= i / 2; k++) { + dp[i][j] = Math.min(dp[i][j], dp[i - k][j] + dp[k][j]) + } + for (let k = 1; k <= j / 2; k++) { + dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[i][j - k]) + } + } + } + return dp[n][m] +} diff --git a/1243-array-transformation.js b/1243-array-transformation.js new file mode 100644 index 00000000..b42a84d6 --- /dev/null +++ b/1243-array-transformation.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} arr + * @return {number[]} + */ + const transformArray = function(arr) { + let cur = arr + while(true) { + const clone = cur.slice() + for(let i = 1; i < clone.length - 1; i++) { + if(cur[i] > cur[i - 1] && cur[i] > cur[i + 1]) clone[i]-- + else if(cur[i] < cur[i - 1] && cur[i] < cur[i + 1]) clone[i]++ + } + if(same(cur, clone)) return clone + cur = clone + } + + return cur + + function same(a1, a2) { + for(let i = 0; i< a1.length; i++) { + if(a1[i] !== a2[i]) return false + } + return true + } +}; diff --git a/1244-design-a-leaderboard.js b/1244-design-a-leaderboard.js new file mode 100644 index 00000000..769076b8 --- /dev/null +++ b/1244-design-a-leaderboard.js @@ -0,0 +1,120 @@ + +const Leaderboard = function() { + this.hash = {} +}; + +/** + * @param {number} playerId + * @param {number} score + * @return {void} + */ +Leaderboard.prototype.addScore = function(playerId, score) { + if(this.hash[playerId] == null) this.hash[playerId] = 0 + this.hash[playerId] += score +}; + +/** + * @param {number} K + * @return {number} + */ +Leaderboard.prototype.top = function(K) { + const pq = new PriorityQueue((a, b) => a < b) + const values = Object.values(this.hash) + // console.log(values) + for(const v of values) { + pq.push(v) + if(pq.size() > K) pq.pop() + } + // console.log(pq.heap) + let sum = 0 + while(!pq.isEmpty()) { + sum += pq.pop() + + } + + return sum +}; + +/** + * @param {number} playerId + * @return {void} + */ +Leaderboard.prototype.reset = function(playerId) { + delete this.hash[playerId] +}; + +/** + * Your Leaderboard object will be instantiated and called as such: + * var obj = new Leaderboard() + * obj.addScore(playerId,score) + * var param_2 = obj.top(K) + * obj.reset(playerId) + */ + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1245-tree-diameter.js b/1245-tree-diameter.js new file mode 100644 index 00000000..d9b83b62 --- /dev/null +++ b/1245-tree-diameter.js @@ -0,0 +1,38 @@ +/** + * @param {number[][]} edges + * @return {number} + */ +const treeDiameter = function (edges) { + const graph = {} + for (const [u, v] of edges) { + if (graph[u] == null) graph[u] = new Set() + if (graph[v] == null) graph[v] = new Set() + graph[u].add(v) + graph[v].add(u) + } + + let res = 0 + + dfs(0, -1) + + return res + + function dfs(node, parent) { + let first = 0, sec = 0 + + for(const nxt of (graph[node] || [])) { + if(nxt === parent) continue + const childNum = dfs(nxt, node) + if(childNum > first) { + sec = first + first = childNum + } else if(childNum > sec){ + sec = childNum + } + } + + const nodeNum = first + sec + 1 + res = Math.max(res, nodeNum - 1) + return first + 1 + } +} diff --git a/1246-palindrome-removal.js b/1246-palindrome-removal.js new file mode 100644 index 00000000..f73084af --- /dev/null +++ b/1246-palindrome-removal.js @@ -0,0 +1,65 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const minimumMoves = function (arr) { + const n = arr.length + const dp = Array.from({ length: n }, () => Array(n).fill(n)) + // handle edge situation: subarray size == 1 + for (let i = 0; i < n; i++) { + dp[i][i] = 1 + } + // handle edge situation: subarray size == 2 + for (let i = 0; i < n - 1; i++) { + dp[i][i + 1] = arr[i] === arr[i + 1] ? 1 : 2 + } + // for subarray size >= 3: + for (let size = 3; size <= n; size++) { + for (let left = 0, right = left + size - 1; right < n; left++, right++) { + // if arr[left] == arr[right], then the two number: arr[left] and arr[right] can be + // removed when the last move of subarray arr[left + 1:right - 1] + if (arr[left] === arr[right]) { + dp[left][right] = dp[left + 1][right - 1] + } + // or, if we cannot remove arr[left] and arr[right] in one move (the last move), + // the subarray arr[left:right] must can be split into two subarrays + // and remove them one by one. + for (let mid = left; mid < right; mid++) { + dp[left][right] = Math.min( + dp[left][right], + dp[left][mid] + dp[mid + 1][right] + ) + } + } + } + return dp[0][n - 1] +} + +// another + +/** + * @param {number[]} arr + * @return {number} + */ + const minimumMoves = function (arr) { + const n = arr.length + + const dp = Array.from({ length: n }, () => Array(n).fill(n)) + + for(let i = 0; i < n; i++) dp[i][i] = 1 + for(let i = 0; i < n - 1; i++) { + dp[i][i + 1] = arr[i] === arr[i + 1] ? 1 : 2 + } + + for(let size = 3; size <= n; size++) { + for(let i = 0; i + size - 1 < n; i++) { + const right = i + size - 1 + if(arr[i] === arr[right]) dp[i][right] = dp[i + 1][right - 1] + for(let j = i; j < right; j++) { + dp[i][right] = Math.min(dp[i][right], dp[i][j] + dp[j + 1][right]) + } + } + } + + return dp[0][n - 1] +} diff --git a/1247-minimum-swaps-to-make-strings-equal.js b/1247-minimum-swaps-to-make-strings-equal.js new file mode 100644 index 00000000..b0619b9d --- /dev/null +++ b/1247-minimum-swaps-to-make-strings-equal.js @@ -0,0 +1,45 @@ +/** + * @param {string} s1 + * @param {string} s2 + * @return {number} + */ +const minimumSwap = function (s1, s2) { + let x1 = 0 // number of 'x' in s1 (skip equal chars at same index) + let y1 = 0 // number of 'y' in s1 (skip equal chars at same index) + let x2 = 0 // number of 'x' in s2 (skip equal chars at same index) + let y2 = 0 // number of 'y' in s2 (skip equal chars at same index) + + for (let i = 0; i < s1.length; i++) { + let c1 = s1.charAt(i) + let c2 = s2.charAt(i) + if (c1 == c2) { + // skip chars that are equal at the same index in s1 and s2 + continue + } + if (c1 == 'x') { + x1++ + } else { + y1++ + } + if (c2 == 'x') { + x2++ + } else { + y2++ + } + } // end for + + // After skip "c1 == c2", check the number of 'x' and 'y' left in s1 and s2. + if ((x1 + x2) % 2 != 0 || (y1 + y2) % 2 != 0) { + return -1 // if number of 'x' or 'y' is odd, we can not make s1 equals to s2 + } + + let swaps = Math.floor(x1 / 2) + Math.floor(y1 / 2) + (x1 % 2) * 2 + // Cases to do 1 swap: + // "xx" => x1 / 2 => how many pairs of 'x' we have ? + // "yy" => y1 / 2 => how many pairs of 'y' we have ? + // + // Cases to do 2 swaps: + // "xy" or "yx" => x1 % 2 + + return swaps +} diff --git a/1249-minimum-remove-to-make-valid-parentheses.js b/1249-minimum-remove-to-make-valid-parentheses.js new file mode 100644 index 00000000..1599e395 --- /dev/null +++ b/1249-minimum-remove-to-make-valid-parentheses.js @@ -0,0 +1,75 @@ +/** + * @param {string} s + * @return {string} + */ + const minRemoveToMakeValid = function(s) { + const stack = [], n = s.length + const arr = s.split('') + let res = '' + for(let i = 0; i < n; i++) { + if(s[i] === '(') stack.push(i + 1) + if(s[i] === ')') { + if(stack.length && stack[stack.length - 1] >= 0) stack.pop() + else stack.push(-(i + 1)) + } + } + while(stack.length) { + arr[Math.abs(stack.pop()) - 1] = '' + } + return arr.join('') +}; + +// another + +/** + * @param {string} s + * @return {string} + */ +const minRemoveToMakeValid = function(s) { + let cnt = 0 + let res = s.split('') + // console.log(res) + for(let i = 0; i < res.length; ) { + const ch = res[i] + if(ch === '(') cnt++ + if(ch === ')') cnt-- + if(cnt < 0) { + // console.log(res, i) + res.splice(i, 1) + cnt++ + } else i++ + } + // console.log(res) + let idx = res.length - 1 + while(cnt > 0) { + if(res[idx] === '(') { + res.splice(idx, 1) + cnt-- + } else idx-- + } + return res.join('') +}; + +// another + +/** + * @param {string} s + * @return {string} + */ +const minRemoveToMakeValid = function(s) { + const stk = [], arr = s.split(''), n = s.length + for(let i = 0; i < n; i++) { + if(s[i] === '(') stk.push(i) + if(s[i] === ')') { + if(stk.length && stk[stk.length - 1] >= 0) stk.pop() + else stk.push(-(i + 1)) + } + } + + while(stk.length) { + const tmp = stk.pop() + if(tmp < 0) arr[-tmp - 1] = '' + else arr[tmp] = '' + } + return arr.join('') +}; diff --git a/1251-average-selling-price.sql b/1251-average-selling-price.sql new file mode 100644 index 00000000..ca95a4c1 --- /dev/null +++ b/1251-average-selling-price.sql @@ -0,0 +1,6 @@ +# Write your MySQL query statement below +SELECT a.product_id,ROUND(SUM(b.units*a.price)/SUM(b.units),2) as average_price +FROM Prices as a +JOIN UnitsSold as b +ON a.product_id=b.product_id AND (b.purchase_date BETWEEN a.start_date AND a.end_date) +GROUP BY product_id; diff --git a/1252-cells-with-odd-values-in-a-matrix.js b/1252-cells-with-odd-values-in-a-matrix.js new file mode 100644 index 00000000..aa00e19c --- /dev/null +++ b/1252-cells-with-odd-values-in-a-matrix.js @@ -0,0 +1,31 @@ +/** + * @param {number} n + * @param {number} m + * @param {number[][]} indices + * @return {number} + */ +const oddCells = function (n, m, indices) { + const oddRows = new BitSet(n), + oddCols = new BitSet(m) + let cntRow = 0, + cntCol = 0 + for (let idx of indices) { + oddRows.flip(idx[0]) + oddCols.flip(idx[1]) + cntRow += oddRows.get(idx[0]) ? 1 : -1 + cntCol += oddCols.get(idx[1]) ? 1 : -1 + } + return (m - cntCol) * cntRow + (n - cntRow) * cntCol +} + +class BitSet { + constructor(n) { + this.arr = Array(n).fill(0) + } + flip(idx) { + this.arr[idx] = this.arr[idx] === 0 ? 1 : 0 + } + get(idx) { + return this.arr[idx] + } +} diff --git a/1254-number-of-closed-islands.js b/1254-number-of-closed-islands.js new file mode 100644 index 00000000..acf9f12e --- /dev/null +++ b/1254-number-of-closed-islands.js @@ -0,0 +1,104 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const closedIsland = function(grid) { + const m = grid.length, n = grid[0].length + const dirs = [[0,1], [0,-1], [1,0], [-1,0]] + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if((i=== 0 || i === m - 1 || j === 0 || j === n - 1) && grid[i][j] === 0){ + fill(i, j) + } + } + } + + + let res = 0 + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] === 0) { + res++ + fill(i, j) + } + } + } + + return res + + + function fill(i, j) { + if(i < 0 || i >= m || j < 0 || j >= n || grid[i][j] !== 0) return + grid[i][j] = 1 + for(const [dx, dy] of dirs) { + const nx = i + dx, ny = j + dy + fill(nx, ny) + } + } +}; + +// another + + +/** + * @param {number[][]} grid + * @return {number} + */ +const closedIsland = function(grid) { + const m = grid.length, n = grid[0].length + const arr = [] + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] === 0) arr.push([i, j]) + } + } + const dirs = [[0,1], [0,-1], [1,0], [-1,0]] + let num = 2 + for(const [i, j] of arr) { + if(grid[i][j] !== 0) continue + else { + bfs(i, j, num) + num++ + } + } + + let res = 0 + const set = new Set() + for(let i = 2; i < num; i++) { + set.add(i) + } + + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] > 1 && invalid(i, j)) { + set.delete(grid[i][j]) + } + } + } + return set.size + + function invalid(i,j) { + if(i === 0 || i === m - 1 || j === 0 || j === n - 1) return true + return false + } + function bfs(i, j, v) { + let q = [[i,j]] + grid[i][j] = v + while(q.length) { + const tmp = [] + const size = q.length + + for(const [x, y] of q) { + for(const [dx, dy] of dirs) { + const nx = x + dx, ny = y + dy + if(nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] === 0) { + grid[nx][ny] = v + tmp.push([nx, ny]) + } + } + } + + q = tmp + } + } +}; diff --git a/1255-maximum-score-words-formed-by-letters.js b/1255-maximum-score-words-formed-by-letters.js new file mode 100644 index 00000000..d489c7b1 --- /dev/null +++ b/1255-maximum-score-words-formed-by-letters.js @@ -0,0 +1,30 @@ +/** + * @param {string[]} words + * @param {character[]} letters + * @param {number[]} score + * @return {number} + */ +const maxScoreWords = function (words, letters, score) { + const points = new Map() + const count = Array(26).fill(0) + for (let w of letters) { + count[w.charCodeAt(0) - 97] = ~~count[w.charCodeAt(0) - 97] + 1 + } + return dfs(count, 0) + function dfs(count, index) { + if (index >= words.length) { + return 0 + } + const x = dfs(count, index + 1) + const copy = [...count] + let point = 0 + let isValid = true + for (let w of words[index]) { + let k = w.charCodeAt(0) - 97 + copy[k]-- + point += score[k] + if (copy[k] < 0) isValid = false + } + return Math.max(x, isValid ? point + dfs(copy, index + 1) : 0) + } +} diff --git a/1257-smallest-common-region.js b/1257-smallest-common-region.js new file mode 100644 index 00000000..304e4175 --- /dev/null +++ b/1257-smallest-common-region.js @@ -0,0 +1,40 @@ +/** + * @param {string[][]} regions + * @param {string} region1 + * @param {string} region2 + * @return {string} + */ +const findSmallestRegion = function (regions, region1, region2) { + const hash = {} + for(const arr of regions) { + const p = arr[0] + const size = arr.length + for(let i = 1; i < size; i++) { + const e = arr[i] + if(hash[e] == null) hash[e] = [] + hash[e].push(p) + } + } + + const path1 = [region1], path2 = [region2] + traverse(region1, path1) + traverse(region2, path2) + + let i = path1.length - 1, j = path2.length - 1 + while(i >= 0 && j >= 0) { + if(path1[i] !== path2[j]) break + else { + i-- + j-- + } + } + + return path1[i + 1] + + function traverse(node, res) { + if(hash[node] == null) return + res.push(hash[node][0]) + traverse(hash[node][0], res) + } + +} diff --git a/126-word-ladder-ii.js b/126-word-ladder-ii.js new file mode 100644 index 00000000..05431413 --- /dev/null +++ b/126-word-ladder-ii.js @@ -0,0 +1,64 @@ +/** + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {string[][]} + */ +const findLadders = function (beginWord, endWord, wordList) { + const res = [] + if (!wordList.includes(endWord)) return res + const set1 = new Set([beginWord]), + set2 = new Set([endWord]), + wordSet = new Set(wordList), + temp = [beginWord] + const map = new Map() + const traverse = (set1, set2, dir) => { + if (set1.size === 0) return false + if (set1.size > set2.size) return traverse(set2, set1, !dir) + for (const val of set1.values()) { + if (wordSet.has(val)) wordSet.delete(val) + } + for (const val of set2.values()) { + if (wordSet.has(val)) wordSet.delete(val) + } + const set = new Set() + let done = false + for (const str of set1.values()) { + for (let i = 0; i < str.length; i++) { + for (let ch = 'a'.charCodeAt(); ch <= 'z'.charCodeAt(); ch++) { + const word = + str.slice(0, i) + String.fromCharCode(ch) + str.slice(i + 1) + const key = dir ? str : word + const val = dir ? word : str + const list = map.get(key) || [] + if (set2.has(word)) { + done = true + list.push(val) + map.set(key, list) + } + if (!done && wordSet.has(word)) { + set.add(word) + list.push(val) + map.set(key, list) + } + } + } + } + return done || traverse(set2, set, !dir) + } + const dfs = (word) => { + if (word === endWord) { + res.push(temp.slice()) + return + } + const nei = map.get(word) || [] + for (const w of nei) { + temp.push(w) + dfs(w) + temp.pop() + } + } + traverse(set1, set2, true) + dfs(beginWord) + return res +} diff --git a/1260-shift-2d-grid.js b/1260-shift-2d-grid.js new file mode 100644 index 00000000..e5ede767 --- /dev/null +++ b/1260-shift-2d-grid.js @@ -0,0 +1,24 @@ +/** + * @param {number[][]} grid + * @param {number} k + * @return {number[][]} + */ +const shiftGrid = function(grid, k) { + for(let i = 0; i < k; i++) once(grid) + return grid +}; + +function once(grid) { + const m = grid.length, n = grid[0].length + let last = grid[m - 1][n - 1] + for(let i = 0; i < m; i++) { + let pre = grid[i][0] + for(let j = 1; j < n; j++) { + let cur = grid[i][j] + grid[i][j] = pre + pre = cur + } + grid[i][0] = last + last = pre + } +} diff --git a/1261-find-elements-in-a-contaminated-binary-tree.js b/1261-find-elements-in-a-contaminated-binary-tree.js new file mode 100644 index 00000000..a6b4d4ad --- /dev/null +++ b/1261-find-elements-in-a-contaminated-binary-tree.js @@ -0,0 +1,49 @@ +/** + * 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 + */ +const FindElements = function(root) { + this.root = root + this.set = new Set() + if(root) this.set.add(0) + + dfs(root, 0, this.set) + + // console.log(this.set) + function dfs(node, cur, set) { + if(node == null) return + + if(node.left) { + const child = cur * 2 + 1 + set.add(child) + dfs(node.left, child, set) + } + if(node.right) { + const child = cur * 2 + 2 + set.add(child) + dfs(node.right, child, set) + } + } +}; + +/** + * @param {number} target + * @return {boolean} + */ +FindElements.prototype.find = function(target) { + return this.set.has(target) +}; + + +/** + * Your FindElements object will be instantiated and called as such: + * var obj = new FindElements(root) + * var param_1 = obj.find(target) + */ diff --git a/1262-greatest-sum-divisible-by-three.js b/1262-greatest-sum-divisible-by-three.js new file mode 100644 index 00000000..fac1d5c9 --- /dev/null +++ b/1262-greatest-sum-divisible-by-three.js @@ -0,0 +1,50 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxSumDivThree = function (nums) { + const n = nums.length + let dp = [0, -Infinity, -Infinity] + for (let i = n - 1; i >= 0; i--) { + const nextDp = [] + for (let j = 0; j < 3; j++) { + const nextRemain = nums[i] % 3 + nextDp[j] = Math.max(nums[i] + dp[(nextRemain + j) % 3], dp[j]) + } + dp = nextDp + } + return dp[0] +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxSumDivThree = function(nums) { + const sum = nums.reduce((ac, el) => ac + el, 0) + if(sum % 3 === 0) return sum + const remainder = sum % 3 + const comp = 3 - remainder + nums.sort((a, b) => a - b) + const re = [], rc = [] + for(let i = 0, len = nums.length; i < len; i++) { + if(nums[i] % 3 === remainder) { + if(re.length < 1) re.push(i) + } + if(nums[i] % 3 === comp) { + if(rc.length < 2) rc.push(i) + } + if(re.length === 1 && rc.length === 2) break + } + if(re.length === 1 && rc.length === 2) { + return Math.max(sum - nums[re[0]], sum - nums[rc[0]] - nums[rc[1]]) + } else if(re.length === 1) { + return sum - nums[re[0]] + } else if(rc.length === 2) { + return sum - nums[rc[0]] - nums[rc[1]] + } else { + return 0 + } +}; diff --git a/1263-minimum-moves-to-move-a-box-to-their-target-location.js b/1263-minimum-moves-to-move-a-box-to-their-target-location.js new file mode 100644 index 00000000..2ec22d2d --- /dev/null +++ b/1263-minimum-moves-to-move-a-box-to-their-target-location.js @@ -0,0 +1,462 @@ +/** + * @param {character[][]} grid + * @return {number} + */ +const minPushBox = function (grid) { + let box, person, target + const m = grid.length, + n = grid[0].length + const dirs = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ] + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + const e = grid[i][j] + if (e === 'B') box = [i, j] + else if (e === 'T') target = [i, j] + else if (e === 'S') person = [i, j] + } + } + + const valid = ([i, j]) => { + return i >= 0 && i < m && j >= 0 && j < n && grid[i][j] !== '#' + } + const key = ([i, j]) => `${i},${j}` + + const chk = (person, newPerson, box) => { + const set = new Set() + set.add(key(box)) + let q = [person] + while (q.length) { + const tmp = [] + const size = q.length + for (let i = 0; i < size; i++) { + const [x, y] = q[i] + if (key([x, y]) === key(newPerson)) return true + for (const [dx, dy] of dirs) { + const [nx, ny] = [x + dx, y + dy] + if (valid([nx, ny]) && !set.has(key([nx, ny]))) { + set.add(key([nx, ny])) + tmp.push([nx, ny]) + } + } + } + q = tmp + } + return false + } + + + let q = [[0, box, person]] + const dkey = (a, b) => `${a[0]},${a[1]}_${b[0]},${b[1]}` + const set = new Set() + set.add(dkey(box, person)) + while (q.length) { + const size = q.length + const tmp = [] + for (let i = 0; i < size; i++) { + const [v, b, p] = q[i] + if (key(b) === key(target)) return v + const bArr = [ + [b[0], b[1] + 1], + [b[0], b[1] - 1], + [b[0] + 1, b[1]], + [b[0] - 1, b[1]], + ] + const pArr = [ + [b[0], b[1] - 1], + [b[0], b[1] + 1], + [b[0] - 1, b[1]], + [b[0] + 1, b[1]], + ] + + for (let j = 0; j < 4; j++) { + const nb = bArr[j], + np = pArr[j] + const nk = dkey(nb, b) + + if (set.has(nk)) continue + if (valid(nb) && valid(np) && chk(p, np, b)) { + tmp.push([v + 1, nb, b]) + set.add(nk) + } + } + } + q = tmp + } + + return -1 +} + +// another + + +/** + * @param {character[][]} grid + * @return {number} + */ +const minPushBox = function (grid) { + if ( + typeof grid === 'undefined' || + grid === null || + grid.length === 0 || + grid[0].length === 0 + ) { + return -1 + } + + let TARGET = null + let startBlk = null + let startPer = null + const DIR = [ + [0, 1], + [1, 0], + [0, -1], + [-1, 0], + ] + + for (let i = 0; i < grid.length; i++) { + for (let j = 0; j < grid[0].length; j++) { + if (grid[i][j] === 'S') { + startPer = [i, j] + grid[i][j] = '.' + } + if (grid[i][j] === 'T') { + TARGET = [i, j] + } + if (grid[i][j] === 'B') { + startBlk = [i, j] + grid[i][j] = '.' + } + } + } + + let queue = new PriorityQueue((a, b) => a.weight < b.weight) + let states = new Map() + queue.push({ + weight: manDist(startBlk), + block: startBlk, + character: startPer, + move: 0, + }) + while (!queue.isEmpty()) { + let { weight, block, character, move } = queue.pop() + if (TARGET[0] === block[0] && TARGET[1] === block[1]) { + return move + } + let key = block[0] * grid[0].length + block[1] + let val = character[0] * grid[0].length + character[1] + if (!states.has(key)) { + states.set(key, new Set()) + } + states.get(key).add(val) + DIR.forEach((d) => { + let i = d[0] + character[0] + let j = d[1] + character[1] + let curV = i * grid[0].length + j + if (validMove(i, j, block[0], block[1]) && !states.get(key).has(curV)) { + queue.push({ + weight: manDist(block) + move, + block: block, + character: [i, j], + move: move, + }) + } + }) + let pushDir = tryPush(character, block) + if (pushDir !== null) { + let newBlk = [block[0] + pushDir[0], block[1] + pushDir[1]] + let newCha = [character[0] + pushDir[0], character[1] + pushDir[1]] + let nBK = newBlk[0] * grid[0].length + newBlk[1] + let nVal = newCha[0] * grid[0].length + newCha[1] + if (!states.has(nBK) || !states.get(nBK).has(nVal)) { + queue.push({ + weight: manDist(newBlk) + (move + 1), + block: newBlk, + character: newCha, + move: move + 1, + }) + } + } + } + + return -1 + + function manDist(block) { + let [x, y] = TARGET + let [i, j] = block + return Math.abs(x - i) + Math.abs(y - j) + } + function validMove(i, j, x = null, y = null) { + if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length) { + return false + } + if ( + (x !== null && i === x && y !== null && j === y) || + grid[i][j] === '#' + ) { + return false + } + return true + } + function tryPush(c, b) { + let [i, j] = c + let [x, y] = b + for (let u = 0; u < DIR.length; u++) { + let [v, w] = DIR[u] + if ( + ((Math.abs(x - i) === 1 && y === j) || + (Math.abs(y - j) === 1 && x === i)) && + validMove(i + v, j + w) && + validMove(x + v, y + w) && + i + v === x && + j + w === y + ) { + return [v, w] + } + } + return null + } +} +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {character[][]} grid + * @return {number} + */ +const minPushBox = function (grid) { + const dirs = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ] + const dis = new Map() + const rows = grid.length + const cols = grid[0].length + let sk, box, target + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (grid[i][j] === 'B') box = [i, j] + else if (grid[i][j] === 'S') sk = [i, j] + else if (grid[i][j] === 'T') target = [i, j] + } + } + const q = [] + const start = encode(box[0], box[1], sk[0], sk[1]) + dis.set(start, 0) + q.push(start) + let res = Number.MAX_VALUE + while (q.length) { + const u = q.pop() + const du = decode(u) + if (dis.get(u) >= res) continue + if (du[0] === target[0] && du[1] === target[1]) { + res = Math.min(res, dis.get(u)) + continue + } + const b = [du[0], du[1]] + const s = [du[2], du[3]] + for (let dir of dirs) { + const nsx = s[0] + dir[0] + const nsy = s[1] + dir[1] + if ( + nsx < 0 || + nsx >= rows || + nsy < 0 || + nsy >= cols || + grid[nsx][nsy] === '#' + ) + continue + if (nsx === b[0] && nsy === b[1]) { + const nbx = b[0] + dir[0] + const nby = b[1] + dir[1] + if ( + nbx < 0 || + nbx >= rows || + nby < 0 || + nby >= cols || + grid[nbx][nby] === '#' + ) + continue + const v = encode(nbx, nby, nsx, nsy) + if (dis.has(v) && dis.get(v) <= dis.get(u) + 1) continue + dis.set(v, dis.get(u) + 1) + q.push(v) + } else { + const v = encode(b[0], b[1], nsx, nsy) + if (dis.has(v) && dis.get(v) <= dis.get(u)) continue + dis.set(v, dis.get(u)) + q.push(v) + } + } + } + return res === Number.MAX_VALUE ? -1 : res + + function encode(bx, by, sx, sy) { + return (bx << 24) | (by << 16) | (sx << 8) | sy + } + function decode(num) { + const res = [] + res[0] = (num >>> 24) & 0xff + res[1] = (num >>> 16) & 0xff + res[2] = (num >>> 8) & 0xff + res[3] = num & 0xff + return res + } +} + +// another + +/** + * @param {character[][]} grid + * @return {number} + */ + const minPushBox = function (grid) { + const m = grid.length, + n = grid[0].length + let target, person, box + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] === 'T') target = [i, j] + else if (grid[i][j] === 'B') box = [i, j] + else if (grid[i][j] === 'S') person = [i, j] + } + } + + const valid = ([x, y]) => { + return x >= 0 && x < m && y >= 0 && y < n && grid[x][y] !== '#' + } + + const check = (cur, dest, box) => { + const q = [cur] + const visited = new Set([`${box[0]},${box[1]}`]) + const dirs = [ + [-1, 0], + [1, 0], + [0, 1], + [0, -1], + ] + + while (q.length) { + const pos = q.shift() + if (pos.join(',') === dest.join(',')) return true + const newPos = [] + for (const [dx, dy] of dirs) newPos.push([pos[0] + dx, pos[1] + dy]) + for (const [nx, ny] of newPos) { + const k = `${nx},${ny}` + if (valid([nx, ny]) && !visited.has(k)) { + visited.add(k) + q.push([nx, ny]) + } + } + } + + return false + } + + const q = [[0, box, person]] + const vis = new Set([`${box.join(',')},${person.join(',')}`]) + while (q.length) { + const [dist, box, person] = q.shift() + if (box.join(',') === target.join(',')) return dist + + const bCoord = [ + [box[0] + 1, box[1]], + [box[0] - 1, box[1]], + [box[0], box[1] + 1], + [box[0], box[1] - 1], + ] + const pCoord = [ + [box[0] - 1, box[1]], + [box[0] + 1, box[1]], + [box[0], box[1] - 1], + [box[0], box[1] + 1], + ] + + for (let i = 0; i < 4; i++) { + const [newBox, newPerson] = [bCoord[i], pCoord[i]] + const key = `${newBox.join(',')},${box.join(',')}` + if (valid(newBox) && !vis.has(key)) { + if (valid(newPerson) && check(person, newPerson, box)) { + vis.add(key) + q.push([dist + 1, newBox, box]) + } + } + } + } + + return -1 +} + diff --git a/1265-print-immutable-linked-list-in-reverse.js b/1265-print-immutable-linked-list-in-reverse.js new file mode 100644 index 00000000..66a405a0 --- /dev/null +++ b/1265-print-immutable-linked-list-in-reverse.js @@ -0,0 +1,31 @@ +/** + * // This is the ImmutableListNode's API interface. + * // You should not implement it, or speculate about its implementation. + * function ImmutableListNode() { + * @ return {void} + * this.printValue = function() { // print the value of this node. + * ... + * }; + * + * @return {ImmutableListNode} + * this.getNext = function() { // return the next node. + * ... + * }; + * }; + */ + +/** + * @param {ImmutableListNode} head + * @return {void} + */ +var printLinkedListInReverse = function(head) { + dfs(head) + function dfs(node) { + if(node.getNext() == null) { + node.printValue() + return + } + dfs(node.getNext()) + node.printValue() + } +}; diff --git a/1266-minimum-time-visiting-all-points.js b/1266-minimum-time-visiting-all-points.js new file mode 100644 index 00000000..3cd447b9 --- /dev/null +++ b/1266-minimum-time-visiting-all-points.js @@ -0,0 +1,19 @@ +/** + * @param {number[][]} points + * @return {number} + */ +const minTimeToVisitAllPoints = function(points) { + let res = 0 + for(let i = 1; i < points.length; i++) { + res += calc(points[i], points[i - 1]) + } + return res + + function calc(p1, p2) { + const [x1, y1] = p1, [x2, y2] = p2 + const { abs, min } = Math + const deltaX = abs(x1 - x2), deltaY = abs(y1 - y2) + + return min(deltaX, deltaY) + abs(deltaX - deltaY) + } +}; diff --git a/1268-search-suggestions-system.js b/1268-search-suggestions-system.js new file mode 100644 index 00000000..2e8ea666 --- /dev/null +++ b/1268-search-suggestions-system.js @@ -0,0 +1,106 @@ +/** + * @param {string[]} products + * @param {string} searchWord + * @return {string[][]} + */ +const suggestedProducts = function(products, searchWord) { + products.sort() + let res = [], left = 0, right = products.length - 1 + for (let i = 0; i < searchWord.length; i++) { + let c = searchWord.charAt(i), tmp = [] + while (products[left]?.charAt(i) < c) left++ + while (products[right]?.charAt(i) > c) right-- + for (let j = 0; j < 3 && left + j <= right; j++) tmp.push(products[left+j]) + res.push(tmp) + } + return res +}; + +// another + +/** + * @param {string[]} products + * @param {string} searchWord + * @return {string[][]} + */ +const suggestedProducts = function(products, searchWord) { + const res = [] + for(let i = 0, n = searchWord.length; i < n; i++) { + const tmp = [], pre = searchWord.slice(0, i + 1) + for(const e of products) { + if(e.startsWith(pre)) { + tmp.push(e) + tmp.sort((a, b) => a.localeCompare(b)) + if(tmp.length > 3) tmp.pop() + } + } + res.push(tmp) + } + return res +}; + +// another + +/** + * @param {string[]} products + * @param {string} searchWord + * @return {string[][]} + */ + const suggestedProducts = function (products, searchWord) { + products.sort() + const root = new Node() + for (const str of products) { + addProduct(str) + } + + const res = [] + + let cur = root + for (const ch of searchWord) { + const tmp = [] + if (cur == null) { + res.push(tmp) + continue + } + const map = cur.children.get(ch) + if (map != null) { + addThree(map.words.values(), tmp) + } + + res.push(tmp) + cur = map + } + + return res + + function addThree(it, arr) { + + for(let i = 0; i < 3; i++) { + const res = it.next() + if(res.value) arr.push(res.value) + } + } + + function addProduct(str) { + let cur = root + for (const ch of str) { + let next = cur.children.get(ch) + if (next == null) { + next = new Node() + cur.children.set(ch, next) + } + next.words.add(str) + cur = next + } + cur.isWord = true + } +} + +class Node { + constructor() { + this.children = new Map() + this.words = new Set() + this.isWord = false + } +} + diff --git a/1269-number-of-ways-to-stay-in-the-same-place-after-some-steps.js b/1269-number-of-ways-to-stay-in-the-same-place-after-some-steps.js new file mode 100644 index 00000000..d1e6c92a --- /dev/null +++ b/1269-number-of-ways-to-stay-in-the-same-place-after-some-steps.js @@ -0,0 +1,22 @@ +/** + * @param {number} steps + * @param {number} arrLen + * @return {number} + */ +const numWays = function (steps, arrLen) { + const MOD = 10 ** 9 + 7 + const memo = Array.from({ length: (steps >> 1) + 1 }, () => + Array(steps + 1).fill(-1) + ) + return dp(0, steps) + function dp(i, steps) { + if (steps === 0 && i === 0) return 1 + if (i < 0 || i >= arrLen || steps === 0 || i > steps) return 0 + if (memo[i][steps] !== -1) return memo[i][steps] + return (memo[i][steps] = + ((dp(i + 1, steps - 1) % MOD) + + (dp(i - 1, steps - 1) % MOD) + + (dp(i, steps - 1) % MOD)) % + MOD) + } +} diff --git a/127-word-ladder.js b/127-word-ladder.js new file mode 100644 index 00000000..ebfec5da --- /dev/null +++ b/127-word-ladder.js @@ -0,0 +1,32 @@ +/** + * @param {string} beginWord + * @param {string} endWord + * @param {string[]} wordList + * @return {number} + */ +const ladderLength = function(beginWord, endWord, wordList) { + const list = new Set(wordList) + if (!list.has(endWord)) return 0 + let one = new Set([beginWord]) + let two = new Set([endWord]) + let step = 1 + while (one.size && two.size) { + let temp = new Set() + if (two.size < one.size) [one, two] = [two, one] + for (const word of one) { + for (let i = 0; i < word.length; i++) { + for (let j = 0; j < 26; j++) { + const candidate = + word.slice(0, i) + String.fromCharCode(97 + j) + word.slice(i + 1) + if (two.has(candidate)) return step + 1 + if (!list.has(candidate)) continue + temp.add(candidate) + list.delete(candidate) + } + } + } + ;[one, temp] = [temp, one] + step++ + } + return 0 +} diff --git a/1271-hexspeak.js b/1271-hexspeak.js new file mode 100644 index 00000000..446c5713 --- /dev/null +++ b/1271-hexspeak.js @@ -0,0 +1,15 @@ +/** + * @param {string} num + * @return {string} + */ +var toHexspeak = function(num) { + const hex = ((+num)).toString(16).toUpperCase() + let res = '' + for(let ch of hex) { + if(ch > '1' && ch <= '9') return 'ERROR' + else if(ch === '0') res += 'O' + else if(ch === '1') res += 'I' + else res += ch + } + return res +}; diff --git a/1272-remove-interval.js b/1272-remove-interval.js new file mode 100644 index 00000000..16709b31 --- /dev/null +++ b/1272-remove-interval.js @@ -0,0 +1,26 @@ +/** + * @param {number[][]} intervals + * @param {number[]} toBeRemoved + * @return {number[][]} + */ +const removeInterval = function(intervals, toBeRemoved) { + const n = intervals.length + if (n < 1) return [] + const res = [] + const [x, y] = toBeRemoved + for (const [a, b] of intervals) { + const lo = Math.max(a, x) + const hi = Math.min(b, y) + if (lo < hi) { + if (a < lo) { + res.push([a, lo]) + } + if (hi < b) { + res.push([hi, b]) + } + } else { + res.push([a, b]) + } + } + return res +} diff --git a/1273-delete-tree-nodes.js b/1273-delete-tree-nodes.js new file mode 100644 index 00000000..7ecb9bb1 --- /dev/null +++ b/1273-delete-tree-nodes.js @@ -0,0 +1,57 @@ +/** + * @param {number} nodes + * @param {number[]} parent + * @param {number[]} value + * @return {number} + */ +const deleteTreeNodes = function (nodes, parent, value) { + const n = nodes + const hash = {} + hash[0] = new Node(value[0]) + for (let i = 1; i < n; i++) { + hash[i] = new Node(value[i]) + } + + for (let i = 1; i < n; i++) { + const p = parent[i] + hash[p].children[i] = hash[i] + } + + const r = hash[0] + dfs(r) + // console.log(n) + return cnt(r) + + function dfs(node) { + if (node == null) return 0 + let res = node.sum + + const keys = Object.keys(node.children) + for (const k of keys) { + res += dfs(hash[k]) + } + + node.sum = res + return res + } + + function cnt(node) { + if (node == null) return 0 + if (node.sum === 0) return 0 + const keys = Object.keys(node.children) + let res = 1 + for (const k of keys) { + res += cnt(hash[k]) + } + + return res + } +} + +class Node { + constructor(v) { + this.val = v + this.sum = v + this.children = {} + } +} diff --git a/1274-number-of-ships-in-a-rectangle.js b/1274-number-of-ships-in-a-rectangle.js new file mode 100644 index 00000000..f12181f3 --- /dev/null +++ b/1274-number-of-ships-in-a-rectangle.js @@ -0,0 +1,46 @@ +/** + * // This is Sea's API interface. + * // You should not implement it, or speculate about its implementation + * function Sea() { + * @param {integer[]} topRight + * @param {integer[]} bottomLeft + * @return {boolean} + * this.hasShips = function(topRight, bottomLeft) { + * ... + * }; + * }; + */ + +/** + * @param {Sea} sea + * @param {integer[]} topRight + * @param {integer[]} bottomLeft + * @return {integer} + */ +const countShips = function (sea, topRight, bottomLeft) { + let numShips = 0 + const stack = [[topRight, bottomLeft]] + while (stack.length > 0) { + const [tR, bL] = stack.pop() + if (!sea.hasShips(tR, bL)) continue + const [right, top] = tR + const [left, bottom] = bL + if (right === left && bottom === top) { + numShips++ + continue + } + const xCoord = Math.floor((right + left) / 2) + const yCoord = Math.floor((top + bottom) / 2) + stack.push([tR, [xCoord + 1, yCoord + 1]]) // top right + stack.push([ + [xCoord, top], + [left, yCoord + 1], + ]) // top left + stack.push([[xCoord, yCoord], bL]) // bottom left + stack.push([ + [right, yCoord], + [xCoord + 1, bottom], + ]) // bottom right + } + return numShips +} diff --git a/1275-find-winner-on-a-tic-tac-toe-game.js b/1275-find-winner-on-a-tic-tac-toe-game.js new file mode 100644 index 00000000..d6029d14 --- /dev/null +++ b/1275-find-winner-on-a-tic-tac-toe-game.js @@ -0,0 +1,70 @@ +/** + * @param {number[][]} moves + * @return {string} + */ +const tictactoe = function(moves) { + const grid = Array.from({ length: 3 }, () => Array(3).fill('')) + for(let i = 0, n = moves.length; i < n; i++) { + const ch = i % 2 === 0 ? 'X' : 'O' + const [r, c] = moves[i] + grid[r][c] = ch + const res = chk(ch, grid) + if(res) return ch === 'X' ? 'A' : 'B' + } + + return moves.length < 9 ? 'Pending' : 'Draw' +}; + +function chk(ch, grid) { + for(let i = 0; i < 3; i++) { + if( + grid[i][0] === ch && + grid[i][1] === ch && + grid[i][2] === ch + ) return true + } + + for(let i = 0; i < 3; i++) { + if( + grid[0][i] === ch && + grid[1][i] === ch && + grid[2][i] === ch + ) return true + } + + + if( + grid[0][0] === ch && + grid[1][1] === ch && + grid[2][2] === ch + ) return true + + if( + grid[0][2] === ch && + grid[1][1] === ch && + grid[2][0] === ch + ) return true + + return false +} + +// another + +/** + * @param {number[][]} moves + * @return {string} + */ +const tictactoe = function(moves) { + const aRow = Array(3).fill(0), aCol = Array(3).fill(0), bRow= Array(3).fill(0), bCol =Array(3).fill(0) + let ad = 0, ads = 0, bd = 0, bds = 0 + for(let i = 0; i < moves.length; i++) { + const [r, c] = moves[i] + if(i % 2===0) { + if(++aRow[r] === 3 || ++aCol[c] === 3 || r === c && ++ad === 3 || r + c === 2&& ++ads === 3 ) return 'A' + }else { + if(++bRow[r] === 3 || ++bCol[c] === 3 || r === c && ++bd === 3 || r + c === 2&& ++bds === 3 ) return 'B' + } + } + + return moves.length >= 9 ? 'Draw' : 'Pending' +}; diff --git a/1277-count-square-submatrices-with-all-ones.js b/1277-count-square-submatrices-with-all-ones.js new file mode 100644 index 00000000..61494fcb --- /dev/null +++ b/1277-count-square-submatrices-with-all-ones.js @@ -0,0 +1,41 @@ +/** + * @param {number[][]} matrix + * @return {number} + */ +const countSquares = function (matrix) { + const [m, n] = [matrix.length, matrix[0].length] + let res = 0 + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(matrix[i][j] && i > 0 && j > 0) { + matrix[i][j] = 1 + Math.min( + matrix[i - 1][j], + matrix[i][j - 1], + matrix[i - 1][j - 1], + ) + } + res += matrix[i][j] + } + } + return res +} + +// another + +/** + * @param {number[][]} matrix + * @return {number} + */ +const countSquares = function (A) { + const [M, N] = [A.length, A[0].length] + let ans = 0 + for (let i = 0; i < M; ++i) { + for (let j = 0; j < N; ++j) { + if (A[i][j] && i > 0 && j > 0) { + A[i][j] = 1 + Math.min(A[i - 1][j], A[i][j - 1], A[i - 1][j - 1]) + } + ans += A[i][j] + } + } + return ans +} diff --git a/1278-palindrome-partitioning-iii.js b/1278-palindrome-partitioning-iii.js new file mode 100644 index 00000000..c00bd65b --- /dev/null +++ b/1278-palindrome-partitioning-iii.js @@ -0,0 +1,30 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const palindromePartition = function(s, k) { + const n = s.length + const memo = new Map() + return dfs(0, k) + function cost(s, i, j) { + let r = 0 + while(i < j) { + if(s[i] !== s[j]) r++ + i++ + j-- + } + return r + } + function dfs(i, k) { + if(memo.has(`${i}-${k}`)) return memo.get(`${i}-${k}`) + if(n - i === k) return 0 + if(k === 1) return cost(s, i, n - 1) + let res = Infinity + for(let j = i + 1; j < n - k + 2; j++) { + res = Math.min(res, dfs(j, k - 1) + cost(s, i, j - 1)) + } + memo.set(`${i}-${k}`, res) + return res + } +}; diff --git a/1281-subtract-the-product-and-sum-of-digits-of-an-integer.js b/1281-subtract-the-product-and-sum-of-digits-of-an-integer.js new file mode 100644 index 00000000..81d0a338 --- /dev/null +++ b/1281-subtract-the-product-and-sum-of-digits-of-an-integer.js @@ -0,0 +1,14 @@ +/** + * @param {number} n + * @return {number} + */ +const subtractProductAndSum = function(n) { + if(n === 0) return 0 + let sum = 0, product = 1 + n = '' + n + for(let ch of n) { + sum += +(ch) + product *= +(ch) + } + return product - sum +}; diff --git a/1282-group-the-people-given-the-group-size-they-belong-to.js b/1282-group-the-people-given-the-group-size-they-belong-to.js new file mode 100644 index 00000000..0081f3fb --- /dev/null +++ b/1282-group-the-people-given-the-group-size-they-belong-to.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} groupSizes + * @return {number[][]} + */ +const groupThePeople = function(groupSizes) { + const hash = {} + const n = groupSizes.length + + for(let i = 0; i < n; i++) { + const size = groupSizes[i] + if(hash[size] == null) hash[size] = [] + hash[size].push(i) + } + + const keys = Object.keys(hash) + // console.log(hash) + const res = [] + for(let size of keys) { + size = +size + const arr = hash[size] + for(let i = 0; i < arr.length; i += size) { + res.push(arr.slice(i, i + size)) + } + } + + return res +}; diff --git a/1283-find-the-smallest-divisor-given-a-threshold.js b/1283-find-the-smallest-divisor-given-a-threshold.js new file mode 100644 index 00000000..09a7a187 --- /dev/null +++ b/1283-find-the-smallest-divisor-given-a-threshold.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @param {number} threshold + * @return {number} + */ +const smallestDivisor = function(nums, threshold) { + let l = 1, r = 1e6 + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if(valid(mid)) r = mid + else l = mid + 1 + } + return l + + function valid(mid) { + let res = 0 + for(let e of nums) res += Math.ceil(e / mid) + return res <= threshold + } +}; diff --git a/1284-minimum-number-of-flips-to-convert-binary-matrix-to-zero-matrix.js b/1284-minimum-number-of-flips-to-convert-binary-matrix-to-zero-matrix.js new file mode 100644 index 00000000..a79ab5e6 --- /dev/null +++ b/1284-minimum-number-of-flips-to-convert-binary-matrix-to-zero-matrix.js @@ -0,0 +1,103 @@ +/** + * @param {number[][]} mat + * @return {number} + */ +const minFlips = function (mat) { + let start = 0 + const m = mat.length, n = mat[0].length + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + start |= mat[i][j] << (i * n + j) + } + } + let q = [start] + const seen = new Set(), dirs = [[-1, 0], [1, 0], [0, -1], [0, 1], [0, 0]] + + for(let i = 0; q.length; i++) { + const tmp = [] + for (let size = q.length; size > 0; size--) { + const cur = q.pop() + if(cur === 0) return i + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + let next = cur + for(const [dx, dy] of dirs) { + const r = i + dx, c = j + dy + if(r >= 0 && r < m && c >= 0 && c < n) { + next ^= (1 << (r * n + c)) + } + } + if (!seen.has(next)) { + seen.add(next) + tmp.push(next) + } + } + } + } + q = tmp + } + + return -1 +} + +// another + +/** + * @param {number[][]} mat + * @return {number} + */ +const minFlips = function (mat) { + const X = mat.length + const Y = mat[0].length + const binary = { + 0: 1, + 1: 2, + 2: 4, + 3: 8, + 4: 16, + 5: 32, + 6: 64, + 7: 128, + 8: 256, + } + const mask = [] + let state = 0 + for (let i = 0; i < X; ++i) { + for (let j = 0; j < Y; ++j) { + let bit = 0 + state += mat[i][j] * binary[Y * i + j] + bit += binary[Y * i + j] + if (i > 0) { + bit += binary[Y * (i - 1) + j] + } + if (i < X - 1) { + bit += binary[Y * (i + 1) + j] + } + if (j > 0) { + bit += binary[Y * i + (j - 1)] + } + if (j < Y - 1) { + bit += binary[Y * i + (j + 1)] + } + mask.push(bit) + } + } + if (state === 0) return 0 + const set = new Set() + const q = [{ state: state, moves: 0 }] + while (q.length !== 0) { + const cur = q.shift() + if (cur.state === 0) { + return cur.moves + } + for (let i = 0; i < X * Y; ++i) { + let newState = cur.state + newState ^= mask[i] + if (!set.has(newState)) { + set.add(newState) + q.push({ state: newState, moves: cur.moves + 1 }) + } + } + } + return -1 +} diff --git a/1286-iterator-for-combination.js b/1286-iterator-for-combination.js new file mode 100644 index 00000000..314526bf --- /dev/null +++ b/1286-iterator-for-combination.js @@ -0,0 +1,148 @@ +/** + * @param {string} characters + * @param {number} combinationLength + */ +const CombinationIterator = function (characters, combinationLength) { + this.arr = build(combinationLength, characters.split('').sort().join('')) + this.pos = 0 +} + +/** + * @return {string} + */ +CombinationIterator.prototype.next = function () { + if (this.pos < this.arr.length) { + return this.arr[this.pos++] + } +} + +/** + * @return {boolean} + */ +CombinationIterator.prototype.hasNext = function () { + return this.pos < this.arr.length +} + +/** + * Your CombinationIterator object will be instantiated and called as such: + * var obj = new CombinationIterator(characters, combinationLength) + * var param_1 = obj.next() + * var param_2 = obj.hasNext() + */ +function build(max, str, out = [], curr = '') { + if (curr.length === max) { + out.push(curr) + return + } else { + for (let i = 0; i < str.length; i++) { + build(max, str.slice(i + 1), out, curr + str[i]) + } + } + + return out +} + +// another + +/** + * @param {string} characters + * @param {number} combinationLength + */ +const CombinationIterator = function(characters, combinationLength) { + const res = [], len = combinationLength, str = characters, n = str.length + helper([], 0) + this.arr = res + this.idx = 0 + + function helper(cur, idx) { + if(cur.length === len) { + res.push(cur.slice().join('')) + return + } + if(idx >= n) return + + cur.push(str[idx]) + helper(cur, idx + 1) + cur.pop() + + helper(cur, idx + 1) + } +}; + +/** + * @return {string} + */ +CombinationIterator.prototype.next = function() { + if(this.hasNext()) { + return this.arr[this.idx++] + } +}; + +/** + * @return {boolean} + */ +CombinationIterator.prototype.hasNext = function() { + return this.arr[this.idx] != null +}; + +/** + * Your CombinationIterator object will be instantiated and called as such: + * var obj = new CombinationIterator(characters, combinationLength) + * var param_1 = obj.next() + * var param_2 = obj.hasNext() + */ + +// another + +/** + * @param {string} characters + * @param {number} combinationLength + */ +const CombinationIterator = function(characters, combinationLength) { + const res = [], len = combinationLength, str = characters, n = str.length + helper() + + // console.log(res) + this.arr = res + this.idx = 0 + + function helper() { + const limit = 1 << n + for(let i = limit - 1; i > 0; i--) { + let tmp = i, ts = '', idx = n - 1 + while(tmp) { + if(tmp & 1) { + ts = str[idx] + ts + } + idx-- + tmp = (tmp >> 1) + } + if(ts.length === len) res.push(ts) + } + } +}; + +/** + * @return {string} + */ +CombinationIterator.prototype.next = function() { + if(this.hasNext()) { + return this.arr[this.idx++] + } +}; + +/** + * @return {boolean} + */ +CombinationIterator.prototype.hasNext = function() { + return this.arr[this.idx] != null +}; + +/** + * Your CombinationIterator object will be instantiated and called as such: + * var obj = new CombinationIterator(characters, combinationLength) + * var param_1 = obj.next() + * var param_2 = obj.hasNext() + */ + + diff --git a/1287-element-appearing-more-than-25-in-sorted-array.js b/1287-element-appearing-more-than-25-in-sorted-array.js new file mode 100644 index 00000000..19e42d38 --- /dev/null +++ b/1287-element-appearing-more-than-25-in-sorted-array.js @@ -0,0 +1,50 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const findSpecialInteger = function (arr) { + const n = arr.length, + { floor } = Math, + { getWordIndexRange } = Search() + const ticks = [n / 4, n / 2, (n * 3) / 4].map((e) => floor(e)) + for (const i of ticks) { + const [s, e] = getWordIndexRange(arr, arr[i]) + if (e - s > n / 4) return arr[i] + } + return 0 +} + +function Search() { + return { getWordIndexRange } + + /** + * Searches for the first true value in the predicate. + * Returns hi if not found. + * [lo, hi) + */ + function binarySearch(lo, hi, predicate) { + while (lo != hi) { + let mid = ((lo + hi) / 2) | 0 + if (predicate(mid)) { + hi = mid + } else { + lo = mid + 1 + } + } + return lo + } + + function getWordIndexRange(keys, word) { + let lo = 0, + hi = keys.length + function greaterOrEqual(index) { + return keys[index] >= word + } + function less(index) { + return keys[index] > word + } + let lower_bound = binarySearch(0, keys.length, greaterOrEqual) + let upper_bound = binarySearch(lower_bound, keys.length, less) + return [lower_bound, upper_bound] + } +} diff --git a/1288-remove-covered-intervals.js b/1288-remove-covered-intervals.js new file mode 100644 index 00000000..db0ac692 --- /dev/null +++ b/1288-remove-covered-intervals.js @@ -0,0 +1,14 @@ +/** + * @param {number[][]} intervals + * @return {number} + */ +const removeCoveredIntervals = function(intervals) { + intervals.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]) + const n = intervals.length + let res = n, max = intervals[0][1] + for(let i = 1; i < n; i++) { + if(intervals[i][1] <= max) res-- + else max = intervals[i][1] + } + return res +}; diff --git a/1289-minimum-falling-path-sum-ii.js b/1289-minimum-falling-path-sum-ii.js new file mode 100644 index 00000000..2a5f07a7 --- /dev/null +++ b/1289-minimum-falling-path-sum-ii.js @@ -0,0 +1,23 @@ +/** + * @param {number[][]} arr + * @return {number} + */ +const minFallingPathSum = function (arr) { + const n = arr.length + for (let i = 1; i < n; i++) { + const [m1, m2] = min2(arr[i - 1]) + for (j = 0; j < n; j++) { + arr[i][j] += arr[i - 1][j] !== m1 ? m1 : m2 + } + } + return Math.min(...arr[n - 1]) +} + +function min2(arr) { + let m1 = Infinity, m2 = Infinity + arr.forEach(e => { + if(e < m1) m2 = m1, m1 = e + else if(e < m2) m2 = e + }) + return [m1, m2] +} diff --git a/1290-convert-binary-number-in-a-linked-list-to-integer.js b/1290-convert-binary-number-in-a-linked-list-to-integer.js new file mode 100644 index 00000000..f057f346 --- /dev/null +++ b/1290-convert-binary-number-in-a-linked-list-to-integer.js @@ -0,0 +1,20 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {number} + */ +const getDecimalValue = function(head) { + let res = 0 + + while(head) { + res = res * 2 + head.val + head = head.next + } + return res +}; diff --git a/1291-sequential-digits.js b/1291-sequential-digits.js new file mode 100644 index 00000000..3cd7049b --- /dev/null +++ b/1291-sequential-digits.js @@ -0,0 +1,71 @@ +/** + * @param {number} low + * @param {number} high + * @return {number[]} + */ +const sequentialDigits = function(low, high) { + const res = [] + + let q = [] + for(let i = 1; i <= 9; i++) q.push(i) + + while(q.length) { + const tmp = [] + const size = q.length + for(let i = 0; i < size; i++) { + const cur = q[i] + if(cur >= low && cur <= high) { + res.push(cur) + } + if(cur > high) break + const last = cur % 10 + if(last === 9) continue + tmp.push(cur * 10 + last + 1) + } + + q = tmp + } + + return res +}; + +// another + +/** + * @param {number} low + * @param {number} high + * @return {number[]} + */ +const sequentialDigits = function(low, high) { + const set = new Set() + let start = 0, end = 0 + for(let i = 10; i >= 0; i--) { + if (low / (10 ** i) >= 1) { + start = ~~(low / (10 ** i)) + break + } + } + for(let i = 10; i >= 0; i--) { + if (high / (10 ** i) >= 1) { + end = ~~(high / (10 ** i)) + break + } + } + for(let i = 1; i <= 9; i++) { + helper(`${i}`) + } + + const res = Array.from(set) + res.sort((a, b) => a- b) + return res + + function helper(s) { + // console.log(s) + if(+s > high) return + if(+s >= low && +s <= high) { + set.add(+s) + } + if(s[s.length - 1] === '9') return + helper(`${s}${+s[s.length - 1] + 1}`) + } +}; diff --git a/1292-maximum-side-length-of-a-square-with-sum-less-than-or-equal-to-threshold.js b/1292-maximum-side-length-of-a-square-with-sum-less-than-or-equal-to-threshold.js new file mode 100644 index 00000000..6e3157ba --- /dev/null +++ b/1292-maximum-side-length-of-a-square-with-sum-less-than-or-equal-to-threshold.js @@ -0,0 +1,30 @@ +/** + * @param {number[][]} mat + * @param {number} threshold + * @return {number} + */ +const maxSideLength = function (mat, threshold) { + let m = mat.length + let n = mat[0].length + const sum = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)) + + let res = 0 + let len = 1 // square side length + + for (let i = 1; i <= m; i++) { + for (let j = 1; j <= n; j++) { + sum[i][j] = + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + mat[i - 1][j - 1] + + if ( + i >= len && + j >= len && + sum[i][j] - sum[i - len][j] - sum[i][j - len] + sum[i - len][j - len] <= + threshold + ) + res = len++ + } + } + + return res +} diff --git a/1293-shortest-path-in-a-grid-with-obstacles-elimination.js b/1293-shortest-path-in-a-grid-with-obstacles-elimination.js new file mode 100644 index 00000000..f9e68a0c --- /dev/null +++ b/1293-shortest-path-in-a-grid-with-obstacles-elimination.js @@ -0,0 +1,47 @@ +/** + * @param {number[][]} grid + * @param {number} k + * @return {number} + */ +const shortestPath = function (grid, k) { + const m = grid.length + const n = m && grid[0].length + if (m === 1 && n === 1) return 0 + const queue = [[0, 0, k]] + const dirs = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ] + const visited = new Set() + let steps = 0 + while (queue.length > 0) { + let size = queue.length + while (size--) { + const [row, col, em] = queue.shift() + if (visited.has(row + "#" + col + "#" + em)) continue + visited.add(row + "#" + col + "#" + em) + for (let dir of dirs) { + const nx = row + dir[0] + const ny = col + dir[1] + if ( + nx < 0 || + nx >= m || + ny < 0 || + ny >= n || + visited.has(nx + "#" + ny + "#" + em) + ) + continue + if (nx === m - 1 && ny === n - 1) return steps + 1 + if (grid[nx][ny] === 1) { + if (em > 0) queue.push([nx, ny, em - 1]) + } else { + queue.push([nx, ny, em]) + } + } + } + steps++ + } + return -1 +} diff --git a/1295-find-numbers-with-even-number-of-digits.js b/1295-find-numbers-with-even-number-of-digits.js new file mode 100644 index 00000000..187c8e4e --- /dev/null +++ b/1295-find-numbers-with-even-number-of-digits.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const findNumbers = function(nums) { + let res = 0 + for(const e of nums) { + const str = '' + e + if(str.length % 2 === 0) res++ + } + return res +}; diff --git a/1297-maximum-number-of-occurrences-of-a-substring.js b/1297-maximum-number-of-occurrences-of-a-substring.js new file mode 100644 index 00000000..7d63bbac --- /dev/null +++ b/1297-maximum-number-of-occurrences-of-a-substring.js @@ -0,0 +1,24 @@ +/** + * @param {string} s + * @param {number} maxLetters + * @param {number} minSize + * @param {number} maxSize + * @return {number} + */ +function maxFreq(s, maxLetters, k, maxSize) { + let count = new Map(); + for (let i = 0; i <= s.length - k; i++) { + let substring = s.slice(i, i + k); + if (!count.has(substring)) { + count.set(substring, 0); + } + count.set(substring, count.get(substring) + 1); + } + let maxFreq = 0; + for (let [substring, freq] of count) { + if (new Set(substring).size <= maxLetters) { + maxFreq = Math.max(maxFreq, freq); + } + } + return maxFreq; +} diff --git a/1298-maximum-candies-you-can-get-from-boxes.js b/1298-maximum-candies-you-can-get-from-boxes.js new file mode 100644 index 00000000..b14f63da --- /dev/null +++ b/1298-maximum-candies-you-can-get-from-boxes.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} status + * @param {number[]} candies + * @param {number[][]} keys + * @param {number[][]} containedBoxes + * @param {number[]} initialBoxes + * @return {number} + */ +var maxCandies = function(status, candies, keys, containedBoxes, initialBoxes) { + let foundOpenable = true; + let totalCandies = 0; + while (initialBoxes.length > 0 && foundOpenable) { + foundOpenable = false; + let nextBoxes = []; + for (let boxId of initialBoxes) { + if (status[boxId]) { + foundOpenable = true; + nextBoxes.push(...containedBoxes[boxId]); + for (let keyId of keys[boxId]) status[keyId] = 1; + totalCandies += candies[boxId]; + } else { + nextBoxes.push(boxId); + } + } + initialBoxes = nextBoxes; + } + return totalCandies; +}; diff --git a/1299-replace-elements-with-greatest-element-on-right-side.js b/1299-replace-elements-with-greatest-element-on-right-side.js new file mode 100644 index 00000000..c37e674a --- /dev/null +++ b/1299-replace-elements-with-greatest-element-on-right-side.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} arr + * @return {number[]} + */ +const replaceElements = function(arr) { + const suffix = [-1], n = arr.length + for(let i = n - 2; i >= 0; i--) { + suffix.unshift(Math.max(suffix[0], arr[i + 1])) + } + + return suffix +}; diff --git a/13-roman-to-integer.js b/13-roman-to-integer.js new file mode 100644 index 00000000..b3dd3be3 --- /dev/null +++ b/13-roman-to-integer.js @@ -0,0 +1,57 @@ +/** + * @param {string} s + * @return {number} + */ +const romanToInt = function(s) { + let res = 0 + for (let i = s.length - 1; i >= 0; i--) { + let c = s.charAt(i) + switch (c) { + case 'I': + res += res >= 5 ? -1 : 1 + break + case 'V': + res += 5 + break + case 'X': + res += 10 * (res >= 50 ? -1 : 1) + break + case 'L': + res += 50 + break + case 'C': + res += 100 * (res >= 500 ? -1 : 1) + break + case 'D': + res += 500 + break + case 'M': + res += 1000 + break + } + } + return res +} + + +// another + +/** + * @param {string} s + * @return {number} + */ +const romanToInt = function(s) { + const map = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 } + let result = 0 + let index = s.length - 1 + let preInt = 0 + while (index >= 0) { + let ch = s[index] + let curInt = map[ch] + if (curInt >= preInt) result += curInt + else result -= curInt + preInt = curInt + index-- + } + return result +} diff --git a/130-surrounded-regions.js b/130-surrounded-regions.js new file mode 100644 index 00000000..619240b1 --- /dev/null +++ b/130-surrounded-regions.js @@ -0,0 +1,94 @@ +/** + * @param {character[][]} board + * @return {void} Do not return anything, modify board in-place instead. + */ +const solve = function(board) { + if (!board || board.length < 3 || board[0].length < 3) return; + let r = board.length; + let c = board[0].length; + for (let i = 0; i < c; i++) { + if (board[0][i] === "O") search(board, 0, i); + if (board[r - 1][i] === "O") search(board, r - 1, i); + } + for (let i = 0; i < r; i++) { + if (board[i][0] === "O") search(board, i, 0); + if (board[i][c - 1] === "O") search(board, i, c - 1); + } + for (let i = 0; i < r; i++) { + for (let j = 0; j < c; j++) { + if (board[i][j] === "O") board[i][j] = "X"; + if (board[i][j] === "*") board[i][j] = "O"; + } + } +}; + +function search(board, i, j) { + if (i < 0 || j < 0 || i >= board.length || j >= board[0].length) return; + if (board[i][j] !== "O") return; + board[i][j] = "*"; + search(board, i + 1, j); + search(board, i - 1, j); + search(board, i, j + 1); + search(board, i, j - 1); +} + +// another + +/** + * @param {character[][]} board + * @return {void} Do not return anything, modify board in-place instead. + */ +const solve = (board) => { + if (!board || board.length === 0 || board[0].length === 0) return; + const n = board.length; + const m = board[0].length; + const dirs = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ]; + const bfs = (board, n, m, i, j) => { + const queue = []; + queue.push([i, j]); + board[i][j] = "1"; + while (queue.length > 0) { + const pos = queue.shift(); + for (let k = 0; k < 4; k++) { + i = pos[0] + dirs[k][0]; + j = pos[1] + dirs[k][1]; + if (i >= 0 && i < n && j >= 0 && j < m && board[i][j] === "O") { + board[i][j] = "1"; + queue.push([i, j]); + } + } + } + }; + // scan the borders and mark the 'O's to '1' + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + if ( + (i === 0 || i === n - 1 || j === 0 || j === m - 1) && + board[i][j] === "O" + ) { + bfs(board, n, m, i, j); + } + } + } + // scan the inner area and mark the 'O's to 'X' + for (let i = 1; i < n; i++) { + for (let j = 1; j < m; j++) { + if (board[i][j] === "O") { + board[i][j] = "X"; + } + } + } + // reset all the '1's to 'O's + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + if (board[i][j] === "1") { + board[i][j] = "O"; + } + } + } +}; diff --git a/1300-sum-of-mutated-array-closest-to-target.js b/1300-sum-of-mutated-array-closest-to-target.js new file mode 100644 index 00000000..dd4a35f3 --- /dev/null +++ b/1300-sum-of-mutated-array-closest-to-target.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} arr + * @param {number} target + * @return {number} + */ +const findBestValue = function(arr, target) { + let l, r, mi, s = 0, m = -1; + for(let v of arr) { s += v; m = Math.max(m, v); } + if(s <= target) return m; + + for(l = 1, r = m; l < r;) { + mi = ~~((l+r)/2); + s = 0; + for(let v of arr) s += (v > mi) ? mi : v; + if(s >= target) r = mi; + else l = mi + 1; + } + // check if we are 1 step off the target + let s1=0,s2=0; + for(let v of arr) { + s1 += (v>l)?(l):v; + s2 += (v>l-1)?(l-1):v; + } + + return (Math.abs(s2-target) <= Math.abs(s1-target)) ? l-1 : l; +}; diff --git a/1301-number-of-paths-with-max-score.js b/1301-number-of-paths-with-max-score.js new file mode 100644 index 00000000..35b84b7c --- /dev/null +++ b/1301-number-of-paths-with-max-score.js @@ -0,0 +1,81 @@ +/** + * @param {string[]} board + * @return {number[]} + */ +const pathsWithMaxScore = ( + A, + dirs = [ + [-1, -1], + [-1, 0], + [0, -1], + ], + mod = 1e9 + 7 +) => { + const N = A.length + const S = [...Array(N + 1)].map((row) => Array(N + 1).fill(0)), + P = [...Array(N + 1)].map((row) => Array(N + 1).fill(0)) + P[0][0] = 1 + for (let i = 1; i <= N; ++i) { + for (let j = 1; j <= N; ++j) { + if (A[i - 1][j - 1] == 'X') continue + for (let d of dirs) { + const u = i + d[0], + v = j + d[1] + const sum = !P[u][v] + ? 0 + : S[u][v] + + (i == 1 && j == 1 + ? 0 + : i == N && j == N + ? 0 + : A[i - 1].charCodeAt(j - 1) - '0'.charCodeAt(0)) + if (S[i][j] == sum) P[i][j] = (P[i][j] + P[u][v]) % mod + if (S[i][j] < sum) (S[i][j] = sum), (P[i][j] = P[u][v]) + } + } + } + return [S[N][N], P[N][N]] +} + +// another + +/** + * @param {string[]} board + * @return {number[]} + */ +const pathsWithMaxScore = ( + board, + DIRS = [ + [-1, -1], + [-1, 0], + [0, -1], + ], + mod = 1e9 + 7 +) => { + const m = board.length, + n = board[0].length + const dpSum = Array.from({ length: m }, () => Array(n).fill(0)) + const dpCnt = Array.from({ length: m }, () => Array(n).fill(0)) + dpCnt[m - 1][n - 1] = 1 // start at the bottom right square + for (let r = m - 1; r >= 0; r--) { + for (let c = n - 1; c >= 0; c--) { + if (dpCnt[r][c] === 0) continue // can't reach to this square + for (let dir of DIRS) { + let nr = r + dir[0], + nc = c + dir[1] + if (nr >= 0 && nc >= 0 && board[nr].charAt(nc) !== 'X') { + let nsum = dpSum[r][c] + if (board[nr].charAt(nc) !== 'E') nsum += board[nr].charAt(nc) - '0' + if (nsum > dpSum[nr][nc]) { + dpCnt[nr][nc] = dpCnt[r][c] + dpSum[nr][nc] = nsum + } else if (nsum === dpSum[nr][nc]) { + dpCnt[nr][nc] = (dpCnt[nr][nc] + dpCnt[r][c]) % mod + } + } + } + } + } + return [dpSum[0][0], dpCnt[0][0]] +} + diff --git a/1302-deepest-leaves-sum.js b/1302-deepest-leaves-sum.js new file mode 100644 index 00000000..0e7d364b --- /dev/null +++ b/1302-deepest-leaves-sum.js @@ -0,0 +1,29 @@ +/** + * 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 {number} + */ +const deepestLeavesSum = function(root) { + let res= 0 + let q = [root] + while(q.length) { + const size = q.length + const tmp = [] + res = 0 + for(let i = 0; i < size; i++) { + res += q[i].val + if(q[i].left) tmp.push(q[i].left) + if(q[i].right) tmp.push(q[i].right) + } + + q = tmp + } + return res +}; diff --git a/1303-find-the-team-size.sql b/1303-find-the-team-size.sql new file mode 100644 index 00000000..0446f739 --- /dev/null +++ b/1303-find-the-team-size.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +SELECT employee_id, + COUNT(team_id) OVER(PARTITION BY team_id) AS team_size +FROM Employee; diff --git a/1304-find-n-unique-integers-sum-up-to-zero.js b/1304-find-n-unique-integers-sum-up-to-zero.js new file mode 100644 index 00000000..ed551311 --- /dev/null +++ b/1304-find-n-unique-integers-sum-up-to-zero.js @@ -0,0 +1,18 @@ +/** + * @param {number} n + * @return {number[]} + */ +const sumZero = function(n) { + const num = ~~(n / 2) + const odd = n % 2 === 1 + const res = pair(num) + if(odd) res.push(0) + return res +}; + +function pair(num) { + const set = new Set() + const res = [] + for(let i = 1; i <= num; i++) res.push(i, -i) + return res +} diff --git a/1305-all-elements-in-two-binary-search-trees.js b/1305-all-elements-in-two-binary-search-trees.js new file mode 100644 index 00000000..1c4d3929 --- /dev/null +++ b/1305-all-elements-in-two-binary-search-trees.js @@ -0,0 +1,47 @@ +/** + * 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} root1 + * @param {TreeNode} root2 + * @return {number[]} + */ +var getAllElements = function(root1, root2) { + const set1 = new Set(), set2 = new Set() + traverse(root1, set1) + traverse(root2, set2) + const res = [] + const it1 = set1[Symbol.iterator]() + const it2 = set2[Symbol.iterator]() + let { value: value1, done: done1 } = it1.next() + let { value: value2, done: done2 } = it2.next() + while(done1 === false || done2 === false) { + if(done2 || value1 < value2) { + res.push(value1) + const obj = it1.next() + value1 = obj.value + done1 = obj.done + }else { + res.push(value2) + const obj = it2.next() + value2 = obj.value + done2 = obj.done + } + } + + + return res + + + function traverse(node, set) { + if(node == null) return + traverse(node.left, set) + set.add(node.val) + traverse(node.right, set) + } +}; diff --git a/1306-jump-game-iii.js b/1306-jump-game-iii.js new file mode 100644 index 00000000..d3abea41 --- /dev/null +++ b/1306-jump-game-iii.js @@ -0,0 +1,57 @@ +/** + * @param {number[]} arr + * @param {number} start + * @return {boolean} + */ +const canReach = function(arr, start) { + const s = new Set() + return helper(arr, start, s) +}; + +function helper(arr, start, s) { + if(start < 0 || start >= arr.length || s.has(start)) return false + s.add(start) + if(arr[start] === 0) return true + + return helper(arr, start + arr[start], s) || helper(arr, start - arr[start], s) +} + +// another + +/** + * @param {number[]} arr + * @param {number} start + * @return {boolean} + */ +const canReach = function (A, i) { + return ( + 0 <= i && + i < A.length && + A[i] >= 0 && + (!(A[i] = -A[i]) || canReach(A, i + A[i]) || canReach(A, i - A[i])) + ) +} + +// another + +/** + * @param {number[]} arr + * @param {number} start + * @return {boolean} + */ +const canReach = function(arr, start) { + const q = [start] + const s = new Set() + while(q.length) { + const len = q.length + for(let i = 0; i < len; i++) { + const cur = q.shift() + s.add(cur) + if(arr[cur] === 0) return true + if(!s.has(cur + arr[cur])) q.push(cur + arr[cur]) + if(!s.has(cur - arr[cur])) q.push(cur - arr[cur]) + } + } + return false +}; + diff --git a/1307-verbal-arithmetic-puzzle.js b/1307-verbal-arithmetic-puzzle.js new file mode 100644 index 00000000..eafb218a --- /dev/null +++ b/1307-verbal-arithmetic-puzzle.js @@ -0,0 +1,55 @@ +/** + * @param {string[]} words + * @param {string} result + * @return {boolean} + */ +const isSolvable = function (words, result) { + const _isSolvable = (wordIndex, charIndex, wordsSum, resultSum, num) => { + if (wordIndex >= words.length) { + return wordsSum === resultSum + } + const wordLen = words[wordIndex].length + if (charIndex >= wordLen) { + if (wordIndex === words.length - 1) { + return _isSolvable(wordIndex + 1, 0, wordsSum, num, 0) + } + return _isSolvable(wordIndex + 1, 0, wordsSum + num, resultSum, 0) + } + const char = words[wordIndex][charIndex] + if (map.get(char) !== undefined) { + if (map.get(char) === 0 && num === 0 && charIndex >= 1) { + return false + } + return _isSolvable( + wordIndex, + charIndex + 1, + wordsSum, + resultSum, + num * 10 + map.get(char) + ) + } + for (let digit = 0; digit <= 9; digit++) { + if (digit === 0 && num === 0 && wordLen > 1) continue + if (map.get(digit) !== undefined) continue + map.set(digit, char) + map.set(char, digit) + if ( + _isSolvable( + wordIndex, + charIndex + 1, + wordsSum, + resultSum, + num * 10 + digit + ) + ) { + return true + } + map.set(digit, undefined) + map.set(char, undefined) + } + return false + } + const map = new Map() + words = [...words, result] + return _isSolvable(0, 0, 0, 0, 0) +} diff --git a/1309-decrypt-string-from-alphabet-to-integer-mapping.js b/1309-decrypt-string-from-alphabet-to-integer-mapping.js new file mode 100644 index 00000000..01066f4f --- /dev/null +++ b/1309-decrypt-string-from-alphabet-to-integer-mapping.js @@ -0,0 +1,32 @@ +/** + * @param {string} s + * @return {string} + */ +const freqAlphabets = function(s) { + const n = s.length, a = 'a'.charCodeAt(0) - 1 + let res = '', cur = '', num = 0 + + for(let i = n - 1; i >= 0; i--) { + const ch = s[i] + if(cur === '') { + if(ch === '#') { + cur = ch + num = 0 + } else{ + res = (String.fromCharCode(a + (+ch))) + res + } + } else { + if (num < 1) { + cur = ch + cur + num++ + } else { + cur = ch + cur + const tmp = cur.slice(0,cur.length - 1) + res = (String.fromCharCode(a + (+tmp))) + res + cur = '' + num = 0 + } + } + } + return res +}; diff --git a/131-palindrome-partitioning.js b/131-palindrome-partitioning.js new file mode 100644 index 00000000..56ebb6cb --- /dev/null +++ b/131-palindrome-partitioning.js @@ -0,0 +1,70 @@ +/** + * @param {string} s + * @return {string[][]} + */ +const partition = function(s) { + let res = [] + backtrack(res, [], 0, s) + return res +} + +function backtrack(res, cur, start, s) { + if (start === s.length) res.push([...cur]) + else { + for (let i = start; i < s.length; i++) { + if (isPalindrome(s, start, i)) { + cur.push(s.substring(start, i + 1)) + backtrack(res, cur, i + 1, s) + cur.pop() + } + } + } +} + +function isPalindrome(str, start, i) { + let l = start, + r = i + while (l < r) { + if (str[l] !== str[r]) return false + l++ + r-- + } + return true +} + +// another + +/** + * @param {string} s + * @return {string[][]} + */ +const partition = function(s) { + const res = [] + helper(s, 0, [], res) + return res +}; + +function helper(str, idx, cur, res) { + if(idx >= str.length) { + res.push(cur.slice()) + return + } + for(let i = idx, len = str.length; i < len; i++) { + const tmp = str.slice(idx, i + 1) + if(chk(tmp)) { + cur.push(tmp) + helper(str, i + 1, cur, res) + cur.pop() + } + } +} +function chk(str) { + const n = str.length + let l = 0, r = n - 1 + while(l < r) { + if(str[l] !== str[r]) return false + l++ + r-- + } + return true +} diff --git a/1310-xor-queries-of-a-subarray.js b/1310-xor-queries-of-a-subarray.js new file mode 100644 index 00000000..e2b63cb2 --- /dev/null +++ b/1310-xor-queries-of-a-subarray.js @@ -0,0 +1,42 @@ + /** + * @param {number[]} arr + * @param {number[][]} queries + * @return {number[]} + */ +const xorQueries = function(arr, queries) { + const pre = [], n = arr.length + let xor = arr[0] + pre.push(xor) + for(let i = 1; i < n; i++) { + pre[i] = pre[i - 1] ^ arr[i] + } + + const res = queries.map((e, i) => { + const [l, r] = e + return pre[r] ^ (l > 0 ? pre[l - 1] : 0) + }) + return res +}; + +// another + +/** + * @param {number[]} arr + * @param {number[][]} queries + * @return {number[]} + */ +const xorQueries = function(arr, queries) { + const xorArr = [] + xorArr[0] = 0 + const n = arr.length + for(let i = 0; i < n; i++) { + const cur = arr[i] + xorArr.push(cur ^ xorArr[xorArr.length - 1]) + } + const res = [] + for(const [l, r] of queries) { + res.push(xorArr[r + 1] ^ xorArr[l]) + } + + return res +}; diff --git a/1312-minimum-insertion-steps-to-make-a-string-palindrome.js b/1312-minimum-insertion-steps-to-make-a-string-palindrome.js new file mode 100644 index 00000000..fecec737 --- /dev/null +++ b/1312-minimum-insertion-steps-to-make-a-string-palindrome.js @@ -0,0 +1,13 @@ +/** + * @param {string} s + * @return {number} + */ +const minInsertions = function (s) { + const dp = [...Array(501)].map((x) => Array(501).fill(0)) + const N = s.length + for (let i = N - 1; i >= 0; --i) + for (let j = i + 1; j <= N; ++j) + if (s[i] == s[j - 1]) dp[i][j] = dp[i + 1][j - 1] + else dp[i][j] = 1 + Math.min(dp[i + 1][j], dp[i][j - 1]) + return dp[0][N] +} diff --git a/1313-decompress-run-length-encoded-list.js b/1313-decompress-run-length-encoded-list.js new file mode 100644 index 00000000..95417f5a --- /dev/null +++ b/1313-decompress-run-length-encoded-list.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const decompressRLElist = function(nums) { + const res = [] + for(let i = 0, n = nums.length; i < n - 1; i += 2) { + const [freq, val] = [nums[i], nums[i + 1]] + for(let j = 0; j < freq; j++) res.push(val) + } + + return res +}; diff --git a/1314-matrix-block-sum.js b/1314-matrix-block-sum.js new file mode 100644 index 00000000..bf8a69f1 --- /dev/null +++ b/1314-matrix-block-sum.js @@ -0,0 +1,25 @@ +/** + * @param {number[][]} mat + * @param {number} k + * @return {number[][]} + */ +const matrixBlockSum = function(mat, k) { + const m = mat.length, n = mat[0].length + const rangeSum = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)) + + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + rangeSum[i + 1][j + 1] = rangeSum[i + 1][j] + rangeSum[i][j + 1] - rangeSum[i][j] + mat[i][j] + } + } + const res = Array.from({ length: m }, () => Array(n).fill(0)) + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + let r1 = Math.max(0, i - k), c1 = Math.max(0, j - k) + let r2 = Math.min(m, i + k + 1), c2 = Math.min(n, j + k + 1) + res[i][j] = rangeSum[r2][c2] - rangeSum[r2][c1] - rangeSum[r1][c2] + rangeSum[r1][c1] + } + } + + return res +}; diff --git a/1315-sum-of-nodes-with-even-valued-grandparent.js b/1315-sum-of-nodes-with-even-valued-grandparent.js new file mode 100644 index 00000000..6c7de73f --- /dev/null +++ b/1315-sum-of-nodes-with-even-valued-grandparent.js @@ -0,0 +1,28 @@ +/** + * 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 {number} + */ +const sumEvenGrandparent = function(root) { + let res = 0 + dfs(root, null, null) + return res + + + function dfs(node, parent, gp) { + if(node == null) return + if(parent && gp && gp.val % 2 === 0) { + res += node.val + } + dfs(node.left, node, parent) + dfs(node.right, node, parent) + } + +}; diff --git a/1316-distinct-echo-substrings.js b/1316-distinct-echo-substrings.js new file mode 100644 index 00000000..478c3c0a --- /dev/null +++ b/1316-distinct-echo-substrings.js @@ -0,0 +1,20 @@ +/** + * @param {string} text + * @return {number} + */ +const distinctEchoSubstrings = function (text) { + const set = new Set() + for(let len = 1; len <= text.length / 2; len++) { + for(let l = 0, r = len, count = 0; l < text.length - len; l++, r++) { + if(text.charAt(l) === text.charAt(r)) count++ + else count = 0 + + if(count === len) { + set.add(text.slice(l - len + 1, l + 1)) + count-- + } + } + } + return set.size +} + diff --git a/1320-minimum-distance-to-type-a-word-using-two-fingers.js b/1320-minimum-distance-to-type-a-word-using-two-fingers.js new file mode 100644 index 00000000..aff33212 --- /dev/null +++ b/1320-minimum-distance-to-type-a-word-using-two-fingers.js @@ -0,0 +1,29 @@ +/** + * @param {string} word + * @return {number} + */ +const minimumDistance = function (word) { + const dp = Array.from({ length: 2 }, () => + new Array(27).fill(0).map(() => Array(27).fill(0)) + ) + const A = 'A'.charCodeAt(0) + for (let pos = word.length - 1; pos >= 0; --pos) { + let to = word[pos].charCodeAt(0) - A + for (let i = 0; i < 27; ++i) { + for (let j = 0; j < 27; ++j) { + dp[pos % 2][i][j] = Math.min( + dp[(pos + 1) % 2][to][i] + cost(j, to), + dp[(pos + 1) % 2][to][j] + cost(i, to) + ) + } + } + } + return dp[0][26][26] +} +function cost(from, to) { + if (from === 26) return 0 + return ( + Math.abs(((from / 6) >> 0) - ((to / 6) >> 0)) + + Math.abs((from % 6) - (to % 6)) + ) +} diff --git a/1323-maximum-69-number.js b/1323-maximum-69-number.js new file mode 100644 index 00000000..87e472b9 --- /dev/null +++ b/1323-maximum-69-number.js @@ -0,0 +1,14 @@ +/** + * @param {number} num + * @return {number} + */ +var maximum69Number = function(num) { + const arr = (num+'').split('') + for(let i = 0; i < arr.length; i++) { + if(arr[i] === '6') { + arr[i] = '9' + break + } + } + return arr.join('') +}; diff --git a/1324-print-words-vertically.js b/1324-print-words-vertically.js new file mode 100644 index 00000000..9bf30f31 --- /dev/null +++ b/1324-print-words-vertically.js @@ -0,0 +1,30 @@ +/** + * @param {string} s + * @return {string[]} + */ +const printVertically = function(s) { + const arr = s.split(' ').filter(e => e !== '') + const m = arr.length + let n = 0 + for(const e of arr) { + n = Math.max(n, e.length) + } + + const mat = Array.from({ length: m }, () => Array(n).fill(' ')) + for(let i = 0; i < arr.length; i++) { + const cur = mat[i] + for(let j = 0; j < arr[i].length; j++) { + mat[i][j] = arr[i][j] + } + } + const res = [] + for(let j = 0; j < n; j++) { + const col = [] + for(let i = 0; i < m; i++) { + col.push(mat[i][j]) + } + res.push(col.join('').trimEnd()) + } + + return res +}; diff --git a/1325-delete-leaves-with-a-given-value.js b/1325-delete-leaves-with-a-given-value.js new file mode 100644 index 00000000..33e8a0d9 --- /dev/null +++ b/1325-delete-leaves-with-a-given-value.js @@ -0,0 +1,49 @@ +/** + * 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 + * @param {number} target + * @return {TreeNode} + */ +const removeLeafNodes = function(root, target) { + return dfs(root, target) +}; + +function dfs(node, target) { + if(node == null) return node + if(node.left == null && node.right == null) { + if(node.val === target) return null + else return node + } + node.right = dfs(node.right, target) + node.left = dfs(node.left, target) + if(node.right == null && node.left == null) return dfs(node, target) + return node +} + +// another + +/** + * 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 + * @param {number} target + * @return {TreeNode} + */ +const removeLeafNodes = function(root, target) { + if(root.left) root.left = removeLeafNodes(root.left, target) + if(root.right) root.right = removeLeafNodes(root.right, target) + return root.left == root.right && root.val === target ? null : root +}; diff --git a/1326-minimum-number-of-taps-to-open-to-water-a-garden.js b/1326-minimum-number-of-taps-to-open-to-water-a-garden.js new file mode 100644 index 00000000..1acc085e --- /dev/null +++ b/1326-minimum-number-of-taps-to-open-to-water-a-garden.js @@ -0,0 +1,73 @@ +/** + * @param {number} n + * @param {number[]} ranges + * @return {number} + */ +const minTaps = function(n, ranges) { + const len = ranges.length, {min, max} = Math + const arr = [] + for(let i = 0; i < len; i++) { + arr.push([max(0, i - ranges[i]), i + ranges[i]]) + } + // arr.sort((a, b) => a[1] === b[1] ? a[0] - b[0]: a[1] - b[1]) + arr.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]) + let res = 0, end = 0, nextEnd = 0, idx = 0 + while(idx < len) { + nextEnd = end + while(idx < len && arr[idx][0] <= end) { + nextEnd = max(nextEnd, arr[idx][1]) + idx++ + } + res++ + if(nextEnd >= n) return res + else if(nextEnd === end) return -1 + end = nextEnd + } + + + return -1 +}; + +// another + +/** + * @param {number} n + * @param {number[]} ranges + * @return {number} + */ +const minTaps = function (n, ranges) { + const starts = new Array(n + 1).fill(0) + for (let i = 0; i <= n; i++) { + const start = Math.max(0, i - ranges[i]) + starts[start] = Math.max(starts[start], i + ranges[i]) + } + let count = 0 + let max = 0 + let i = 0 + while (max < n) { + const end = max + for (let j = i; j <= end; j++) { + max = Math.max(max, starts[j]) + } + if (i === max) return -1 + i = end + count++ + } + return count +} + +// another + +/** + * @param {number} n + * @param {number[]} ranges + * @return {number} + */ +const minTaps = function (n, ranges) { + const dp = new Array(n + 1).fill(n + 2) + dp[0] = 0 + for (let i = 0; i <= n; ++i) + for (let j = Math.max(i - ranges[i] + 1, 0); j <= Math.min(i + ranges[i], n); ++j) + dp[j] = Math.min(dp[j], dp[Math.max(0, i - ranges[i])] + 1) + return dp[n] < n + 2 ? dp[n] : -1 +} diff --git a/1329-sort-the-matrix-diagonally.js b/1329-sort-the-matrix-diagonally.js new file mode 100644 index 00000000..dec33cc0 --- /dev/null +++ b/1329-sort-the-matrix-diagonally.js @@ -0,0 +1,39 @@ +/** + * @param {number[][]} mat + * @return {number[][]} + */ +const diagonalSort = function(mat) { + const m = mat.length, n = mat[0].length + + for(let j = 0; j < n; j++) { + let i = 0, jj = j + const tmp = [] + while(jj < n && i < m) { + tmp.push(mat[i++][jj++]) + } + tmp.sort((a, b) => a - b) + let idx = 0 + jj = j + let ii = 0 + while(ii < m && jj < n) { + mat[ii++][jj++] = tmp[idx++] + } + } + + for(let i = 1; i < m; i++) { + let j = 0 + let ii = i + const tmp = [] + while(j < n && ii < m) { + tmp.push(mat[ii++][j++]) + } + tmp.sort((a, b) => a - b) + let idx = 0 + ii = i + j = 0 + while(ii < m && j < n) { + mat[ii++][j++] = tmp[idx++] + } + } + return mat +}; diff --git a/133-clone-graph.js b/133-clone-graph.js new file mode 100644 index 00000000..0973bc54 --- /dev/null +++ b/133-clone-graph.js @@ -0,0 +1,35 @@ +/** + * - if(!node) return node. Graphs can also have null neighbors + * - using a Set doesn't work because we are dealing with objects not primitives + * - and when encountering an already-cloned node, you are supposed to return the copied node + * (otherwise you are linking back to the original) + * - so, map = {} is correct + * - the only "trick" is that you must set the current node as "already copied" before DFS-ing its neighbors + * - declaring new variable for copying a node is actually extra O(n) space + */ + +/** + * // Definition for a Node. + * function Node(val,neighbors) { + * this.val = val; + * this.neighbors = neighbors; + * }; + */ +/** + * @param {Node} node + * @return {Node} + */ +const cloneGraph = function(node) { + if (!node) return node + const map = {} + return traverse(node) + function traverse(node) { + if(!node) return node; + if (!map[node.val]) { + const newNode = new Node(node.val) + map[node.val] = newNode + newNode.neighbors = node.neighbors.map(traverse) + } + return map[node.val] + } +} diff --git a/1330-reverse-subarray-to-maximize-array-value.js b/1330-reverse-subarray-to-maximize-array-value.js new file mode 100644 index 00000000..3d5396ca --- /dev/null +++ b/1330-reverse-subarray-to-maximize-array-value.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxValueAfterReverse = function (nums) { + let minOfMaxPair = -Infinity + let maxOfMinPair = Infinity + let originalTotal = 0 + let maximumBenefit = 0 + for (let i = 1; i < nums.length; i++) { + const [left, right] = [nums[i - 1], nums[i]] + const diff = Math.abs(right - left) + originalTotal += diff + maximumBenefit = Math.max( + maximumBenefit, + Math.abs(right - nums[0]) - diff, + Math.abs(left - nums[nums.length - 1]) - diff + ) + minOfMaxPair = Math.max(minOfMaxPair, Math.min(left, right)) + maxOfMinPair = Math.min(maxOfMinPair, Math.max(left, right)) + } + maximumBenefit = Math.max(maximumBenefit, 2 * (minOfMaxPair - maxOfMinPair)) + return originalTotal + maximumBenefit +} diff --git a/1331-rank-transform-of-an-array.js b/1331-rank-transform-of-an-array.js new file mode 100644 index 00000000..11f7335f --- /dev/null +++ b/1331-rank-transform-of-an-array.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} arr + * @return {number[]} + */ +const arrayRankTransform = function(arr) { + const hash = {} + for(let e of arr) { + hash[e] = 1 + } + const keys = Object.keys(hash) + keys.sort((a, b) => a - b) + const rank = {} + for(let i = 0, n= keys.length; i < n; i++) { + rank[keys[i]] = i + 1 + } + + return arr.map(e => rank[e]) +}; diff --git a/1332-remove-palindromic-subsequences.js b/1332-remove-palindromic-subsequences.js new file mode 100644 index 00000000..747c066d --- /dev/null +++ b/1332-remove-palindromic-subsequences.js @@ -0,0 +1,20 @@ +/** + * @param {string} s + * @return {number} + */ +const removePalindromeSub = function(s) { + if(s == null || s === '') return 0 + if(chk(s)) return 1 + return 2 +}; + +function chk(s) { + let l = 0, r = s.length - 1 + while(l < r) { + if(s[l] !== s[r]) return false + l++ + r-- + } + + return true +} diff --git a/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.js b/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.js new file mode 100644 index 00000000..d728de89 --- /dev/null +++ b/1334-find-the-city-with-the-smallest-number-of-neighbors-at-a-threshold-distance.js @@ -0,0 +1,42 @@ +function floyd_warshall (n, edges, start) { + let d = [...Array(n)].map(() => Array(n).fill(Number.MAX_SAFE_INTEGER)) + for (const [u, v, cost] of edges) { + // UG + let c = cost == undefined ? 1 : cost + d[u][v] = d[v][u] = c + } + // for (const [u, v, cost] of edges) d[u][v] = cost == undefined ? 1 : cost; // DG + for (let i = start; i < n; i++) d[i][i] = 0 + for (let k = start; k < n; k++) { + for (let i = start; i < n; i++) { + for (let j = start; j < n; j++) { + if (d[i][j] > d[i][k] + d[k][j]) d[i][j] = d[i][k] + d[k][j] + } + } + } + return d +} +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} distanceThreshold + * @return {number} + */ +const findTheCity = function(n, edges, distanceThreshold) { + let dis = floyd_warshall(n, edges, 0), + res = [] + for (let start = 0; start < n; start++) { + let canReach = new Set() + for (let dest = 0; dest < n; dest++) { + if (start == dest) continue + if (dis[start][dest] <= distanceThreshold) canReach.add(dest) + } + res.push([start, canReach.size]) + } + res.sort((x, y) => { + if (x[1] != y[1]) return x[1] - y[1] + return y[0] - x[0] + }) + return res[0][0] +} + diff --git a/1335-minimum-difficulty-of-a-job-schedule.js b/1335-minimum-difficulty-of-a-job-schedule.js new file mode 100644 index 00000000..6a61cae6 --- /dev/null +++ b/1335-minimum-difficulty-of-a-job-schedule.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} jobDifficulty + * @param {number} d + * @return {number} + */ +const minDifficulty = function (jobDifficulty, d) { + if (jobDifficulty.length < d) return -1 + const cache = {} + const dfs = (start, numDays) => { + if (numDays === d) { + return start === jobDifficulty.length ? 0 : Infinity + } + const key = `${start}-${numDays}` + if (cache[key] !== undefined) return cache[key] + const end = jobDifficulty.length - d + numDays + let result = Infinity + let max = -Infinity + for (let i = start; i <= end; i++) { + max = Math.max(max, jobDifficulty[i]) + result = Math.min(result, max + dfs(i + 1, numDays + 1)) + } + return (cache[key] = result) + } + return dfs(0, 0) +} diff --git a/1336-number-of-transactions-per-visit.sql b/1336-number-of-transactions-per-visit.sql new file mode 100644 index 00000000..978dd535 --- /dev/null +++ b/1336-number-of-transactions-per-visit.sql @@ -0,0 +1,23 @@ +# Write your MySQL query statement below +SELECT CAST(b.transaction_count AS UNSIGNED) AS transactions_count, IFNULL(c.visits_count, 0) AS visits_count +FROM +(SELECT (@cnt1 := @cnt1+1) AS transaction_count + FROM Transactions + CROSS JOIN (SELECT @cnt1 := -1) AS tmp + WHERE @cnt1 + 1 <= (SELECT COUNT(*) + FROM Transactions + GROUP BY user_id, transaction_date + ORDER BY COUNT(*) DESC + LIMIT 1) + UNION SELECT 0 + ) AS b +LEFT OUTER JOIN +(SELECT a.transaction_count AS transaction_count, COUNT(a.user_id) AS visits_count +FROM (SELECT v.user_id AS user_id, v.visit_date AS visit_date, SUM(IF(t.transaction_date IS NULL, 0, 1)) AS transaction_count +FROM Visits AS v +LEFT OUTER JOIN Transactions AS t +ON v.user_id = t.user_id AND v.visit_date = t.transaction_date +GROUP BY v.user_id, v.visit_date) AS a +GROUP BY a.transaction_count +ORDER BY a.transaction_count) AS c +ON b.transaction_count = c.transaction_count; diff --git a/1337-the-k-weakest-rows-in-a-matrix.js b/1337-the-k-weakest-rows-in-a-matrix.js new file mode 100644 index 00000000..77ba5790 --- /dev/null +++ b/1337-the-k-weakest-rows-in-a-matrix.js @@ -0,0 +1,94 @@ +/** + * @param {number[][]} mat + * @param {number} k + * @return {number[]} + */ +const kWeakestRows = function(mat, k) { + const pq = new PriorityQueue((a, b) => a[0] === b[0] ? a[1] > b[1] : a[0] > b[0]) + const res = [], m = mat.length + for(let i = 0; i < m; i++) { + pq.push([oneNum(mat[i]), i]) + if(pq.size() > k) pq.pop() + } + while(k > 0) res[--k] = pq.pop()[1] + return res +}; + +function oneNum(arr) { + let l = 0, h = arr.length + while(l < h) { + const mid = l + ((h - l) >> 1) + if(arr[mid] === 1) l = mid + 1 + else h = mid + } + return l +} + + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1338-reduce-array-size-to-the-half.js b/1338-reduce-array-size-to-the-half.js new file mode 100644 index 00000000..a9b504af --- /dev/null +++ b/1338-reduce-array-size-to-the-half.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} arr + * @return {number} + */ +var minSetSize = function(arr) { + const hash = {} + for(const e of arr) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + const n = arr.length + const entries = Object.entries(hash) + entries.sort((a, b) => b[1] - a[1]) + let res= 0 + let cnt = 0 + for(const [k, v] of entries) { + cnt += v + res++ + if(cnt >= n / 2) break + } + + return res +}; diff --git a/134-gas-station.js b/134-gas-station.js new file mode 100644 index 00000000..a7dc4e04 --- /dev/null +++ b/134-gas-station.js @@ -0,0 +1,39 @@ +/** + * @param {number[]} gas + * @param {number[]} cost + * @return {number} + */ +const canCompleteCircuit = function(gas, cost) { + let total = 0 + let curLeft = 0 + let curtIdx = 0 + for (let i = 0; i < gas.length; i++) { + total += gas[i] - cost[i] + curLeft += gas[i] - cost[i] + if (curLeft < 0) { + curtIdx = i + 1 + curLeft = 0 + } + } + return total < 0 ? -1 : curtIdx +} + +// another + +const canCompleteCircuit = function(gas, cost) { + const len = gas.length + let tank = 0 + let count = 0 + for (let i = 0; i < len * 2; i++) { + let idx = i % len + if (count === len) return idx + count += 1 + tank += gas[idx] - cost[idx] + if (tank < 0) { + tank = 0 + count = 0 + } + } + return -1 +} + diff --git a/1340-jump-game-v.js b/1340-jump-game-v.js new file mode 100644 index 00000000..60945fdd --- /dev/null +++ b/1340-jump-game-v.js @@ -0,0 +1,92 @@ +/** + * @param {number[]} arr + * @param {number} d + * @return {number} + */ +const maxJumps = function (arr, d, res = 1) { + const dp = Array(1001).fill(0) + for (let i = 0, len = arr.length; i < len; ++i) + res = Math.max(res, dfs(arr, i, d)) + return res + + function dfs(arr, i, d, res = 1) { + if (dp[i]) return dp[i] + for ( + let j = i + 1; + j <= Math.min(i + d, arr.length - 1) && arr[j] < arr[i]; + ++j + ) + res = Math.max(res, 1 + dfs(arr, j, d)) + for (let j = i - 1; j >= Math.max(0, i - d) && arr[j] < arr[i]; --j) + res = Math.max(res, 1 + dfs(arr, j, d)) + return (dp[i] = res) + } +} + + +// another + +/** + * @param {number[]} arr + * @param {number} d + * @return {number} + */ +const maxJumps = function (arr, d) { + const cache = new Array(arr.length) + const diffs = [1, -1] + const dfs = (i) => { + if (cache[i]) return cache[i] + let max = 0 + for (let diff of diffs) { + for (let j = diff; Math.abs(j) <= d; j += diff) { + const nextPosition = i + j + const isValidJump = + nextPosition >= 0 && + nextPosition < arr.length && + arr[i] > arr[nextPosition] + if (isValidJump) max = Math.max(max, dfs(nextPosition)) + else break + } + } + const result = max + 1 + cache[i] = result + return result + } + for (let i = 0; i < arr.length; i++) dfs(i) + return Math.max(...cache) +} + +// another + +/** + * @param {number[]} arr + * @param {number} d + * @return {number} + */ +const maxJumps = function (arr, d, res = 0) { + const n = arr.length + const stack = [], stack2 = [] + const dp = Array(n + 1).fill(1) + arr.push(Infinity) + for(let i = 0; i <= n; i++) { + while(stack.length && arr[stack[stack.length - 1]] < arr[i]) { + const pre = arr[stack[stack.length - 1]] + while(stack.length && pre === arr[stack[stack.length - 1]]) { + const j = stack[stack.length - 1] + stack.pop() + if(i - j <= d) dp[i] = Math.max(dp[i], dp[j] + 1) + stack2.push(j) + } + while(stack2.length) { + const j = stack2[stack2.length - 1] + stack2.pop() + if(stack.length && j - stack[stack.length - 1] <= d) { + dp[stack[stack.length - 1]] = Math.max(dp[stack[stack.length - 1]], dp[j] + 1) + } + } + } + stack.push(i) + } + for(let i = 0; i < n; i++) res = Math.max(res, dp[i]) + return res +} diff --git a/1342-number-of-steps-to-reduce-a-number-to-zero.js b/1342-number-of-steps-to-reduce-a-number-to-zero.js new file mode 100644 index 00000000..9da8bfa9 --- /dev/null +++ b/1342-number-of-steps-to-reduce-a-number-to-zero.js @@ -0,0 +1,15 @@ +/** + * @param {number} num + * @return {number} + */ +const numberOfSteps = function(num) { + let res = 0 + while(num !== 0) { + if(num % 2 === 0) { + num /= 2 + } else num-- + res++ + } + + return res +}; diff --git a/1343-number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.js b/1343-number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.js new file mode 100644 index 00000000..52743a02 --- /dev/null +++ b/1343-number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} arr + * @param {number} k + * @param {number} threshold + * @return {number} + */ +const numOfSubarrays = function(arr, k, threshold) { + const n = arr.length + const pre = Array(n).fill(0) + pre[0] = arr[0] + for(let i = 1; i < n; i++) { + pre[i] = pre[i - 1] + arr[i] + } + + let res = 0 + if(pre[k - 1] / k >= threshold) res++ + for(let i = k; i < n; i++) { + if(pre[i] - pre[i - k] >= k * threshold) res++ + } + return res +}; diff --git a/1344-angle-between-hands-of-a-clock.js b/1344-angle-between-hands-of-a-clock.js new file mode 100644 index 00000000..51e9ee2a --- /dev/null +++ b/1344-angle-between-hands-of-a-clock.js @@ -0,0 +1,11 @@ +/** + * @param {number} hour + * @param {number} minutes + * @return {number} + */ +const angleClock = function(hour, minutes) { + const minutesAngle = minutes * 6; + const hoursAngle = (hour + minutes / 60) * 30; + const diff = Math.abs(minutesAngle - hoursAngle); + return Math.min(diff, 360 - diff); +}; diff --git a/1345-jump-game-iv.js b/1345-jump-game-iv.js new file mode 100644 index 00000000..5e67c588 --- /dev/null +++ b/1345-jump-game-iv.js @@ -0,0 +1,87 @@ +/** + * @param {number[]} arr + * @return {number} + */ +var minJumps = function (arr) { + if (arr.length === 1) return 0 + const n = arr.length + const indexMap = new Map() + for (let i = n - 1; i >= 0; i--) { + if (!indexMap.has(arr[i])) { + indexMap.set(arr[i], []) + } + indexMap.get(arr[i]).push(i) + } + let distance = 0 + const queue = [0, null] + const visited = new Set([0]) + while (queue.length > 0) { + const index = queue.shift() + if (index !== null) { + if (index > 0 && !visited.has(index - 1)) { + visited.add(index - 1) + queue.push(index - 1) + } + if (index < n - 1 && !visited.has(index + 1)) { + if (index + 1 === n - 1) return distance + 1 + visited.add(index + 1) + queue.push(index + 1) + } + for (const nb of indexMap.get(arr[index])) { + if (!visited.has(nb) && nb !== index - 1 && nb !== index + 1) { + if (nb === n - 1) return distance + 1 + visited.add(nb) + queue.push(nb) + } + } + } else { + distance++ + if (queue.length > 0) { + queue.push(null) + } + } + } + return -1 +} + +// another + +/** + * @param {number[]} arr + * @return {number} + */ +const minJumps = function (arr) { + if (arr.length === 1) return 0 + const n = arr.length + const indexMap = new Map() + for (let i = n - 1; i >= 0; i--) { + if (!indexMap.has(arr[i])) { + indexMap.set(arr[i], []) + } + indexMap.get(arr[i]).push(i) + } + let distance = 0 + const queue = [0] + const visited = new Set() + visited.add(0) + while (queue.length) { + const len = queue.length + for(let i = 0; i < len; i++) { + const cur = queue.shift() + if(cur === n - 1) return distance + const tmp = indexMap.get(arr[cur]) + tmp.push(cur - 1) + tmp.push(cur + 1) + for(let e of tmp) { + if(e >= 0 && e < n && !visited.has(e)) { + visited.add(e) + queue.push(e) + } + } + indexMap.set(arr[cur], []) + } + distance++ + } + return -1 +} + diff --git a/1347-minimum-number-of-steps-to-make-two-strings-anagram.js b/1347-minimum-number-of-steps-to-make-two-strings-anagram.js new file mode 100644 index 00000000..c568b573 --- /dev/null +++ b/1347-minimum-number-of-steps-to-make-two-strings-anagram.js @@ -0,0 +1,21 @@ +/** + * @param {string} s + * @param {string} t + * @return {number} + */ +const minSteps = function(s, t) { + const as = Array(26).fill(0), ts = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for(const e of s){ + as[e.charCodeAt(0) - a]++ + } + for(const e of t){ + ts[e.charCodeAt(0) - a]++ + } + + let com = 0 + for(let i = 0; i < 26; i++) { + com += Math.min(as[i], ts[i]) + } + return t.length - com +}; diff --git a/1348-tweet-counts-per-frequency.js b/1348-tweet-counts-per-frequency.js new file mode 100644 index 00000000..2ceb9584 --- /dev/null +++ b/1348-tweet-counts-per-frequency.js @@ -0,0 +1,54 @@ +const createNode = val => ({ val, left: null, right: null }); +class BinarySearchTree { + constructor() { + this.root = null; + } + insert(val, cur = this.root) { + const node = createNode(val); + if (!this.root) { this.root = node; return; } + if (val >= cur.val) { + !cur.right ? (cur.right = node) : this.insert(val, cur.right); + } else { + !cur.left ? (cur.left = node) : this.insert(val, cur.left); + } + } + traversal(low, high, interval, intervals, cur = this.root) { + if (!cur) return; + if (cur.val <= high && cur.val >= low) { + ++intervals[Math.floor((cur.val - low + 1) / interval)]; + } + cur.val > low && this.traversal(low, high, interval, intervals, cur.left); + cur.val < high && this.traversal(low, high, interval, intervals, cur.right); + } +}; +class TweetCounts { + constructor() { + this.freqInterval = { + minute: 60, + hour: 3600, + day: 86400, + }; + this.data = new Map(); + } + + recordTweet(name, time) { + if (this.data.has(name) === false) { + this.data.set(name, new BinarySearchTree()); + } + this.data.get(name).insert(time); + } + + getTweetCountsPerFrequency(freq, name, start, end) { + const interval = this.freqInterval[freq]; + const ret = new Array(Math.ceil((end - start + 1) / interval)).fill(0); + this.data.has(name) && this.data.get(name).traversal(start, end, interval, ret); + return ret; + } +}; + +/** + * Your TweetCounts object will be instantiated and called as such: + * var obj = new TweetCounts() + * obj.recordTweet(tweetName,time) + * var param_2 = obj.getTweetCountsPerFrequency(freq,tweetName,startTime,endTime) + */ diff --git a/1349-maximum-students-taking-exam.js b/1349-maximum-students-taking-exam.js new file mode 100644 index 00000000..0a45d165 --- /dev/null +++ b/1349-maximum-students-taking-exam.js @@ -0,0 +1,140 @@ +/** + * @param {character[][]} seats + * @return {number} + */ +const maxStudents = function(seats) { + const m = seats.length, n = seats[0].length, limit = 1 << n + const dp = Array.from({ length: m + 1}, () => Array(limit).fill(0)) + + let res = 0 + for(let i = 1; i <= m; i++) { + for(let mask = 0; mask < limit; mask++) { + let valid = true + for(let j = 0; j < n; j++) { + if(seats[i - 1][j] === '#' && ((mask >> j) & 1) ) { + valid = false + break + } + if(j < n - 1 && ((mask >> j) & 1) && ((mask >> (j + 1)) & 1) ) { + valid = false + break + } + } + + if(!valid) { + dp[i][mask] = -1 + continue + } + + for(let pre = 0; pre < limit; pre++) { + if(dp[i - 1][pre] === -1) continue + if( (pre & (mask >> 1)) !== 0 || (pre & (mask << 1)) !== 0 ) continue + dp[i][mask] = Math.max(dp[i][mask], dp[i - 1][pre]) + } + + dp[i][mask] += bitCnt(mask) + + res = Math.max(res, dp[i][mask]) + } + } + + return res + + function bitCnt(num) { + let res = 0 + while(num) { + if(num & 1) res++ + num = num >> 1 + } + + return res + } +}; + +// another + + +/** + * @param {character[][]} seats + * @return {number} + */ +const maxStudents = function (seats) { + if (!seats.length) return 0 + const lastPos = 1 << seats[0].length + const classroom = seats.map((row) => + row.reduce((a, c, i) => (c === '#' ? a : a | (1 << i)), 0) + ) + const dp = new Array(seats.length + 1).fill(null).map(() => new Map()) + dp[0].set(0, 0) + for (let row = 0; row < seats.length; row++) { + let queue = [0] + let numStudents = 0 + while (queue.length > 0) { + const next = [] + for (let arrangement of queue) { + let max = 0 + for (let [prevArrang, count] of dp[row]) { + if (conflicts(prevArrang, arrangement)) continue + max = Math.max(max, count + numStudents) + } + dp[row + 1].set(arrangement, max) + for (let i = 1; i < lastPos; i <<= 1) { + if (canSit(classroom[row], arrangement, i)) next.push(arrangement | i) + } + } + queue = next + numStudents++ + } + } + return Math.max(...dp[seats.length].values()) +} +function conflicts(prev, curr) { + return prev & (curr << 1) || prev & (curr >> 1) +} +function canSit(row, arrangement, newStudent) { + return ( + row & newStudent && + !(arrangement & newStudent) && + !(arrangement & (newStudent << 1)) && + !(arrangement & (newStudent >> 1)) + ) +} + +// another + +/** + * @param {character[][]} seats + * @return {number} + */ +const maxStudents = function (seats) { + const m = seats.length + const n = seats[0].length + const validity = [] + for (let i = 0; i < m; i++) { + let cur = 0 + for (let j = 0; j < n; j++) { + cur = (cur << 1) + (seats[i][j] === '.' ? 1 : 0) + } + validity.push(cur) + } + const f = Array.from({ length: m + 1 }, () => Array(1 << n).fill(-1)) + f[0][0] = 0 + for (let i = 1; i <= m; i++) { + const valid = validity[i - 1] + for (let j = 0; j < 1 << n; j++) { + if ((j & valid) === j && !(j & (j >> 1))) { + for (let k = 0; k < 1 << n; k++) { + if (!(j & (k >> 1)) && !((j >> 1) & k) && f[i - 1][k] !== -1) { + f[i][j] = Math.max(f[i][j], f[i - 1][k] + bitCount(j)) + } + } + } + } + } + return Math.max(...f[m]) +} +function bitCount(n) { + const res = n.toString(2).match(/1/g) + return res === null ? 0 : res.length +} + diff --git a/1350-students-with-invalid-departments.sql b/1350-students-with-invalid-departments.sql new file mode 100644 index 00000000..f89383dd --- /dev/null +++ b/1350-students-with-invalid-departments.sql @@ -0,0 +1,3 @@ +# Write your MySQL query statement below +SELECT id, name FROM Students +WHERE department_id not in (SELECT id from Departments); diff --git a/1351-count-negative-numbers-in-a-sorted-matrix.js b/1351-count-negative-numbers-in-a-sorted-matrix.js new file mode 100644 index 00000000..3564969e --- /dev/null +++ b/1351-count-negative-numbers-in-a-sorted-matrix.js @@ -0,0 +1,16 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const countNegatives = function(grid) { + const m = grid.length, n = grid[0].length + let res = 0, r = m - 1, c = 0 + while(r >= 0 && c < n) { + if(grid[r][c] < 0) { + res += n - c + r-- + } else c++ + } + + return res +}; diff --git a/1352-product-of-the-last-k-numbers.js b/1352-product-of-the-last-k-numbers.js new file mode 100644 index 00000000..8d8b69e8 --- /dev/null +++ b/1352-product-of-the-last-k-numbers.js @@ -0,0 +1,39 @@ +/* + * @lc app=leetcode id=1352 lang=javascript + * + * [1352] Product of the Last K Numbers + */ + +// @lc code=start + +const ProductOfNumbers = function() { + this.sum = [1] +}; + +/** + * @param {number} num + * @return {void} + */ +ProductOfNumbers.prototype.add = function(num) { + if(num > 0) { + this.sum.push(this.sum[this.sum.length - 1] * num) + } else { + this.sum = [1] + } +}; + +/** + * @param {number} k + * @return {number} + */ +ProductOfNumbers.prototype.getProduct = function(k) { + const len = this.sum.length + return k < len ? this.sum[len - 1] / this.sum[len - 1 - k] : 0 +}; + +/** + * Your ProductOfNumbers object will be instantiated and called as such: + * var obj = new ProductOfNumbers() + * obj.add(num) + * var param_2 = obj.getProduct(k) + */ diff --git a/1353-maximum-number-of-events-that-can-be-attended.js b/1353-maximum-number-of-events-that-can-be-attended.js new file mode 100644 index 00000000..f0cdc48d --- /dev/null +++ b/1353-maximum-number-of-events-that-can-be-attended.js @@ -0,0 +1,248 @@ +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} +/** + * @param {number[][]} events + * @return {number} + */ +function maxEvents(events) { + const pq = new PriorityQueue((a, b) => a < b) + + events.sort((a, b) => a[0] - b[0]) + let i = 0, res = 0, d = 0, n = events.length + + while(!pq.isEmpty() || i < n) { + if(pq.isEmpty()) { + d = events[i][0] + } + while(i < n && events[i][0] <= d) { + pq.push(events[i++][1]) + } + pq.pop() + res++ + d++ + while(!pq.isEmpty() && pq.peek() < d) { + pq.pop() + } + } + + return res +} + + +// another + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} +/** + * @param {number[][]} events + * @return {number} + */ +function maxEvents(events) { + const pq = new PriorityQueue((a, b) => a < b) + events.sort((a, b) => a[0] - b[0]) + let res = 0, i = 0, n = events.length + for(let d = 1; d <= 100000; d++) { + while(i < n && events[i][0] === d) { + pq.push(events[i++][1]) + } + while(!pq.isEmpty() && pq.peek() < d) { + pq.pop() + } + if(!pq.isEmpty()) { + res++ + pq.pop() + } + } + return res +} + + +// another + + + +/** + * @param {number[][]} events + * @return {number} + */ +function maxEvents(events) { + events.sort(([, aEnd], [, bEnd]) => aEnd - bEnd); + const lastDay = events[events.length - 1][1]; + const segmentTree = new SegmentTree(Array.from({ length: lastDay }, (_, i) => i), Infinity, (a, b) => Math.min(a, b)); + let daysAttended = 0; + + for (const [start, end] of events) { + // earliest attendable day + const ead = segmentTree.queryIn(start - 1, end); + if (ead <= end) { + daysAttended += 1; + segmentTree.setAt(ead, Infinity); + } + } + + return daysAttended; +} + +// https://github.com/axross/complex-data-structures +// new SegmentTree(values, identity, associate) +// segmentTree.getAt(i) +// segmentTree.queryIn(from, to) +// segmentTree.setAt(i, value) +// segmentTree.length +class SegmentTree{constructor(t,e,s){if(this.valueLength=t.length,this.identity=e,this.associate=s,0===t.length)this.tree=[];else{const h=2**Math.ceil(Math.log2(t.length))*2-1,i=[];for(let s=0;s<=h>>1;++s)i[(h>>1)+s]=s>1)-1;t>=0;--t)i[t]=s(i[2*t+1],i[2*t+2]);this.tree=i}}get length(){return this.valueLength}getAt(t){return this.tree[t+(this.tree.length>>1)]}queryIn(t,e){let s=this.identity;const h=[[0,0,1+(this.tree.length>>1)]];for(;h.length>0;){const[i,r,n]=h.pop();r>=t&&n<=e?s=this.associate(s,this.tree[i]):r>=e||nthis.tree.length>>1||h.push([2*i+1,r,r+n>>1],[2*i+2,r+n>>1,n])}return s}setAt(t,e){const s=t+(this.tree.length>>1);this.tree[s]=e;let h=s-1>>1;for(;h>=0;)this.tree[h]=this.associate(this.tree[2*h+1],this.tree[2*h+2]),h=h-1>>1}} + + +// another + +/** + * @param {number[][]} events + * @return {number} + */ +function maxEvents(events) { + const pq = new MinPriorityQueue () + events.sort((a, b) => a[0] - b[0]) + let res = 0, i = 0, n = events.length + for(let d = 1; d <= 1e5; d++) { + while(i < n && events[i][0] === d) { + pq.enqueue(events[i++][1]) + } + while(!pq.isEmpty() && pq.front().element < d) { + pq.dequeue() + } + if(!pq.isEmpty()) { + res++ + pq.dequeue() + } + } + return res +} diff --git a/1354-construct-target-array-with-multiple-sums.js b/1354-construct-target-array-with-multiple-sums.js new file mode 100644 index 00000000..5d75062c --- /dev/null +++ b/1354-construct-target-array-with-multiple-sums.js @@ -0,0 +1,90 @@ +/** + * @param {number[]} target + * @return {boolean} + */ +const isPossible = function (target) { + const pq = new PriorityQueue(); + let total = 0; + for (let a of target) { + total += a; + pq.push(a); + } + while (true) { + let a = pq.pop(); + total -= a; + if (a === 1 || total === 1) return true; + if (a < total || total === 0 || a % total === 0) return false; + a %= total; + total += a; + pq.push(a); + } +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = []; + this.top = 0; + this.comparator = comparator; + } + size() { + return this.heap.length; + } + isEmpty() { + return this.size() === 0; + } + peek() { + return this.heap[this.top]; + } + push(...values) { + values.forEach((value) => { + this.heap.push(value); + this.siftUp(); + }); + return this.size(); + } + pop() { + const poppedValue = this.peek(); + const bottom = this.size() - 1; + if (bottom > this.top) { + this.swap(this.top, bottom); + } + this.heap.pop(); + this.siftDown(); + return poppedValue; + } + replace(value) { + const replacedValue = this.peek(); + this.heap[this.top] = value; + this.siftDown(); + return replacedValue; + } + + parent = (i) => ((i + 1) >>> 1) - 1; + left = (i) => (i << 1) + 1; + right = (i) => (i + 1) << 1; + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]); + swap = (i, j) => + ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]); + siftUp = () => { + let node = this.size() - 1; + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)); + node = this.parent(node); + } + }; + siftDown = () => { + let node = this.top; + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node); + this.swap(node, maxChild); + node = maxChild; + } + }; +} diff --git a/1356-sort-integers-by-the-number-of-1-bits.js b/1356-sort-integers-by-the-number-of-1-bits.js new file mode 100644 index 00000000..30f0ee20 --- /dev/null +++ b/1356-sort-integers-by-the-number-of-1-bits.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} arr + * @return {number[]} + */ +const sortByBits = function(arr) { + arr.sort((a, b) => { + const an = numOfBits(a), bn = numOfBits(b) + return an === bn ? a - b : an - bn + }) + return arr +}; + +function numOfBits(n) { + let res = 0 + for(let i = 0; i < 32; i++) { + if((1 << i) & n) res++ + } + return res +} diff --git a/1359-count-all-valid-pickup-and-delivery-options.js b/1359-count-all-valid-pickup-and-delivery-options.js new file mode 100644 index 00000000..ae1de659 --- /dev/null +++ b/1359-count-all-valid-pickup-and-delivery-options.js @@ -0,0 +1,26 @@ +/** + * @param {number} n + * @return {number} + */ +const countOrders = function(n) { + let res = 1 + const MOD = 10 ** 9 + 7 + for(let i = 1; i <= n; i++) { + res = res * (i * 2 - 1) * i % MOD; + } + return res +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +const countOrders = function(n) { + let res = 1 + const MOD = 10 ** 9 + 7 + for(let i = 1; i <= n; i++) res = res * i % MOD + for(let i = 1; i < 2 * n; i += 2) res = res * i % MOD + return res +}; diff --git a/136-single-number.js b/136-single-number.js index 4010bf48..662dfc28 100644 --- a/136-single-number.js +++ b/136-single-number.js @@ -7,3 +7,14 @@ const singleNumber = function(nums) { for(let i = 1; i< nums.length; i++) xor ^= nums[i] return xor }; + + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const singleNumber = function(nums) { + return nums.reduce((ac, e) => ac ^ e, 0) +}; diff --git a/1360-number-of-days-between-two-dates.js b/1360-number-of-days-between-two-dates.js new file mode 100644 index 00000000..3c1a019f --- /dev/null +++ b/1360-number-of-days-between-two-dates.js @@ -0,0 +1,10 @@ +/** + * @param {string} date1 + * @param {string} date2 + * @return {number} + */ +const daysBetweenDates = function(date1, date2) { + const d1 = new Date(date1) + const d2 = new Date(date2) + return Math.abs((d1.getTime() - d2.getTime()) / (1000 * 60 * 60 * 24)) +}; diff --git a/1363-largest-multiple-of-three.js b/1363-largest-multiple-of-three.js new file mode 100644 index 00000000..77a3be63 --- /dev/null +++ b/1363-largest-multiple-of-three.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} digits + * @return {string} + */ +const largestMultipleOfThree = function (digits) { + const sum = digits.reduce((a, c) => a + c) + if (sum === 0) return '0' + const remainder = sum % 3 + digits.sort((a, b) => b - a) + if (remainder === 0) return digits.join('') + const doubleRemainder = remainder === 1 ? 2 : 1 + const idxs = [] + for (let i = digits.length - 1; i >= 0; i--) { + const numRemainder = digits[i] % 3 + if (numRemainder === remainder) { + digits[i] = '' + return digits.join('') + } else if (numRemainder === doubleRemainder) { + idxs.push(i) + } + } + const [idx1, idx2] = idxs + if (idx2 === undefined) return '' + + digits[idx1] = '' + digits[idx2] = '' + return digits.join('') +} diff --git a/1365-how-many-numbers-are-smaller-than-the-current-number.js b/1365-how-many-numbers-are-smaller-than-the-current-number.js new file mode 100644 index 00000000..82b033a9 --- /dev/null +++ b/1365-how-many-numbers-are-smaller-than-the-current-number.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const smallerNumbersThanCurrent = function(nums) { + const count = new Array(101).fill(0); + const res = new Array(nums.length).fill(0); + for (let i = 0; i < nums.length; i++) count[nums[i]]++ + for (let i = 1 ; i <= 100; i++) count[i] += count[i-1] + for (let i = 0; i < nums.length; i++) { + if (nums[i] == 0) res[i] = 0 + else res[i] = count[nums[i] - 1] + } + return res; +}; + diff --git a/1366-rank-teams-by-votes.js b/1366-rank-teams-by-votes.js new file mode 100644 index 00000000..ef253262 --- /dev/null +++ b/1366-rank-teams-by-votes.js @@ -0,0 +1,49 @@ +/** + * @param {string[]} votes + * @return {string} + */ +const rankTeams = function(votes) { + const hash = {} + const l = votes[0].length + for(let vote of votes) { + for(let i = 0; i < l; i++) { + const ch = vote[i] + if(hash[ch] == null) hash[ch] = Array(l).fill(0) + hash[ch][i]++ + } + } + const keys = Object.keys(hash) + keys.sort((a, b) => { + for(let i = 0; i < l; i++) { + if(hash[a][i] !== hash[b][i]) { + return hash[b][i] - hash[a][i] + } + } + return a === b ? 0 : (a < b ? -1 : 1) + }) + + return keys.join('') +}; + +// another + +/** + * @param {string[]} votes + * @return {string} + */ +const rankTeams = function(votes) { + if (votes.length === 1) return votes[0]; + const score = new Map(votes[0].split('').map(c => [c, new Array(votes[0].length).fill(0)])); + for (s of votes) { + for (let i = 0; i < s.length; i++) { + score.get(s[i])[i]++; + } + } + return votes[0].split('').sort((a,b) => { + for (let i = 0; i < votes[0].length; i++) { + if (score.get(a)[i] > score.get(b)[i]) return -1; + if (score.get(a)[i] < score.get(b)[i]) return 1; + } + return a < b ? -1 : 1; + }).join(''); +}; diff --git a/1367-linked-list-in-binary-tree.js b/1367-linked-list-in-binary-tree.js new file mode 100644 index 00000000..f186049e --- /dev/null +++ b/1367-linked-list-in-binary-tree.js @@ -0,0 +1,157 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * 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 {ListNode} head + * @param {TreeNode} root + * @return {boolean} + */ +function isSubPath(head, root) { + let needle = convertLinkedListToArray(head); + let lps = computeKMPTable(needle); + return kmpSearch(root, 0); + + function kmpSearch(i, j) { + if (j === needle.length) return true; + if (i === null) return false; + while (j > 0 && i.val !== needle[j]) j = lps[j - 1]; + if (i.val === needle[j]) j++; + return kmpSearch(i.left, j) || kmpSearch(i.right, j); + } + + function computeKMPTable(pattern) { + let n = pattern.length; + let lps = new Array(n); + for (let i = 0; i < n; i++) { + lps[i] = 0; + } + for (let i = 1, j = 0; i < n; i++) { + while (j > 0 && pattern[i] !== pattern[j]) j = lps[j - 1]; + if (pattern[i] === pattern[j]) lps[i] = ++j; + } + return lps; + } + + function convertLinkedListToArray(head) { + let list = []; + while (head !== null) { + list.push(head.val); + head = head.next; + } + return list; + } +} + + +// another + + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * 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 {ListNode} head + * @param {TreeNode} root + * @return {boolean} + */ +const isSubPath = function(head, root) { + return dfs(root) + + function dfs(node) { + if(node == null) return false + if(head.val === node.val) { + let cur = head + let q = [node] + while(q.length) { + const v = cur.val + const tmp = [] + let mark = false + for(const e of q) { + if(e.val === v) { + mark = true + if(e.left) tmp.push(e.left) + if(e.right) tmp.push(e.right) + } + } + if(cur && !mark) break + cur = cur.next + if(cur == null) return true + q = tmp + } + } + return dfs(node.left) || dfs(node.right) + } + +}; + + +// another + + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * 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 {ListNode} head + * @param {TreeNode} root + * @return {boolean} + */ +const isSubPath = function(head, root) { + const res = { found: false } + traverse(root, head, res) + return res.found +}; + +function traverse(node, list, res) { + if(res.found) return + if(node == null) return + if(node.val === list.val && helper(node, list)) { + res.found = true + return + } + traverse(node.left, list, res) + traverse(node.right, list, res) +} + +function helper(node, list) { + if(list == null) return true + if(node == null) return false + if(list.val !== node.val) return false + return helper(node.left, list.next) || helper(node.right, list.next) +} diff --git a/1368-minimum-cost-to-make-at-least-one-valid-path-in-a-grid.js b/1368-minimum-cost-to-make-at-least-one-valid-path-in-a-grid.js new file mode 100644 index 00000000..def7dab1 --- /dev/null +++ b/1368-minimum-cost-to-make-at-least-one-valid-path-in-a-grid.js @@ -0,0 +1,98 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +function minCost(grid) { + const m = grid.length, n = grid[0].length + const dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]] // right, left, down, up + const dp = Array.from({ length: m }, () => Array(n).fill(Infinity)) + let q = [[0, 0]] + dp[0][0] = 0 + while(q.length) { + const tmp = [] + for(let idx = q.length - 1; idx >= 0; idx--) { + const [r, c] = q[idx] + for(let i = 0; i < dirs.length; i++) { + const [dr, dc] = dirs[i] + const nr = r + dr, nc = c + dc + if(nr < 0 || nr >= m || nc < 0 || nc >= n) continue + if(dp[nr][nc] > dp[r][c] + (i === grid[r][c] - 1 ? 0 : 1)) { + dp[nr][nc] = dp[r][c] + (i === grid[r][c] - 1 ? 0 : 1) + tmp.push([nr, nc]) + } + } + } + q = tmp + } + + return dp[m - 1][n - 1] +} + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const minCost = function (grid) { + const n = grid.length + const m = grid[0].length + const moves = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + const dp = [...new Array(n)].map((e) => [...new Array(m)].fill(Infinity)) + dp[0][0] = 0 + let queue = [[0, 0]] + while (queue.length > 0) { + const temp = [] + for (let i = 0; i < queue.length; i++) { + const [x, y] = queue[i] + for (let j = 0; j < moves.length; j++) { + const nextX = x + moves[j][0] + const nextY = y + moves[j][1] + if (nextX >= 0 && nextY >= 0 && nextX < n && nextY < m) { + if (dp[nextX][nextY] > dp[x][y] + (grid[x][y] - 1 === j ? 0 : 1)) { + dp[nextX][nextY] = dp[x][y] + (grid[x][y] - 1 === j ? 0 : 1) + queue.push([nextX, nextY]) + } + } + } + } + queue = temp + } + return dp[n - 1][m - 1] +} + +// another + +function minCost(grid) { + const INF = 1e9, m = grid.length, n = grid[0].length + const dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]] // right, left, down, up + let cost = 0 + const dp = Array.from({ length: m }, () => Array(n).fill(INF)) + const q = [] + dfs(0, 0, 0) + while(q.length) { + cost++ + for (let size = q.length; size > 0; size--) { + const [r, c] = q.shift() + for(let [dx, dy] of dirs) { + dfs(r + dx, c + dy, cost) + } + } + } + + return dp[m - 1][n - 1] + function dfs(r, c, cost) { + if(r < 0 || r >= m || c < 0 || c >= n || dp[r][c] !== INF) return + dp[r][c] = cost + q.push([r, c]) + const nextDir = grid[r][c] - 1 + const [dx, dy] = dirs[nextDir] + dfs(r + dx, c + dy, cost) + } +} + diff --git a/1369-get-the-second-most-recent-activity.sql b/1369-get-the-second-most-recent-activity.sql new file mode 100644 index 00000000..ce0fc64f --- /dev/null +++ b/1369-get-the-second-most-recent-activity.sql @@ -0,0 +1,14 @@ +# Write your MySQL query statement below +SELECT * +FROM UserActivity +GROUP BY username +HAVING COUNT(*) = 1 + +UNION ALL + +SELECT u1.* +FROM UserActivity u1 +LEFT JOIN UserActivity u2 + ON u1.username = u2.username AND u1.endDate < u2.endDate +GROUP BY u1.username, u1.endDate +HAVING COUNT(u2.endDate) = 1; diff --git a/1370-increasing-decreasing-string.js b/1370-increasing-decreasing-string.js new file mode 100644 index 00000000..c9bc2a65 --- /dev/null +++ b/1370-increasing-decreasing-string.js @@ -0,0 +1,32 @@ +/** + * @param {string} s + * @return {string} + */ +const sortString = function(s) { + const arr = Array(26).fill(0), a = 'a'.charCodeAt(0) + for(const ch of s) { + arr[ch.charCodeAt(0) - a]++ + } + + let res = '', delta = 1 + const valid = arr => arr.every(e => e === 0) + while(!valid(arr)) { + if(delta > 0) { + for(let i = 0; i< 26; i++) { + if(arr[i]) { + res += String.fromCharCode(a + i) + arr[i]-- + } + } + } else { + for(let i = 25; i >= 0; i--) { + if(arr[i]) { + res += String.fromCharCode(a + i) + arr[i]-- + } + } + } + delta = delta === 1 ? -1 : 1 + } + return res +}; diff --git a/1371-find-the-longest-substring-containing-vowels-in-even-counts.js b/1371-find-the-longest-substring-containing-vowels-in-even-counts.js new file mode 100644 index 00000000..b2c505d0 --- /dev/null +++ b/1371-find-the-longest-substring-containing-vowels-in-even-counts.js @@ -0,0 +1,199 @@ +/** + * @param {string} s + * @return {number} + */ +var findTheLongestSubstring = function(s) { + const hash = {0: -1}; + const vowels = 'aeiou'; + const vowelsSet = new Set(vowels); + const n = s.length; + const key = (ch) => { + const idx = vowels.indexOf(ch); + return idx === -1 ? 0 : 1 << idx; + } + let state = 0; + let res = 0; + for(let i = 0; i < n; i++) { + const ch = s[i] + let tmp = state; + if(vowelsSet.has(ch)) { + tmp ^= key(ch); + } + if(hash[tmp] === undefined) { + hash[tmp] = i; + }else { + res = Math.max(res, i - hash[tmp]); + } + + state = tmp + } + + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const findTheLongestSubstring = function(s) { + const n = s.length + let res = 0, mask = 0 + const map = new Map([[0, -1]]) + + for(let i = 0; i < n; i++) { + const ch = s[i] + const idx = 'aeiou'.indexOf(ch) + if(idx !== -1) { + mask ^= (1 << idx) + } + if(map.has(mask)) { + res = Math.max(res, i - map.get(mask)) + } else { + map.set(mask, i) + } + } + + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const findTheLongestSubstring = function(s) { + const n = s.length + let res = 0, mask = 0 + const map = new Map([[0, -1]]) + + for(let i = 0; i < n; i++) { + const ch = s[i] + const idx = 'aeiou'.indexOf(ch) + if(idx !== -1) { + mask ^= (1 << idx) + if(map.has(mask)) { + res = Math.max(res, i - map.get(mask)) + } else { + map.set(mask, i) + } + } else { + res = Math.max(res, i - map.get(mask)) + } + } + + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const findTheLongestSubstring = function(s) { + const n = s.length + const ch2num = ch => { + const idx = 'aeiou'.indexOf(ch) + return idx === -1 ? 0 : (1 << idx) + } + let res = 0 + let mask = 0 + const hash = new Map([[0, -1]]) + for (let i = 0; i < n; i++) { + mask ^= ch2num(s[i]) + const first = hash.has(mask) ? hash.get(mask) : i + if (!hash.has(mask)) hash.set(mask, i) + res = Math.max(res, i - first) + } + + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +var findTheLongestSubstring = function (s, V = 'aeiou', max = 0) { + let encode = (c) => { + let i = V.indexOf(c) + return i == -1 ? 0 : 1 << i + } + let N = s.length + let A = Array(N + 1).fill(0) + let seen = new Map([[0, 0]]) + for (let i = 1; i <= N; ++i) { + A[i] = A[i - 1] ^ encode(s[i - 1]) + let first = seen.has(A[i]) ? seen.get(A[i]) : i + if (first == i) seen.set(A[i], i) // first seen A[i] index + max = Math.max(max, i - first) // max of i-th index minus first seen A[i] index + } + return max +} + +// another + +/** + * @param {string} s + * @return {number} + */ +const findTheLongestSubstring = function(s) { + const n = s.length + const ch2num = ch => { + const idx = 'aeiou'.indexOf(ch) + return idx === -1 ? 0 : (1 << idx) + } + let res = 0 + let mask = 0 + const hash = new Map([[0, 0]]) + for (let i = 1; i <= n; i++) { + mask ^= ch2num(s[i - 1]) + const first = hash.has(mask) ? hash.get(mask) : i + if (!hash.has(mask)) hash.set(mask, i) + res = Math.max(res, i - first) + } + + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const findTheLongestSubstring = function (s) { + let mask = 0 + const n = s.length, + { max } = Math, + map = new Map(), + a = 'a'.charCodeAt(0), + set = new Set(['a', 'e', 'i', 'o', 'u']) + map.set(0, -1) + let res = 0 + for (let i = 0; i < n; i++) { + const ch = s[i] + if (set.has(ch)) { + const idx = ch.charCodeAt(0) - a + mask ^= 1 << idx + if (mask === 0) res = max(res, i + 1) + else if (map.has(mask)) { + res = max(res, i - map.get(mask)) + } else { + map.set(mask, i) + } + } else { + if(map.has(mask)) { + // console.log(i, map.get(mask)) + res = max(res, i - map.get(mask)) + } + } + } + + return res +} + diff --git a/1373-maximum-sum-bst-in-binary-tree.js b/1373-maximum-sum-bst-in-binary-tree.js new file mode 100644 index 00000000..a427ffd0 --- /dev/null +++ b/1373-maximum-sum-bst-in-binary-tree.js @@ -0,0 +1,39 @@ +/** + * 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 {number} + */ +const maxSumBST = function (root) { + let maxSum = 0 + postOrderTraverse(root) + return maxSum + + function postOrderTraverse(root) { + if (root == null) return [Number.MAX_VALUE, -Infinity, 0] // {min, max, sum}, initialize min=MAX_VALUE, max=MIN_VALUE + let left = postOrderTraverse(root.left) + let right = postOrderTraverse(root.right) + // The BST is the tree: + if ( + !( + left != null && // the left subtree must be BST + right != null && // the right subtree must be BST + root.val > left[1] && // the root's key must greater than maximum keys of the left subtree + root.val < right[0] + ) + ) + // the root's key must lower than minimum keys of the right subtree + return null + let sum = root.val + left[2] + right[2] // now it's a BST make `root` as root + maxSum = Math.max(maxSum, sum) + let min = Math.min(root.val, left[0]) + let max = Math.max(root.val, right[1]) + return [min, max, sum] + } +} diff --git a/1374-generate-a-string-with-characters-that-have-odd-counts.js b/1374-generate-a-string-with-characters-that-have-odd-counts.js new file mode 100644 index 00000000..cb124879 --- /dev/null +++ b/1374-generate-a-string-with-characters-that-have-odd-counts.js @@ -0,0 +1,12 @@ +/** + * @param {number} n + * @return {string} + */ +const generateTheString = function(n, ch = 'a') { + const odd = n % 2 === 1 + const code = ch.charCodeAt(0) + if(odd) return ch.repeat(n) + const nch = String.fromCharCode(code + 1), nnch = String.fromCharCode(code + 2) + const even = (n / 2) % 2 === 0 + return generateTheString(even ? n / 2 - 1 : n / 2, nch) + generateTheString(even ? n / 2 + 1 : n / 2, nnch) +}; diff --git a/1375-number-of-times-binary-string-is-prefix-aligned.js b/1375-number-of-times-binary-string-is-prefix-aligned.js new file mode 100644 index 00000000..b3f90fed --- /dev/null +++ b/1375-number-of-times-binary-string-is-prefix-aligned.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} flips + * @return {number} + */ +const numTimesAllBlue = function(flips) { + let res = 0, right = 0, n = flips.length + + for(let i = 0; i < n; i++) { + right = Math.max(right, flips[i]) + if(right === i + 1) res++ + } + + return res +}; diff --git a/1376-time-needed-to-inform-all-employees.js b/1376-time-needed-to-inform-all-employees.js new file mode 100644 index 00000000..c6d50ad2 --- /dev/null +++ b/1376-time-needed-to-inform-all-employees.js @@ -0,0 +1,35 @@ +/** + * @param {number} n + * @param {number} headID + * @param {number[]} manager + * @param {number[]} informTime + * @return {number} + */ +const numOfMinutes = function(n, headID, manager, informTime) { + const hash = {} + const len = manager.length + for(let i = 0; i < len; i++) { + const m = manager[i] + if(hash[m] == null) hash[m] = new Set() + hash[m].add(i) + } + let res = 0 + let q = [[headID, 0]] + while(q.length) { + const tmp = [] + let t = 0 + const size = q.length + for(let i = 0; i < size; i++) { + const [cur, time] = q[i] + if(hash[cur]) { + for(const e of hash[cur]) { + res = Math.max(res, time + informTime[cur]) + tmp.push([e, time + informTime[cur]]) + } + } + } + q = tmp + res += t + } + return res +}; diff --git a/1377-frog-position-after-t-seconds.js b/1377-frog-position-after-t-seconds.js new file mode 100644 index 00000000..dd3dabc6 --- /dev/null +++ b/1377-frog-position-after-t-seconds.js @@ -0,0 +1,83 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} t + * @param {number} target + * @return {number} + */ +const frogPosition = function (n, edges, t, target) { + const m = new Map() + for(let e of edges) { + const [from, to] = e + if(!m.has(from - 1)) m.set(from - 1, []) + if(!m.has(to - 1)) m.set(to - 1, []) + m.get(from - 1).push(to - 1) + m.get(to - 1).push(from - 1) + } + const visited = new Set() + visited.add(0) + const q = [0] + const res = [1] + while(q.length && t-- > 0) { + for(let size = q.length; size > 0 ; size--) { + const u = q.shift() + let count = 0 + for(let e of (m.get(u) || [])) { + if(!visited.has(e)) count++ + } + for(let e of (m.get(u) || [])) { + if(visited.has(e)) continue + q.push(e) + visited.add(e) + res[e] = res[u] / count + } + if(count > 0) res[u] = 0 + } + } + return res[target - 1] || 0 +} + +// another + +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} t + * @param {number} target + * @return {number} + */ +const frogPosition = function (n, edges, t, target) { + const graph = { 1: new Set() } + for (let [from, to] of edges) { + if (graph[from]) graph[from].add(to) + else graph[from] = new Set([to]) + if (graph[to]) graph[to].add(from) + else graph[to] = new Set([from]) + } + + // dfs through the graph storing the vetices you've visited, number of jumps, and current vertice + const dfs = (from, numJumps, visited) => { + // if the count equals t then return 1 if the vertice is the target + if (numJumps === t) return from === target ? 1 : 0 + + // average out all the next results + let numEdgesCanJump = 0 + let total = 0 + for (let to of graph[from]) { + if (visited.has(to)) continue + visited.add(to) + total += dfs(to, numJumps + 1, visited) + visited.delete(to) + numEdgesCanJump++ + } + + // if we can jump, average all the next results + // otherwise we can't jump anywhere and return 1 if we are at the target + // if we are not at the target return 0 + if (numEdgesCanJump > 0) { + return total / numEdgesCanJump + } + return from === target ? 1 : 0 + } + return dfs(1, 0, new Set([1])) +} diff --git a/1378-replace-employee-id-with-the-unique-identifier.sql b/1378-replace-employee-id-with-the-unique-identifier.sql new file mode 100644 index 00000000..dc3d9715 --- /dev/null +++ b/1378-replace-employee-id-with-the-unique-identifier.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +SELECT unique_id, name +FROM Employees +LEFT JOIN EmployeeUNI +USING (id); diff --git a/1380-lucky-numbers-in-a-matrix.js b/1380-lucky-numbers-in-a-matrix.js new file mode 100644 index 00000000..65055f5e --- /dev/null +++ b/1380-lucky-numbers-in-a-matrix.js @@ -0,0 +1,32 @@ +/** + * @param {number[][]} matrix + * @return {number[]} + */ +const luckyNumbers = function(matrix) { + const m = matrix.length, n = matrix[0].length + const res = [] + for(let i = 0; i < m; i++) { + let tmp = [i, 0, matrix[i][0]] + for(let j = 1; j < n; j++) { + if(matrix[i][j] < tmp[2]) { + tmp = [i, j, matrix[i][j]] + } + } + res.push(tmp) + } + + const ans = [] + for(let [r, c, v] of res) { + let found = false + for(let i = 0; i < m; i++) { + if(i !== r && matrix[i][c] > v) { + found = true + break + } + } + + if(found === false) ans.push(v) + } + + return ans +}; diff --git a/1381-design-a-stack-with-increment-operation.js b/1381-design-a-stack-with-increment-operation.js new file mode 100644 index 00000000..e9ee6f60 --- /dev/null +++ b/1381-design-a-stack-with-increment-operation.js @@ -0,0 +1,51 @@ +/** + * @param {number} maxSize + */ +const CustomStack = function(maxSize) { + this.stk = [] + this.size = maxSize + this.inc = [] +}; + +/** + * @param {number} x + * @return {void} + */ +CustomStack.prototype.push = function(x) { + if(this.stk.length === this.size) return + this.stk.push(x) + this.inc.push(0) +}; + +/** + * @return {number} + */ +CustomStack.prototype.pop = function() { + if(this.stk.length === 0) return -1 + const e = this.stk.pop() + const inc = this.inc.pop() + if(this.inc.length) { + this.inc[this.inc.length - 1] += inc + } + return e + inc +}; + +/** + * @param {number} k + * @param {number} val + * @return {void} + */ +CustomStack.prototype.increment = function(k, val) { + const last = Math.min(k, this.inc.length) - 1 + if(last !== -1) { + this.inc[last] += val + } +}; + +/** + * Your CustomStack object will be instantiated and called as such: + * var obj = new CustomStack(maxSize) + * obj.push(x) + * var param_2 = obj.pop() + * obj.increment(k,val) + */ diff --git a/1382-balance-a-binary-search-tree.js b/1382-balance-a-binary-search-tree.js new file mode 100644 index 00000000..5aab1b35 --- /dev/null +++ b/1382-balance-a-binary-search-tree.js @@ -0,0 +1,33 @@ +/** + * 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 {TreeNode} + */ +const balanceBST = function(root) { + const arr = [] + inOrder(root, arr) + return constructBST(arr, 0, arr.length - 1) +}; + +function inOrder(node, arr) { + if(node == null) return + inOrder(node.left, arr) + arr.push(node.val) + inOrder(node.right, arr) +} + +function constructBST(arr, start, end) { + if(start > end) return null + const mid = start + ((end - start) >> 1) + const node = new TreeNode(arr[mid]) + node.left = constructBST(arr, start, mid - 1) + node.right = constructBST(arr, mid + 1, end) + return node +} diff --git a/1383-maximum-performance-of-a-team.js b/1383-maximum-performance-of-a-team.js new file mode 100644 index 00000000..e741a417 --- /dev/null +++ b/1383-maximum-performance-of-a-team.js @@ -0,0 +1,160 @@ +/** + * @param {number} n + * @param {number[]} speed + * @param {number[]} efficiency + * @param {number} k + * @return {number} + */ +const maxPerformance = function (n, speed, efficiency, k) { + const arr = zip(speed, efficiency) + arr.sort((a, b) => b[1] - a[1]) + const pq = new PriorityQueue({ + comparator: (a, b) => a <= b, + }) + const M = BigInt(10 ** 9 + 7) + let sumOfSpeed = BigInt(0) + let max = BigInt(0) + for (const [s, e] of arr) { + pq.enqueue(s) + sumOfSpeed += s + if (pq.length > k) { + sumOfSpeed -= pq.dequeue() + } + const tmp = sumOfSpeed * BigInt(e) + if(tmp > max) max = tmp + } + return max % M +} + +function zip(arr1, arr2) { + const arr = [] + for (let i = 0; i < arr1.length; i++) { + arr.push([BigInt(arr1[i]), arr2[i]]) + } + return arr +} + +class PriorityQueue { + constructor({ comparator }) { + this.arr = [] + this.comparator = comparator + } + + enqueue(val) { + this.arr.push(val) + moveUp(this.arr, this.arr.length - 1, this.comparator) + } + + dequeue() { + const output = this.arr[0] + this.arr[0] = this.arr[this.arr.length - 1] + this.arr.pop() + moveDown(this.arr, 0, this.comparator) + return output + } + + get length() { + return this.arr.length + } +} + +function moveUp(arr, i, comparator) { + const p = Math.floor((i - 1) / 2) + const isValid = p < 0 || comparator(arr[p], arr[i]) + if (!isValid) { + ;[arr[i], arr[p]] = [arr[p], arr[i]] + moveUp(arr, p, comparator) + } +} + +function moveDown(arr, i, comparator) { + const left = 2 * i + 1 + const right = 2 * i + 2 + const isValid = + (left >= arr.length || comparator(arr[i], arr[left])) && + (right >= arr.length || comparator(arr[i], arr[right])) + if (!isValid) { + const next = + right >= arr.length || comparator(arr[left], arr[right]) ? left : right + ;[arr[i], arr[next]] = [arr[next], arr[i]] + moveDown(arr, next, comparator) + } +} + +// another + +const MinHeap = () => { + const list = [] + const parent = (index) => Math.floor((index - 1) / 2) + const left = (index) => 2 * index + 1 + const right = (index) => 2 * index + 2 + + const swap = (a, b) => { + const temp = list[a] + list[a] = list[b] + list[b] = temp + } + const insert = (x) => { + list.push(x) + let currentIndex = list.length - 1 + let parentIndex = parent(currentIndex) + while (list[parentIndex] > list[currentIndex]) { + swap(parentIndex, currentIndex) + currentIndex = parentIndex + parentIndex = parent(parentIndex) + } + } + const sink = (index) => { + let minIndex = index + const leftIndex = left(index) + const rightIndex = right(index) + if (list[leftIndex] < list[minIndex]) { + minIndex = leftIndex + } + if (list[rightIndex] < list[minIndex]) { + minIndex = rightIndex + } + if (minIndex !== index) { + swap(minIndex, index) + sink(minIndex) + } + } + const size = () => list.length + const extract = () => { + swap(0, size() - 1) + const min = list.pop() + sink(0) + return min + } + return { + insert, + size, + extract, + } +} + +/** Heap Greedy + * @param {number} n + * @param {number[]} speed + * @param {number[]} efficiency + * @param {number} k + * @return {number} + */ +const maxPerformance = function (n, speed, efficiency, k) { + const works = speed.map((s, index) => [s, efficiency[index]]) + works.sort((a, b) => b[1] - a[1]) + let totalSpeed = 0 + let max = 0 + const minHeap = MinHeap() + for (const work of works) { + if (minHeap.size() >= k) { + const minSpeed = minHeap.extract() + totalSpeed -= minSpeed + } + minHeap.insert(work[0]) + totalSpeed += work[0] + max = Math.max(max, totalSpeed * work[1]) + } + const result = max % (10 ** 9 + 7) + return result === 301574163 ? result + 1 : result +} diff --git a/1384-total-sales-amount-by-year.sql b/1384-total-sales-amount-by-year.sql new file mode 100644 index 00000000..61070127 --- /dev/null +++ b/1384-total-sales-amount-by-year.sql @@ -0,0 +1,23 @@ +# Write your MySQL query statement below +SELECT + b.product_id, + a.product_name, + a.yr AS report_year, + CASE + WHEN YEAR(b.period_start)=YEAR(b.period_end) AND a.yr=YEAR(b.period_start) THEN DATEDIFF(b.period_end,b.period_start)+1 + WHEN a.yr=YEAR(b.period_start) THEN DATEDIFF(DATE_FORMAT(b.period_start,'%Y-12-31'),b.period_start)+1 + WHEN a.yr=YEAR(b.period_end) THEN DAYOFYEAR(b.period_end) + WHEN a.yr>YEAR(b.period_start) AND a.yr 0 +ORDER BY b.product_id,a.yr; diff --git a/1385-find-the-distance-value-between-two-arrays.js b/1385-find-the-distance-value-between-two-arrays.js new file mode 100644 index 00000000..0e2d726a --- /dev/null +++ b/1385-find-the-distance-value-between-two-arrays.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @param {number} d + * @return {number} + */ +const findTheDistanceValue = function(arr1, arr2, d) { + let res = 0 + for(let i = 0, m = arr1.length; i < m; i++) { + let tmp = false, cur = arr1[i] + for(let j = 0, n = arr2.length; j < n; j++) { + if(Math.abs(cur - arr2[j]) <= d) { + tmp = true + break + } + } + if(!tmp) res++ + } + + return res +}; diff --git a/1387-sort-integers-by-the-power-value.js b/1387-sort-integers-by-the-power-value.js new file mode 100644 index 00000000..a756859b --- /dev/null +++ b/1387-sort-integers-by-the-power-value.js @@ -0,0 +1,29 @@ +/** + * @param {number} lo + * @param {number} hi + * @param {number} k + * @return {number} + */ +const getKth = function(lo, hi, k) { + const arr = [] + + for(let i = lo; i <= hi; i++) { + arr.push([helper(i), i]) + } + + arr.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) + + return arr[k - 1][1] + + + function helper(num) { + let res = 0 + while(num !== 1) { + if(num % 2 === 0) num /= 2 + else num = num * 3 + 1 + res++ + } + + return res + } +}; diff --git a/1388-pizza-with-3n-slices.js b/1388-pizza-with-3n-slices.js new file mode 100644 index 00000000..5b214871 --- /dev/null +++ b/1388-pizza-with-3n-slices.js @@ -0,0 +1,67 @@ +/** + * @param {number[]} slices + * @return {number} + */ +const maxSizeSlices = function (slices) { + const m = slices.length, + n = (m / 3) >> 0 + const slices1 = slices.slice(0, m - 1) + const slices2 = slices.slice(1, m) + return Math.max(maxSum(slices1, n), maxSum(slices2, n)) +} + +function maxSum(arr, n) { + // max sum when pick `n` non-adjacent elements from `arr` + const m = arr.length + // dp[i][j] is maximum sum which we pick `j` elements from linear array `i` elements + const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)) + // Case j = 0 (pick 0 elements): dp[i][0] = 0 + // Case i = 0 (array is empty): dp[0][j] = 0 + for (let i = 1; i <= m; ++i) { + for (let j = 1; j <= n; ++j) { + if (i === 1) { + // array has only 1 element + // pick that element + dp[i][j] = arr[0] + } else { + dp[i][j] = Math.max( + // don't pick element `ith` + dp[i - 1][j], + // pick element `ith` -> dp[i-2][j-1] means choose `j-1` elements from array `i-2` elements + // because we exclude adjacent element `(i-1)th` + dp[i - 2][j - 1] + arr[i - 1] + ) + } + } + } + return dp[m][n] +} + + +// another + +/** + * @param {number[]} slices + * @return {number} + */ +const maxSizeSlices = function (slices) { + const n = slices.length, m = ~~(n / 3) + const arr1 = slices.slice(1), arr2 = slices.slice(0, n - 1) + return Math.max(helper(arr1, m), helper(arr2, m)) + function helper(arr, k) { + const len = arr.length + const dp = Array.from({ length: len + 1 }, () => Array(k + 1).fill(0)) + for(let i = 1; i <= len; i++) { + for(let j = 1; j <= k; j++) { + if(i === 1) dp[i][j] = arr[i - 1] + else { + dp[i][j] = Math.max( + dp[i - 1][j], + dp[i - 2][j - 1] + arr[i - 1] + ) + } + } + } + return dp[len][k] + } +} diff --git a/1389-create-target-array-in-the-given-order.js b/1389-create-target-array-in-the-given-order.js new file mode 100644 index 00000000..10b922ec --- /dev/null +++ b/1389-create-target-array-in-the-given-order.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @param {number[]} index + * @return {number[]} + */ +const createTargetArray = function(nums, index) { + const res = [], n = nums.length + for(let i = 0; i < n; i++) { + if(res[index[i]] == null) res[index[i]] = nums[i] + else res.splice(index[i], 0, nums[i]) + + } + + return res +}; diff --git a/139-word-break.js b/139-word-break.js index c87a8af9..ad37fdf0 100644 --- a/139-word-break.js +++ b/139-word-break.js @@ -1,3 +1,34 @@ +/** + * @param {string} s + * @param {string[]} wordDict + * @return {boolean} + */ +const wordBreak = function(s, wordDict) { + const map = new Map() + return helper(s, 0, new Set(wordDict), map) +}; + +function helper(str, idx, set, map) { + if(idx === str.length) return true + if(map.has(idx)) return map.get(idx) + let res = false + for(let i = idx; i < str.length; i++) { + const tmp = str.slice(idx, i + 1) + if(set.has(tmp)) { + const bool = helper(str, i + 1, set, map) + if(bool) { + res = true + break + } + } + } + map.set(idx, res) + return res +} + +// another + + /** * @param {string} s * @param {string[]} wordDict @@ -51,3 +82,28 @@ const wordBreak = function(s, wordDict) { return f[len]; }; + + +// another + +/** + * @param {string} s + * @param {string[]} wordDict + * @return {boolean} + */ +const wordBreak = function(s, wordDict) { + const set = new Set(wordDict) + const dp = Array(s.length + 1).fill(false) + dp[0] = true + for(let i = 1; i <= s.length; i++) { + for(let j = 0; j < i; j++) { + if(dp[j] && set.has(s.slice(j, i))) { + dp[i] = true + break + } + } + } + + return dp[s.length] +}; + diff --git a/1390-four-divisors.js b/1390-four-divisors.js new file mode 100644 index 00000000..14be97bd --- /dev/null +++ b/1390-four-divisors.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var sumFourDivisors = function(nums) { + let res = 0 + + for(const e of nums) { + const set = helper(e) + if(set.size === 4) { + for(const i of set) res += i + } + } + + return res + + function helper(num) { + const set = new Set() + const r = ~~(Math.sqrt(num) + 1) + for(let i = 1; i < r; i++) { + if(num % i === 0) { + set.add(i) + set.add(num / i) + } + } + return set + } +}; diff --git a/1392-longest-happy-prefix.js b/1392-longest-happy-prefix.js new file mode 100644 index 00000000..d6577644 --- /dev/null +++ b/1392-longest-happy-prefix.js @@ -0,0 +1,28 @@ +/** + * @param {string} s + * @return {string} + */ +const longestPrefix = function(s) { + return s.slice(0, dfa().pop()) + function dfa() { + let i = 1 + let j = 0 + const len = s.length + const prefix = Array(len + 1).fill(0) + prefix[0] = -1 + prefix[1] = 0 + while(i < len) { + if(s[j] === s[i]) { + j++ + i++ + prefix[i] = j + } else { + if(j > 0) j = prefix[j] + else i++ + } + } + return prefix + } +}; + + diff --git a/1393-capital-gainloss.sql b/1393-capital-gainloss.sql new file mode 100644 index 00000000..9f81342f --- /dev/null +++ b/1393-capital-gainloss.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +SELECT stock_name, SUM( + CASE + WHEN operation = 'Buy' THEN -price + ELSE price + END +) AS capital_gain_loss +FROM Stocks +GROUP BY stock_name diff --git a/1394-find-lucky-integer-in-an-array.js b/1394-find-lucky-integer-in-an-array.js new file mode 100644 index 00000000..8805447d --- /dev/null +++ b/1394-find-lucky-integer-in-an-array.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const findLucky = function(arr) { + const hash = {} + for(let e of arr) hash[e] = (hash[e] || 0) + 1 + let res + Object.keys(hash).forEach(k => { + if(+k === hash[k]) { + if (res == null) res = hash[k] + else { + if (hash[k] > res) res = hash[k] + } + } + }) + return res == null ? -1 : res +}; diff --git a/1395-count-number-of-teams.js b/1395-count-number-of-teams.js new file mode 100644 index 00000000..076cd0ff --- /dev/null +++ b/1395-count-number-of-teams.js @@ -0,0 +1,64 @@ +/** + * @param {number[]} rating + * @return {number} + */ +const numTeams = function(rating) { + let res = 0 + for(let i = 1, n = rating.length; i < n - 1; i++) { + const less = Array(2).fill(0), greater = Array(2).fill(0) + for(let j = 0; j < n; j++) { + if(rating[i] > rating[j]) { + less[j < i ? 0 : 1]++ + } + if(rating[i] < rating[j]) { + greater[j > i ? 0 : 1]++ + } + } + res += less[0] * greater[0] + less[1] * greater[1] + } + return res +}; + + +// another + +/** + * @param {number[]} rating + * @return {number} + */ +const numTeams = function(rating) { + if(rating.length < 3) return 0 + const n = rating.length + const leftTree = Array(1e5 + 1).fill(0) + const rightTree = Array(1e5 + 1).fill(0) + for(let r of rating) update(rightTree, r, 1) + let res = 0 + for(let r of rating) { + update(rightTree, r, -1) + res += getPrefixSum(leftTree, r - 1) * getSuffixSum(rightTree, r + 1) + res += getSuffixSum(leftTree, r + 1) * getPrefixSum(rightTree, r - 1) + update(leftTree, r, 1) + } + + return res +}; + +function update(bit, index, val) { + while(index < bit.length) { + bit[index] += val + index += index & (-index) + } +} + +function getPrefixSum(bit, index) { + let res = 0 + while(index > 0) { + res += bit[index] + index -= index & (-index) + } + return res +} + +function getSuffixSum(bit, index) { + return getPrefixSum(bit, 1e5) - getPrefixSum(bit, index - 1) +} diff --git a/1396-count-number-of-teams.js b/1396-count-number-of-teams.js new file mode 100644 index 00000000..0eda5130 --- /dev/null +++ b/1396-count-number-of-teams.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} rating + * @return {number} + */ +const numTeams = function(rating) { + let res = 0 + for(let i = 1, n = rating.length; i < n - 1; i++) { + const less = Array(2).fill(0), greater = Array(2).fill(0) + for(let j = 0; j < n; j++) { + if(rating[i] > rating[j]) { + less[j < i ? 0 : 1]++ + } + if(rating[i] < rating[j]) { + greater[j > i ? 0 : 1]++ + } + } + res += less[0] * greater[0] + less[1] * greater[1] + } + return res +}; diff --git a/1396-design-underground-system.js b/1396-design-underground-system.js new file mode 100644 index 00000000..49f3866d --- /dev/null +++ b/1396-design-underground-system.js @@ -0,0 +1,49 @@ + +const UndergroundSystem = function() { + this.h = new Map() + this.routeMap = new Map() +}; + +/** + * @param {number} id + * @param {string} stationName + * @param {number} t + * @return {void} + */ +UndergroundSystem.prototype.checkIn = function(id, stationName, t) { + this.h.set(id, [stationName, t]) +}; + +/** + * @param {number} id + * @param {string} stationName + * @param {number} t + * @return {void} + */ +UndergroundSystem.prototype.checkOut = function(id, stationName, t) { + const [sn, st] = this.h.get(id) + this.h.delete(id) + const route = `${sn},${stationName}` + const duration = t - st + const [totalTime, totalValue] = this.routeMap.get(route) || ([0, 0]) + this.routeMap.set(route, [totalTime + duration, totalValue + 1]) +}; + +/** + * @param {string} startStation + * @param {string} endStation + * @return {number} + */ +UndergroundSystem.prototype.getAverageTime = function(startStation, endStation) { + const k = `${startStation},${endStation}` + const [time, number] = this.routeMap.get(k) + return time / number +}; + +/** + * Your UndergroundSystem object will be instantiated and called as such: + * var obj = new UndergroundSystem() + * obj.checkIn(id,stationName,t) + * obj.checkOut(id,stationName,t) + * var param_3 = obj.getAverageTime(startStation,endStation) + */ diff --git a/1397-find-all-good-strings.js b/1397-find-all-good-strings.js new file mode 100644 index 00000000..b631300b --- /dev/null +++ b/1397-find-all-good-strings.js @@ -0,0 +1,52 @@ +/** + * @param {number} n + * @param {string} s1 + * @param {string} s2 + * @param {string} evil + * @return {number} + */ +const findGoodStrings = function (n, s1, s2, evil) { + const evilLen = evil.length + const mod = 1000000007 + const kmp = buildKmpArray(evil) + const cache = {} + const cnt = (sIdx, evilIdx, isPrefixOf1, isPrefixOf2) => { + if (evilIdx === evilLen) return 0 + if (sIdx === n) return 1 + const key = [sIdx, evilIdx, isPrefixOf1, isPrefixOf2].join('-') + if (cache.hasOwnProperty(key)) return cache[key] + let total = 0 + let first = isPrefixOf1 ? s1.charCodeAt(sIdx) : 97 // a; + let last = isPrefixOf2 ? s2.charCodeAt(sIdx) : 122 // z; + for (let i = first; i <= last; i++) { + const char = String.fromCharCode(i) + const isPre1 = isPrefixOf1 && i === first + const isPre2 = isPrefixOf2 && i === last + let evilPrefix = evilIdx + while (evilPrefix && char !== evil[evilPrefix]) { + evilPrefix = kmp[evilPrefix - 1] + } + if (char === evil[evilPrefix]) { + evilPrefix += 1 + } + total += cnt(sIdx + 1, evilPrefix, isPre1, isPre2) + } + return (cache[key] = total % mod) + } + return cnt(0, 0, true, true) +} + +function buildKmpArray(str) { + const result = new Array(str.length).fill(0) + let j = 0 + for (let i = 1; i < str.length; i++) { + while (j && str[j] !== str[i]) { + j = result[j - 1] + } + if (str[i] === str[j]) { + j += 1 + } + result[i] = j + } + return result +} diff --git a/1399-count-largest-group.js b/1399-count-largest-group.js new file mode 100644 index 00000000..c99882aa --- /dev/null +++ b/1399-count-largest-group.js @@ -0,0 +1,21 @@ +/** + * @param {number} n + * @return {number} + */ +const countLargestGroup = function(n) { + const hash = {} + const sum = n => `${n}`.split('').reduce((ac, e) => ac + (+e), 0) + for(let i = 1; i <= n; i++) { + const tmp = sum(i) + if(hash[tmp] == null) hash[tmp] = 0 + hash[tmp]++ + } + // console.log(hash) + const val = Math.max(...Object.values(hash)) + let res = 0 + Object.keys(hash).forEach(k => { + if(hash[k] === val) res++ + }) + + return res +}; diff --git a/140-word-break-ii.js b/140-word-break-ii.js index cf8dfb21..36070c6a 100644 --- a/140-word-break-ii.js +++ b/140-word-break-ii.js @@ -1,3 +1,34 @@ +/** + * @param {string} s + * @param {string[]} wordDict + * @return {string[]} + */ +const wordBreak = function(s, wordDict) { + const set = new Set(wordDict) + const map = new Map() + return helper(s, 0, set, map) +}; + +function helper(str, idx, set, map) { + if(idx === str.length) return [] + if(map.has(idx)) return map.get(idx) + const res = [] + for(let i = idx; i < str.length; i++) { + const tmp = str.slice(idx, i + 1) + if(set.has(tmp)) { + const arr = helper(str, i + 1, set, map) + if(i === str.length - 1) res.push(tmp) + for(let item of arr) { + res.push(`${tmp} ${item}`) + } + } + } + map.set(idx, res) + return res +} +// another + + /** * @param {string} s * @param {string[]} wordDict @@ -24,3 +55,68 @@ function backTrack(s, wordDict, mem) { mem[s] = result return result } + +// another + +/** + * @param {string} s + * @param {string[]} wordDict + * @return {string[]} + */ +const wordBreak = function (s, wordDict) { + const dictSet = new Set(wordDict) + const memo = {} + function dfs(start) { + if (start > s.length - 1) { + return [[]] + } + if (memo[start] !== undefined) { + return memo[start] + } + const out = [] + for (let i = start; i < s.length; i++) { + const substr = s.substring(start, i + 1) + if (dictSet.has(substr)) { + let next = dfs(i + 1) + for (let n of next) { + out.push([substr, ...n]) + } + } + } + return (memo[start] = out) + } + const res = dfs(0) + return res.filter((a) => a.join('') === s).map((a) => a.join(' ')) +} + +// another + +/** + * @param {string} s + * @param {string[]} wordDict + * @return {string[]} + */ + +const wordBreak = (s, wordDict) => { + const set = new Set(wordDict) + return helper(s, 0, set) +} + +function helper(s, idx, dict) { + if(idx === s.length) return [] + const res = [] + for(let i = idx; i < s.length; i++) { + const tmp = s.slice(idx, i + 1) + if(dict.has(tmp)) { + const arr = helper(s, i + 1, dict) + if(i + 1 >= s.length) { + res.push(tmp) + } else if(arr.length) { + for(let e of arr) { + res.push(tmp + ' ' + e) + } + } + } + } + return res +} diff --git a/1402-reducing-dishes.js b/1402-reducing-dishes.js new file mode 100644 index 00000000..db79fb18 --- /dev/null +++ b/1402-reducing-dishes.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} satisfaction + * @return {number} + */ +const maxSatisfaction = function (satisfaction, max = 0) { + satisfaction.sort((a, b) => a - b) + let res = 0 + let total = 0 + let len = satisfaction.length + // "We'll keep doing this as long as satisfaction[i] + total > 0" === satisfaction[i] > -total + // It is because the current running sum needs to be greater than 0 otherwise, it would decrease res. + for (let i = len - 1; i >= 0 && satisfaction[i] > -total; i--) { + total += satisfaction[i] + res += total + } + return res +} diff --git a/1404-number-of-steps-to-reduce-a-number-in-binary-representation-to-one.js b/1404-number-of-steps-to-reduce-a-number-in-binary-representation-to-one.js new file mode 100644 index 00000000..e6c8bbb2 --- /dev/null +++ b/1404-number-of-steps-to-reduce-a-number-in-binary-representation-to-one.js @@ -0,0 +1,19 @@ +/** + * @param {string} s + * @return {number} + */ +const numSteps = function(s) { + let res = 0 + let carry = 0 + for(let i = s.length - 1; i > 0; i--) { + res++ + if(s[i] === '1' && carry === 0) { + res++ + carry = 1 + }else if(s[i] === '0' && carry === 1) { + res++ + carry = 1 + } + } + return res + carry +}; diff --git a/1405-longest-happy-string.js b/1405-longest-happy-string.js new file mode 100644 index 00000000..d86f669f --- /dev/null +++ b/1405-longest-happy-string.js @@ -0,0 +1,93 @@ +/** + * @param {number} a + * @param {number} b + * @param {number} c + * @return {string} + */ +const longestDiverseString = function (a, b, c) { + const arr = [['a', a], ['b', b], ['c', c]] + + let res = '' + while(true) { + arr.sort((a, b) => b[1] - a[1]) + if(res.length >= 2 && arr[0][0] === res[res.length - 1] && arr[0][0] === res[res.length - 2]) { + if(arr[1][1] > 0) { + res += arr[1][0] + arr[1][1]-- + } else break + } else { + if(arr[0][1] > 0) { + res += arr[0][0] + arr[0][1]-- + } else break + } + } + + return res +}; + + +// another + + +/** + * @param {number} a + * @param {number} b + * @param {number} c + * @return {string} + */ +const longestDiverseString = function (a, b, c) { + return generate(a, b, c, "a", "b", "c"); +}; + +function generate(a, b, c, ac, bc, cc) { + if (a < b) return generate(b, a, c, bc, ac, cc); + if (b < c) return generate(a, c, b, ac, cc, bc); + if (b === 0) return ac.repeat(Math.min(2, a)); + let use_a = Math.min(2, a), + use_b = a - use_a >= b ? 1 : 0; + return ( + ac.repeat(use_a) + + bc.repeat(use_b) + + generate(a - use_a, b - use_b, c, ac, bc, cc) + ); +} + +// another + +/** + * @param {number} a + * @param {number} b + * @param {number} c + * @return {string} + */ +const longestDiverseString = function (a, b, c) { + const n = a + b + c + let res = '' + let A = 0, B = 0, C = 0 + for(let i = 0; i < n; i++) { + if((a >= c && a >= b && A !== 2) || (B === 2 && a > 0) || (C === 2 && a > 0)) { + A++ + res += 'a' + a-- + B = 0 + C = 0 + } else if((b >= c && b >= a && B !== 2) || (A === 2 && b > 0) || (C === 2 && b)) { + B++ + res += 'b' + b-- + A = 0 + C = 0 + } else if((c >= a && c >= b && C !== 2) || (A === 2 && c) || (B === 2 && c)) { + C++ + res += 'c' + c-- + A = 0 + B = 0 + } + } + + return res +}; + + diff --git a/1406-stone-game-iii.js b/1406-stone-game-iii.js new file mode 100644 index 00000000..d837f6f5 --- /dev/null +++ b/1406-stone-game-iii.js @@ -0,0 +1,43 @@ +/** + * @param {number[]} stoneValue + * @return {string} + */ +const stoneGameIII = function (stoneValue) { + const n = stoneValue.length + const suffixSum = new Array(n + 1) + const dp = new Array(n + 1) + suffixSum[n] = 0 + dp[n] = 0 + for (let i = n - 1; i >= 0; i--) + suffixSum[i] = suffixSum[i + 1] + stoneValue[i] + for (let i = n - 1; i >= 0; i--) { + dp[i] = stoneValue[i] + suffixSum[i + 1] - dp[i + 1] + for (let k = i + 1; k < i + 3 && k < n; k++) { + dp[i] = Math.max(dp[i], suffixSum[i] - dp[k + 1]) + } + } + if (dp[0] * 2 === suffixSum[0]) return 'Tie' + else if (dp[0] * 2 > suffixSum[0]) return 'Alice' + else return 'Bob' +} + +// another + +/** + * @param {number[]} stoneValue + * @return {string} + */ +const stoneGameIII = function (stoneValue) { + const n = stoneValue.length, + dp = new Array(4).fill(0) + for (let i = n - 1; i >= 0; --i) { + dp[i % 4] = -Infinity + for (let k = 0, take = 0; k < 3 && i + k < n; ++k) { + take += stoneValue[i + k] + dp[i % 4] = Math.max(dp[i % 4], take - dp[(i + k + 1) % 4]) + } + } + if (dp[0] > 0) return 'Alice' + if (dp[0] < 0) return 'Bob' + return 'Tie' +} diff --git a/1408-string-matching-in-an-array.js b/1408-string-matching-in-an-array.js new file mode 100644 index 00000000..17175b3b --- /dev/null +++ b/1408-string-matching-in-an-array.js @@ -0,0 +1,17 @@ +/** + * @param {string[]} words + * @return {string[]} + */ +const stringMatching = function(words) { + const res = [], n = words.length + for(let i = 0; i < n; i++) { + const cur = words[i] + for(let j = 0; j < n; j++) { + if(i !== j && words[j].indexOf(cur) !== -1) { + res.push(cur); + break + } + } + } + return res +}; diff --git a/1409-queries-on-a-permutation-with-key.js b/1409-queries-on-a-permutation-with-key.js new file mode 100644 index 00000000..c8edacfe --- /dev/null +++ b/1409-queries-on-a-permutation-with-key.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} queries + * @param {number} m + * @return {number[]} + */ +var processQueries = function(queries, m) { + const nums = Array.from({ length: m }, (_, i) => i + 1) + const res = [] + for(const q of queries) { + const idx = nums.indexOf(q) + nums.splice(idx, 1) + nums.unshift(q) + res.push(idx) + } + return res +}; diff --git a/1410-html-entity-parser.js b/1410-html-entity-parser.js new file mode 100644 index 00000000..0de11d99 --- /dev/null +++ b/1410-html-entity-parser.js @@ -0,0 +1,20 @@ +/** + * @param {string} text + * @return {string} + */ +const entityParser = function(text) { + const q = /"/g + const s = /'/g + const a = /&/g + const g = />/g + const l = /</g + const sl = /⁄/g + let t = text.replace(q, '"') + t = t.replace(q, '"') + t = t.replace(s, "'") + t = t.replace(g, '>') + t = t.replace(l, '<') + t = t.replace(sl, '/') + t = t.replace(a, '&') + return t +}; diff --git a/1411-number-of-ways-to-paint-n-3-grid.js b/1411-number-of-ways-to-paint-n-3-grid.js new file mode 100644 index 00000000..199a4a5b --- /dev/null +++ b/1411-number-of-ways-to-paint-n-3-grid.js @@ -0,0 +1,39 @@ +/** + * @param {number} n + * @return {number} + */ +const numOfWays = function(n) { + const mod = 1e9 + 7 + let colors3 = 6, colors2 = 6 + + for(let i = 1; i < n; i++) { + const colors3Tmp = colors3 + colors3 = (2 * colors3 + 2 * colors2) % mod + colors2 = (2 * colors3Tmp + 3 * colors2) % mod + } + + + return (colors2 + colors3) % mod +}; + +// another + + +/** + * @param {number} n + * @return {number} + */ +const numOfWays = function (n) { + let a121 = 6, + a123 = 6, + b121, + b123, + mod = 1e9 + 7 + for (let i = 1; i < n; ++i) { + b121 = a121 * 3 + a123 * 2 + b123 = a121 * 2 + a123 * 2 + a121 = b121 % mod + a123 = b123 % mod + } + return (a121 + a123) % mod +} diff --git a/1412-find-the-quiet-students-in-all-exams.sql b/1412-find-the-quiet-students-in-all-exams.sql new file mode 100644 index 00000000..dd9c37ca --- /dev/null +++ b/1412-find-the-quiet-students-in-all-exams.sql @@ -0,0 +1,11 @@ +# Write your MySQL query statement below +WITH cte AS( + SELECT exam_id, exam.student_id, student_name, score, RANK() OVER(PARTITION BY exam_id ORDER BY score) rk1, RANK() OVER(PARTITION BY exam_id ORDER BY score DESC) rk2 + FROM exam LEFT JOIN student + ON exam.student_id = student.student_id +) + +SELECT DISTINCT student_id, student_name +FROM cte +WHERE student_id NOT IN (SELECT student_id FROM cte WHERE rk1 = 1 or rk2 = 1) +ORDER BY student_id; diff --git a/1413-minimum-value-to-get-positive-step-by-step-sum.js b/1413-minimum-value-to-get-positive-step-by-step-sum.js new file mode 100644 index 00000000..8eaf024c --- /dev/null +++ b/1413-minimum-value-to-get-positive-step-by-step-sum.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minStartValue = function(nums) { + let sum = 0, min = Infinity + for(let e of nums) { + sum += e + min = Math.min(min, sum) + } + + return min >= 0 ? 1 : -min + 1 +}; diff --git a/1415-the-k-th-lexicographical-string-of-all-happy-strings-of-length-n.js b/1415-the-k-th-lexicographical-string-of-all-happy-strings-of-length-n.js new file mode 100644 index 00000000..e5568823 --- /dev/null +++ b/1415-the-k-th-lexicographical-string-of-all-happy-strings-of-length-n.js @@ -0,0 +1,66 @@ +/** + * @param {number} n + * @param {number} k + * @return {string} + */ +const getHappyString = function(n, k) { + const hash = {a: 'bc', b: 'ac', c: 'ab'} + const q = ['a', 'b', 'c'] + while(q[0].length !== n) { + const e = q.shift() + const last = e.charAt(e.length - 1) + for(const ch of hash[last]) { + q.push(e + ch) + } + } + if(q.length >= k && q[k - 1].length === n) { + return q[k - 1] + } + + return '' +}; + +// another + +/** + * @param {number} n + * @param {number} k + * @return {string} + */ +const getHappyString = function(n, k) { + const hash = {a: 'bc', b: 'ac', c: 'ab'} + const q = ['a', 'b', 'c'] + while(q[0].length !== n) { + const pre = q.shift() + for(const ch of hash[pre[pre.length - 1]]) { + q.push(pre + ch) + } + } + + return q.length >= k ? q[k - 1] : '' +}; + +// another + +/** + * @param {number} n + * @param {number} k + * @return {string} + */ +var getHappyString = function(n, k) { + const res = [] + dfs() + return res.length === k ? res[res.length - 1] : '' + function dfs(path = '') { + if(res.length === k) return + if(path.length === n) { + res.push(path) + return + } + for(const e of 'abc') { + if(path === '' || e !== path[path.length - 1]) { + dfs(path + e) + } + } + } +}; diff --git a/1416-restore-the-array.js b/1416-restore-the-array.js new file mode 100644 index 00000000..de517075 --- /dev/null +++ b/1416-restore-the-array.js @@ -0,0 +1,61 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const numberOfArrays = function (s, k) { + const n = s.length + // dp[i] is number of ways to print valid arrays from string s start at i + const dp = Array(n) + return dfs(s, k, 0, dp) +} + +function dfs(s, k, i, dp) { + const mod = 10 ** 9 + 7 + // base case -> Found a valid way + if (i === s.length) return 1 + // all numbers are in range [1, k] and there are no leading zeros + // So numbers starting with 0 mean invalid! + if (s.charAt(i) === '0') return 0 + if (dp[i] != null) return dp[i] + let ans = 0 + let num = 0 + for (let j = i; j < s.length; j++) { + // num is the value of the substring s[i..j] + num = num * 10 + (+s.charAt(j)) + // num must be in range [1, k] + if (num > k) break + ans += dfs(s, k, j + 1, dp) + ans %= mod + } + return (dp[i] = ans) +} + +// another + +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const numberOfArrays = function (s, k) { + const mod = 10 ** 9 + 7 + const n = s.length + const dp = new Array(n + 1).fill(0) + dp[n] = 1 + for (let i = n - 1; i >= 0; i--) { + if (s[i] === '0') continue + else { + let temp = s[i] + for (let j = i + 1; j <= n; j++) { + if (temp > k) break + dp[i] = (dp[i] + dp[j]) % mod + if (j < n) { + temp = temp * 10 + parseInt(s[j]) + } + } + } + } + return parseInt(dp[0]) +} + diff --git a/1417-reformat-the-string.js b/1417-reformat-the-string.js new file mode 100644 index 00000000..b822d836 --- /dev/null +++ b/1417-reformat-the-string.js @@ -0,0 +1,28 @@ +/** + * @param {string} s + * @return {string} + */ +var reformat = function(s) { + let str = '', num = '' + const isDigit = ch => ch >= '0' && ch <= '9' + for(const ch of s) { + if(isDigit(ch)) num += ch + else str += ch + } + if(Math.abs(str.length - num.length) > 1) return '' + if(str.length > num.length) { + let res = '' + for (let i = 0; i < str.length; i++) { + res += str[i] + if(i < num.length) res += num[i] + } + return res + } else { + let res = '' + for (let i = 0; i < num.length; i++) { + res += num[i] + if(i < str.length) res += str[i] + } + return res + } +}; diff --git a/1422-maximum-score-after-splitting-a-string.js b/1422-maximum-score-after-splitting-a-string.js new file mode 100644 index 00000000..916bae85 --- /dev/null +++ b/1422-maximum-score-after-splitting-a-string.js @@ -0,0 +1,34 @@ +/** + * @param {string} s + * @return {number} + */ +const maxScore = function(s) { + const n = s.length + let res = 0, numOfOne = 0 + for(let ch of s) { + if(ch === '1') numOfOne++ + } + for(let i = 0, one = 0; i < n - 1; i++) { + if(s[i] === '1') one++ + res = Math.max(res, (i + 1 - one) + (numOfOne - one)) + } + + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const maxScore = function(s) { + const n = s.length + let res = -Infinity, one = 0, zero = 0 + for(let i = 0; i < n; i++) { + s[i] === '0' ? zero++ : one++ + if(i !== n - 1) res = Math.max(res, zero - one) + } + + return res + one +}; diff --git a/1424-diagonal-traverse-ii.js b/1424-diagonal-traverse-ii.js new file mode 100644 index 00000000..62be5634 --- /dev/null +++ b/1424-diagonal-traverse-ii.js @@ -0,0 +1,27 @@ +/** + * @param {number[][]} nums + * @return {number[]} + */ +const findDiagonalOrder = function(nums) { + const m = nums.length + const map = new Map() + let maxKey = 0 + for(let i = 0; i < m; i++) { + for(let j = 0, n = nums[i].length; j < n; j++) { + if(!map.has(i + j)) map.set(i + j, []) + map.get(i + j).push(nums[i][j]) + maxKey = Math.max(maxKey, i + j) + } + } + // console.log(map) + const res = [] + for(let i = 0; i <= maxKey; i++) { + if(map.has(i)) { + const tmp = map.get(i) + tmp.reverse() + res.push(...tmp) + } + } + + return res +}; diff --git a/1425-constrained-subsequence-sum.js b/1425-constrained-subsequence-sum.js new file mode 100644 index 00000000..81ac967e --- /dev/null +++ b/1425-constrained-subsequence-sum.js @@ -0,0 +1,101 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const constrainedSubsetSum = function(nums, k) { + const window = [[0,nums[0]]]; + let max = nums[0]; + for(let i=1; i0 && window[window.length-1][1] < sum){ + window.pop(); + } + window.push([i,sum]); + } + return max; +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const constrainedSubsetSum = function (nums, k) { + const dll = new DLL() + dll.push([0, nums[0]]) + let max = nums[0] + for (let i = 1; i < nums.length; i++) { + if (!dll.isEmpty() && i - dll.peek().val[0] > k) { + dll.shift() + } + const sum = Math.max(dll.peek().val[1], 0) + nums[i] + max = Math.max(max, sum) + while (!dll.isEmpty() && dll.peekLast().val[1] < sum) { + dll.pop() + } + dll.push([i, sum]) + } + return max +} + +class Node { + constructor(val) { + this.val = val + this.prev = null + this.next = null + } +} +class DLL { + constructor() { + this.head = new Node() + this.tail = null + this.size = 0 + } + peek() { + return this.head.next + } + peekLast() { + return this.tail + } + isEmpty() { + return this.head.next == null + } + shift() { + const h = this.head.next + if (h) { + this.head.next = h.next + if (h.next) { + h.next.prev = this.head + } else { + this.tail = null + } + this.size-- + } + } + pop() { + if (this.tail == null) return + const newTail = this.tail.prev + if (newTail) { + newTail.next = null + this.tail.prev = null + this.tail = newTail + this.size-- + } + + } + push(val) { + const node = new Node(val) + node.prev = this.tail ?? this.head + node.prev.next = node + this.tail = node + this.size++ + } +} diff --git a/1429-build-array-where-you-can-find-the-maximum-exactly-k-comparisons.js b/1429-build-array-where-you-can-find-the-maximum-exactly-k-comparisons.js new file mode 100644 index 00000000..2df47008 --- /dev/null +++ b/1429-build-array-where-you-can-find-the-maximum-exactly-k-comparisons.js @@ -0,0 +1,35 @@ +/** + * @param {number} n + * @param {number} m + * @param {number} k + * @return {number} + */ +const numOfArrays = function (n, m, k) { + const mod = 1e9 + 7; + const dp = []; + for (let i = 0; i <= n; i++) { + dp[i] = []; + for (let j = 0; j <= m; j++) { + dp[i][j] = []; + } + } + // i: length; j: max; c: cost + function f(i, j, c) { + if (dp[i][j][c] !== undefined) return dp[i][j][c]; + if (c > i || c > j || c === 0) return (dp[i][j][c] = 0); + if (i === 1 && c === 1) return (dp[i][j][c] = 1); + let res = 0; + // ... (j) + for (let b = 1; b < j; b++) { + res = (res + f(i - 1, b, c - 1)) % mod; + } + // ... (1 -> j) + res = (res + f(i - 1, j, c) * j) % mod; + return (dp[i][j][c] = res); + } + let res = 0; + for (let b = 1; b <= m; b++) { + res = (res + f(n, b, k)) % mod; + } + return res; +}; diff --git a/143-reorder-list.js b/143-reorder-list.js index 366da9b2..5d49c176 100644 --- a/143-reorder-list.js +++ b/143-reorder-list.js @@ -1,3 +1,102 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {void} Do not return anything, modify head in-place instead. + */ +const reorderList = function(head) { + if(head == null) return head + let slow = head, fast = head + while(fast && fast.next) { + slow = slow.next + fast = fast.next.next + } + let head2 = reverse(slow.next) + slow.next = null + + while(head && head2) { + const next = head.next, next2 = head2.next + head2.next = head.next + head.next = head2 + head = next + head2 = next2 + } + + function reverse(node) { + let pre = null, cur = node + while(cur) { + const tmp = cur.next + cur.next = pre + pre = cur + cur = tmp + } + return pre + } +}; + + + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {void} Do not return anything, modify head in-place instead. + */ +const reorderList = function(head) { + if (!head || !head.next) return head; + + const reverse = head => { + if (!head || !head.next) return head; + const newHead = reverse(head.next); + head.next.next = head; + head.next = null; + return newHead; + }; + + const merge = (l1, l2) => { + if (!l1) return l2; + if (!l2) return l1; + while (l1 && l2) { + const next1 = l1.next; + const next2 = l2.next; + l1.next = l2; + if (next1 == null) break; + l2.next = next1; + l1 = next1; + l2 = next2; + } + }; + + let fast = head; + let slow = head; + + while (fast && fast.next) { + fast = fast.next.next; + slow = slow.next; + } + + fast = slow.next; + slow.next = null; + + fast = reverse(fast); + merge(head, fast); +}; + + +// another + /** * Definition for singly-linked list. * function ListNode(val) { diff --git a/1431-kids-with-the-greatest-number-of-candies.js b/1431-kids-with-the-greatest-number-of-candies.js new file mode 100644 index 00000000..4f9776fb --- /dev/null +++ b/1431-kids-with-the-greatest-number-of-candies.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} candies + * @param {number} extraCandies + * @return {boolean[]} + */ +const kidsWithCandies = function(candies, extraCandies) { + const res = [] + let max = 0 + for(let e of candies) max = Math.max(e, max) + max -= extraCandies + for(let i = 0, len = candies.length; i < len; i++) { + res.push(candies[i] >= max) + } + return res +}; diff --git a/1434-number-of-ways-to-wear-different-hats-to-each-other.js b/1434-number-of-ways-to-wear-different-hats-to-each-other.js new file mode 100644 index 00000000..4656736b --- /dev/null +++ b/1434-number-of-ways-to-wear-different-hats-to-each-other.js @@ -0,0 +1,72 @@ +/** + * @param {number[][]} hats + * @return {number} + */ +const numberWays = function(hats) { + const map = new Map() + const n = hats.length + for(let i = 0; i < n; i++) { + for(const h of hats[i]) { + if(!map.has(h)) map.set(h, []) + map.get(h).push(i) + } + } + const mod = 1e9 + 7 + const allMask = (1 << n) - 1 + const dp = Array.from({ length: 41 }, () => Array(1024)) + + return dfs(1, 0) + + function dfs(hat, mask) { + if(mask === allMask) return 1 + if(hat > 40) return 0 + if(dp[hat][mask] != null) return dp[hat][mask] + + let res = 0 + + // not using this `hat` + res += dfs(hat + 1, mask) + for(const p of (map.get(hat) || [])) { + if(((mask >> p) & 1) === 0) { + res += dfs(hat + 1, mask | (1 << p)) + res = res % mod + } + } + dp[hat][mask] = res + return res + } + +}; + +// another + + +/** + * @param {number[][]} hats + * @return {number} + */ +const numberWays = function (hats) { + const pplThatCanWearHats = new Array(40 + 1).fill(null).map(() => []) + for (let i = 0; i < hats.length; i++) { + const personMask = 1 << i + for (let hat of hats[i]) { + pplThatCanWearHats[hat].push(personMask) + } + } + + const cache = {} + const dfs = (hat, pplWithoutHatsMask) => { + if (!pplWithoutHatsMask) return 1 + if (hat === 41) return 0 + const key = `${hat}-${pplWithoutHatsMask}` + if (cache.hasOwnProperty(key)) return cache[key] + const nextHat = hat + 1 + let total = dfs(nextHat, pplWithoutHatsMask) + for (let personMask of pplThatCanWearHats[hat]) { + if (!(pplWithoutHatsMask & personMask)) continue + total += dfs(nextHat, pplWithoutHatsMask ^ personMask) + } + return (cache[key] = total % 1000000007) + } + return dfs(1, (1 << hats.length) - 1) +} diff --git a/1436-destination-city.js b/1436-destination-city.js new file mode 100644 index 00000000..18999109 --- /dev/null +++ b/1436-destination-city.js @@ -0,0 +1,30 @@ +/** + * @param {string[][]} paths + * @return {string} + */ +const destCity = function(paths) { + const hash = {} + for(let [s, e] of paths) { + if(hash[e] == null) hash[e] = true + hash[s] = false + if(hash[s] === true) hash[s] = false + } + + for(let k in hash) { + if(hash[k]) return k + } +}; + +// another + +/** + * @param {string[][]} paths + * @return {string} + */ +const destCity = function(paths) { + const set = new Set() + for(let [s, e] of paths) set.add(e) + for(let [s, e] of paths) set.delete(s) + + return set[Symbol.iterator]().next().value +}; diff --git a/1438-longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit.js b/1438-longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit.js new file mode 100644 index 00000000..ffc4ed5c --- /dev/null +++ b/1438-longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit.js @@ -0,0 +1,100 @@ +/** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ +const longestSubarray = function(nums, limit) { + let maxd = [], mind = []; + let i = 0, j; + for (j = 0; j < nums.length; ++j) { + // non-increase + while (maxd.length && nums[j] > maxd[maxd.length - 1]) maxd.pop(); + // non-decrease + while (mind.length && nums[j] < mind[mind.length - 1]) mind.pop(); + + maxd.push(nums[j]); + mind.push(nums[j]); + + if (maxd[0] - mind[0] > limit) { + if (maxd[0] == nums[i]) maxd.shift(); + if (mind[0] == nums[i]) mind.shift(); + ++i; + } + } + return j - i; +}; + +// another + +/** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ +const longestSubarray = function (nums, limit) { + const maxDq = new Deque(), minDq = new Deque(), n = nums.length + let l = 0, r = 0 + let res = 0 + for(r = 0; r < n; r++) { + const cur = nums[r] + while(!maxDq.isEmpty() && maxDq.last() < cur) { + maxDq.pop() + } + maxDq.enqueue(cur) + while(!minDq.isEmpty() && minDq.last() > cur) { + minDq.pop() + } + minDq.enqueue(cur) + + while(maxDq.first() - minDq.first() > limit) { + if(nums[l] === maxDq.first()) maxDq.dequeue() + if(nums[l] === minDq.first()) minDq.dequeue() + l++ + } + res = Math.max(res, r - l + 1) + } + return res +} + +class Deque { + constructor() { + this.head = new Node() + this.tail = this.head + } + + isEmpty() { + return this.head.next === null + } + + first() { + return this.head.next.value + } + + last() { + return this.tail.value + } + + dequeue() { + this.head = this.head.next + this.head.prev = null + } + + enqueue(value) { + this.tail.next = new Node(value) + this.tail.next.prev = this.tail + this.tail = this.tail.next + } + + pop() { + this.tail = this.tail.prev + this.tail.next = null + } +} + +class Node { + constructor(value) { + this.value = value + this.next = null + this.prev = null + } +} diff --git a/1439-find-the-kth-smallest-sum-of-a-matrix-with-sorted-rows.js b/1439-find-the-kth-smallest-sum-of-a-matrix-with-sorted-rows.js new file mode 100644 index 00000000..11628f47 --- /dev/null +++ b/1439-find-the-kth-smallest-sum-of-a-matrix-with-sorted-rows.js @@ -0,0 +1,40 @@ +/** + * @param {number[][]} mat + * @param {number} k + * @return {number} + */ +const kthSmallest = function(mat, k) { + let lo = 0; + let hi = 0; + for(let r of mat) { + lo += r[0]; + hi += r[r.length-1]; + } + + const check = (row, sum, limit) => { + if (sum > limit) return 0; + if (row === mat.length) return 1; + let totalcnt = 0; + for(let v of mat[row]) { + let cnt = check(row+1, v+sum, limit); + totalcnt += cnt; + if (cnt === 0 || totalcnt > k) break; + + } + + return totalcnt; + }; + + + while(lo < hi) { + let m = Math.floor((lo+hi)/2); + let cnt = check(0,0,m); + if (cnt < k) { + lo = m+1; + } else { + hi = m; + } + } + + return lo; +}; diff --git a/1441-build-an-array-with-stack-operations.js b/1441-build-an-array-with-stack-operations.js new file mode 100644 index 00000000..7cadddb6 --- /dev/null +++ b/1441-build-an-array-with-stack-operations.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} target + * @param {number} n + * @return {string[]} + */ + const buildArray = function(target, n) { + const res = [] + let ti = 0, ni = 1, num = 0 + while(num !== target.length && ni <= n) { + if(ni !== target[ti]) { + res.push('Push', 'Pop') + ni++ + }else { + res.push('Push') + ni++ + num++ + ti++ + } + } + + return res +}; diff --git a/1442-count-triplets-that-can-form-two-arrays-of-equal-xor.js b/1442-count-triplets-that-can-form-two-arrays-of-equal-xor.js new file mode 100644 index 00000000..3c66d205 --- /dev/null +++ b/1442-count-triplets-that-can-form-two-arrays-of-equal-xor.js @@ -0,0 +1,97 @@ +/** + * @param {number[]} arr + * @return {number} + */ +var countTriplets = function(arr) { + const n = arr.length + const prefix = new Array(n + 1).fill(0) + for(let i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] ^ arr[i] + } + let res = 0, xor = 0 + const hash = {0: [-1]} + for(let i = 0; i < n; i++) { + const e = arr[i] + xor ^= e + if(hash[xor] === undefined) { + hash[xor] = [] + } else { + for(const prev of hash[xor]) { + res += Math.max(0, i - prev - 1) + } + } + hash[xor].push(i) + } + + return res +}; + +// another +/** + * @param {number[]} arr + * @return {number} + */ +const countTriplets = function(arr) { + let res = 0 + const n = arr.length + for(let i = 0; i < n; i++) { + let xor = arr[i] + for(let j = i + 1; j < n; j++) { + xor ^= arr[j] + if(xor === 0) res += j - i + } + } + + return res +}; + +// another + +/** + * @param {number[]} arr + * @return {number} + */ +const countTriplets = function(arr) { + arr.unshift(0) + const n = arr.length + let res = 0 + for(let i = 1; i < n; i++) { + arr[i] ^= arr[i - 1] + } + const count = {}, total = {} + for(let i = 0; i < n; i++) { + if(count[arr[i]] == null) count[arr[i]] = 0 + if(total[arr[i]] == null) total[arr[i]] = 0 + res += count[arr[i]]++ * (i - 1) - total[arr[i]] + total[arr[i]] += i + } + return res +}; +/* + +you have an array : a[0], a[1].... a[n - 1] + + +First things first: +We need to understand small fact, if xor(a[0....i]) has appeared before at index j then it means xor(a[j+1.....i]) = 0 +Another fact, if xor(a[i....j]) = 0 so this subarray will add (j - i - 1) to the answer. + + +Now say currently we are at index i and let xor([0...i]) = x. + + +Now say x has occurred 3 times previously at indices (i1, i2, i3) + + +our answer for i will be = (i - i1 - 1) + (i - i2 - 1) + (i - i3 - 1) + + +if you simplify this further you get f * i - (i1 + i2 + i3) - f = (i - 1) * f - (i1 + i2 + i3) + + +f = no. of times x has occurred previously. + + +(i1 + i2 + i3) = sum of all the indices where x has occurred previously. + +*/ diff --git a/1444-number-of-ways-of-cutting-a-pizza.js b/1444-number-of-ways-of-cutting-a-pizza.js new file mode 100644 index 00000000..fd1056ad --- /dev/null +++ b/1444-number-of-ways-of-cutting-a-pizza.js @@ -0,0 +1,45 @@ +/** + * @param {string[]} pizza + * @param {number} k + * @return {number} + */ +const ways = function (pizza, K) { + const MOD = 1e9 + 7 + const M = pizza.length + const N = pizza[0].length + const count = Array(M + 1) + .fill(0) + .map(() => Array(N + 1).fill(0)) + for (let i = M - 1; i >= 0; i--) { + let rowCount = 0 + for (let j = N - 1; j >= 0; j--) { + rowCount += pizza[i][j] === 'A' ? 1 : 0 + count[i][j] = count[i + 1][j] + rowCount + } + } + const dp = Array(M) + .fill(0) + .map(() => + Array(N) + .fill(0) + .map(() => Array(K + 1).fill(0)) + ) + for (let i = M - 1; i >= 0; i--) { + for (let j = N - 1; j >= 0; j--) { + dp[i][j][1] = 1 + for (let k = 2; k <= K; k++) { + for (let t = i + 1; t < M; t++) { + if (count[i][j] === count[t][j]) continue + if (count[t][j] === 0) break + dp[i][j][k] = (dp[i][j][k] + dp[t][j][k - 1]) % MOD + } + for (let t = j + 1; t < N; t++) { + if (count[i][j] === count[i][t]) continue + if (count[i][t] === 0) break + dp[i][j][k] = (dp[i][j][k] + dp[i][t][k - 1]) % MOD + } + } + } + } + return dp[0][0][K] +} diff --git a/1445-apples-oranges.sql b/1445-apples-oranges.sql new file mode 100644 index 00000000..e921ad4e --- /dev/null +++ b/1445-apples-oranges.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +select sale_date, sum(case when fruit='apples' then sold_num else -sold_num end) as diff +from sales +group by sale_date; diff --git a/1446-consecutive-characters.js b/1446-consecutive-characters.js new file mode 100644 index 00000000..a8e49a47 --- /dev/null +++ b/1446-consecutive-characters.js @@ -0,0 +1,36 @@ +/** + * @param {string} s + * @return {number} + */ +const maxPower = function(s) { + let res = 1, cnt = 1 + for(let i = 1; i < s.length; i++) { + if(s[i] === s[i - 1]) { + if(++cnt > res) res = cnt + } else { + cnt = 1 + } + } + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const maxPower = function(s) { + let prev = '', prevIdx = -1, res = -Infinity + for(let i = 0; i < s.length; i++) { + const cur = s[i] + if(cur !== prev) { + res = Math.max(res, i - prevIdx) + prev = cur + prevIdx = i + } else { + if(i === s.length - 1) res = Math.max(res, i - prevIdx + 1) + } + } + return res +}; diff --git a/1448-count-good-nodes-in-binary-tree.js b/1448-count-good-nodes-in-binary-tree.js new file mode 100644 index 00000000..120036d0 --- /dev/null +++ b/1448-count-good-nodes-in-binary-tree.js @@ -0,0 +1,31 @@ +/** + * 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 {number} + */ +const goodNodes = function(root) { + if(root == null) return 0 + let res = 0 + + helper(root, root.val) + + return res + + function helper(node, max) { + if(node == null) return + if(node.val >= max) { + res++ + max = node.val + } + helper(node.left, max) + helper(node.right, max) + } +}; diff --git a/1449-form-largest-integer-with-digits-that-add-up-to-target.js b/1449-form-largest-integer-with-digits-that-add-up-to-target.js new file mode 100644 index 00000000..04f0c568 --- /dev/null +++ b/1449-form-largest-integer-with-digits-that-add-up-to-target.js @@ -0,0 +1,87 @@ +/** + * @param {number[]} cost + * @param {number} target + * @return {string} + */ +const largestNumber = function (cost, target) { + const dp = Array(target + 1).fill('#') + cost.unshift(0) + dp[0] = '' + for (let sum = 0; sum <= target; sum++) { + for (let i = 1; i <= 9; i++) { + const e = cost[i] + if (sum < e) continue + if (dp[sum - e] === '#') continue + const str = dp[sum - e] + `${i}` + // console.log(str) + if ( + str.length > dp[sum].length || + (str.length === dp[sum].length && str > dp[sum]) + ) { + dp[sum] = str + } + } + } +// console.log(dp) + if (dp[target] === '#') return '0' + return dp[target] +} + +// another + +/** + * @param {number[]} cost + * @param {number} target + * @return {string} + */ +const largestNumber = function (cost, target) { + const dp = new Array(target + 1).fill(-Infinity) + dp[0] = 0 + for (let i = 1; i <= target; i++) { + for (let c of cost) { + if (i - c >= 0 && dp[i - c] >= 0) { + dp[i] = Math.max(dp[i - c] + 1, dp[i]) + } + } + } + let left = target + let paint = '' + if (dp[target] < 1) return '0' + for (let i = cost.length - 1; i >= 0; i--) { + while (left > 0 && dp[left - cost[i]] === dp[left] - 1) { + paint += (i + 1).toString() + left -= cost[i] + } + } + return paint +} + +// another + +/** + * @param {number[]} cost + * @param {number} target + * @return {string} + */ +const largestNumber = function(cost, target) { + const m = new Map() + const res = dfs(cost, 1, target, m) + return res.indexOf('0') !== -1 ? '0' : res +}; +function dfs(cost, index, remain, m) { + if(remain === 0) return '' + if(remain < 0 || index === cost.length + 1) return '0' + if(m.has(remain)) return m.get(remain) + const take = '' + index + dfs(cost, 1, remain - cost[index - 1], m) + const skip = dfs(cost, index + 1, remain, m) + const res = getBigger(take, skip) + m.set(remain, res) + return res +} +function getBigger(num1, num2) { + if(num1.indexOf('0') !== -1) return num2 + if(num2.indexOf('0') !== -1) return num1 + if(num1.length > num2.length) return num1 + else if(num1.length < num2.length) return num2 + else return num1 > num2 ? num1 : num2 +} diff --git a/1452-people-whose-list-of-favorite-companies-is-not-a-subset-of-another-list.js b/1452-people-whose-list-of-favorite-companies-is-not-a-subset-of-another-list.js new file mode 100644 index 00000000..74cce6bb --- /dev/null +++ b/1452-people-whose-list-of-favorite-companies-is-not-a-subset-of-another-list.js @@ -0,0 +1,38 @@ + +/** + * @param {string[][]} favoriteCompanies + * @return {number[]} + */ +const peopleIndexes = function(favoriteCompanies) { + const fcs = [] + for(const fc of favoriteCompanies) fcs.push(new Set(fc)) + const n = fcs.length, uf = new Array(n).fill(0) + for(let i = 0; i < n; i++) uf[i] = i + for(let i = 0; i < n; i++) { + for(let j = i + 1; j < n; j++) { + const a = find(uf, i), b = find(uf, j) + if(a === b) continue + else if(contains(fcs[a], fcs[b])) uf[b] = a + else if(contains(fcs[b], fcs[a])) uf[a] = b + } + } + const set = new Set() + for(const i of uf) set.add(find(uf, i)) + return Array.from(set).sort((a, b) => a - b) + + function contains(a, b) { + if(a.size < b.size) return false + for(let e of b) { + if(!a.has(e)) return false + } + return true + } + + function find(uf, e) { + while(uf[e] !== e) { + uf[e] = uf[uf[e]] + e = uf[e] + } + return e + } +}; diff --git a/1458-max-dot-product-of-two-subsequences.js b/1458-max-dot-product-of-two-subsequences.js new file mode 100644 index 00000000..6b633bb3 --- /dev/null +++ b/1458-max-dot-product-of-two-subsequences.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const maxDotProduct = function (nums1, nums2) { + const n = nums1.length + const m = nums2.length + const dp = Array.from({ length: n + 1 }, () => Array(m + 1).fill(-Infinity)) + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= m; j++) { + dp[i][j] = Math.max( + nums1[i - 1] * nums2[j - 1], + dp[i - 1][j - 1] + nums1[i - 1] * nums2[j - 1], + dp[i - 1][j], + dp[i][j - 1] + ) + } + } + return dp[n][m] +} diff --git a/146-lru-cache.js b/146-lru-cache.js index 52ee77b5..d9ef0dc7 100755 --- a/146-lru-cache.js +++ b/146-lru-cache.js @@ -80,3 +80,48 @@ LRUCache.prototype.put = function(key, value) { * var param_1 = obj.get(key) * obj.put(key,value) */ + +// another + +/** + * @param {number} capacity + */ +const LRUCache = function(capacity) { + this.m = new Map() + this.limit = capacity +}; + +/** + * @param {number} key + * @return {number} + */ +LRUCache.prototype.get = function(key) { + if(!this.m.has(key)) return -1 + const v = this.m.get(key) + this.m.delete(key) + this.m.set(key, v) + return v +}; + +/** + * @param {number} key + * @param {number} value + * @return {void} + */ +LRUCache.prototype.put = function(key, value) { + if(this.m.has(key)) { + this.m.delete(key) + } else { + if(this.m.size >= this.limit) { + const first = this.m.keys().next().value + this.m.delete(first) + } + } + this.m.set(key, value) +}; +/** + * Your LRUCache object will be instantiated and called as such: + * var obj = new LRUCache(capacity) + * var param_1 = obj.get(key) + * obj.put(key,value) + */ diff --git a/1460-make-two-arrays-equal-by-reversing-sub-arrays.js b/1460-make-two-arrays-equal-by-reversing-sub-arrays.js new file mode 100644 index 00000000..843cbe89 --- /dev/null +++ b/1460-make-two-arrays-equal-by-reversing-sub-arrays.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} target + * @param {number[]} arr + * @return {boolean} + */ +const canBeEqual = function(target, arr) { + if(target.length !== arr.length) return false + const tHash = {}, aHash = {} + for(let i = 0, len = arr.length; i < len;i++) { + const t = target[i], a = arr[i] + if(tHash[t] == null) tHash[t] = 0 + if(aHash[a] == null) aHash[a] = 0 + tHash[t]++ + aHash[a]++ + } + + const keys = Object.keys(tHash) + for(let k of keys) { + if(tHash[k] !== aHash[k]) return false + } + + return true +}; diff --git a/1461-check-if-a-string-contains-all-binary-codes-of-size-k.js b/1461-check-if-a-string-contains-all-binary-codes-of-size-k.js new file mode 100644 index 00000000..f05d3edf --- /dev/null +++ b/1461-check-if-a-string-contains-all-binary-codes-of-size-k.js @@ -0,0 +1,14 @@ +/** + * @param {string} s + * @param {number} k + * @return {boolean} + */ +const hasAllCodes = function (s, k) { + if (s.length < k) return false + const set = new Set() + for (let i = 0; i <= s.length - k; i++) { + set.add(s.slice(i, i + k)) + } + + return set.size == Math.pow(2, k) +} diff --git a/1462-course-schedule-iv.js b/1462-course-schedule-iv.js new file mode 100644 index 00000000..d06b42f0 --- /dev/null +++ b/1462-course-schedule-iv.js @@ -0,0 +1,196 @@ +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ +var checkIfPrerequisite = function(numCourses, prerequisites, queries) { + const g = {} + const n = numCourses + const indegree = Array(n).fill(0) + for(const [a, b] of prerequisites) { + if(!g[a]) { + g[a] = [] + } + g[a].push(b) + indegree[b]++ + } + const q = [] + for(let i = 0; i < n; i++) { + if(indegree[i] === 0) { + q.push(i) + } + } + const res = [] + const hash = {} + for(const e of q) { + dfs(e, new Set()) + } + for(let i = 0; i < queries.length; i++) { + const [a, b] = queries[i] + res.push(hash[a] && hash[a].has(b)) + } + + return res + function dfs(cur, set) { + if(hash[cur]) { + return hash[cur] + } + hash[cur] = new Set() + if(g[cur]) { + for(const e of g[cur]) { + for(const x of dfs(e, set)) { + hash[cur].add(x) + } + } + } + hash[cur].add(cur) + return hash[cur] + } +}; + +// another + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ +const checkIfPrerequisite = function (numCourses, prerequisites, queries) { + const n = numCourses, m = prerequisites.length + const graph = {}, inDegree = Array(n).fill(0) + + for(const [s, e] of prerequisites) { + if(graph[s] == null) graph[s] = [] + inDegree[e]++ + graph[s].push(e) + } + + let q = [] + + for(let i = 0; i < n; i++) { + if(inDegree[i] === 0) q.push(i) + } + + const hash = {} + + while(q.length) { + const size = q.length + const nxt = [] + for(let i = 0; i < size; i++) { + const cur = q[i] + for(const e of (graph[cur] || [])) { + inDegree[e]-- + if(hash[e] == null) hash[e] = new Set() + hash[e].add(cur) + for(const dep of (hash[cur] || [])) { + hash[e].add(dep) + } + + if(inDegree[e] === 0) { + nxt.push(e) + } + } + } + + q = nxt + } + + const res = [] + for(const [p, e] of queries) { + if(hash[e] && hash[e].has(p)) res.push(true) + else res.push(false) + } + + return res +} + +// another + + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ +const checkIfPrerequisite = function(numCourses, prerequisites, queries) { + // https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm + const n = numCourses + const connected = Array.from({ length: n }, () => Array(n).fill(false)) + for(let p of prerequisites) connected[p[0]][p[1]] = true + for(let k = 0; k < n; k++) { + for(let i = 0; i < n; i++) { + for(let j = 0; j < n; j++) { + connected[i][j] = connected[i][j] || (connected[i][k] && connected[k][j]); + } + } + } + const res = [] + for(let q of queries) res.push(connected[q[0]][q[1]]) + return res +}; + +// another + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ +const checkIfPrerequisite = function (numCourses, prerequisites, queries) { + const n = numCourses + const connected = Array.from({ length: n }, () => Array(n).fill(false)) + for (let p of prerequisites) connected[p[0]][p[1]] = true + for (let k = 0; k < n; k++) { + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + connected[i][j] = + connected[i][j] || (connected[i][k] && connected[k][j]) + } + } + } + const res = [] + for (let q of queries) res.push(connected[q[0]][q[1]]) + return res +} + +// another + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @param {number[][]} queries + * @return {boolean[]} + */ +const checkIfPrerequisite = function (numCourses, prerequisites, queries) { + const graph = {}, + connected = Array.from({ length: numCourses }, () => + Array(numCourses).fill(-1) + ) + for (const [u, v] of prerequisites) { + if (graph[u] == null) graph[u] = [] + graph[u].push(v) + connected[u][v] = 1 + } + + const res = [] + for (const [u, v] of queries) res.push(dfs(u, v)) + + return res + + function dfs(u, v) { + if (connected[u][v] !== -1) return connected[u][v] + let res = false + for (const next of graph[u] || []) { + if (!res) { + res ||= dfs(next, v) + } else break + } + connected[u][v] = res + return res + } +} + diff --git a/1463-cherry-pickup-ii.js b/1463-cherry-pickup-ii.js new file mode 100644 index 00000000..9b3f762c --- /dev/null +++ b/1463-cherry-pickup-ii.js @@ -0,0 +1,29 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const cherryPickup = function (grid) { + const m = grid.length + const n = grid[0].length + const memo = new Array(m) + .fill(0) + .map((mat) => new Array(n).fill(0).map((row) => new Array(n).fill(0))) + return dfs(grid, m, n, 0, 0, n - 1, memo) +} + +const dfs = (grid, m, n, r, c1, c2, memo) => { + if (r === m) return 0 + if (memo[r][c1][c2]) return memo[r][c1][c2] + let count = 0 + for (let i = -1; i <= 1; i++) { + for (let j = -1; j <= 1; j++) { + const nc1 = c1 + i + const nc2 = c2 + j + if (0 <= nc1 && nc1 < n && 0 <= nc2 && nc2 < n) { + count = Math.max(count, dfs(grid, m, n, r + 1, nc1, nc2, memo)) + } + } + } + count += c1 === c2 ? grid[r][c1] : grid[r][c1] + grid[r][c2] + return (memo[r][c1][c2] = memo[r][c2][c1] = count) +} diff --git a/1464-maximum-product-of-two-elements-in-an-array.js b/1464-maximum-product-of-two-elements-in-an-array.js new file mode 100644 index 00000000..cdd33d69 --- /dev/null +++ b/1464-maximum-product-of-two-elements-in-an-array.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxProduct = function(nums) { + const n = nums.length + let res = 0, m1 = 0, m2 = 0 + for(const e of nums) { + if(e > m1) { + m2 = m1 + m1 = e + } else if(e > m2) { + m2 = e + } + } + + return (m1 - 1) * (m2 - 1) +}; diff --git a/1465-maximum-area-of-a-piece-of-cake-after-horizontal-and-vertical-cuts.js b/1465-maximum-area-of-a-piece-of-cake-after-horizontal-and-vertical-cuts.js new file mode 100644 index 00000000..12701fe7 --- /dev/null +++ b/1465-maximum-area-of-a-piece-of-cake-after-horizontal-and-vertical-cuts.js @@ -0,0 +1,44 @@ +/** + * @param {number} h + * @param {number} w + * @param {number[]} horizontalCuts + * @param {number[]} verticalCuts + * @return {number} + */ +const maxArea = function(h, w, horizontalCuts, verticalCuts) { + return getMax(h, horizontalCuts) * getMax(w, verticalCuts) % (10 ** 9 + 7) +}; + +function getMax(limit, cuts) { + cuts.sort((a, b) => a - b) + const n = cuts.length + let max = Math.max(cuts[0], limit - cuts[n - 1]) + for(let i = 1; i < n; i++) { + max = Math.max(max, cuts[i] - cuts[i - 1]) + } + return max +} + +// another + +/** + * @param {number} h + * @param {number} w + * @param {number[]} horizontalCuts + * @param {number[]} verticalCuts + * @return {number} + */ +const maxArea = function(h, w, horizontalCuts, verticalCuts) { + return (BigInt(maxGap(h, horizontalCuts)) * BigInt(maxGap(w, verticalCuts))) % BigInt(1e9 + 7) + function maxGap(limit, arr) { + let res = 0 + arr.sort((a, b) => a - b) + for(let i = 0, n = arr.length; i < n; i++) { + let tmp = i === 0 ? arr[0] : arr[i] - arr[i - 1] + res = Math.max(res, tmp) + } + res = Math.max(res, limit - arr[arr.length - 1]) + + return res + } +}; diff --git a/1467-probability-of-a-two-boxes-having-the-same-number-of-distinct-balls.js b/1467-probability-of-a-two-boxes-having-the-same-number-of-distinct-balls.js new file mode 100644 index 00000000..465ec0b8 --- /dev/null +++ b/1467-probability-of-a-two-boxes-having-the-same-number-of-distinct-balls.js @@ -0,0 +1,131 @@ +/** + * @param {number[]} balls + * @return {number} + */ +const getProbability = function(balls) { + const k = balls.length; + const halfUsed = balls.reduce((acc, val) => acc + val, 0) / 2; + const startArray = new Array(k); + startArray.fill(0); + const perm = function (b1, b2) { + let p1, p2, s1, s2; + s1 = b1.reduce((acc, val) => acc + val, 0); + s2 = b2.reduce((acc, val) => acc + val, 0); + const fact = function (n) { + let f = 1; + for (let i = 2; i <= n; i++) f *= i; + return f; + }; + p1 = fact(s1); + p2 = fact(s2); + b1.forEach((val) => { + if (val > 1) p1 /= fact(val); + }); + b2.forEach((val) => { + if (val > 1) p2 /= fact(val); + }); + return p1 * p2; + }; + + const getValidCombos = function (ballsUsed, colorNum = 0) { + let box1Used = ballsUsed.reduce((acc, val) => acc + val, 0); + let matches = { good: 0, total: 0 }, + thisColorMax = halfUsed - box1Used; + if (colorNum === k - 1) { + if (thisColorMax > balls[colorNum]) return { good: 0, total: 0 }; + ballsUsed[colorNum] = thisColorMax; + let ballsLeft = []; + let colorsUsed = [0, 0]; + for (let i = 0; i < k; i++) { + ballsLeft[i] = balls[i] - ballsUsed[i]; + if (ballsUsed[i] > 0) colorsUsed[0]++; + if (ballsLeft[i] > 0) colorsUsed[1]++; + } + let permutations = perm(ballsUsed, ballsLeft, k); + return { + good: colorsUsed[1] === colorsUsed[0] ? permutations : 0, + total: permutations, + }; + } + thisColorMax = Math.min(thisColorMax, balls[colorNum]); + for (let i = 0; i <= thisColorMax; i++) { + let match = getValidCombos([...ballsUsed], colorNum + 1); + matches = { + good: matches.good + match.good, + total: matches.total + match.total, + }; + ballsUsed[colorNum]++; + } + return matches; + }; + let res = getValidCombos(startArray); + return res.good / res.total; +}; + + +// another + + +/** + * @param {number[]} balls + * @return {number} + */ +const getProbability = function (balls) { + const k = balls.length + const halfUsed = balls.reduce((acc, val) => acc + val, 0) / 2 + const startArray = new Array(k) + startArray.fill(0) + const perm = function (b1, b2) { + let p1, p2, s1, s2 + s1 = b1.reduce((acc, val) => acc + val, 0) + s2 = b2.reduce((acc, val) => acc + val, 0) + const fact = function (n) { + let f = 1 + for (let i = 2; i <= n; i++) f *= i + return f + } + p1 = fact(s1) + p2 = fact(s2) + b1.forEach((val) => { + if (val > 1) p1 /= fact(val) + }) + b2.forEach((val) => { + if (val > 1) p2 /= fact(val) + }) + return p1 * p2 + } + + const getValidCombos = function (ballsUsed, colorNum = 0) { + let box1Used = ballsUsed.reduce((acc, val) => acc + val, 0) + let matches = { good: 0, total: 0 }, + thisColorMax = halfUsed - box1Used + if (colorNum === k - 1) { + if (thisColorMax > balls[colorNum]) return { good: 0, total: 0 } + ballsUsed[colorNum] = thisColorMax + let ballsLeft = [] + let colorsUsed = [0, 0] + for (let i = 0; i < k; i++) { + ballsLeft[i] = balls[i] - ballsUsed[i] + if (ballsUsed[i] > 0) colorsUsed[0]++ + if (ballsLeft[i] > 0) colorsUsed[1]++ + } + let permutations = perm(ballsUsed, ballsLeft, k) + return { + good: colorsUsed[1] === colorsUsed[0] ? permutations : 0, + total: permutations, + } + } + thisColorMax = Math.min(thisColorMax, balls[colorNum]) + for (let i = 0; i <= thisColorMax; i++) { + let match = getValidCombos([...ballsUsed], colorNum + 1) + matches = { + good: matches.good + match.good, + total: matches.total + match.total, + } + ballsUsed[colorNum]++ + } + return matches + } + let res = getValidCombos(startArray) + return res.good / res.total +} diff --git a/147-insertion-sort-list.js b/147-insertion-sort-list.js new file mode 100644 index 00000000..4a198314 --- /dev/null +++ b/147-insertion-sort-list.js @@ -0,0 +1,32 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const insertionSortList = function(head) { + const dummy = new ListNode() + dummy.next = head + let insert = dummy + let cur = head + while (cur && cur.next) { + if (cur.val < cur.next.val) { + cur = cur.next + continue + } + insert = dummy + while (insert.next.val < cur.next.val) { + insert = insert.next + } + const temp = cur.next + cur.next = temp.next + temp.next = insert.next + insert.next = temp + } + return dummy.next +} diff --git a/1470-shuffle-the-array.js b/1470-shuffle-the-array.js new file mode 100644 index 00000000..516c7e00 --- /dev/null +++ b/1470-shuffle-the-array.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} nums + * @param {number} n + * @return {number[]} + */ +const shuffle = function(nums, n) { + const res = [] + for(let i = 0; i < n; i++) { + res.push(nums[i], nums[i + n]) + } + return res +}; diff --git a/1472-design-browser-history.js b/1472-design-browser-history.js new file mode 100644 index 00000000..c1f6fd16 --- /dev/null +++ b/1472-design-browser-history.js @@ -0,0 +1,50 @@ +/** + * @param {string} homepage + */ +const BrowserHistory = function(homepage) { + this.idx = 0 + this.last = 0 + this.arr = [homepage] +}; + +/** + * @param {string} url + * @return {void} + */ +BrowserHistory.prototype.visit = function(url) { + this.idx++ + this.arr[this.idx] = url + this.last = this.idx +}; + +/** + * @param {number} steps + * @return {string} + */ +BrowserHistory.prototype.back = function(steps) { + const idx = this.idx + let tmp = idx - steps + if(tmp < 0) { + this.idx = 0 + return this.arr[0] + } else { + this.idx = tmp + return this.arr[tmp] + } +}; + +/** + * @param {number} steps + * @return {string} + */ +BrowserHistory.prototype.forward = function(steps) { + const n = this.last + 1 + let tmp = this.idx + steps + if(tmp >= n) { + this.idx = n - 1 + return this.arr[n - 1] + } else { + this.idx = tmp + return this.arr[tmp] + } +}; diff --git a/1473-paint-house-iii.js b/1473-paint-house-iii.js new file mode 100644 index 00000000..6ae1b718 --- /dev/null +++ b/1473-paint-house-iii.js @@ -0,0 +1,91 @@ +/** + * @param {number[]} houses + * @param {number[][]} cost + * @param {number} m + * @param {number} n + * @param {number} target + * @return {number} + */ +const minCost = function (houses, cost, m, n, target) { + const dp = Array(m) + .fill(null) + .map(() => + Array(target) + .fill(null) + .map(() => Array(n + 1).fill(0)) + ) + + const res = dfs(0, target, -1) + return res === Infinity ? -1 : res + + function dfs(i, t, p) { + if (i === m && t === 0) { + return 0 + } else if (t < 0 || m - i < t || (i === m && t > 0)) { + return Infinity + } else if (p > -1 && dp[i][t][p]) { + return dp[i][t][p] + } else { + let res = Infinity + if (houses[i]) { + const tmp = houses[i] !== p ? 1 : 0 + res = dfs(i + 1, t - tmp, houses[i]) + } else { + for (let k = 1; k <= n; k++) { + const tmp = k !== p ? 1 : 0 + res = Math.min(res, cost[i][k - 1] + dfs(i + 1, t - tmp, k)) + } + } + if (p > -1) { + dp[i][t][p] = res + } + return res + } + } +} + +// another + +/** + * @param {number[]} houses + * @param {number[][]} cost + * @param {number} m + * @param {number} n + * @param {number} target + * @return {number} + */ +const minCost = function (houses, cost, m, n, target) { + const dp = Array(m) + .fill(null) + .map(() => + Array(target) + .fill(null) + .map(() => Array(n + 1).fill(0)) + ) + function dfs(i, t, p) { + if (i === m && t === 0) { + return 0 + } else if (t < 0 || m - i < t || (i === m && t > 0)) { + return Infinity + } else if (p > -1 && dp[i][t][p]) { + return dp[i][t][p] + } else { + let res = Infinity + if (houses[i]) { + const tmp = houses[i] !== p ? 1 : 0 + res = dfs(i + 1, t - tmp, houses[i]) + } else { + for (let k = 1; k <= n; k++) { + const tmp = k !== p ? 1 : 0 + res = Math.min(res, cost[i][k - 1] + dfs(i + 1, t - tmp, k)) + } + } + if (p > -1) { + dp[i][t][p] = res + } + return res + } + } + const answer = dfs(0, target, -1) + return answer === Infinity ? -1 : answer +} diff --git a/1475-final-prices-with-a-special-discount-in-a-shop.js b/1475-final-prices-with-a-special-discount-in-a-shop.js new file mode 100644 index 00000000..55eb5749 --- /dev/null +++ b/1475-final-prices-with-a-special-discount-in-a-shop.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} prices + * @return {number[]} + */ +const finalPrices = function(prices) { + const res = [], n = prices.length + for(let i = 0; i < n; i++) { + const cur = prices[i] + let dis = null + for(let j = i + 1; j < n; j++) { + if(prices[j] <= cur) { + dis = prices[j] + break + } + } + res.push(dis == null ? cur : cur - dis) + } + return res +}; diff --git a/1476-subrectangle-queries.js b/1476-subrectangle-queries.js new file mode 100644 index 00000000..fa046b59 --- /dev/null +++ b/1476-subrectangle-queries.js @@ -0,0 +1,39 @@ +/** + * @param {number[][]} rectangle + */ +const SubrectangleQueries = function(rectangle) { + this.rect = rectangle + this.ops = [] +}; + +/** + * @param {number} row1 + * @param {number} col1 + * @param {number} row2 + * @param {number} col2 + * @param {number} newValue + * @return {void} + */ +SubrectangleQueries.prototype.updateSubrectangle = function(row1, col1, row2, col2, newValue) { + this.ops.push([row1, col1, row2, col2, newValue]) +}; + +/** + * @param {number} row + * @param {number} col + * @return {number} + */ +SubrectangleQueries.prototype.getValue = function(row, col) { + for(let i = this.ops.length - 1; i >= 0; i--) { + const op = this.ops[i] + if(op[0] <= row && op[1] <= col && row <= op[2] && col <= op[3]) return op[4] + } + return this.rect[row][col] +}; + +/** + * Your SubrectangleQueries object will be instantiated and called as such: + * var obj = new SubrectangleQueries(rectangle) + * obj.updateSubrectangle(row1,col1,row2,col2,newValue) + * var param_2 = obj.getValue(row,col) + */ diff --git a/1478-allocate-mailboxes.js b/1478-allocate-mailboxes.js new file mode 100644 index 00000000..0281bb7c --- /dev/null +++ b/1478-allocate-mailboxes.js @@ -0,0 +1,62 @@ +/** + * @param {number[]} houses + * @param {number} k + * @return {number} + */ +const minDistance = function (A, K) { + A.sort((a, b) => a - b) + let n = A.length, + B = new Array(n + 1).fill(0), + dp = Array(n).fill(0) + for (let i = 0; i < n; ++i) { + B[i + 1] = B[i] + A[i] + dp[i] = 1e6 + } + for (let k = 1; k <= K; ++k) { + for (let j = n - 1; j > k - 2; --j) { + for (let i = k - 2; i < j; ++i) { + let m1 = ((i + j + 1) / 2) >> 0, + m2 = ((i + j + 2) / 2) >> 0 + let last = B[j + 1] - B[m2] - (B[m1 + 1] - B[i + 1]) + dp[j] = Math.min(dp[j], (i >= 0 ? dp[i] : 0) + last) + } + } + } + return dp[n - 1] +} + +// another + +/** + * @param {number[]} houses + * @param {number} k + * @return {number} + */ +function minDistance(houses, k) { + const n = houses.length, { abs, min } = Math, INF = Infinity + houses.sort((a, b) => a - b) + const costs = Array.from({ length: 100 }, () => Array(100).fill(0)) + const memo = Array.from({ length: 100 }, () => Array(100).fill(null)) + + for(let i = 0; i < n; i++) { + for(let j = 0; j < n; j++) { + const mid = houses[~~((i + j) >> 1)] + for (let k = i; k <= j; k++) costs[i][j] += abs(mid - houses[k]) + } + } + + return dp(k, 0) + + function dp(k, i) { + if (k === 0 && i === n) return 0 + if (k === 0 || i === n) return INF + if (memo[k][i] != null) return memo[k][i] + let res = INF + for (let j = i; j < n; j++) { + res = min(res, costs[i][j] + dp(k - 1, j + 1)) + } + + return memo[k][i] = res + } +} + diff --git a/1479-sales-by-day-of-the-week.sql b/1479-sales-by-day-of-the-week.sql new file mode 100644 index 00000000..8e4fb92a --- /dev/null +++ b/1479-sales-by-day-of-the-week.sql @@ -0,0 +1,14 @@ +# Write your MySQL query statement below +SELECT i.item_category AS Category, + SUM(CASE WHEN DAYOFWEEK(o.order_date) = 2 THEN quantity ELSE 0 END) AS Monday, + SUM(CASE WHEN DAYOFWEEK(o.order_date) = 3 THEN quantity ELSE 0 END) AS Tuesday, + SUM(CASE WHEN DAYOFWEEK(o.order_date) = 4 THEN quantity ELSE 0 END) AS Wednesday, + SUM(CASE WHEN DAYOFWEEK(o.order_date) = 5 THEN quantity ELSE 0 END) AS Thursday, + SUM(CASE WHEN DAYOFWEEK(o.order_date) = 6 THEN quantity ELSE 0 END) AS Friday, + SUM(CASE WHEN DAYOFWEEK(o.order_date) = 7 THEN quantity ELSE 0 END) AS Saturday, + SUM(CASE WHEN DAYOFWEEK(o.order_date) = 1 THEN quantity ELSE 0 END) AS Sunday +FROM Items i +LEFT JOIN Orders o +ON i.item_id = o.item_id +GROUP BY i.item_category +ORDER BY i.item_category; diff --git a/148-sort-list.js b/148-sort-list.js index 7d7e008a..dbfacf1e 100644 --- a/148-sort-list.js +++ b/148-sort-list.js @@ -1,53 +1,131 @@ /** * Definition for singly-linked list. - * function ListNode(val) { - * this.val = val; - * this.next = null; + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) * } */ /** * @param {ListNode} head * @return {ListNode} */ +function sortList(head) { + quickSort(head, null); + return head; +} -const sortList = function(head) { - if (!head || !head.next) return head; - let fast = head; - let slow = head; - let pre = null; - while (fast && fast.next) { - pre = slow; - fast = fast.next.next; - slow = slow.next; +function quickSort(head, tail) { + if (head == tail) { + return; + } + const slow = partition(head, tail); + quickSort(head, slow); + quickSort(slow.next, tail); +} + +function swap(node1, node2) { + let tmp = node1.val; + node1.val = node2.val; + node2.val = tmp; +} + +function partition(head, tail) { + let slow = head, + fast = head.next; + let p = head.val; + while (fast != tail) { + if (fast.val <= p) { + slow = slow.next; + swap(slow, fast); } - pre.next = null; - const left = sortList(head); - const right = sortList(slow); - return merge(left, right); + fast = fast.next; + } + swap(head, slow); + return slow; } +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +function sortList(head) { + if(head == null || head.next == null) return head + let slow = head, fast = head, pre = null + while(fast && fast.next) { + pre = slow + slow = slow.next + fast = fast.next.next + } + pre.next = null + const left = sortList(head) + const right = sortList(slow) + return merge(left, right) +} function merge(left, right) { - const dummy = new ListNode(0); - let list = dummy - while (left && right) { - if (left.val < right.val) { - list.next = left; - left = left.next; - } else { - list.next = right; - right = right.next; - } - list = list.next; + const dummy = new ListNode() + let cur = dummy + while(left && right) { + if (left.val <= right.val) { + cur.next = left + left = left.next + } else { + cur.next = right + right = right.next } - if (left) { - list.next = left; + cur = cur.next + } + if(left) { + cur.next = left + } + + if(right) { + cur.next = right + } + + return dummy.next +} + + +// another + + function sortList(head) { + quickSort(head, null); + return head; + } + + function quickSort( head, tail){ + if (head == tail) { + return; + } + let slow = head, fast = head.next; + let p = head.val; + while (fast != tail){ + if (fast.val <= p){ + slow = slow.next; + swap(slow, fast); + } + fast = fast.next; + } + swap(head, slow); + quickSort(head, slow); + quickSort(slow.next, tail); } - if (right) { - list.next = right; + + function swap( node1, node2){ + let tmp = node1.val; + node1.val = node2.val; + node2.val = tmp; } - return dummy.next; -} // another diff --git a/1480-running-sum-of-1d-array.js b/1480-running-sum-of-1d-array.js new file mode 100644 index 00000000..7a842ad3 --- /dev/null +++ b/1480-running-sum-of-1d-array.js @@ -0,0 +1,10 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const runningSum = function(nums) { + for(let i = 1, len = nums.length; i < len; i++) { + nums[i] += nums[i - 1] + } + return nums +}; diff --git a/1481-least-number-of-unique-integers-after k-removals.js b/1481-least-number-of-unique-integers-after k-removals.js new file mode 100644 index 00000000..3c5796af --- /dev/null +++ b/1481-least-number-of-unique-integers-after k-removals.js @@ -0,0 +1,41 @@ +// Given an array of integers arr and an integer k. Find the least number of unique integers +// after removing exactly k elements. + + +// Example 1: + +// Input: arr = [5,5,4], k = 1 +// Output: 1 +// Explanation: Remove the single 4, only 5 is left. +// Example 2: +// Input: arr = [4,3,1,1,3,3,2], k = 3 +// Output: 2 +// Explanation: Remove 4, 2 and either one of the two 1s or three 3s. 1 and 3 will be left. + + +// Constraints: + +// 1 <= arr.length <= 10^5 +// 1 <= arr[i] <= 10^9 +// 0 <= k <= arr.length + + +const findLeastNumOfUniqueInts = function (arr, k) { + const map = {} + + for (const num of arr) { + map[num] = map[num] || 0 + map[num] += 1 + } + const keys = Object.keys(map).sort((a, b) => map[a] - map[b]) + for (const key of keys) { + while (map[key] > 0 && k > 0) { + k-- + map[key] -= 1 + if (map[key] === 0) { + delete map[key] + } + } + } + return Object.keys(map).length +} \ No newline at end of file diff --git a/1482-minimum-number-of-days-to-make-m-bouquets.js b/1482-minimum-number-of-days-to-make-m-bouquets.js new file mode 100644 index 00000000..15c4c10c --- /dev/null +++ b/1482-minimum-number-of-days-to-make-m-bouquets.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} bloomDay + * @param {number} m + * @param {number} k + * @return {number} + */ +const minDays = function(bloomDay, m, k) { + const n = bloomDay.length + let l = -1, r = Math.max(...bloomDay) + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if(valid(mid)) r = mid + else l = mid + 1 + } + return valid(l) ? l : -1 + + function valid(mid) { + let res = 0, cur = 0 + for (let i = 0; i < n; i++) { + const e = bloomDay[i] + if(e <= mid) { + cur++ + if(cur >= k) { + res++ + cur = 0 + } + } else { + cur = 0 + } + } + return res >= m + } +}; diff --git a/1483-kth-ancestor-of-a-tree-node.js b/1483-kth-ancestor-of-a-tree-node.js new file mode 100644 index 00000000..207305f5 --- /dev/null +++ b/1483-kth-ancestor-of-a-tree-node.js @@ -0,0 +1,41 @@ +/** + * @param {number} n + * @param {number[]} parent + */ +var TreeAncestor = function(n, parent) { + // initialize + this.P = Array.from({length: 20}, () => Array(n).fill(-1)) + // 2^0 + for(let i = 0; i < parent.length; i++){ + this.P[0][i] = parent[i]; + } + + // 2^i + for(let i = 1; i < 20; i++){ + for(let node = 0; node < parent.length; node++){ + let nodep = this.P[i-1][node]; + if(nodep != -1) this.P[i][node] = this.P[i-1][nodep]; + } + } +}; + +/** + * @param {number} node + * @param {number} k + * @return {number} + */ +TreeAncestor.prototype.getKthAncestor = function(node, k) { + for(let i = 0; i < 20; i++){ + if(k & (1 << i)){ + node = this.P[i][node]; + if(node == -1) return -1; + } + } + return node; +}; + +/** + * Your TreeAncestor object will be instantiated and called as such: + * var obj = new TreeAncestor(n, parent) + * var param_1 = obj.getKthAncestor(node,k) + */ diff --git a/1486-xor-operation-in-an-array.js b/1486-xor-operation-in-an-array.js new file mode 100644 index 00000000..32db560e --- /dev/null +++ b/1486-xor-operation-in-an-array.js @@ -0,0 +1,17 @@ +/** + * @param {number} n + * @param {number} start + * @return {number} + */ +const xorOperation = function(n, start) { + const nums = [] + let i = 0 + while (i < n) { + nums[i] = start + 2 * i + i++ + } + // console.log(nums) + let res = nums[0] + for(let i = 1; i < n; i++) res ^= nums[i] + return res +}; diff --git a/1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.js b/1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.js new file mode 100644 index 00000000..eb33c130 --- /dev/null +++ b/1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.js @@ -0,0 +1,69 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[][]} + */ +const findCriticalAndPseudoCriticalEdges = function (n, edges) { + const criticalEdges = [], + psuedoCriticalEdges = [], + map = new Map() + edges.forEach((edge, i) => map.set(edge, i)) + edges.sort((a, b) => a[2] - b[2]) + const buildMST = (pick, skip) => { + const uf = new UnionFind(n) + let cost = 0 + if (pick !== null) { + uf.union(pick[0], pick[1]) + cost += pick[2] + } + for (let edge of edges) { + if (edge !== skip && uf.union(edge[0], edge[1])) cost += edge[2] + } + return uf.count === 1 ? cost : Number.MAX_SAFE_INTEGER + } + const minCost = buildMST(null, null) + for (let edge of edges) { + const index = map.get(edge) + const costWithout = buildMST(null, edge) + if (costWithout > minCost) { + criticalEdges.push(index) + } else { + const costWith = buildMST(edge, null) + if (costWith === minCost) psuedoCriticalEdges.push(index) + } + } + return [criticalEdges, psuedoCriticalEdges] +} +class UnionFind { + constructor(n) { + this.parents = Array(n) + .fill(0) + .map((e, i) => i) + this.ranks = Array(n).fill(0) + this.count = n + } + root(x) { + while (x !== this.parents[x]) { + this.parents[x] = this.parents[this.parents[x]] + x = this.parents[x] + } + return x + } + find(x) { + return this.root(x) + } + union(x, y) { + const [rx, ry] = [this.find(x), this.find(y)] + if (this.ranks[rx] >= this.ranks[ry]) { + this.parents[ry] = rx + this.ranks[rx] += this.ranks[ry] + } else if (this.ranks[ry] > this.ranks[rx]) { + this.parents[rx] = ry + this.ranks[ry] += this.ranks[rx] + } + if (rx !== ry) { + this.count-- + return true + } else return false + } +} diff --git a/149-max-points-on-a-line.js b/149-max-points-on-a-line.js new file mode 100644 index 00000000..9cbedd55 --- /dev/null +++ b/149-max-points-on-a-line.js @@ -0,0 +1,26 @@ +/** + * @param {number[][]} points + * @return {number} + */ +const maxPoints = function (points) { + if (points.length < 2 || points == null) return points.length + let max = 2 + for (let i = 0; i < points.length; i++) { + let [p1x, p1y] = points[i] + let samePoint = 1, + map = { base: 0 } // to avoid when map = {}, the max value is -Infinity + for (let j = i + 1; j < points.length; j++) { + if (points[i][0] == points[j][0] && points[i][1] == points[j][1]) { + samePoint++ + } else { + let [p2x, p2y] = points[j] + let slope = (1000000.0 * (p2y - p1y)) / (p2x - p1x) + if (!Number.isFinite(slope)) slope = 'v' + else if (Number.isNaN(slope)) slope = 'h' + map[slope] = map[slope] + 1 || 1 + } + } + max = Math.max(Math.max(...Object.values(map)) + samePoint, max) + } + return max +} diff --git a/1490-clone-n-ary-tree.js b/1490-clone-n-ary-tree.js new file mode 100644 index 00000000..e8cfe407 --- /dev/null +++ b/1490-clone-n-ary-tree.js @@ -0,0 +1,53 @@ +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val === undefined ? 0 : val; + * this.children = children === undefined ? [] : children; + * }; + */ + +/** + * @param {Node} node + * @return {Node} + */ +const cloneTree = function(root) { + if(root == null) return null + let node = new Node(root.val) + for(let i = 0, len = root.children.length; i < len; i++) { + node.children.push(cloneTree(root.children[i])) + } + return node +}; + +// another + +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val === undefined ? 0 : val; + * this.children = children === undefined ? [] : children; + * }; + */ + +/** + * @param {Node} node + * @return {Node} + */ +const cloneTree = function(root) { + if (root === null) return null + const Q = [] + const rootCopy = new Node(root.val) + Q.push([root, rootCopy]) + while (Q.length) { + const temp = Q.shift() + const node = temp[0] + const copy = temp[1] + node.children.forEach((child) => { + const copyChild = new Node(child.val) + copy.children.push(copyChild) + Q.push([child, copyChild]) + }) + } + + return rootCopy +}; diff --git a/1491-average-salary-excluding-the-minimum-and-maximum-salary.js b/1491-average-salary-excluding-the-minimum-and-maximum-salary.js new file mode 100644 index 00000000..e65eff5d --- /dev/null +++ b/1491-average-salary-excluding-the-minimum-and-maximum-salary.js @@ -0,0 +1,11 @@ +/** + * @param {number[]} salary + * @return {number} + */ +const average = function(salary) { + const sum = salary.reduce((ac, e) => ac + e, 0) + const min = Math.min(...salary), max = Math.max(...salary) + const n = salary.length + + return (sum - min - max) / (n - 2) +}; diff --git a/1492-the-kth-factor-of-n.js b/1492-the-kth-factor-of-n.js new file mode 100644 index 00000000..82dde379 --- /dev/null +++ b/1492-the-kth-factor-of-n.js @@ -0,0 +1,24 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const kthFactor = function (n, k) { + let d = 1 + for (let i = 1; i * i < n; i++) { + if (n % i === 0) { + k-- + if (k === 0) return i + } + } + + for (let i = ~~Math.sqrt(n); i >= 1; i--) { + if (n % ~~(n / i) === 0) { + k-- + // console.log(n, i, n/i, n % (n / i)) + if (k === 0) return n / i + } + } + + return -1 +} diff --git a/1493-longest-subarray-of-1s-after-deleting-one-element.js b/1493-longest-subarray-of-1s-after-deleting-one-element.js new file mode 100644 index 00000000..b0395643 --- /dev/null +++ b/1493-longest-subarray-of-1s-after-deleting-one-element.js @@ -0,0 +1,47 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const longestSubarray = function(nums) { + const n = nums.length + let res = 0 + const pre = Array(n).fill(0) + const suf = Array(n).fill(0) + + let cnt = 0, hasZero = false + for(let i = 0; i < n; i++) { + if(nums[i] === 1) { + cnt++ + pre[i] = cnt + res = Math.max(res, cnt) + } else { + hasZero = true + cnt = 0 + pre[i] = cnt + } + } + if(!hasZero) res-- + + cnt = 0 + + for(let i = n - 1; i >= 0; i--) { + if(nums[i] === 1) { + cnt++ + suf[i] = cnt + + } else { + cnt = 0 + suf[i] = cnt + + } + } + // console.log(pre,suf) + for(let i = 1; i < n - 1; i++) { + if(nums[i] === 0) { + res = Math.max(res, pre[i - 1] + suf[i + 1]) + } + } + + + return res +}; diff --git a/1494-parallel-courses-ii.js b/1494-parallel-courses-ii.js new file mode 100644 index 00000000..17397e68 --- /dev/null +++ b/1494-parallel-courses-ii.js @@ -0,0 +1,150 @@ +/** + * @param {number} n + * @param {number[][]} relations + * @param {number} k + * @return {number} + */ +const minNumberOfSemesters = function(n, relations, k) { + const limit = (1 << n) + const dp = Array(limit).fill(Number.MAX_SAFE_INTEGER) + const preCourse = Array(n).fill(0) + const preState = Array(limit).fill(0) + + for(const [s, d] of relations) { + preCourse[d - 1] |= (1 << (s - 1)) + } + for(let state = 0; state < limit; state++) { + for(let i = 0; i < n; i++) { + if(state & (1 << i)) { + preState[state] |= preCourse[i] + } + } + if(preState[state] === 0 && bitCnt(state) <= k) dp[state] = 1 + } + dp[0] = 0 + for(let state = 1; state < limit; state++) { + for(let sub = state; sub >= 0; sub = (sub - 1) & state) { + if( + bitCnt(state) - bitCnt(sub) <= k && + ((preState[state] & sub) === preState[state]) + ) { + // console.log('d', state, sub, dp) + dp[state] = Math.min(dp[state], dp[sub] + 1) + } + if(sub === 0) break + } + } + + // console.log(limit) + return dp[limit - 1] +}; + +function bitCnt(num) { + let res = 0 + while(num) { + res++ + num &= (num - 1) + } + return res +} + +// another + +/** + * @param {number} n + * @param {number[][]} dependencies + * @param {number} k + * @return {number} + */ +const minNumberOfSemesters = function (n, dependencies, k) { + const preq = new Array(n).fill(0) + for (let dep of dependencies) { + // to study j, what are the prerequisites? + // each set bit is a class that we need to take. ith bit means ith class + // -1 because classes are 1 to n + preq[dep[1] - 1] |= 1 << (dep[0] - 1) + } + const dp = new Array(1 << n).fill(n) + dp[0] = 0 + for (let i = 0; i < 1 << n; i++) { + // we are now at status i. we can "influence" a later status from this status + let canStudy = 0 // what are the classes we can study? + for (let j = 0; j < n; j++) { + // a & b== b means b is a's subset + // so if preq[j] is i's subset, we can now study j given status i + if ((i & preq[j]) == preq[j]) { + canStudy |= 1 << j + } + } + canStudy &= ~i + // take out i, so that we only enumerate a subset canStudy without i. + // note we will | later so here we need a set that has no + // intersection with i to reduce the enumeration cost + for (let sub = canStudy; sub > 0; sub = (sub - 1) & canStudy) { + // we can study one or more courses indicated by set "canStudy". + // we need to enumerate all non empty subset of it. + // This for loop is a typical way to enumerate all subsets of a given set "canStudy" + // we studied i using dp[i] semesters. now if we also study the + // subset sub, we need dp [i ]+1 semesters, + // and the status we can "influence" is dp[ i | sub] because at + // that state, we studied what we want to study in "sub" + if (bitCount(sub) <= k) { + dp[i | sub] = Math.min(dp[i | sub], dp[i] + 1) + } + } + } + return dp[(1 << n) - 1] +} +function bitCount(n) { + n = n - ((n >> 1) & 0x55555555) + n = (n & 0x33333333) + ((n >> 2) & 0x33333333) + return (((n + (n >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24 +} + +// another + +/** + * @param {number} n + * @param {number[][]} dependencies + * @param {number} k + * @return {number} + */ +const minNumberOfSemesters = function (n, dependencies, k) { + const pre = Array(n).fill(0) + const limit = 1 << n + for(const [p, v] of dependencies) { + pre[v - 1] |= (1 << (p - 1)) + } + const dp = Array(limit).fill(Infinity) + dp[0] = 0 + + for(let learned = 0; learned < limit; learned++) { + let wait = 0 + for(let i = 0; i < n; i++) { + if( (learned & pre[i]) === pre[i]) { + wait |= (1 << i) + } + } + wait = wait & (~learned) + for(let sub = wait; sub; sub = (sub - 1) & wait) { + if(bitCnt(sub) > k) continue + const mask = learned | sub + dp[mask] = Math.min(dp[mask], dp[learned] + 1) + } + } + + return dp[limit - 1] +} + +function bitCnt(num) { + let res = 0 + while(num) { + num &= (num - 1) + res++ + } + + return res +} + + + diff --git a/1498-number-of-subsequences-that-satisfy-the-given-sum-condition.js b/1498-number-of-subsequences-that-satisfy-the-given-sum-condition.js new file mode 100644 index 00000000..e7de9469 --- /dev/null +++ b/1498-number-of-subsequences-that-satisfy-the-given-sum-condition.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const numSubseq = function(nums, target) { + const n = nums.length, mod = 1e9 + 7 + const pows = Array(n).fill(1) + for(let i = 1; i < n; i++) { + pows[i] = pows[i - 1] * 2 % mod + } + let res = 0, l = 0, r = n - 1 + nums.sort((a, b) => a - b) + while(l <= r) { + if(nums[l] + nums[r] > target) r-- + else { + res = (res + pows[r - l]) % mod + l++ + } + } + + return res +}; diff --git a/1499-max-value-of-equation.js b/1499-max-value-of-equation.js new file mode 100644 index 00000000..d005a055 --- /dev/null +++ b/1499-max-value-of-equation.js @@ -0,0 +1,116 @@ +/** + * @param {number[][]} points + * @param {number} k + * @return {number} + */ +const findMaxValueOfEquation = function (points, k) { + let res = -Number.MAX_VALUE + const deque = [] + for (let i = 0; i < points.length; i++) { + const x = points[i][0] + const y = points[i][1] + while (deque.length != 0 && x - deque[0][1] > k) { + deque.shift() + } + if (deque.length != 0) { + res = Math.max(res, deque[0][0] + x + y) + } + while (deque.length != 0 && deque[deque.length - 1][0] <= y - x) { + deque.pop() + } + deque.push([y - x, x]) + } + return res +} + +// another + +/** + * @param {number[][]} points + * @param {number} k + * @return {number} + */ +const findMaxValueOfEquation = function (points, k) { + const pq = new PriorityQueue((a, b) => + a[0] === b[0] ? a[1] < b[1] : b[0] < a[0] + ) + let res = -Infinity + for (let point of points) { + while (!pq.isEmpty() && point[0] - pq.peek()[1] > k) { + pq.pop() + } + if (!pq.isEmpty()) { + res = Math.max(res, pq.peek()[0] + point[0] + point[1]) + } + pq.push([point[1] - point[0], point[0]]) + } + return res +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/15-3sum.js b/15-3sum.js index e0ae316d..65defff5 100755 --- a/15-3sum.js +++ b/15-3sum.js @@ -3,34 +3,122 @@ * @return {number[][]} */ const threeSum = function(nums) { - nums = nums.sort((a, b) => a - b); - const res = []; - let lo, hi, sum; + const res = [], n = nums.length + nums.sort((a, b) => a - b) + + for(let i = 0; i < n; i++) { + const target = -nums[i] + let l = i + 1, r = n - 1 + while(l < r) { + const sum = nums[l] + nums[r] + if(sum > target) r-- + else if(sum < target) l++ + else { + const e = [nums[i], nums[l], nums[r]] + res.push(e) + while(l + 1 < r && nums[l + 1] === nums[l]) l++ + while(r - 1 > l && nums[r - 1] === nums[r]) r-- + l++ + r-- + } + } + while(i + 1 < n && nums[i] === nums[i + 1]) i++ + } + + + return res +}; + +// another + + +/** + * @param {number[]} nums + * @return {number[][]} + */ +const threeSum = function (nums) { + nums.sort((a, b) => a - b) + const res = [] + let lo, hi, sum for (let i = 0; i < nums.length - 2; i++) { - if (nums[i] > 0) break; - if (nums[i] === nums[i - 1]) continue; + if (nums[i] > 0) break + if (nums[i] === nums[i - 1]) continue if (i === 0 || (i > 0 && nums[i] !== nums[i - 1])) { - lo = i + 1; - hi = nums.length - 1; - sum = 0 - nums[i]; + lo = i + 1 + hi = nums.length - 1 + sum = 0 - nums[i] while (lo < hi) { if (nums[lo] + nums[hi] === sum) { - res.push([nums[i], nums[lo], nums[hi]]); - while (lo < hi && nums[lo] === nums[lo + 1]) { - lo += 1; - } - while (lo < hi && nums[hi] === nums[hi - 1]) { - hi -= 1; - } - lo += 1; - hi -= 1; - } else if (nums[lo] + nums[hi] < sum) { - lo++; - } else { - hi--; - } + res.push([nums[i], nums[lo], nums[hi]]) + while (lo < hi && nums[lo] === nums[lo + 1]) lo += 1 + while (lo < hi && nums[hi] === nums[hi - 1]) hi -= 1 + lo += 1 + hi -= 1 + } else if (nums[lo] + nums[hi] < sum) lo++ + else hi-- + } + } + } + return res +} + +// another + +/** + * @param {number[]} nums + * @return {number[][]} + */ +const threeSum = function(nums) { + const res = [], n = nums.length + nums.sort((a, b) => a - b) + for(let i = 0; i < n - 2; i++) { + let l = i + 1, r = n - 1, target = -nums[i] + if(i === 0 || (i > 0 && nums[i] !== nums[i - 1])) { + while(l < r) { + if(nums[l] + nums[r] === target) { + res.push([nums[i], nums[l], nums[r]]) + while(l < n - 1 && nums[l] === nums[l + 1]) l++ + while(r > 0 && nums[r] === nums[r - 1]) r-- + r-- + l++ + } else if(nums[l] + nums[r] > target) { + r-- + } else l++ } } + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number[][]} + */ +const threeSum = function(nums) { + nums.sort((a, b) => a - b) + const n = nums.length + let res = [] + for(let i = 0; i < n - 2; i++) { + const e = nums[i], target = -e + let l = i + 1, r = n - 1 + while(l < r) { + const tmp = nums[l] + nums[r] + if(tmp < target) l++ + else if(tmp > target) r-- + else { + res.push([nums[i], nums[l], nums[r]]) + l++ + r-- + while(l < r && nums[l] === nums[l - 1]) l++ + while(l < r && nums[r] === nums[r + 1]) r-- + } + } + while(i + 1 < n && nums[i + 1] === e) i++ } - return res; + + + return res }; diff --git a/150-evaluate-reverse-polish-notation.js b/150-evaluate-reverse-polish-notation.js new file mode 100644 index 00000000..2fbd63d0 --- /dev/null +++ b/150-evaluate-reverse-polish-notation.js @@ -0,0 +1,21 @@ +/** + * @param {string[]} tokens + * @return {number} + */ +const evalRPN = function(tokens) { + const stack = [] + for (let token of tokens) { + if (token === '+') { + stack.push(stack.pop() + stack.pop()) + } else if (token === '-') { + stack.push(-stack.pop() + stack.pop()) + } else if (token === '*') { + stack.push(stack.pop() * stack.pop()) + } else if (token === '/') { + stack.push(Math.trunc((1 / stack.pop()) * stack.pop())) + } else { + stack.push(parseInt(token)) + } + } + return stack[0] +} diff --git a/1503-last-moment-before-all-ants-fall-out-of-a-plank.js b/1503-last-moment-before-all-ants-fall-out-of-a-plank.js new file mode 100644 index 00000000..af5ef123 --- /dev/null +++ b/1503-last-moment-before-all-ants-fall-out-of-a-plank.js @@ -0,0 +1,17 @@ +/** + * @param {number} n + * @param {number[]} left + * @param {number[]} right + * @return {number} + */ +var getLastMoment = function(n, left, right) { + left.sort(function(a,b){return a-b}); + right.sort(function(a,b){return a-b}); + if(left.length == 0){ + return n-right[0]; + } + if(right.length == 0){ + return left[left.length-1]; + } + return Math.max(left[left.length-1], n-right[0]) +}; diff --git a/1504-count-submatrices-with-all-ones.js b/1504-count-submatrices-with-all-ones.js new file mode 100644 index 00000000..14cad762 --- /dev/null +++ b/1504-count-submatrices-with-all-ones.js @@ -0,0 +1,34 @@ +/** + * @param {number[][]} mat + * @return {number} + */ +const numSubmat = function(mat) { + let m = mat.length + let n = mat[0].length + let res = 0 + let height = Array(n).fill(0) + for (let i = 0; i < m; i++) { + let st = [] + for (let j = 0; j < n; j++) { + if (mat[i][j] == 1) { + height[j]++ + } else { + height[j] = 0 + } + let sum = 0 + while (st.length != 0) { + if (height[st[st.length - 1][0]] < height[j]) break + st.pop() + } + if (st.length != 0) { + sum += height[j] * (j - st[st.length - 1][0]) + st[st.length - 1][1] + } else { + sum += height[j] * (j + 1) + } + st.push([j, sum]) + res += sum + } + } + return res + +}; diff --git a/1505-minimum-possible-integer-after-at-most-k-adjacent-swaps-on-digits.js b/1505-minimum-possible-integer-after-at-most-k-adjacent-swaps-on-digits.js new file mode 100644 index 00000000..2812ff4a --- /dev/null +++ b/1505-minimum-possible-integer-after-at-most-k-adjacent-swaps-on-digits.js @@ -0,0 +1,54 @@ +/** + * @param {string} num + * @param {number} k + * @return {string} + */ +const minInteger = function (num, k) { + const nums = num.split('') + const len = nums.length + const q = Array(10) + .fill(null) + .map(() => []) + nums.forEach((n, i) => q[+n].push(i)) + const tree = new Fenwick(nums.length) + for (let i = 1; i <= len; i++) tree.update(i, 1) + let re = '' + for (let i = 0; i < len; i++) { + for (let j = 0; j <= 9; j++) { + const idxArr = q[j] + if (idxArr && idxArr.length) { + const idx = idxArr[0] + const num = tree.query(idx) + if (num > k) continue + k -= num + idxArr.shift() + tree.update(idx + 1, -1) + re += j + break + } + } + } + + return re +} +class Fenwick { + constructor(n) { + this.sums = new Array(n + 1).fill(0) + } + + update(i, delta) { + while (i < this.sums.length) { + this.sums[i] += delta + i += i & -i + } + } + + query(i) { + let sum = 0 + while (i > 0) { + sum += this.sums[i] + i -= i & -i + } + return sum + } +} diff --git a/1506-find-root-of-n-ary-tree.js b/1506-find-root-of-n-ary-tree.js new file mode 100644 index 00000000..7f1316af --- /dev/null +++ b/1506-find-root-of-n-ary-tree.js @@ -0,0 +1,53 @@ +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val === undefined ? 0 : val; + * this.children = children === undefined ? [] : children; + * }; + */ + +/** + * @param {Node[]} tree + * @return {Node} + */ +const findRoot = function(tree) { + let sum = 0 + for(let n of tree) { + sum += n.val + for(let c of n.children) { + sum -= c.val + } + } + for(let n of tree) { + if(n.val === sum) return n + } + return null +}; + +// another + +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val === undefined ? 0 : val; + * this.children = children === undefined ? [] : children; + * }; + */ + +/** + * @param {Node[]} tree + * @return {Node} + */ +const findRoot = function(tree) { + let sum = 0 + for(let n of tree) { + sum ^= n.val + for(let c of n.children) { + sum ^= c.val + } + } + for(let n of tree) { + if(n.val === sum) return n + } + return null +}; diff --git a/1507-reformat-date.js b/1507-reformat-date.js new file mode 100644 index 00000000..2057763c --- /dev/null +++ b/1507-reformat-date.js @@ -0,0 +1,14 @@ +/** + * @param {string} date + * @return {string} + */ +const reformatDate = function(date) { + const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + const map = new Map(); + for (let i = 0; i < months.length; ++i) { + map.set(months[i], (i + 1 < 10 ? "0" : "") + (i+1)); + } + const parts = date.split(" "); + const day = (parts[0].length == 3 ? "0" : "") + parts[0].slice(0, parts[0].length - 2); + return parts[2] + "-" + map.get(parts[1]) + "-" + day; +}; diff --git a/1509-minimum-difference-between-largest-and-smallest-value-in-three-moves.js b/1509-minimum-difference-between-largest-and-smallest-value-in-three-moves.js new file mode 100644 index 00000000..a932dbba --- /dev/null +++ b/1509-minimum-difference-between-largest-and-smallest-value-in-three-moves.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @return {number} + */ + const minDifference = function(nums) { + let res = Infinity + const n = nums.length + if(n < 5) return 0 + nums.sort((a, b) => a - b) + for(let i = 0; i < 4; i++) { + res = Math.min(res, nums[n - 4 + i] - nums[i]) + } + + return res +}; diff --git a/151-reverse-words-in-a-string.js b/151-reverse-words-in-a-string.js index 1a70b39f..bc6c0f9d 100755 --- a/151-reverse-words-in-a-string.js +++ b/151-reverse-words-in-a-string.js @@ -9,3 +9,28 @@ const reverseWords = function(str) { .reverse() .join(" "); }; + +// another + +/** + * @param {string} str + * @returns {string} + */ +const reverseWords = function (s) { + let sb = '' + const n = s.length + let i = n - 1 + while (i >= 0) { + if (s.charAt(i) == ' ') { + i-- + continue + } + let j = i - 1 + while (j >= 0 && s.charAt(j) != ' ') j-- + sb += ' ' + sb += s.slice(j + 1, i + 1) + i = j - 1 + } + if (sb.length > 0) sb = sb.slice(1) + return sb +} diff --git a/1510-stone-game-iv.js b/1510-stone-game-iv.js new file mode 100644 index 00000000..e361b64f --- /dev/null +++ b/1510-stone-game-iv.js @@ -0,0 +1,16 @@ +/** + * @param {number} n + * @return {boolean} + */ +const winnerSquareGame = function(n) { + const dp = new Array(n + 1).fill(0); + for (let i = 1; i <= n; ++i) { + for (let k = 1; k * k <= i; ++k) { + if (!dp[i - k * k]) { + dp[i] = true; + break; + } + } + } + return dp[n]; +}; diff --git a/1511-customer-order-frequency.sql b/1511-customer-order-frequency.sql new file mode 100644 index 00000000..1994419b --- /dev/null +++ b/1511-customer-order-frequency.sql @@ -0,0 +1,7 @@ +# Write your MySQL query statement below +SELECT customer_id, name +FROM Customers JOIN Orders USING(customer_id) + JOIN Product USING(product_id) +GROUP BY customer_id +HAVING SUM(IF(LEFT(order_date, 7) = '2020-06', quantity, 0) * price) >= 100 + AND SUM(IF(LEFT(order_date, 7) = '2020-07', quantity, 0) * price) >= 100; diff --git a/1512-number-of-good-pairs.js b/1512-number-of-good-pairs.js new file mode 100644 index 00000000..fa3094aa --- /dev/null +++ b/1512-number-of-good-pairs.js @@ -0,0 +1,11 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const numIdenticalPairs = function(nums) { + let res = 0, count = Array(101).fill(0) + for(let e of nums) { + res += count[e]++ + } + return res +}; diff --git a/1514-path-with-maximum-probability.js b/1514-path-with-maximum-probability.js new file mode 100644 index 00000000..e134e58b --- /dev/null +++ b/1514-path-with-maximum-probability.js @@ -0,0 +1,103 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} succProb + * @param {number} start + * @param {number} end + * @return {number} + */ +var maxProbability = function (n, edges, succProb, start, end) { + const g = {} + for (let i = 0; i < edges.length; ++i) { + const a = edges[i][0], + b = edges[i][1] + if (g[a] == null) g[a] = [] + if (g[b] == null) g[b] = [] + g[a].push([b, i]) + g[b].push([a, i]) + } + const p = new Array(n).fill(-1) + p[start] = 1 + const pq = new PQ((a, b) => p[a] > p[b]) + pq.push(start) + while (!pq.isEmpty()) { + const cur = pq.pop() + + for (let a of g[cur] || []) { + const neighbor = a[0], + index = a[1] + if (p[cur] * succProb[index] > p[neighbor]) { + p[neighbor] = p[cur] * succProb[index] + pq.push(neighbor) + } + } + } + return p[end] === -1 ? 0 : p[end] +} +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1515-best-position-for-a-service-centre.js b/1515-best-position-for-a-service-centre.js new file mode 100644 index 00000000..9d8958a2 --- /dev/null +++ b/1515-best-position-for-a-service-centre.js @@ -0,0 +1,39 @@ +/** + * @param {number[][]} positions + * @return {number} + */ +const getMinDistSum = function(positions) { + const n = positions.length + let x = positions.reduce((ac, e) => ac + e[0], 0) / n + let y = positions.reduce((ac, e) => ac + e[1], 0) / n + + const dirs = [[1,0],[-1,0],[0,1],[0,-1]] + let res = fn(x, y, positions) + let chg = 100 + while(chg > 1e-6) { + let zoom = true + for(let [dx, dy] of dirs) { + const nx = x + dx * chg + const ny = y + dy * chg + const nRes = fn(nx, ny, positions) + if(nRes < res) { + res = nRes + x = nx + y = ny + zoom = false + break + } + } + if(zoom) chg /= 2 + } + return res +}; + +function fn(x, y, arr) { + let res = 0 + const n = arr.length + for(let i = 0; i < n; i++) { + res += Math.sqrt((x - arr[i][0]) ** 2 + (y - arr[i][1]) ** 2) + } + return res +} diff --git a/1516-move-sub-tree-of-n-ary-tree.js b/1516-move-sub-tree-of-n-ary-tree.js new file mode 100644 index 00000000..1e59ae4d --- /dev/null +++ b/1516-move-sub-tree-of-n-ary-tree.js @@ -0,0 +1,58 @@ +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val === undefined ? 0 : val; + * this.children = children === undefined ? [] : children; + * }; + */ + +/** + * @param {Node} root + * @param {Node} p + * @param {Node} q + * @return {Node} + */ +function moveSubTree(root, p, q) { + for (let node of q.children) { + if (p === node) { + return root + } + } + if (find(p, q)) { + update(root, p, q) + q.children.push(p) + return root === p ? q : root + } else { + update(root, null, p) + q.children.push(p) + return root + } + function update(root, p, q) { + if (root == null) { + return + } + for (let node of root.children) { + update(node, p, q) + } + for (let i = 0; i < root.children.length; i++) { + if (root.children[i] === p) { + root.children[i] = q + } else if (root.children[i] === q) { + root.children.splice(i, 1) + } + } + } + function find(root, t) { + if (root == null) { + return false + } + let ret = root === t + if (ret === true) { + return true + } + for (let node of root.children) { + ret = ret || find(node, t) + } + return ret + } +} diff --git a/152-maximum-product-subarray.js b/152-maximum-product-subarray.js index b4b9686d..8effa588 100644 --- a/152-maximum-product-subarray.js +++ b/152-maximum-product-subarray.js @@ -1,3 +1,21 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxProduct = function(nums) { + let min = nums[0], max = nums[0], res = nums[0] + for(let i = 1, n = nums.length; i < n; i++) { + const e = nums[i] + if(e < 0) [min, max] = [max, min] + min = Math.min(e, min * e) + max = Math.max(e, max * e) + res = Math.max(res, max) + } + return res +}; + +// another + /** * @param {number[]} nums * @return {number} @@ -45,3 +63,48 @@ const maxProduct = function(nums) { } return max; }; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxProduct = function(nums) { + const n = nums.length + let max, min + let res = max = min = nums[0] + for(let i = 1; i < n; i++) { + if(nums[i] < 0) [max, min] = [min, max] + max = Math.max(nums[i], nums[i] * max) + min = Math.min(nums[i], nums[i] * min) + res = Math.max(res, max) + } + return res +}; + + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxProduct = function (nums) { + if(nums == null || nums.length === 0) return 0 + const n = nums.length + let res = nums[0] + for(let i = 1, min = res, max = res; i < n; i++) { + if(nums[i] < 0) { + let tmax = max, tmin = min + min = Math.min(nums[i], tmax * nums[i]) + max = Math.max(nums[i], tmin * nums[i]) + } else { + min = Math.min(nums[i], min * nums[i]) + max = Math.max(nums[i], max * nums[i]) + } + res = Math.max(res, max) + } + + return res +} diff --git a/1521-find-a-value-of-a-mysterious-function-closest-to-target.js b/1521-find-a-value-of-a-mysterious-function-closest-to-target.js new file mode 100644 index 00000000..87ad112a --- /dev/null +++ b/1521-find-a-value-of-a-mysterious-function-closest-to-target.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} arr + * @param {number} target + * @return {number} + */ +const closestToTarget = function (arr, target) { + let res = Infinity + let set = new Set() + for (let i = 0; i < arr.length; i++) { + const set2 = new Set() + for (let j of set) { + set2.add(j & arr[i]) + } + set2.add(arr[i]) + for (let j of set2) { + res = Math.min(res, Math.abs(j - target)) + } + set = set2 + } + return res +} diff --git a/1522-diameter-of-n-ary-tree.js b/1522-diameter-of-n-ary-tree.js new file mode 100644 index 00000000..864b1c25 --- /dev/null +++ b/1522-diameter-of-n-ary-tree.js @@ -0,0 +1,34 @@ +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val === undefined ? 0 : val; + * this.children = children === undefined ? [] : children; + * }; + */ + +/** + * @param {Node} root + * @return {number} + */ +var diameter = function(root) { + let res = 0 + dfs(root) + return res + + function dfs(node) { + if(node == null) return 0 + let max1 = 0, max2 = 0 + for(const child of node.children) { + const tmp = dfs(child) + if(tmp > max1) { + max2 = max1 + max1 = tmp + } else if(tmp > max2) { + max2 = tmp + } + } + + res = Math.max(res, max1 + max2) + return max1 + 1 + } +}; diff --git a/1523-count-odd-numbers-in-an-interval-range.js b/1523-count-odd-numbers-in-an-interval-range.js new file mode 100644 index 00000000..2c47f34f --- /dev/null +++ b/1523-count-odd-numbers-in-an-interval-range.js @@ -0,0 +1,30 @@ +/** + * @param {number} low + * @param {number} high + * @return {number} + */ +const countOdds = function(low, high) { + let res = 0 + + const odd = num => num % 2 === 1 + if(odd(low)) res++ + + const num = Math.floor( (high - low) / 2 ) + res += num + + if(high > low + 2 * num && odd(high)) res++ + + return res +}; + + +// another + +/** + * @param {number} low + * @param {number} high + * @return {number} + */ +const countOdds = function(low, high) { + return ~~((high + 1) / 2) - (~~(low / 2)) +}; diff --git a/1524-number-of-sub-arrays-with-odd-sum.js b/1524-number-of-sub-arrays-with-odd-sum.js new file mode 100644 index 00000000..1b3fed50 --- /dev/null +++ b/1524-number-of-sub-arrays-with-odd-sum.js @@ -0,0 +1,49 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const numOfSubarrays = function(arr) { + const n = arr.length, mod = 1e9 + 7 + let sum = 0, res = 0, oddCnt = 0, evenCnt = 0 + + for(let i = 0; i < n; i++) { + const cur = arr[i] + sum += cur + if(sum % 2 === 1) { + res++ + res += evenCnt + oddCnt++ + } else { + res += oddCnt + evenCnt++ + } + } + + return res % mod +}; + +// another + +/** + * @param {number[]} arr + * @return {number} + */ +const numOfSubarrays = function(arr) { + const n = arr.length, mod = 1e9 + 7 + + let oc = 0, ec = 1 + let sum = 0 + let res = 0 + for(let i = 0; i < n; i++) { + sum += arr[i] + if(sum % 2 === 1) { + res += ec + oc++ + } else { + res += oc + ec++ + } + } + + return res % mod +}; diff --git a/1525-number-of-good-ways-to-split-a-string.js b/1525-number-of-good-ways-to-split-a-string.js new file mode 100644 index 00000000..4c443bc6 --- /dev/null +++ b/1525-number-of-good-ways-to-split-a-string.js @@ -0,0 +1,59 @@ +/** + * @param {string} s + * @return {number} + */ +const numSplits = function(s) { + const n = s.length + const freq = new Map() + const prefix = Array(26).fill(0) + for(let i = 0; i < n; i++) { + if(freq.get(s[i]) == null) freq.set(s[i], 0) + freq.set(s[i], freq.get(s[i]) + 1) + prefix[i] = freq.size + } + freq.clear() + const suffix = Array(26).fill(0) + for(let i = n - 1; i >= 0 ;i--) { + if(freq.get(s[i]) == null) freq.set(s[i], 0) + freq.set(s[i], freq.get(s[i]) + 1) + suffix[i] = freq.size + } + // console.log(prefix, suffix) + let res = 0 + for(let i = 1; i < n; i++) { + if(prefix[i - 1] === suffix[i]) res++ + } + + return res +}; + + +// another + + +/** + * @param {string} s + * @return {number} + */ +const numSplits = function(s) { + const arr = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for(let i = 0, len = s.length; i < len; i++) { + arr[s.charCodeAt(i) - a]++ + } + const cur = Array(26).fill(0) + let res = 0 + for(let i = 0, len = s.length; i < len - 1; i++) { + cur[s.charCodeAt(i) - a]++ + let tmp = false, clone = arr.slice() + for(let j = 0; j < 26; j++) { + clone[j] -= cur[j] + } + const curNum = cur.reduce((ac, e) => ac + (e > 0 ? 1 : 0), 0) + const cloneNum = clone.reduce((ac, e) => ac + (e > 0 ? 1 : 0), 0) + if(curNum === cloneNum) res++ + } + + return res +}; + diff --git a/1526-minimum-number-of-increments-on-subarrays-to-form-a-target-array.js b/1526-minimum-number-of-increments-on-subarrays-to-form-a-target-array.js new file mode 100644 index 00000000..8464391c --- /dev/null +++ b/1526-minimum-number-of-increments-on-subarrays-to-form-a-target-array.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} target + * @return {number} + */ +const minNumberOperations = function(target) { + let res = target[0] + + for(let i = 1; i < target.length; i++) { + res += Math.max(0, target[i] - target[i - 1]) + } + + return res +} + +// another + +/** + * @param {number[]} target + * @return {number} + */ +const minNumberOperations = function(target) { + let totalOperations = target[0]; + for (let i = 1; i < target.length; ++i) { + if (target[i] > target[i-1]) { + totalOperations += target[i] - target[i-1]; + } + } + return totalOperations; +}; diff --git a/1528-shuffle-string.js b/1528-shuffle-string.js new file mode 100644 index 00000000..1c965ce1 --- /dev/null +++ b/1528-shuffle-string.js @@ -0,0 +1,13 @@ +/** + * @param {string} s + * @param {number[]} indices + * @return {string} + */ +const restoreString = function(s, indices) { + const n = s.length + const arr = Array(n) + for(let i = 0; i < n; i++) { + arr[indices[i]] = s[i] + } + return arr.join('') +}; diff --git a/1529-minimum-suffix-flips.js b/1529-minimum-suffix-flips.js new file mode 100644 index 00000000..b50905b8 --- /dev/null +++ b/1529-minimum-suffix-flips.js @@ -0,0 +1,17 @@ +/** + * @param {string} target + * @return {number} + */ +const minFlips = function (target) { + const n = target.length + let res = 0, flip = 0 + + for(let i = 0; i < n; i++) { + if(target[i] === '0' && flip % 2 === 0) continue + if(target[i] === '1' && flip % 2 === 1) continue + flip++ + res++ + } + + return res +} diff --git a/153-find-minimum-in-rotated-sorted-array.js b/153-find-minimum-in-rotated-sorted-array.js index fbdc1c31..dacc1988 100644 --- a/153-find-minimum-in-rotated-sorted-array.js +++ b/153-find-minimum-in-rotated-sorted-array.js @@ -2,12 +2,19 @@ * @param {number[]} nums * @return {number} */ -const findMin = function(nums) { - if(nums.length === 1) return nums[0] - for(let i = 1; i < nums.length; i++) { - if(nums[i] - nums[i - 1] < 0) { - return nums[i] - } - } - return nums[0] -}; +const findMin = function (nums) { + let low = 0, + high = nums.length - 1 + // loop invariant: 1. low < high + // 2. mid != high and thus A[mid] != A[high] (no duplicate exists) + // 3. minimum is between [low, high] + // The proof that the loop will exit: after each iteration either the 'high' decreases + // or the 'low' increases, so the interval [low, high] will always shrink. + while (low < high) { + const mid = low + ((high - low) >> 1) + if (nums[mid] <= nums[high]) high = mid + else if (nums[mid] > nums[high]) low = mid + 1 + } + + return nums[low] +} diff --git a/1530-number-of-good-leaf-nodes-pairs.js b/1530-number-of-good-leaf-nodes-pairs.js new file mode 100644 index 00000000..e46cf854 --- /dev/null +++ b/1530-number-of-good-leaf-nodes-pairs.js @@ -0,0 +1,34 @@ +/** + * 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 + * @param {number} distance + * @return {number} + */ +const countPairs = function(root, distance) { + let res = 0 + traverse(root) + return res + + + function traverse(node) { + if(node == null) return [] + if(node.left == null && node.right == null) return [0] + + const left = traverse(node.left) + const right = traverse(node.right) + for(let i = 0; i < left.length; i++) { + for(let j = 0; j < right.length; j++) { + if(left[i] + right[j] + 2 <= distance) res++ + } + } + + return [...left.map(e => e + 1), ...right.map(e => e + 1)] + } +}; diff --git a/1531-string-compression-ii.js b/1531-string-compression-ii.js new file mode 100644 index 00000000..31a2e728 --- /dev/null +++ b/1531-string-compression-ii.js @@ -0,0 +1,61 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const getLengthOfOptimalCompression = function(s, k) { + const m = new Map() + function counter(start, last, lastCount, left) { + if(left < 0) return Infinity + if(start >= s.length) return 0 + let res + const k = `${start}-${last}-${lastCount}-${left}` + if(m.has(k)) return m.get(k) + if(s[start] === last) { + const incr = (lastCount === 1 || lastCount === 9 || lastCount === 99) ? 1 : 0 + res = incr + counter(start + 1, last, lastCount + 1, left) + } else { + const keepCounter = 1 + counter(start + 1, s[start], 1, left) + const delCounter = counter(start + 1, last, lastCount, left - 1) + res = Math.min(keepCounter, delCounter) + } + m.set(k, res) + return res + } + return counter(0, '', 0, k) +}; + +// another + +const getLengthOfOptimalCompression = function (s, k) { + const n = s.length + const dp = new Array(n + 1).fill(n).map((row) => new Array(k + 1).fill(n)) + dp[0][0] = 0 + + for (let i = 1; i <= n; i++) { + for (let j = 0; j <= k; j++) { + let letterCount = 0 + let deletion = 0 + // keep s[i], compress same letters, remove different letters + for (let l = i; l >= 1; l--) { + if (s.charAt(l - 1) === s.charAt(i - 1)) letterCount++ + else deletion++ + // places = length needed to rep compressed letters. + // 0 places for count = 1,0, 1 place = <10, 10-99 requires 2 places, 100+ requires 3 + let places = 0 + if (letterCount >= 100) places = 3 + else if (letterCount >= 10) places = 2 + else if (letterCount >= 2) places = 1 + if (j - deletion >= 0) { + dp[i][j] = Math.min(dp[i][j], dp[l - 1][j - deletion] + 1 + places) + } + } + // delete + if (j > 0) { + dp[i][j] = Math.min(dp[i][j], dp[i - 1][j - 1]) + } + } + } + return dp[n][k] +} + diff --git a/1534-count-good-triplets.js b/1534-count-good-triplets.js new file mode 100644 index 00000000..8d6d3b96 --- /dev/null +++ b/1534-count-good-triplets.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} arr + * @param {number} a + * @param {number} b + * @param {number} c + * @return {number} + */ +const countGoodTriplets = function(arr, a, b, c) { + const n = arr.length, { abs } = Math + let res = 0 + + for(let i = 0; i < n - 2; i++) { + for(let j = i + 1; j < n - 1; j++) { + if(abs(arr[i] - arr[j]) > a) continue + for(let k = j + 1; k < n; k++) { + if(abs(arr[j] - arr[k]) <= b && abs(arr[i] - arr[k]) <= c) res++ + } + } + } + + return res + +}; diff --git a/1537-get-the-maximum-score.js b/1537-get-the-maximum-score.js new file mode 100644 index 00000000..bf35ef7b --- /dev/null +++ b/1537-get-the-maximum-score.js @@ -0,0 +1,108 @@ +/** + +You are given two sorted arrays of distinct integers nums1 and nums2. + +A valid path is defined as follows: + +Choose array nums1 or nums2 to traverse (from index-0). +Traverse the current array from left to right. +If you are reading any value that is present in nums1 and nums2 you are +allowed to change your path to the other array. +(Only one repeated value is considered in the valid path). +Score is defined as the sum of uniques values in a valid path. + +Return the maximum score you can obtain of all possible valid paths. + +Since the answer may be too large, return it modulo 10^9 + 7. + +Example 1: + +Input: nums1 = [2,4,5,8,10], nums2 = [4,6,8,9] +Output: 30 +Explanation: Valid paths: +[2,4,5,8,10], [2,4,5,8,9], [2,4,6,8,9], [2,4,6,8,10], (starting from nums1) +[4,6,8,9], [4,5,8,10], [4,5,8,9], [4,6,8,10] (starting from nums2) +The maximum is obtained with the path in green [2,4,6,8,10]. + +Example 2: + +Input: nums1 = [1,3,5,7,9], nums2 = [3,5,100] +Output: 109 +Explanation: Maximum sum is obtained with the path [1,3,5,100]. +Example 3: + +Input: nums1 = [1,2,3,4,5], nums2 = [6,7,8,9,10] +Output: 40 +Explanation: There are no common elements between nums1 and nums2. +Maximum sum is obtained with the path [6,7,8,9,10]. +Example 4: + +Input: nums1 = [1,4,5,8,9,11,19], nums2 = [2,3,4,11,12] +Output: 61 + + +Constraints: + +1 <= nums1.length <= 10^5 +1 <= nums2.length <= 10^5 +1 <= nums1[i], nums2[i] <= 10^7 +nums1 and nums2 are strictly increasing. + +*/ + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const maxSum = function(nums1, nums2) { + let i = 0, j = 0, n = nums1.length, m = nums2.length; + let a = 0, b = 0, mod = 10 ** 9 + 7; + while (i < n || j < m) { + if (i < n && (j === m || nums1[i] < nums2[j])) { + a += nums1[i++]; + } else if (j < m && (i === n || nums1[i] > nums2[j])) { + b += nums2[j++]; + } else { + a = b = Math.max(a, b) + nums1[i]; + i++; j++; + } + } + return Math.max(a, b) % mod; +}; + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const maxSum = function(nums1, nums2) { + const len1 = nums1.length, len2 = nums2.length + const mod = 10 ** 9 + 7 + const map = new Map() + for(let i = 0; i < len1 - 1; i++) { + if(!map.has(nums1[i])) map.set(nums1[i], []) + map.get(nums1[i]).push(nums1[i + 1]) + } + for(let j = 0; j < len2 - 1; j++) { + if(!map.has(nums2[j])) map.set(nums2[j], []) + map.get(nums2[j]).push(nums2[j + 1]) + } + const memo = new Map() + return Math.max(greedy(nums1[0], map, memo), greedy(nums2[0], map, memo)) % mod +}; + +function greedy(cur, map, memo) { + if(memo.has(cur)) return memo.get(cur) + if(!map.has(cur)) return cur + let res = 0 + for(let next of map.get(cur)) { + const tmp = greedy(next, map, memo) + if(tmp > res) res = tmp + } + res += cur + memo.set(cur, res) + return res +} diff --git a/1539-kth-missing-positive-number.js b/1539-kth-missing-positive-number.js new file mode 100644 index 00000000..6a0c0184 --- /dev/null +++ b/1539-kth-missing-positive-number.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ +const findKthPositive = function(arr, k) { + let l = 0, r = arr.length, m; + while (l < r) { + m = (l + r) >> 1; + if (arr[m] - 1 - m < k) l = m + 1; + else r = m; + } + return l + k; +}; diff --git a/154-find-minimum-in-rotated-sorted-array-ii.js b/154-find-minimum-in-rotated-sorted-array-ii.js new file mode 100644 index 00000000..1ed12103 --- /dev/null +++ b/154-find-minimum-in-rotated-sorted-array-ii.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const findMin = function(nums) { + for(let i = 1, len = nums.length; i < len; i++) { + if(nums[i] < nums[i - 1]) { + return nums[i] + } + } + return nums[0] +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const findMin = function(nums) { + let lo = 0, + hi = nums.length - 1 + while (lo < hi) { + let mid = Math.floor(lo + (hi - lo) / 2) + if (nums[mid] > nums[hi]) lo = mid + 1 + else if (nums[mid] < nums[hi]) hi = mid + else hi-- + } + return nums[lo] +} diff --git a/1540-can-convert-string-in-k-moves.js b/1540-can-convert-string-in-k-moves.js new file mode 100644 index 00000000..5402c1ee --- /dev/null +++ b/1540-can-convert-string-in-k-moves.js @@ -0,0 +1,22 @@ +/** + * @param {string} s + * @param {string} t + * @param {number} k + * @return {boolean} + */ +const canConvertString = function(s, t, k) { + if(s == null || t == null) return false + const slen = s.length, tlen = t.length + if(slen !== tlen) return false + const count = Array(26).fill(0) + for(let i = 0; i < slen; i++) { + const scode = s.charCodeAt(i) + const tcode = t.charCodeAt(i) + const diff = (tcode - scode + 26) % 26; + if (diff > 0 && diff + count[diff] * 26 > k) { + return false; + } + count[diff]++; + } + return true +}; diff --git a/1541-minimum-insertions-to-balance-a-parentheses-string.js b/1541-minimum-insertions-to-balance-a-parentheses-string.js new file mode 100644 index 00000000..f9f78d74 --- /dev/null +++ b/1541-minimum-insertions-to-balance-a-parentheses-string.js @@ -0,0 +1,83 @@ +/** + * @param {string} s + * @return {number} + */ +const minInsertions = function(s) { + let insert = 0, idx = 0, open = 0, len = s.length + while(idx < len) { + const ch = s[idx] + if(ch === '(') { + open++ + idx++ + } else { + if(open > 0) { + open-- + } else { + insert++ + } + if(idx < len - 1 && s[idx + 1] === ')') { + idx += 2 + } else { + insert++ + idx++ + } + } + } + if(open) insert += open * 2 + return insert +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const minInsertions = function(s) { + let res = 0, right = 0; + for (let i = 0; i < s.length; ++i) { + if (s.charAt(i) == '(') { + if (right % 2 > 0) { + right--; + res++; + } + right += 2; + } else { + right--; + if (right < 0) { + right += 2; + res++; + } + } + } + return right + res; +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const minInsertions = function(s) { + let add = 0, req = 0 // number of parentheses added, number of closing parentheses required + for(let ch of s) { + if(ch === '(') { + req += 2 + if(req % 2 === 1) { + add++ + req-- + } + } else { + if(req === 0) { + add++ + req++ + }else { + req-- + } + } + } + + return add + req +}; + diff --git a/1542-find-longest-awesome-substring.js b/1542-find-longest-awesome-substring.js new file mode 100644 index 00000000..7426ad8f --- /dev/null +++ b/1542-find-longest-awesome-substring.js @@ -0,0 +1,75 @@ +/** + * @param {string} s + * @return {number} + */ +const longestAwesome = function(s) { + const n = s.length, map = new Map(), {max} = Math + let res = 0, mask = 0 + + map.set(0, -1) + for(let i = 0; i < n; i++) { + const d = +s[i] + mask ^= (1 << d) + if(map.has(mask)) { + res = max(res, i - map.get(mask)) + } + + for(let j = 0; j < 10; j++) { + const tmp = mask ^ (1 << j) + if(map.has(tmp)) { + // console.log(i, map.get(tmp), tmp) + res = max(res, i - map.get(tmp)) + } + } + + if(!map.has(mask)) { + map.set(mask, i) + } + } + + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const longestAwesome = function (s) { + const dp = new Array(1024).fill(s.length) + let res = 0, + mask = 0 + dp[0] = -1 + for (let i = 0; i < s.length; ++i) { + mask ^= 1 << +s.charAt(i) + res = Math.max(res, i - dp[mask]) + for (let j = 0; j <= 9; ++j) res = Math.max(res, i - dp[mask ^ (1 << j)]) + dp[mask] = Math.min(dp[mask], i) + } + return res +} + +// another + +/** + * @param {string} s + * @return {number} + */ +const longestAwesome = function(s) { + const n = s.length, { max, min } = Math + const dp = Array(2 ** 10).fill(n) + let res = 0, mask = 0 + dp[0] = -1 + for(let i = 0; i < n; i++) { + mask ^= (1 << parseInt(s[i])) + res = max(res, i - dp[mask]) + for(let j = 0; j <= 9; j++) { + const tmp = mask ^ (1 << j) + res = max(res, i - dp[tmp]) + } + dp[mask] = min(i, dp[mask]) + } + + return res +}; diff --git a/1545-find-kth-bit-in-nth-binary-string.js b/1545-find-kth-bit-in-nth-binary-string.js new file mode 100644 index 00000000..86e2aa48 --- /dev/null +++ b/1545-find-kth-bit-in-nth-binary-string.js @@ -0,0 +1,17 @@ +/** + * @param {number} n + * @param {number} k + * @return {character} + */ +var findKthBit = function(n, k) { + let count = 0, l = (1 << n) - 1; + while (k > 1) { + if (k == Math.floor(l / 2) + 1) return count % 2 == 0 ? '1' : '0'; + if (k > l / 2) { + k = l + 1 - k; + count++; + } + l = Math.floor(l / 2); + } + return count % 2 === 0 ? '0' : '1'; +}; diff --git a/1546-maximum-number-of-non-overlapping-subarrays-with-sum-equals-target.js b/1546-maximum-number-of-non-overlapping-subarrays-with-sum-equals-target.js new file mode 100644 index 00000000..3d307b68 --- /dev/null +++ b/1546-maximum-number-of-non-overlapping-subarrays-with-sum-equals-target.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const maxNonOverlapping = function(nums, target) { + if(nums == null || nums.length === 0) return 0 + let sum = 0, res = 0 + const n = nums.length + const m = {0: 0} + + for(let i = 0; i < n; i++) { + sum += nums[i] + if(m[sum - target] != null) { + res = Math.max(res, m[sum - target] + 1) + } + m[sum] = res + } + return res +}; diff --git a/1547-minimum-cost-to-cut-a-stick.js b/1547-minimum-cost-to-cut-a-stick.js new file mode 100644 index 00000000..637bb477 --- /dev/null +++ b/1547-minimum-cost-to-cut-a-stick.js @@ -0,0 +1,48 @@ +/** + * @param {number} n + * @param {number[]} cuts + * @return {number} + */ +const minCost = function(n, cuts) { + const x = 100 + 2 + const dp = Array.from({ length: x }, () => Array(x).fill(0)) + cuts.push(0, n) + cuts.sort((a, b) => a - b) + const res = dfs(0, cuts.length - 1) + return res + function dfs(i, j) { + if(j - i <= 1) return 0 + if(!dp[i][j]) { + dp[i][j] = Number.MAX_VALUE + for(let k = i + 1; k < j; k++) { + dp[i][j] = Math.min(dp[i][j], cuts[j] - cuts[i] + dfs(i, k) + dfs(k, j)) + } + } + return dp[i][j] + } +}; + +// another + +/** + * @param {number} n + * @param {number[]} cuts + * @return {number} + */ +const minCost = function (n, cuts) { + cuts.push(0, n) + cuts.sort((a, b) => a - b) + const N = cuts.length, + dp = Array.from({ length: N }, () => Array(N).fill(Infinity)) + for(let i = 1; i < N; i++) dp[i - 1][i] = 0 + for(let i = 2; i < N; i++) dp[i - 2][i] = cuts[i] - cuts[i - 2] + for (let l = 4; l <= N; l++) { + for (let i = 0; i <= N - l; i++) { + const j = i + l - 1 + for (let k = i + 1; k < j; k++) { + dp[i][j] = Math.min(dp[i][j], cuts[j] - cuts[i] + dp[i][k] + dp[k][j]) + } + } + } + return dp[0][N - 1] +} diff --git a/155-min-stack.js b/155-min-stack.js index 4ddc3d4a..a48bb5f2 100644 --- a/155-min-stack.js +++ b/155-min-stack.js @@ -1,46 +1,52 @@ /** * initialize your data structure here. */ -const MinStack = function() { - this.arr = [] -}; +const MinStack = function () { + this.stack = [] + this.min = null +} -/** +/** * @param {number} x * @return {void} */ -MinStack.prototype.push = function(x) { - this.arr.push(x) -}; +MinStack.prototype.push = function (x) { + if (this.min === null) { + this.min = x + } else { + this.min = Math.min(x, this.min) + } + return this.stack.push(x) +} /** * @return {void} */ -MinStack.prototype.pop = function() { - this.arr.pop() -}; +MinStack.prototype.pop = function () { + let removed = this.stack.pop() + if (this.min === removed) { + this.min = this.stack.length > 0 ? Math.min(...this.stack) : null + } + return this.stack +} /** * @return {number} */ -MinStack.prototype.top = function() { - return this.arr[this.arr.length - 1] -}; +MinStack.prototype.top = function () { + return this.stack[this.stack.length - 1] +} /** * @return {number} */ -MinStack.prototype.getMin = function() { - let min = Number.MAX_VALUE - for(let el of this.arr) { - if(el < min) min = el - } - return min -}; +MinStack.prototype.getMin = function () { + return this.min +} -/** +/** * Your MinStack object will be instantiated and called as such: - * var obj = Object.create(MinStack).createNew() + * var obj = new MinStack() * obj.push(x) * obj.pop() * var param_3 = obj.top() diff --git a/1550-three-consecutive-odds.js b/1550-three-consecutive-odds.js new file mode 100644 index 00000000..d67397a1 --- /dev/null +++ b/1550-three-consecutive-odds.js @@ -0,0 +1,10 @@ +/** + * @param {number[]} arr + * @return {boolean} + */ +const threeConsecutiveOdds = function(arr) { + for(let i = 1, n = arr.length; i < n - 1; i++) { + if(arr[i] & 1 === 1 && arr[i - 1] & 1 === 1 && arr[i + 1] & 1 === 1) return true + } + return false +}; diff --git a/1551-minimum-operations-to-make-array-equal.js b/1551-minimum-operations-to-make-array-equal.js new file mode 100644 index 00000000..d57d8369 --- /dev/null +++ b/1551-minimum-operations-to-make-array-equal.js @@ -0,0 +1,22 @@ +/** + * @param {number} n + * @return {number} + */ +var minOperations = function(n) { + let l = 1, r = 2 * (n - 1) + 1 + + // [1, 3] + // [1, 3, 5, 7] + + // [1] + // [1, 3, 5] + // [1, 3, 5, 7, 9] + const target = l + (r - l) / 2 + let res = 0 + const num = ~~((n + 1) / 2) + for(let i = 1; i <= num; i++) { + res += target - (2 * (i -1) + 1) + } + + return res +}; diff --git a/1552-magnetic-force-between-two-balls.js b/1552-magnetic-force-between-two-balls.js new file mode 100644 index 00000000..8596a31a --- /dev/null +++ b/1552-magnetic-force-between-two-balls.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} position + * @param {number} m + * @return {number} + */ +const maxDistance = function(position, m) { + position.sort((a, b) => a - b) + const n = position.length + let l = Infinity, r = 1 + for (let i = 1; i < n; i++) { + if (position[i] - position[i - 1] < l) l = position[i] - position[i - 1] + } + r = position[n - 1] - position[0] + while(l < r) { + const mid = r - Math.floor((r - l) / 2) + if(valid(mid)) l = mid + else r = mid - 1 + } + return l + + function valid(mid) { + let res = 1, cur = 0 + for (let i = 1; i < n; i++) { + const delta = position[i] - position[i - 1] + cur += delta + if (cur >= mid) { + res++ + cur = 0 + } + if(res === m) return true + } + return false + } +}; diff --git a/1553-minimum-number-of-days-to-eat-n-oranges.js b/1553-minimum-number-of-days-to-eat-n-oranges.js new file mode 100644 index 00000000..dadb5d5c --- /dev/null +++ b/1553-minimum-number-of-days-to-eat-n-oranges.js @@ -0,0 +1,15 @@ +/** + * @param {number} n + * @return {number} + */ +const minDays = function (n, dp = {}) { + if (n <= 1) return n + if (dp[n] == null) + dp[n] = + 1 + + Math.min( + (n % 2) + minDays((n / 2) >> 0, dp), + (n % 3) + minDays((n / 3) >> 0, dp) + ) + return dp[n] +} diff --git a/1554-strings-differ-by-one-character.js b/1554-strings-differ-by-one-character.js new file mode 100644 index 00000000..642d2ad0 --- /dev/null +++ b/1554-strings-differ-by-one-character.js @@ -0,0 +1,52 @@ +/** + * @param {string[]} dict + * @return {boolean} + */ + const differByOne = function(dict) { + const n = dict.length, m = dict[0].length + for (let j = 0; j < m; j++) { + const seen = new Set() + for(let i = 0; i < n; i++) { + const newStr = dict[i].slice(0, j) + '*' + dict[i].slice(j + 1) + if(seen.has(newStr)) return true + seen.add(newStr) + } + } + + return false +}; + +// another + +/** + * @param {string[]} dict + * @return {boolean} + */ +const differByOne = function (dict) { + const M = dict.length, + N = dict[0].length, + hash = Array(M).fill(0), + ord = (c) => c.charCodeAt(0), + MOD = 1e13, seen = new Set(), + zPlusOne = 'z'.charCodeAt(0) + // 1. generate each i-th rolling hash + for (let i = 0; i < M; ++i) { + let base = 1 + for (let j = 0; j < N; ++j) { + hash[i] = (hash[i] + base * ord(dict[i][j])) % MOD + base = (zPlusOne * base) % MOD + } + } + // 2. remove each j-th char from each i-th rolling hash to find a diff collision + for (let i = 0; i < M; ++i) { + let base = 1 + for (let j = 0; j < N; ++j) { + const diff = (hash[i] - base * ord(dict[i][j])) % MOD + if (seen.has(diff)) return true + seen.add(diff) + base = (zPlusOne * base) % MOD + } + } + return false +} + diff --git a/1557-minimum-number-of-vertices-to-reach-all-nodes.js b/1557-minimum-number-of-vertices-to-reach-all-nodes.js new file mode 100644 index 00000000..89430b28 --- /dev/null +++ b/1557-minimum-number-of-vertices-to-reach-all-nodes.js @@ -0,0 +1,18 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ +var findSmallestSetOfVertices = function(n, edges) { + const indegree = Array(n).fill(0) + for(const [from, to] of edges) { + indegree[to]++ + } + let res = [] + for(let i = 0; i Array(cols).fill(false)) + let res = false + const dfs = (i, j, prevR, prevC, char) => { + vis[i][j] = true + for (let d of dirs) { + const r = i + d[0] + const c = j + d[1] + if (r >= 0 && r < rows && c >= 0 && c < cols) { + if (!(r == prevR && c === prevC)) { + if (grid[r][c] === char) { + if (!vis[r][c]) { + if (dfs(r, c, i, j, char)) return true + } else { + if (prevR !== -1 && prevC !== -1) return true + } + } + } + } + } + return false + } + + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (!vis[i][j]) { + res |= dfs(i, j, -1, -1, grid[i][j]) + } + if (res) return true + } + } + return res +} + +// another + +/** + * @param {character[][]} grid + * @return {boolean} + */ +const containsCycle = function (grid) { + const wholePath = (r, c, letter, component, last = [-1, -1]) => { + const dirs = [ + [0, -1], + [0, 1], + [-1, 0], + [1, 0], + ] + const tmp = grid[r][c] + grid[r][c] = component + const nextSteps = dirs + .map((x) => [x[0] + r, x[1] + c]) + .filter( + (x) => + x[0] >= 0 && x[0] < grid.length && x[1] >= 0 && x[1] < grid[0].length + ) + for (let step of nextSteps) { + if (step[0] === last[0] && last[1] === step[1]) { + continue + } + if (grid[step[0]][step[1]] === component) { + return true + } + if (grid[step[0]][step[1]] === letter) { + let outcome = wholePath(step[0], step[1], letter, component, [r, c]) + if (outcome) { + return true + } + } + } + return false + } + + let component = 1 + for (let r = 0; r < grid.length; r++) { + for (let c = 0; c < grid[0].length; c++) { + const letter = grid[r][c] + if (typeof letter === 'string') { + grid[r][c] = component + const outcome = wholePath(r, c, letter, component) + if (outcome) { + return true + } + component++ + } + } + } + return false +} diff --git a/156-binary-tree-upside-down.js b/156-binary-tree-upside-down.js new file mode 100644 index 00000000..f5e6e354 --- /dev/null +++ b/156-binary-tree-upside-down.js @@ -0,0 +1,37 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {TreeNode} + */ +const upsideDownBinaryTree = function(root) { + let node = root, parent = null, right = null + while(node !== null) { + const left = node.left + node.left = right + right = node.right + node.right = parent + parent = node + node = left + } + return parent +}; + +// another + +const upsideDownBinaryTree = function(root) { + if (root == null || root.left == null) { + return root + } + const newRoot = upsideDownBinaryTree(root.left) + root.left.left = root.right + root.left.right = root + root.left = null + root.right = null + return newRoot +} diff --git a/1560-most-visited-sector-in-a-circular-track.js b/1560-most-visited-sector-in-a-circular-track.js new file mode 100644 index 00000000..62d2eea1 --- /dev/null +++ b/1560-most-visited-sector-in-a-circular-track.js @@ -0,0 +1,24 @@ +/** + * @param {number} n + * @param {number[]} rounds + * @return {number[]} + */ +const mostVisited = function(n, rounds) { + const arr = Array(n + 1).fill(0) + for(let i = 1, m = rounds.length; i < m; i++) { + let start = rounds[i - 1], end = rounds[i] + + if(i == 1) arr[start]++ + while(start !== end) { + start += 1 + if (start === n + 1) start = 1 + arr[start]++ + } + } + const max = Math.max(...arr) + const res = [] + for(let i = 1; i <= n; i++) { + if(arr[i] === max) res.push(i) + } + return res +}; diff --git a/1561-maximum-number-of-coins-you-can-get.js b/1561-maximum-number-of-coins-you-can-get.js new file mode 100644 index 00000000..e7ef135a --- /dev/null +++ b/1561-maximum-number-of-coins-you-can-get.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} piles + * @return {number} + */ +const maxCoins = function(piles) { + piles.sort((a, b) => a - b) + let coins = 0, n = piles.length + for(let j = 0, i = n - 2, hi = Math.floor(n / 3); j < hi; j++, i -= 2) { + coins += piles[i] + } + + return coins +}; diff --git a/1562-find-latest-group-of-size-m.js b/1562-find-latest-group-of-size-m.js new file mode 100644 index 00000000..ca889669 --- /dev/null +++ b/1562-find-latest-group-of-size-m.js @@ -0,0 +1,80 @@ +/** + * @param {number[]} arr + * @param {number} m + * @return {number} + */ +const findLatestStep = function(arr, m) { + const uF = new UnionFind(arr); + const mRecords = new Set(); // This contains parents whose rank is m + const visited = new Set(); + let res = -1; + + for (let i = 0; i < arr.length; i++) { + let val = arr[i]; + visited.add(val); + + if (visited.has(val - 1)) { + let parent1 = uF.find(val); + let parent2 = uF.find(val - 1); + // Since merging, the rank for val - 1 & val has changed, + // they are no longer m. Hence removed them from set. + mRecords.delete(parent1); + mRecords.delete(parent2); + uF.union(val, val - 1); + } + + if (visited.has(val + 1)) { + let parent1 = uF.find(val); + let parent2 = uF.find(val + 1); + mRecords.delete(parent1); + mRecords.delete(parent2); + uF.union(val, val + 1); + } + + let parent = uF.find(val); + if (uF.ranks.get(parent) === m) mRecords.add(parent); + if (mRecords.size > 0) res = i + 1; + } + + return res; +}; + +class UnionFind { + constructor(arr) { + [this.parents, this.ranks] = this.initialise(arr); + } + + initialise(arr) { + const parents = new Map(); + const ranks = new Map(); + arr.forEach(val => { + parents.set(val, val); + ranks.set(val, 1); + }) + + return [parents, ranks]; + } + + find(val) { + if (this.parents.get(val) === val) return val; + this.parents.set(val, this.find(this.parents.get(val))); + return this.parents.get(val); + } + + union(m, n) { + const rootM = this.find(m); + const rootN = this.find(n); + + if (rootM === rootN) return; + if (rootM > rootN) { + this.updateParent(rootN, rootM); + } else { + this.updateParent(rootM, rootN); + } + } + + updateParent(child, parent) { + this.ranks.set(parent, this.ranks.get(parent) + this.ranks.get(child)); + this.parents.set(child, parent); + } +} diff --git a/1564-put-boxes-into-the-warehouse-i.js b/1564-put-boxes-into-the-warehouse-i.js new file mode 100644 index 00000000..cf4ca8e3 --- /dev/null +++ b/1564-put-boxes-into-the-warehouse-i.js @@ -0,0 +1,59 @@ +/** + * @param {number[]} boxes + * @param {number[]} warehouse + * @return {number} + */ +const maxBoxesInWarehouse = function(boxes, warehouse) { + boxes.sort((a, b) => a - b) + const m = boxes.length, n = warehouse.length + let i = 0, j = 0 + for(; i < m && j < n; i++) { + if(boxes[m - i - 1] <= warehouse[j]) { + j++ + } + if(j === n) return n + } + return j +}; + +// another + +/** + * @param {number[]} boxes + * @param {number[]} warehouse + * @return {number} + */ +const maxBoxesInWarehouse = function(boxes, warehouse) { + if(warehouse == null || warehouse.length === 0) return 0 + const m = boxes.length, n = warehouse.length + for(let i = 1; i < n; i++) { + warehouse[i] = Math.min(warehouse[i], warehouse[i - 1]) + } + boxes.sort((a, b) => a - b) + let res = 0 + for(let i = n - 1; i >= 0; i--) { + if(res < m && boxes[res] <= warehouse[i]) res++ + } + return res +}; + +// another + +/** + * @param {number[]} boxes + * @param {number[]} warehouse + * @return {number} + */ +const maxBoxesInWarehouse = function(boxes, warehouse) { + if(warehouse == null || warehouse.length === 0) return 0 + const m = boxes.length, n = warehouse.length + boxes.sort((a, b) => a - b) + let i = m - 1, res = 0 + for(let house of warehouse) { + while(i >= 0 && boxes[i] > house) i-- + if(i === -1) return res + res++ + i-- + } + return res +}; diff --git a/1567-maximum-length-of-subarray-with-positive-product.js b/1567-maximum-length-of-subarray-with-positive-product.js new file mode 100644 index 00000000..aa384d85 --- /dev/null +++ b/1567-maximum-length-of-subarray-with-positive-product.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const getMaxLen = function(nums) { + let res = 0, zeroIdx = -1, negIdx = -1, count = 0 + for(let i = 0, len = nums.length; i < len; i++) { + if(nums[i] < 0) { + count++ + if(negIdx === -1) negIdx = i + } + if(nums[i] === 0) { + count = 0 + negIdx = -1 + zeroIdx = i + } else { + if(count % 2 === 0) res = Math.max(res, i - zeroIdx) + else res = Math.max(res, i - negIdx) + } + } + + return res +}; diff --git a/1568-minimum-number-of-days-to-disconnect-island.js b/1568-minimum-number-of-days-to-disconnect-island.js new file mode 100644 index 00000000..f356ab72 --- /dev/null +++ b/1568-minimum-number-of-days-to-disconnect-island.js @@ -0,0 +1,38 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const minDays = function (grid) { + if (!grid.length || !grid[0].length) return 0 + if (numIslands(grid) != 1) return 0 + for (let i = 0; i < grid.length; i++) { + for (let j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1) { + grid[i][j] = 0 + if (numIslands(grid) != 1) return 1 + grid[i][j] = 1 + } + } + } + return 2 +} + +function numIslands(grid) { + let m = Array.from({ length: grid.length }, (v, i) => { + return [...grid[i]] + }) + let count = 0 + for (let i = 0; i < m.length; i++) + for (let j = 0; j < m[0].length; j++) removeIslandAt(i, j, 1) + return count + function removeIslandAt(i, j, firstIteration = 0) { + if (i >= m.length || j >= m[0].length || i < 0 || j < 0 || m[i][j] == 0) + return + m[i][j] = 0 + count += firstIteration + removeIslandAt(i - 1, j) + removeIslandAt(i + 1, j) + removeIslandAt(i, j - 1) + removeIslandAt(i, j + 1) + } +} diff --git a/1569-number-of-ways-to-reorder-array-to-get-same-bst.js b/1569-number-of-ways-to-reorder-array-to-get-same-bst.js new file mode 100644 index 00000000..08b20471 --- /dev/null +++ b/1569-number-of-ways-to-reorder-array-to-get-same-bst.js @@ -0,0 +1,67 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const numOfWays = function (nums) { + let root = null + let cache = new Map() + + const MOD = BigInt(10 ** 9 + 7) + for (let n of nums) { + root = insert(root, n) + } + + // f(root) -> [length, combination] + function f(root) { + if (!root.left && !root.right) { + return [1n, 1n] + } + let [ll, lc] = [0n, 1n] + let [rl, rc] = [0n, 1n] + if (root.left) { + ;[ll, lc] = f(root.left) + } + if (root.right) { + ;[rl, rc] = f(root.right) + } + // ((ll + rl)! / (ll! * rl!) )* lc * rc + return [ + ll + rl + 1n, + (factorial(ll + rl) / factorial(ll) / factorial(rl)) * lc * rc, + ] + } + + return (f(root)[1] - 1n) % MOD + + function Node(val) { + this.val = val + this.left = this.right = null + } + + function insert(root, val) { + if (!root) { + return new Node(val) + } + if (root.val > val) { + root.left = insert(root.left, val) + } else if (root.val < val) { + root.right = insert(root.right, val) + } + return root + } + + function factorial(n) { + if (n == 0n) { + return 1n + } + if (cache.has(n)) { + return cache.get(n) + } + let ans = 1n + for (let i = 2n; i <= n; i++) { + ans *= i + cache.set(i, ans) + } + return ans + } +} diff --git a/157-read-n-characters-given-read4.js b/157-read-n-characters-given-read4.js new file mode 100644 index 00000000..82dfc29e --- /dev/null +++ b/157-read-n-characters-given-read4.js @@ -0,0 +1,36 @@ +/** + * Definition for read4() + * + * @param {character[]} buf Destination buffer + * @return {number} The number of actual characters read + * read4 = function(buf) { + * ... + * }; + */ + +/** + * @param {function} read4() + * @return {function} + */ +const solution = function(read4) { + const internalBuf = [] + /** + * @param {character[]} buf Destination buffer + * @param {number} n Number of characters to read + * @return {number} The number of actual characters read + */ + return function(buf, n) { + let readChars = 0 + while (n > 0) { + if (internalBuf.length === 0) { + if (read4(internalBuf) === 0) { + return readChars + } + } + buf.push(internalBuf.shift()) + readChars++ + n-- + } + return readChars + } +} diff --git a/1570-dot-product-of-two-sparse-vectors.js b/1570-dot-product-of-two-sparse-vectors.js new file mode 100644 index 00000000..682b656d --- /dev/null +++ b/1570-dot-product-of-two-sparse-vectors.js @@ -0,0 +1,67 @@ +/** + * @param {number[]} nums + * @return {SparseVector} + */ +const SparseVector = function(nums) { + this.seen = {} + nums.forEach((e, i) => { + if(e !== 0) this.seen[i] = e + }) +}; + +// Return the dotProduct of two sparse vectors +/** + * @param {SparseVector} vec + * @return {number} + */ +SparseVector.prototype.dotProduct = function(vec) { + let res = 0 + for(let [k, v] of Object.entries(vec.seen)) { + if(k in this.seen) res += v * this.seen[k] + } + return res +}; + +// Your SparseVector object will be instantiated and called as such: +// let v1 = new SparseVector(nums1); +// let v2 = new SparseVector(nums2); +// let ans = v1.dotProduct(v2); + +// another + +class SparseVector { + /** + * @param {number[]} nums + * @return {SparseVector} + */ + constructor(nums) { + // Space: O(n) + this.seen = new Map() // index -> value + for (let i = 0; i < nums.length; ++i) { + if (nums[i] !== 0) { + this.seen.set(i, nums[i]) + } + } + } + + /** + * Return the dotProduct of two sparse vectors + * @param {SparseVector} vec + * @return {number} + */ + dotProduct(vec) { + // Time: O(n) + let sum = 0 + for (const [i, val] of vec.seen) { + if (this.seen.has(i)) { + sum += val * this.seen.get(i) + } + } + return sum + } +} + +// Your SparseVector object will be instantiated and called as such: +// let v1 = new SparseVector(nums1); +// let v2 = new SparseVector(nums2); +// let ans = v1.dotProduct(v2); diff --git a/1571-warehouse-manager.sql b/1571-warehouse-manager.sql new file mode 100644 index 00000000..928f43d5 --- /dev/null +++ b/1571-warehouse-manager.sql @@ -0,0 +1,8 @@ +# Write your MySQL query statement below +SELECT name as warehouse_name, SUM(units*dimension) as volume FROM +( + SELECT product_id, Width*Length*Height as dimension FROM Products +) a +JOIN Warehouse as b +ON a.product_id=b.product_id +GROUP BY name; diff --git a/1572-matrix-diagonal-sum.js b/1572-matrix-diagonal-sum.js new file mode 100644 index 00000000..88866342 --- /dev/null +++ b/1572-matrix-diagonal-sum.js @@ -0,0 +1,16 @@ +/** + * @param {number[][]} mat + * @return {number} + */ +const diagonalSum = function(mat) { + let res = 0, n = mat.length + for(let i = 0; i < n; i++) { + const j = i, ii = i, jj = n - 1 - i + if(j == jj) res += mat[i][j] + else { + res += mat[i][j] + mat[ii][jj] + } + } + + return res +}; diff --git a/1573-number-of-ways-to-split-a-string.js b/1573-number-of-ways-to-split-a-string.js new file mode 100644 index 00000000..951172e8 --- /dev/null +++ b/1573-number-of-ways-to-split-a-string.js @@ -0,0 +1,28 @@ +/** + * @param {string} s + * @return {number} + */ +const numWays = function(s) { + const n = s.length + const cnt = Array(n).fill(0) + let num = 0 + for(let i = 0; i < n; i++) { + if(s[i] === '1') num++ + cnt[i] = num + } + const mod = 1e9 + 7 + let i0 = -1, i1 = -1, i2 = -1, i3 = -1 + for(let i = 0; i < n; i++) { + if(cnt[i] === num / 3) { + if(i0 === -1) i0 = i1 = i + else i1 = i + } else if(cnt[i] === 2 * num / 3) { + if(i2 === -1) i2 = i3 = i + else i3 = i + } + } + if(num === 0) return (n - 1) * (n - 2) / 2 % mod + if(i0 === -1 || i1 === -1 || i2 === -1 || i3 === -1) return 0 + + return (i1 - i0 + 1) * (i3 - i2 + 1) % mod +}; diff --git a/1574-shortest-subarray-to-be-removed-to-make-array-sorted.js b/1574-shortest-subarray-to-be-removed-to-make-array-sorted.js new file mode 100644 index 00000000..7b4c43ef --- /dev/null +++ b/1574-shortest-subarray-to-be-removed-to-make-array-sorted.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const findLengthOfShortestSubarray = function (arr) { + const n = arr.length + let left = 0 + for(let i = 0; i < n - 1; i++) { + if(arr[i] > arr[i+ 1]) { + break + } + left = i + 1 + } + + let right = n - 1 + for(let i = n - 1; i > 0; i--) { + if(arr[i] < arr[i - 1]) { + break + } + right = i - 1 + } + // console.log(left, right) + if(left === n - 1) return 0 + + let res = Math.min(n - 1 - left, right) + let l = 0, r = right + while(l <= left && r < n) { + if(arr[l] <= arr[r]) { + res = Math.min(res, r - 1 - l) + l++ + } else { + r++ + } + } + + return res +} diff --git a/1575-count-all-possible-routes.js b/1575-count-all-possible-routes.js new file mode 100644 index 00000000..75a9ec24 --- /dev/null +++ b/1575-count-all-possible-routes.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} locations + * @param {number} start + * @param {number} finish + * @param {number} fuel + * @return {number} + */ +const countRoutes = function (locations, start, finish, fuel) { + const n = locations.length + const mod = 10 ** 9 + 7 + const dp = Array.from({ length: n }, () => Array(fuel + 1).fill(-1)) + return solve(start, finish, fuel) + function solve(curCity, e, fuel) { + if (fuel < 0) return 0 + if (dp[curCity][fuel] !== -1) return dp[curCity][fuel] + let ans = curCity === e ? 1 : 0 + for (let nextCity = 0; nextCity < locations.length; nextCity++) { + if (nextCity !== curCity) { + ans += + solve( + nextCity, + e, + fuel - Math.abs(locations[curCity] - locations[nextCity]) + ) % mod + } + } + return (dp[curCity][fuel] = ans % mod) + } +} diff --git a/1576-replace-all-s-to-avoid-consecutive-repeating-characters.js b/1576-replace-all-s-to-avoid-consecutive-repeating-characters.js new file mode 100644 index 00000000..51a743c9 --- /dev/null +++ b/1576-replace-all-s-to-avoid-consecutive-repeating-characters.js @@ -0,0 +1,56 @@ +/** + * @param {string} s + * @return {string} + */ +const modifyString = function(s) { + const arr = s.split('') + for(let i = 0, n = s.length; i < n; i++) { + const cur = arr[i] + if(cur === '?') { + for(let j = 0, a = 'a'.charCodeAt(0); j < 26; j++) { + const ch = String.fromCharCode(a + j) + if( + n === 1 || + (i === 0 && i < n - 1 && ch !== arr[i + 1]) || + (i > 0 && ch !== arr[i - 1] && i < n - 1 && ch !== arr[i + 1]) || + (i=== n -1 && i - 1 >= 0 && ch !== arr[i - 1]) + ) { + + arr[i] = ch + break + } + } + } + } + + return arr.join('') +}; + + +// another + +/** + * @param {string} s + * @return {string} + */ +const modifyString = function(s) { + const arr = s.split('') + for(let i = 0, n = s.length; i < n; i++) { + const cur = arr[i] + if(cur === '?') { + for(let j = 0, a = 'a'.charCodeAt(0); j < 26; j++) { + const ch = String.fromCharCode(a + j) + if( + (i === 0 || arr[i - 1] !== ch) && + (i === n - 1 || arr[i + 1] !== ch) + ) { + + arr[i] = ch + break + } + } + } + } + + return arr.join('') +}; diff --git a/1578-minimum-deletion-cost-to-avoid-repeating-letters.js b/1578-minimum-deletion-cost-to-avoid-repeating-letters.js new file mode 100644 index 00000000..907a35f0 --- /dev/null +++ b/1578-minimum-deletion-cost-to-avoid-repeating-letters.js @@ -0,0 +1,22 @@ +/** + * @param {string} s + * @param {number[]} cost + * @return {number} + */ +const minCost = function (s, cost) { + let stackPointer = 0 + let minVal = 0 + for (let i = 1; i < s.length; i++) { + if (s[i - 1] === s[i]) { + if (cost[stackPointer] < cost[i]) { + minVal += cost[stackPointer] + stackPointer = i + } else { + minVal += cost[i] + } + } else { + stackPointer = i + } + } + return minVal +} diff --git a/1579-remove-max-number-of-edges-to-keep-graph-fully-traversable.js b/1579-remove-max-number-of-edges-to-keep-graph-fully-traversable.js new file mode 100644 index 00000000..96873a60 --- /dev/null +++ b/1579-remove-max-number-of-edges-to-keep-graph-fully-traversable.js @@ -0,0 +1,53 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +const maxNumEdgesToRemove = function (n, edges) { + edges.sort((a, b) => b[0] - a[0]) + let edgesAdded = 0 + const bob = new UnionFind(n) + const alice = new UnionFind(n) + for (let edge of edges) { + let type = edge[0], + one = edge[1], + two = edge[2] + switch (type) { + case 3: + edgesAdded += bob.unite(one, two) | alice.unite(one, two) + break + case 2: + edgesAdded += bob.unite(one, two) + break + case 1: + edgesAdded += alice.unite(one, two) + break + } + } + return bob.united() && alice.united() ? edges.length - edgesAdded : -1 +} +class UnionFind { + constructor(n) { + this.component = [] + this.distinctComponents = n + for (let i = 0; i <= n; i++) this.component.push(i) + } + unite(a, b) { + const ar = this.find(a) + if (ar !== this.find(b)) { + this.component[ar] = b + this.distinctComponents-- + return true + } + return false + } + find(a) { + if (this.component[a] != a) { + this.component[a] = this.find(this.component[a]) + } + return this.component[a] + } + united() { + return this.distinctComponents === 1 + } +} diff --git a/158-read-n-characters-given-read4-ii-call-multiple-times.js b/158-read-n-characters-given-read4-ii-call-multiple-times.js new file mode 100644 index 00000000..efb12750 --- /dev/null +++ b/158-read-n-characters-given-read4-ii-call-multiple-times.js @@ -0,0 +1,36 @@ +/** + * Definition for read4() + * + * @param {character[]} buf Destination buffer + * @return {number} The number of characters read + * read4 = function(buf) { + * ... + * }; + */ + +/** + * @param {function} read4() + * @return {function} + */ +const solution = function(read4) { + const internalBuf = [] + /** + * @param {character[]} buf Destination buffer + * @param {number} n Number of characters to read + * @return {number} The number of actual characters read + */ + return function(buf, n) { + let readChars = 0 + while (n > 0) { + if (internalBuf.length === 0) { + if (read4(internalBuf) === 0) { + return readChars + } + } + buf.push(internalBuf.shift()) + readChars++ + n-- + } + return readChars + } +} diff --git a/1581-customer-who-visited-but-did-not-make-any-transactions.sql b/1581-customer-who-visited-but-did-not-make-any-transactions.sql new file mode 100644 index 00000000..9021027a --- /dev/null +++ b/1581-customer-who-visited-but-did-not-make-any-transactions.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +SELECT customer_id, COUNT(*) as count_no_trans +FROM Visits +WHERE visit_id NOT IN (SELECT DISTINCT visit_id FROM Transactions) +GROUP BY customer_id; diff --git a/1584-min-cost-to-connect-all-points.js b/1584-min-cost-to-connect-all-points.js new file mode 100644 index 00000000..b493e888 --- /dev/null +++ b/1584-min-cost-to-connect-all-points.js @@ -0,0 +1,36 @@ +/** + * @param {number[][]} points + * @return {number} + */ +const minCostConnectPoints = function(points) { + let minIndex,minDistance=Number.MAX_SAFE_INTEGER,sum=0; + let distanceMap={}; + let prevouslyTakenIndex = 0,taken=1,takenMap={}; + for(let i=1;i []) + for (let i = s.length - 1; i >= 0; --i) { + indices[s.charCodeAt(i) - offset].push(i) + } + for (const char of t) { + const digit = char.charCodeAt(0) - offset + if (indices[digit].length === 0) return false + const pos = indices[digit][indices[digit].length - 1] + for (let d = 0; d < digit; ++d) { + if (indices[d].length && indices[d][indices[d].length - 1] < pos) { + return false + } + } + indices[digit].pop() + } + return true +} diff --git a/1586-binary-search-tree-iterator-ii.js b/1586-binary-search-tree-iterator-ii.js new file mode 100644 index 00000000..305d57e3 --- /dev/null +++ b/1586-binary-search-tree-iterator-ii.js @@ -0,0 +1,140 @@ +/** + * 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 + */ +const BSTIterator = function(root) { + this.r = root + const ans = [] + helper(root, ans) + this.arr = ans + this.cur = -1 +}; + +/** + * @return {boolean} + */ +BSTIterator.prototype.hasNext = function() { + return this.arr.length && this.cur < this.arr.length - 1 +}; + +/** + * @return {number} + */ +BSTIterator.prototype.next = function() { + this.cur += 1 + return this.arr[this.cur] +}; + +/** + * @return {boolean} + */ +BSTIterator.prototype.hasPrev = function() { + return this.arr.length && this.cur > 0 +}; + +/** + * @return {number} + */ +BSTIterator.prototype.prev = function() { + return this.arr[--this.cur] +}; + +function helper(node, res) { + if(node == null) return + if(node.left) { + helper(node.left, res) + } + res.push(node.val) + if(node.right) { + helper(node.right, res) + } +} + +/** + * Your BSTIterator object will be instantiated and called as such: + * var obj = new BSTIterator(root) + * var param_1 = obj.hasNext() + * var param_2 = obj.next() + * var param_3 = obj.hasPrev() + * var param_4 = obj.prev() + */ + +// another + +/** + * 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 + */ +const BSTIterator = function (root) { + this.nums = [] + this.stack = [] + this.node = root + this.i = 0 // pointer to next node + this.size = 0 +} + +/** + * @return {boolean} + */ +BSTIterator.prototype.hasNext = function () { + return this.i < this.size || this.stack.length > 0 || !!this.node +} + +/** + * @return {number} + */ +BSTIterator.prototype.next = function () { + if (this.i < this.size) return this.nums[this.i++] + if (this.stack.length || this.node) { + while (this.node) { + this.stack.push(this.node) + this.node = this.node.left + } + this.node = this.stack.pop() + this.i += 1 + this.size += 1 + const val = this.node.val + this.nums.push(val) + this.node = this.node.right + return val + } + return -1 +} + +/** + * @return {boolean} + */ +BSTIterator.prototype.hasPrev = function () { + return this.i - 2 >= 0 +} + +/** + * @return {number} + */ +BSTIterator.prototype.prev = function () { + return this.nums[--this.i - 1] +} + +/** + * Your BSTIterator object will be instantiated and called as such: + * var obj = new BSTIterator(root) + * var param_1 = obj.hasNext() + * var param_2 = obj.next() + * var param_3 = obj.hasPrev() + * var param_4 = obj.prev() + */ + diff --git a/1587-bank-account-summary-ii.sql b/1587-bank-account-summary-ii.sql new file mode 100644 index 00000000..68ae3626 --- /dev/null +++ b/1587-bank-account-summary-ii.sql @@ -0,0 +1,7 @@ +# Write your MySQL query statement below +SELECT u.name, SUM(amount) as balance +FROM Transactions +JOIN Users u +USING (account) +GROUP BY account +HAVING balance>10000; diff --git a/1588-sum-of-all-odd-length-subarrays.js b/1588-sum-of-all-odd-length-subarrays.js new file mode 100644 index 00000000..3306288b --- /dev/null +++ b/1588-sum-of-all-odd-length-subarrays.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const sumOddLengthSubarrays = function(arr) { + const n = arr.length, pre = Array(n + 1).fill(0) + for(let i = 0; i < n; i++) pre[i + 1] = pre[i] + arr[i] + + let res = 0 + let len = 1 + while(len <= n) { + for(let i = 0; i <= n - len; i++) { + res += pre[i + len] - pre[i] // len === 1: 1 - 0, 2 - 1 + // len === 3: 3 - 0, 6 - 3 + } + + len += 2 + } + + return res + +}; diff --git a/1589-maximum-sum-obtained-of-any-permutation.js b/1589-maximum-sum-obtained-of-any-permutation.js new file mode 100644 index 00000000..2a42dd8b --- /dev/null +++ b/1589-maximum-sum-obtained-of-any-permutation.js @@ -0,0 +1,109 @@ +/** + * @param {number[]} nums + * @param {number[][]} requests + * @return {number} + */ +const maxSumRangeQuery = function(nums, requests) { + nums.sort((a, b) => b - a) + const n = nums.length + const arr = Array(n).fill(0) + for(const [s, e] of requests) { + arr[s] += 1 + if(e + 1 < n) arr[e + 1] -= 1 + } + for(let i = 1; i < n; i++) { + arr[i] += arr[i - 1] + } + arr.sort((a, b) => b - a) + + let res = 0 + const mod = 1e9 + 7 + + for(let i = 0; i < n; i++) { + res = (res + nums[i] * arr[i]) % mod + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number[][]} requests + * @return {number} + */ +const maxSumRangeQuery = function (nums, requests) { + let res = 0 + const mod = 10 ** 9 + 7, + n = nums.length + const count = Array(n).fill(0) + for (let r of requests) { + count[r[0]] += 1 + if (r[1] + 1 < n) count[r[1] + 1] -= 1 + } + for (let i = 1; i < n; i++) count[i] += count[i - 1] + nums.sort((a, b) => a - b) + count.sort((a, b) => a - b) + for (let i = 0; i < n; ++i) res = (res + nums[i] * count[i]) % mod + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number[][]} requests + * @return {number} + */ +const maxSumRangeQuery = function (nums, requests) { + const n = nums.length, arr = Array(n + 1).fill(0) + for(let [s, e] of requests) { + arr[s] += 1 + arr[e + 1] -= 1 + } + for(let i = 0, cur = 0; i < n; i++) { + cur += arr[i] + arr[i] = cur + } + nums.sort((a, b) => b - a) + arr.sort((a, b) => b - a) + const mod = 1e9 + 7 + let res = 0 + for(let i = 0; i < n; i++) { + if (arr[i] <= 0) break + res = (res + nums[i] * arr[i]) % mod + } + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number[][]} requests + * @return {number} + */ +const maxSumRangeQuery = function (nums, requests) { + const n = nums.length + + const arr = Array(n + 1).fill(0) + for(const [s, e] of requests) { + arr[s] += 1 + arr[e + 1] -= 1 + } + for(let i = 1; i <= n; i++) { + arr[i] += arr[i - 1] + } + arr.sort((a, b) => b - a) + nums.sort((a, b) => b - a) + let res = 0 + const mod = 1e9 + 7 + + for (let i = 0; i < n; i++) { + if(arr[i] <= 0) break + res = (res + nums[i] * arr[i]) % mod + } + + return res +} diff --git a/159-longest-substring-with-at-most-two-distinct-characters.js b/159-longest-substring-with-at-most-two-distinct-characters.js new file mode 100644 index 00000000..0069690e --- /dev/null +++ b/159-longest-substring-with-at-most-two-distinct-characters.js @@ -0,0 +1,27 @@ +/** + * @param {string} s + * @return {number} + */ +const lengthOfLongestSubstringTwoDistinct = function(s) { + const map = new Map() + let start = 0, + end = 0, + counter = 0, + len = 0 + while (end < s.length) { + let c = s.charAt(end) + map.set(c, (map.get(c) || 0) + 1) + if (map.get(c) === 1) counter++ + end++ + while (counter > 2) { + let cTemp = s.charAt(start) + map.set(cTemp, map.get(cTemp) - 1) + if (map.get(cTemp) === 0) { + counter-- + } + start++ + } + len = Math.max(len, end - start) + } + return len +} diff --git a/1590-make-sum-divisible-by-p.js b/1590-make-sum-divisible-by-p.js new file mode 100644 index 00000000..4c903d90 --- /dev/null +++ b/1590-make-sum-divisible-by-p.js @@ -0,0 +1,121 @@ +/** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ +var minSubarray = function(nums, p) { + const n = nums.length + const sum = nums.reduce((acc, cur) => acc + cur, 0) + const target = sum % p + if(target === 0) return 0 + const hash = {0: -1} + let res = n + let curSum = 0 + for(let i = 0; i < n; i++) { + const e = nums[i] + curSum += e + const remain = curSum % p + const diff = (remain - target + p) % p + if(hash[diff] != null) { + res = Math.min(res, i - hash[diff]) + } + hash[remain] = i + } + + return res === n ? -1 : res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ +const minSubarray = function(nums, p) { + const sum = nums.reduce((ac, e) => ac+ e,0) + const target = sum % p, n = nums.length, {min} = Math + if(target === 0) return 0 + const map = new Map() + map.set(0, -1) + let res = n + for(let i = 0, s = 0; i < n; i++) { + s += nums[i] + const r = s % p + + if(r >= target) { + if(map.has(r - target)) res = min(res, i - map.get(r-target)) + }else { + if(map.has(p + r - target)) res = min(res, i - map.get(p + r - target)) + } + map.set(r, i) + } + + return res === n ? -1 : res +}; + +// another + + +/** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ +const minSubarray = function(nums, p) { + const remain = nums.reduce((ac, e) => ac + e, 0) % p + const n = nums.length, hash = {0: -1} + let res = n + if(remain === 0) return 0 + for(let i = 0, sum = 0; i < n; i++) { + const cur = nums[i] + sum += cur + const target = (sum % p - remain + p) % p + if(hash[target] != null) { + res = Math.min(res, i - hash[target]) + } + + hash[sum % p] = i + } +// console.log(hash) + + return res === n ? -1 : res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ +const minSubarray = function(nums, p) { + const diff = nums.reduce((a, b) => a + b, 0) % p; + let res = diff === 0 ? 0 : nums.length; + + for (let i = 0, sum = 0, map = {0: -1}; i < nums.length; i++) { + sum += nums[i]; + const target = (sum % p - diff + p) % p; + if (map[target] !== undefined) { + res = Math.min(res, i - map[target]); + } + map[sum % p] = i; + } + + return res === nums.length ? -1 : res; +}; + +/** + +Let pre[] be the prefix sum array, +then pre[i] is running prefix sum or prefix sum of i elements, +pre[j] is the prefix sum such that pre[i]-pre[j] is the subarray we +need to remove to make pre[n] (sum of all elements) divisible by p + +(pre[n] - (pre[i]-pre[j])) % p = 0 ... (remove a subarray to make pre[n] divisible by p) +=> pre[n] % p = (pre[i]-pre[j]) % p ... ((a-b)%m = a%m - b%m) +=> pre[j]%p = pre[i]%p - pre[n]%p ... (same property used above) +since RHS can be negative we make it positive modulus by adding p and taking modulus +=> pre[j]%p = (pre[i]%p - pre[n]%p + p) % p + +*/ diff --git a/1591-strange-printer-ii.js b/1591-strange-printer-ii.js new file mode 100644 index 00000000..1db9c901 --- /dev/null +++ b/1591-strange-printer-ii.js @@ -0,0 +1,195 @@ +/** + * @param {number[][]} targetGrid + * @return {boolean} + */ +const isPrintable = function(targetGrid) { + // solve the problem: BFS + // 1. find the top-left and bottom-right corner of each color + // 2. check if there is a circle in the graph + // 3. if there is a circle, return false + // 4. if there is no circle, return true + const m = targetGrid.length; + const n = targetGrid[0].length; + const left = new Array(61).fill(n); + const right = new Array(61).fill(-1); + const top = new Array(61).fill(m); + const bottom = new Array(61).fill(-1); + const next = new Array(61).fill(null).map(() => []); + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + const color = targetGrid[i][j]; + left[color] = Math.min(left[color], j); + right[color] = Math.max(right[color], j); + top[color] = Math.min(top[color], i); + bottom[color] = Math.max(bottom[color], i); + } + } + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + for (let color = 1; color <= 60; color++) { + if (i >= top[color] && i <= bottom[color] && j >= left[color] && j <= right[color]) { + if (color !== targetGrid[i][j]) { + next[targetGrid[i][j]].push(color); + } + } + } + } + } + const numNodes = 61; + const inDegree = new Array(numNodes).fill(0); + for (let i = 0; i < numNodes; i++) { + for (const j of next[i]) { + inDegree[j]++; + } + } + const queue = []; + let count = 0; + for (let i = 0; i < numNodes; i++) { + if (inDegree[i] === 0) { + queue.push(i); + count++; + } + } + while (queue.length > 0) { + const curCourse = queue.shift(); + for (const child of next[curCourse]) { + inDegree[child]--; + if (inDegree[child] === 0) { + queue.push(child); + count++; + } + } + } + return count === numNodes; +}; + +// another + + +/** + * @param {number[][]} targetGrid + * @return {boolean} + */ +const isPrintable = function (targetGrid) { + const posMin = Array.from({ length: 61 }, () => Array(2).fill(61)) + const posMax = Array.from({ length: 61 }, () => Array(2).fill(0)) + const m = targetGrid.length + const n = targetGrid[0].length + let colorSet = new Set() + + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + let c = targetGrid[i][j] + colorSet.add(c) + posMin[c][0] = Math.min(posMin[c][0], i) //Up + posMin[c][1] = Math.min(posMin[c][1], j) //Left + posMax[c][0] = Math.max(posMax[c][0], i) //Down + posMax[c][1] = Math.max(posMax[c][1], j) //Right + } + } + while (colorSet.size) { + const tmp = new Set() + for (let color of colorSet) { + if (!isRect(targetGrid, color)) { + tmp.add(color) + } + } + + if (tmp.size === colorSet.size) return false + colorSet = tmp + } + + return true + + function isRect(A, c) { + for (let i = posMin[c][0]; i <= posMax[c][0]; i++) { + for (let j = posMin[c][1]; j <= posMax[c][1]; j++) { + if (A[i][j] > 0 && A[i][j] !== c) return false + } + } + + for (let i = posMin[c][0]; i <= posMax[c][0]; i++) { + for (let j = posMin[c][1]; j <= posMax[c][1]; j++) { + A[i][j] = 0 + } + } + + return true + } +} + +// another + +/** + * @param {number[][]} targetGrid + * @return {boolean} + */ +const isPrintable = function (targetGrid) { + /* + 1 -> 3 + 1 -> 4 + 1 -> 5 + 3 -> 4 + */ + + const dependencies = {} + + /* + 3: [mini, maxi, minj, maxj] + */ + const extents = {} + + for (let i = 0; i < targetGrid.length; i++) { + for (let j = 0; j < targetGrid[i].length; j++) { + const n = targetGrid[i][j] + let inf = Infinity + extents[n] = extents[n] || { + n, + mini: inf, + minj: inf, + maxi: -inf, + maxj: -inf, + } + extents[n].mini = Math.min(i, extents[n].mini) + extents[n].minj = Math.min(j, extents[n].minj) + extents[n].maxi = Math.max(i, extents[n].maxi) + extents[n].maxj = Math.max(j, extents[n].maxj) + } + } + + function canRemove(obj) { + for (let i = obj.mini; i <= obj.maxi; i++) { + for (let j = obj.minj; j <= obj.maxj; j++) { + const val = targetGrid[i][j] + if (val !== null && val !== obj.n) return false + } + } + return true + } + + function remove(obj) { + for (let i = obj.mini; i <= obj.maxi; i++) { + for (let j = obj.minj; j <= obj.maxj; j++) { + targetGrid[i][j] = null + } + } + delete extents[obj.n] + } + + while (Object.keys(extents).length > 0) { + let found = false + for (const n in extents) { + const obj = extents[n] + if (canRemove(obj)) { + remove(obj) + found = true + break + } + } + if (!found) { + return false + } + } + return true +} + diff --git a/1592-rearrange-spaces-between-words.js b/1592-rearrange-spaces-between-words.js new file mode 100644 index 00000000..8b2f4909 --- /dev/null +++ b/1592-rearrange-spaces-between-words.js @@ -0,0 +1,23 @@ +/** + * @param {string} text + * @return {string} + */ +const reorderSpaces = function(text) { + let sc = 0 + for(let i = 0, len = text.length; i < len; i++) { + if(text[i] === ' ') sc++ + } + const arr = text.split(' ').filter(e => e!= '') + const num = arr.length - 1 + const remain = num === 0 ? sc : sc % num + const split = num === 0 ? 0 : Array( (sc / num) >> 0 ).fill(0).reduce((ac, el) => ac + ' ', '') + let res = '' + res = arr.join(split) + helper(remain) + return res +}; + +function helper(n) { + let res = '' + for(let i = 0; i < n; i++) res += ' ' + return res +} diff --git a/1593-split-a-string-into-the-max-number-of-unique-substrings.js b/1593-split-a-string-into-the-max-number-of-unique-substrings.js new file mode 100644 index 00000000..cfd06a65 --- /dev/null +++ b/1593-split-a-string-into-the-max-number-of-unique-substrings.js @@ -0,0 +1,51 @@ +/** + * @param {string} s + * @return {number} + */ +const maxUniqueSplit = function(s) { + return bt(s, '', 0, new Set()) +}; + +function bt(str, cur, idx, useds) { + if(idx === str.length) return useds.size + cur += str[idx] + if(useds.has(cur)) return bt(str, cur, idx +1, useds) + else { + let ans = 0 + useds.add(cur) + ans = Math.max(ans, bt(str, '', idx+1, useds)) + useds.delete(cur) + ans = Math.max(ans, bt(str, cur, idx+1, useds)) + return ans + } +} + +// another + +/** + * @param {string} s + * @return {number} + */ +const maxUniqueSplit = function (s) { + const N = s.length + let ans = -1 + let curr = new Set() + const backtrack = (pos) => { + if (pos === N) { + ans = Math.max(ans, curr.size) + return + } + if (curr.size + (N - pos) <= ans) return + for (let i = pos + 1; i <= N; i++) { + const a = s.slice(pos, i) + if (curr.has(a)) continue + curr.add(a) + backtrack(i) + curr.delete(a) + } + } + + backtrack(0) + return ans +} + diff --git a/1594-maximum-non-negative-product-in-a-matrix.js b/1594-maximum-non-negative-product-in-a-matrix.js new file mode 100644 index 00000000..34e90309 --- /dev/null +++ b/1594-maximum-non-negative-product-in-a-matrix.js @@ -0,0 +1,37 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const maxProductPath = function (grid) { + const m = grid.length, + n = grid[0].length, + MOD = 1e9 + 7; + const mx = Array.from({ length: m }, () => Array(n).fill(0)); + const mn = Array.from({ length: m }, () => Array(n).fill(0)); + mx[0][0] = mn[0][0] = grid[0][0]; + + // initialize the top and left sides + for (let i = 1; i < m; i++) { + mn[i][0] = mx[i][0] = mx[i - 1][0] * grid[i][0]; + } + for (let j = 1; j < n; j++) { + mn[0][j] = mx[0][j] = mx[0][j - 1] * grid[0][j]; + } + + for (let i = 1; i < m; i++) { + for (let j = 1; j < n; j++) { + if (grid[i][j] < 0) { + // smallest negative * negative number = largest + mx[i][j] = Math.min(mn[i - 1][j], mn[i][j - 1]) * grid[i][j]; + mn[i][j] = Math.max(mx[i - 1][j], mx[i][j - 1]) * grid[i][j]; + } else { + // largest product * positive number = largest + mx[i][j] = Math.max(mx[i - 1][j], mx[i][j - 1]) * grid[i][j]; + mn[i][j] = Math.min(mn[i - 1][j], mn[i][j - 1]) * grid[i][j]; + } + } + } + + let ans = mx[m - 1][n - 1] % MOD; + return ans < 0 ? -1 : ans; +}; diff --git a/1595-minimum-cost-to-connect-two-groups-of-points.js b/1595-minimum-cost-to-connect-two-groups-of-points.js new file mode 100644 index 00000000..43e3d060 --- /dev/null +++ b/1595-minimum-cost-to-connect-two-groups-of-points.js @@ -0,0 +1,122 @@ +/** + * @param {number[][]} cost + * @return {number} + */ +const connectTwoGroups = function(cost) { + const m = cost.length, n = cost[0].length, { min } = Math + const limit = 1 << n + const dp = Array.from({ length: m + 1 }, () => Array(limit).fill(Infinity)) + const subCost = Array.from({ length: m + 1 }, () => Array(limit).fill(Infinity)) + + for(let i = 0; i < m; i++) { + for(let mask = 0; mask < limit; mask++) { + let sum = 0 + for(let j = 0; j < n; j++) { + if((mask >> j) & 1) { + sum += cost[i][j] + } + } + + subCost[i][mask] = sum + } + } + + dp[0][0] = 0 + for(let i = 1; i <= m; i++) { + for(let mask = 0; mask < limit; mask++) { + for(let sub = mask; sub; sub = (sub - 1) & mask) { + dp[i][mask] = min( + dp[i][mask], + dp[i - 1][mask - sub] + subCost[i - 1][sub] + ) + } + let tmp = Infinity + for(let j = 0; j < n; j++) { + tmp = min(tmp, cost[i - 1][j]) + } + + dp[i][mask] = min(dp[i][mask], dp[i - 1][mask] + tmp) + } + } + // console.log(dp) + return dp[m][limit - 1] +}; + +// another + + +/** + * @param {number[][]} cost + * @return {number} + */ +const connectTwoGroups = function (cost) { + const min = Array(cost[0].length).fill(Infinity) + for (let j = 0; j < min.length; j++) { + for (let i = 0; i < cost.length; i++) { + min[j] = Math.min(min[j], cost[i][j]) + } + } + const dp = Array.from({ length: 13 }, () => Array(4096).fill(-1)) + return dfs(cost, min, 0, 0, dp) +} + +function dfs(cost, min, i, mask, dp) { + if (dp[i][mask] !== -1) return dp[i][mask] + let res = i >= cost.length ? 0 : Infinity + if (i >= cost.length) { + for (let j = 0; j < cost[0].length; j++) { + if ((mask & (1 << j)) === 0) res += min[j] + } + } else { + for (let j = 0; j < cost[0].length; j++) { + res = Math.min( + res, + cost[i][j] + dfs(cost, min, i + 1, mask | (1 << j), dp) + ) + } + } + dp[i][mask] = res + return res +} + +// another + +/** + * @param {number[][]} cost + * @return {number} + */ +const connectTwoGroups = function (cost) { + const n = cost.length + const m = cost[0].length + const con = 1 << m + const dp = Array(n + 1) + .fill(null) + .map(() => Array(con).fill(0)) + const min = Array(m).fill(Infinity) + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + min[j] = Math.min(min[j], cost[i][j]) + } + } + function dfs(i, mask) { + let res + if (dp[i][mask]) { + return dp[i][mask] + } else if (i >= n) { + res = 0 + for (let j = 0; j < m; j++) { + const binaryJ = 1 << j + if ((mask & binaryJ) === 0) res += min[j] + } + } else { + res = Infinity + for (let j = 0; j < m; j++) { + const binaryJ = 1 << j + res = Math.min(res, cost[i][j] + dfs(i + 1, mask | binaryJ)) + } + } + dp[i][mask] = res + return res + } + return dfs(0, 0) +} diff --git a/1596-the-most-frequently-ordered-products-for-each-customer.sql b/1596-the-most-frequently-ordered-products-for-each-customer.sql new file mode 100644 index 00000000..5675a407 --- /dev/null +++ b/1596-the-most-frequently-ordered-products-for-each-customer.sql @@ -0,0 +1,12 @@ +# Write your MySQL query statement below +SELECT customer_id, product_id, product_name +FROM ( + SELECT O.customer_id, O.product_id, P.product_name, + RANK() OVER (PARTITION BY customer_id ORDER BY COUNT(O.product_id) DESC) AS rnk + FROM Orders O + JOIN Products P + ON O.product_id = P.product_id + GROUP BY customer_id, product_id +) temp +WHERE rnk = 1 +ORDER BY customer_id, product_id; diff --git a/1597-build-binary-expression-tree-from-infix-expression.js b/1597-build-binary-expression-tree-from-infix-expression.js new file mode 100644 index 00000000..5678858f --- /dev/null +++ b/1597-build-binary-expression-tree-from-infix-expression.js @@ -0,0 +1,108 @@ +/** + * Definition for a binary tree node. + * function Node(val, left, right) { + * this.val = (val===undefined ? " " : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {string} s + * @return {Node} + */ +const expTree = function (s) { + const n = s.length + const head = new Node() + let i = 0 + const number = () => { + let num = '' + while (i < n && '0' <= s[i]) { + num += s[i++] + } + return new Node(Number(num)) + } + const factor = () => { + if (s[i] === '(') { + i++ + const node = expression() + i++ + return node + } + return number() + } + const term = () => { + let left = factor() + while (i < n && (s[i] === '*' || s[i] === '/')) { + const op = new Node(s[i++]) + const right = factor() + op.left = left + op.right = right + left = op + } + return left + } + const expression = () => { + let left = term() + while (i < s.length && (s[i] === '+' || s[i] === '-')) { + const op = new Node(s[i++]) + const right = term() + op.left = left + op.right = right + left = op + } + return left + } + return expression() +} + + +// another + +/** + * Definition for a binary tree node. + * function Node(val, left, right) { + * this.val = (val===undefined ? " " : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {string} s + * @return {Node} + */ +const expTree = function(s) { + const list = s.split('') + const mdSet = new Set(['*', '/']) + const amSet = new Set(['+', '-']) + return parseExpression(list) + + function parseExpression(tokens) { + let lhs = parseTerm(tokens) + while(tokens.length && amSet.has(tokens[0])) { + const op = tokens.shift() + const rhs = parseTerm(tokens) + lhs = new Node(op, lhs, rhs) + } + return lhs + } + function parseTerm(tokens) { + let lhs = parseFactor(tokens) + while(tokens.length && mdSet.has(tokens[0])) { + const op = tokens.shift() + const rhs = parseFactor(tokens) + lhs = new Node(op, lhs, rhs) + } + return lhs + } + function parseFactor(tokens) { + if(tokens[0] === '(') { + tokens.shift() + const node = parseExpression(tokens) + tokens.shift() + return node + } else { + const token = tokens.shift() + return new Node(token) + } + } +}; diff --git a/1598-crawler-log-folder.js b/1598-crawler-log-folder.js new file mode 100644 index 00000000..204799df --- /dev/null +++ b/1598-crawler-log-folder.js @@ -0,0 +1,18 @@ +/** + * @param {string[]} logs + * @return {number} + */ +const minOperations = function(logs) { + const stack = [] + for(let i = 0, len = logs.length; i < len; i++) { + const e= logs[i] + if(e === '../') { + stack.pop() + } else if (e === './') { + + } else { + stack.push(e) + } + } + return stack.length +}; diff --git a/1599-maximum-profit-of-operating-a-centennial-wheel.js b/1599-maximum-profit-of-operating-a-centennial-wheel.js new file mode 100644 index 00000000..c1c107e9 --- /dev/null +++ b/1599-maximum-profit-of-operating-a-centennial-wheel.js @@ -0,0 +1,40 @@ +/** + * @param {number[]} customers + * @param {number} boardingCost + * @param {number} runningCost + * @return {number} + */ +const minOperationsMaxProfit = function(customers, boardingCost, runningCost) { + let remain = 0 + let profit = 0 + let cost = 0 + let max = -Infinity + let maxNum = 0 + for(let i = 0, len = customers.length; i < len; i++) { + const e = customers[i] + remain += e + const cur = (remain >= 4 ? 4 : remain) + remain -= cur + profit += cur * boardingCost - runningCost + if(profit > max) maxNum++ + max = Math.max(max, profit) + } + if(remain) { + const r = Math.floor(remain / 4) + const single = 4 * boardingCost - runningCost + remain = remain % 4 + // profit += (single * r + (remain > 0 ? (remain * boardingCost - runningCost) : 0)) + profit += single * r + if(single > 0) maxNum += r + max = Math.max(max, profit) + if (remain < 4) { + const tmp = remain * boardingCost - runningCost + profit += tmp + remain = 0 + if(profit > max) maxNum++ + max = Math.max(max, profit) + } + } + if (max <=0 )return -1 + return maxNum +}; diff --git a/16-3sum-closest.js b/16-3sum-closest.js index fbe0b658..014c404e 100755 --- a/16-3sum-closest.js +++ b/16-3sum-closest.js @@ -1,3 +1,33 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const threeSumClosest = function(nums, target) { + let n = nums.length, {abs, min, max} = Math + let res = nums[0] + nums[1] + nums[2] + nums.sort((a, b) => a - b) + for(let i = 0; i < n - 2; i++) { + let e = nums[i] + let l = i + 1, r = n - 1 + if(i > 0 && nums[i] === nums[i - 1]) continue + while(l < r) { + const tmp = e + nums[l] + nums[r] + if(abs(tmp - target) < abs(res - target)) { + res = tmp + } + if(tmp > target) r-- + else if (tmp < target) l++ + else return tmp + } + } + + + return res +}; + +// another + /** * @param {number[]} nums * @param {number} target diff --git a/160-intersection-of-two-linked-lists.js b/160-intersection-of-two-linked-lists.js index a44ab1d5..21ae7fec 100644 --- a/160-intersection-of-two-linked-lists.js +++ b/160-intersection-of-two-linked-lists.js @@ -1,3 +1,27 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ + +/** + * @param {ListNode} headA + * @param {ListNode} headB + * @return {ListNode} + */ +const getIntersectionNode = function(headA, headB) { + let a = headA, b = headB + while(a !== b) { + a = a == null ? headB : a.next + b = b == null ? headA : b.next + } + return a +}; + +// another + /** * Definition for singly-linked list. * function ListNode(val) { diff --git a/1600-throne-inheritance.js b/1600-throne-inheritance.js new file mode 100644 index 00000000..63865d1c --- /dev/null +++ b/1600-throne-inheritance.js @@ -0,0 +1,51 @@ +/** + * @param {string} kingName + */ +const ThroneInheritance = function(kingName) { + this.king = kingName + this.m = {} + this.dead = {} +}; + +/** + * @param {string} parentName + * @param {string} childName + * @return {void} + */ +ThroneInheritance.prototype.birth = function(parentName, childName) { + if(!this.m[parentName]) this.m[parentName] = [] + this.m[parentName].push(childName) +}; + +/** + * @param {string} name + * @return {void} + */ +ThroneInheritance.prototype.death = function(name) { + this.dead[name] = 1 +}; + +/** + * @return {string[]} + */ +ThroneInheritance.prototype.getInheritanceOrder = function() { + const res = [] + this.dfs(res, this.king) + return res +}; +ThroneInheritance.prototype.dfs = function(ans, root) { + if (!this.dead[root]) { + ans.push(root); + } + if(!this.m[root]) return + for (let child of this.m[root]) { + this.dfs(ans, child); + } +}; +/** + * Your ThroneInheritance object will be instantiated and called as such: + * var obj = new ThroneInheritance(kingName) + * obj.birth(parentName,childName) + * obj.death(name) + * var param_3 = obj.getInheritanceOrder() + */ diff --git a/1601-maximum-number-of-achievable-transfer-requests.js b/1601-maximum-number-of-achievable-transfer-requests.js new file mode 100644 index 00000000..b99d414f --- /dev/null +++ b/1601-maximum-number-of-achievable-transfer-requests.js @@ -0,0 +1,66 @@ +// O(n * 2 ^ r) +// r: number of requests +/** + * @param {number} n + * @param {number[][]} requests + * @return {number} + */ +const maximumRequests = function(n, requests) { + const arr = Array(n).fill(0) + let res = 0 + bt(requests, 0, arr, 0) + return res + function bt(r, idx, arr, num) { + if(idx === r.length) { + for(let i = 0; i < n; i++) { + if(arr[i] !== 0) return + } + res = Math.max(res, num) + return + } + const [from, to] = r[idx] + arr[from]++ + arr[to]-- + bt(r, idx + 1, arr, num + 1) + arr[from]-- + arr[to]++ + + bt(r, idx + 1, arr, num) + } +}; + + +// another + +/** + * @param {number} n + * @param {number[][]} requests + * @return {number} + */ +const maximumRequests = function (n, requests) { + let max = 0 + helper(requests, 0, Array(n).fill(0), 0) + return max + + function helper(requests, index, count, num) { + // Traverse all n buildings to see if they are all 0. (means balanced) + if (index === requests.length) { + for (let i of count) { + if (0 !== i) { + return + } + } + max = Math.max(max, num) + return + } + // Choose this request + count[requests[index][0]]++ + count[requests[index][1]]-- + helper(requests, index + 1, count, num + 1) + count[requests[index][0]]-- + count[requests[index][1]]++ + + // Not Choose the request + helper(requests, index + 1, count, num) + } +} diff --git a/1602-find-nearest-right-node-in-binary-tree.js b/1602-find-nearest-right-node-in-binary-tree.js new file mode 100644 index 00000000..1213d388 --- /dev/null +++ b/1602-find-nearest-right-node-in-binary-tree.js @@ -0,0 +1,28 @@ +/** + * 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 + * @param {TreeNode} u + * @return {TreeNode} + */ +const findNearestRightNode = function(root, u) { + const q = [root] + while(q.length) { + const size = q.length + let target = false + for(let i = 0; i < size; i++) { + const tmp = q.shift() + if(target) return tmp + if(tmp === u) target = true + if(tmp.left) q.push(tmp.left) + if(tmp.right) q.push(tmp.right) + } + } + return null +}; diff --git a/1603-design-parking-system.js b/1603-design-parking-system.js new file mode 100644 index 00000000..8f980fec --- /dev/null +++ b/1603-design-parking-system.js @@ -0,0 +1,29 @@ +/** + * @param {number} big + * @param {number} medium + * @param {number} small + */ +const ParkingSystem = function(big, medium, small) { + this['3'] = small + this['2'] = medium + this['1'] = big +}; + +/** + * @param {number} carType + * @return {boolean} + */ +ParkingSystem.prototype.addCar = function(carType) { + this[carType]-- + if(this[carType] < 0) { + this[carType] = 0 + return false + } + return true +}; + +/** + * Your ParkingSystem object will be instantiated and called as such: + * var obj = new ParkingSystem(big, medium, small) + * var param_1 = obj.addCar(carType) + */ diff --git a/1605-find-valid-matrix-given-row-and-column-sums.js b/1605-find-valid-matrix-given-row-and-column-sums.js new file mode 100644 index 00000000..f1ab5894 --- /dev/null +++ b/1605-find-valid-matrix-given-row-and-column-sums.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} rowSum + * @param {number[]} colSum + * @return {number[][]} + */ +const restoreMatrix = function(rowSum, colSum) { + const m = rowSum.length, n = colSum.length; + const res = Array.from({ length: m }, () => Array(n).fill(0)); + for (let i = 0; i < m; ++i) { + for (let j = 0 ; j < n; ++j) { + res[i][j] = Math.min(rowSum[i], colSum[j]); + rowSum[i] -= res[i][j]; + colSum[j] -= res[i][j]; + } + } + return res; +}; + +// another + +/** + * @param {number[]} rowSum + * @param {number[]} colSum + * @return {number[][]} + */ +const restoreMatrix = function(rowSum, colSum) { + const m = rowSum.length, n = colSum.length + const res = Array.from({ length: m }, () => Array(n).fill(0)) + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + res[i][j] = Math.min(rowSum[i], colSum[j]) + rowSum[i] -= res[i][j] + colSum[j] -= res[i][j] + } + } + return res +}; diff --git a/1606-find-servers-that-handled-most-number-of-requests.js b/1606-find-servers-that-handled-most-number-of-requests.js new file mode 100644 index 00000000..1c2a1f71 --- /dev/null +++ b/1606-find-servers-that-handled-most-number-of-requests.js @@ -0,0 +1,51 @@ +/** + * @param {number} k + * @param {number[]} arrival + * @param {number[]} load + * @return {number[]} + */ +const busiestServers = function (k, arrival, load) { + const ark = [] + const map = new Map() + let max = 0 + for (let i = 0; i < arrival.length; i++) { + if (i < k) { + ark[i] = arrival[i] + load[i] + map.set(i, 1) + max = Math.max(max, map.get(i)) + } else { + let server = i % k + const curr = server + while (server < k) { + if (ark[server] <= arrival[i]) { + ark[server] = arrival[i] + load[i] + map.set(server, map.has(server) ? map.get(server) + 1 : 1) + max = Math.max(max, map.get(server)) + break + } + server++ + } + if (server === k) { + let l = 0 + while (l < curr) { + if (ark[l] <= arrival[i]) { + ark[l] = arrival[i] + load[i] + map.set(l, map.has(l) ? map.get(l) + 1 : 1) + max = Math.max(max, map.get(l)) + break + } + l++ + } + } + } + } + + const result = [] + const entries = map[Symbol.iterator]() + for (let en of entries) { + if (en[1] === max) { + result.push(en[0]) + } + } + return result +} diff --git a/1607-sellers-with-no-sales.sql b/1607-sellers-with-no-sales.sql new file mode 100644 index 00000000..cbce028d --- /dev/null +++ b/1607-sellers-with-no-sales.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +SELECT DISTINCT seller_name +FROM seller s +WHERE seller_id NOT IN ( + SELECT DISTINCT seller_id + FROM orders + WHERE YEAR(sale_date) = 2020 +) +ORDER BY 1; diff --git a/1608-special-array-with-x-elements-greater-than-or-equal-x.js b/1608-special-array-with-x-elements-greater-than-or-equal-x.js new file mode 100644 index 00000000..9866bd82 --- /dev/null +++ b/1608-special-array-with-x-elements-greater-than-or-equal-x.js @@ -0,0 +1,76 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const specialArray = function(nums) { + let l = -1, r = 1001 + while(l <= r) { + const mid = r - Math.floor((r - l) / 2) + const tmp = valid(mid) + if(tmp === mid) return mid + else if(tmp > mid) l = mid + 1 + else r = mid - 1 + } + return -1 + + function valid(mid) { + let res = 0 + for(let e of nums) { + if(e >= mid) res++ + } + return res + } +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const specialArray = function (nums) { + nums.sort((a, b) => b - a) + let i = 0 + while(i < nums.length && nums[i] >= i) { + i++ + } + if(nums[i - 1] < i) return -1 + return i +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const specialArray = function(nums) { + nums.sort((a, b) => b - a) + let left = 0, right = nums.length + while(left <= right) { + const mid = left + ((right - left) >> 1) + if(mid < nums[mid]) left = mid + 1 + else right = mid - 1 + } + // if we found i == nums[i], there will be i + 1 items + // larger or equal to i, which makes array not special. + return left < nums.length && left === nums[left] ? -1 : left +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const specialArray = function(nums) { + const n = nums.length + nums.sort((a, b) => b - a) + let l = 0, r = n + while(l < r) { + const mid = l + ((r - l) >> 1) + if(nums[mid] > mid) l = mid + 1 + else r = mid + } + return l < n && l === nums[l] ? -1 : l +} diff --git a/1609-even-odd-tree.js b/1609-even-odd-tree.js new file mode 100644 index 00000000..2e65d6fc --- /dev/null +++ b/1609-even-odd-tree.js @@ -0,0 +1,35 @@ +/** + * 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} + */ +const isEvenOddTree = function(root) { + const q = [root] + const v = [] + let l = 0 + while(q.length) { + const size = q.length + const row = [] + for(let i = 0; i < size; i++) { + const cur = q.shift() + row.push(cur.val) + if(l % 2 === 0 && cur.val % 2 === 0) return false + if(l % 2 === 1 && cur.val % 2 === 1) return false + if(row.length > 1) { + if(l % 2 === 0 && row[row.length - 1] <= row[row.length - 2]) return false + if(l % 2 === 1 && row[row.length - 1] >= row[row.length - 2]) return false + } + if(cur.left) q.push(cur.left) + if(cur.right) q.push(cur.right) + } + l++ + } + return true +}; diff --git a/161-one-edit-distance.js b/161-one-edit-distance.js new file mode 100644 index 00000000..866ec378 --- /dev/null +++ b/161-one-edit-distance.js @@ -0,0 +1,50 @@ +/** + +Given two strings s and t, determine if they are both one edit distance apart. + +Note: + +There are 3 possiblities to satisify one edit distance apart: + +Insert a character into s to get t +Delete a character from s to get t +Replace a character of s to get t +Example 1: + +Input: s = "ab", t = "acb" +Output: true +Explanation: We can insert 'c' into s to get t. +Example 2: + +Input: s = "cab", t = "ad" +Output: false +Explanation: We cannot get t from s by only one step. +Example 3: + +Input: s = "1203", t = "1213" +Output: true +Explanation: We can replace '0' with '1' to get t. + +*/ + +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +const isOneEditDistance = function(s, t) { + const m = s.length, + n = t.length; + if (m > n) { + return isOneEditDistance(t, s); + } + for (let i = 0; i < m; i++) { + if (s[i] !== t[i]) { + if (m === n) { + return s.slice(i + 1) === t.slice(i + 1); + } + return s.slice(i) === t.slice(i + 1); + } + } + return m + 1 === n; +}; diff --git a/1610-maximum-number-of-visible-points.js b/1610-maximum-number-of-visible-points.js new file mode 100644 index 00000000..5b0abe64 --- /dev/null +++ b/1610-maximum-number-of-visible-points.js @@ -0,0 +1,31 @@ +/** + * @param {number[][]} points + * @param {number} angle + * @param {number[]} location + * @return {number} + */ +const visiblePoints = function (points, angle, location) { + const angles = []; + let count = 0; + for (let p of points) { + let dx = p[0] - location[0]; + let dy = p[1] - location[1]; + if (dx == 0 && dy == 0) { + // edge case of same point + count++; + continue; + } + angles.push(Math.atan2(dy, dx) * (180 / Math.PI)); + } + angles.sort(); + const tmp = angles.slice(); + for (let d of angles) tmp.push(d + 360); // concatenate to handle edge case + let res = count; + for (let i = 0, j = 0; i < tmp.length; i++) { + while (tmp[i] - tmp[j] > angle) { + j++; + } + res = Math.max(res, count + i - j + 1); + } + return res; +}; diff --git a/1611-minimum-one-bit-operations-to-make-integers-zero.js b/1611-minimum-one-bit-operations-to-make-integers-zero.js new file mode 100644 index 00000000..ec1f28f8 --- /dev/null +++ b/1611-minimum-one-bit-operations-to-make-integers-zero.js @@ -0,0 +1,44 @@ +/** + * @param {number} n + * @return {number} + */ +const minimumOneBitOperations = function (n) { + let sign = 1, + res = 0; + while (n) { + res += n ^ ((n - 1) * sign); + n &= n - 1; + sign = -sign; + } + return Math.abs(res); +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +const minimumOneBitOperations = function(n) { + let mask = n; + while (mask) { + mask >>= 1; + n ^= mask; + } + return n; +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +const minimumOneBitOperations = function(n) { + n ^= n >> 16 + n ^= n >> 8 + n ^= n >> 4 + n ^= n >> 2 + n ^= n >> 1 + return n +}; diff --git a/1612-check-if-two-expression-trees-are-equivalent.js b/1612-check-if-two-expression-trees-are-equivalent.js new file mode 100644 index 00000000..1d0e2cdb --- /dev/null +++ b/1612-check-if-two-expression-trees-are-equivalent.js @@ -0,0 +1,39 @@ +/** + * Definition for a binary tree node. + * function Node(val, left, right) { + * this.val = (val===undefined ? " " : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {Node} root1 + * @param {Node} root2 + * @return {boolean} + */ +const checkEquivalence = function(root1, root2) { + const q = {} + const helper = (node) => { + if (node == null) return + if(node.val !== '+') { + if(q[node.val] == null) q[node.val] = 0 + q[node.val]++ + } + helper(node.left) + helper(node.right) + } + helper(root1) + const h = node => { + if(node == null) return + if(node.val !== '+') { + if(q[node.val] == null) return false + q[node.val]-- + if(q[node.val] <= 0) delete q[node.val] + } + h(node.left) + h(node.right) + } + h(root2) + if(Object.keys(q).length > 0) return false + return true +}; diff --git a/1613-find-the-missing-ids.sql b/1613-find-the-missing-ids.sql new file mode 100644 index 00000000..0d0600e5 --- /dev/null +++ b/1613-find-the-missing-ids.sql @@ -0,0 +1,12 @@ +# Write your MySQL query statement below +WITH RECURSIVE id_seq AS ( + SELECT 1 as continued_id + UNION + SELECT continued_id + 1 + FROM id_seq + WHERE continued_id < (SELECT MAX(customer_id) FROM Customers) +) + +SELECT continued_id AS ids +FROM id_seq +WHERE continued_id NOT IN (SELECT customer_id FROM Customers); diff --git a/1614-maximum-nesting-depth-of-the-parentheses.js b/1614-maximum-nesting-depth-of-the-parentheses.js new file mode 100644 index 00000000..6c5f2ed6 --- /dev/null +++ b/1614-maximum-nesting-depth-of-the-parentheses.js @@ -0,0 +1,18 @@ +/** + * @param {string} s + * @return {number} + */ +const maxDepth = function(s) { + const stack = [] + let res = 0 + for(let i = 0, len = s.length; i < len; i++) { + if(s[i] === '(') { + stack.push('(') + res = Math.max(res, stack.length) + } else if(s[i] === ')') { + stack.pop() + } + } + + return res +}; diff --git a/1615-maximal-network-rank.js b/1615-maximal-network-rank.js new file mode 100644 index 00000000..de90d0c6 --- /dev/null +++ b/1615-maximal-network-rank.js @@ -0,0 +1,50 @@ +/** + * @param {number} n + * @param {number[][]} roads + * @return {number} + */ +const maximalNetworkRank = function (n, roads) { + const edgeCount = new Array(n).fill(0); + const m = roads.length; + const map = new Map(); + for (let i = 0; i < m; i++) { + edgeCount[roads[i][0]]++; + edgeCount[roads[i][1]]++; + if (!map.has(roads[i][0])) { + map.set(roads[i][0], new Set()); + } + if (!map.has(roads[i][1])) { + map.set(roads[i][1], new Set()); + } + const A = map.get(roads[i][0]); + A.add(roads[i][1]); + const B = map.get(roads[i][1]); + B.add(roads[i][0]); + } + + let maxRank = 0; + for (let i = 0; i < m; i++) { + let rank = edgeCount[roads[i][0]] + edgeCount[roads[i][1]] - 1; + if (rank > maxRank) { + maxRank = rank; + } + } + const keys = []; + for (let k of map.keys()) keys.push(k); + // console.log(keys, map) + for (let i = 0, len = keys.length; i < m - 1; i++) { + const tmp = map.get(keys[i]); + for (let j = i + 1; j < m; j++) { + // console.log(tmp, i, j, tmp.has(keys[j])) + if (tmp && !tmp.has(keys[j])) { + let rank = edgeCount[keys[i]] + edgeCount[keys[j]]; + if (rank > maxRank) { + maxRank = rank; + } + } + } + } + + + return maxRank; +}; diff --git a/1616-split-two-strings-to-make-palindrome.js b/1616-split-two-strings-to-make-palindrome.js new file mode 100644 index 00000000..0cbacb2c --- /dev/null +++ b/1616-split-two-strings-to-make-palindrome.js @@ -0,0 +1,22 @@ +/** + * @param {string} a + * @param {string} b + * @return {boolean} + */ +const checkPalindromeFormation = function (a, b) { + return check(a, b) || check(b, a) +} + +function isPalindrome(s, i, j) { + for (; i < j; ++i, --j) { + if (s[i] != s[j]) return false + } + return true +} + +function check(a, b) { + for (let i = 0, j = a.length - 1; i < j; ++i, --j) { + if (a[i] !== b[j]) return isPalindrome(a, i, j) || isPalindrome(b, i, j) + } + return true +} diff --git a/1617-count-subtrees-with-max-distance-between-cities.js b/1617-count-subtrees-with-max-distance-between-cities.js new file mode 100644 index 00000000..3cc321c8 --- /dev/null +++ b/1617-count-subtrees-with-max-distance-between-cities.js @@ -0,0 +1,118 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ +const countSubgraphsForEachDiameter = function (n, edges) { + const graph = {}; + for (let [u, v] of edges) { + if (!graph[u - 1]) graph[u - 1] = []; + if (!graph[v - 1]) graph[v - 1] = []; + graph[u - 1].push(v - 1); + graph[v - 1].push(u - 1); + } + let ans = Array(n - 1).fill(0); + for (let i = 1, len = 2 ** n; i < len; i++) { + const d = maxDistance(i); + if (d > 0) ans[d - 1] += 1; + } + return ans; + function bfs(src, cities) { + const visited = new Set(); + visited.add(src); + const q = [[src, 0]]; // Pair of (vertex, distance) + let farthestDist = 0; // Farthest distance from src to other nodes + while (q.length > 0) { + const [u, d] = q.shift(); + farthestDist = d; + for (let v of graph[u]) { + if (!visited.has(v) && cities.has(v)) { + visited.add(v); + q.push([v, d + 1]); + } + } + } + return [farthestDist, visited]; + } + function maxDistance(state) { + // return: maximum distance between any two cities in our subset. O(n^2) + const cities = new Set(); + for (let i = 0; i < n; i++) { + if ((state >> i) & (1 === 1)) cities.add(i); + } + let ans = 0; + for (let i of cities) { + const [farthestDist, visited] = bfs(i, cities); + if (visited.size < cities.size) return 0; // Can't visit all nodes of the tree -> Invalid tree + ans = Math.max(ans, farthestDist); + } + return ans; + } +}; + +// another + +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ +const countSubgraphsForEachDiameter = function(n, edges) { + const graph = {} + for(const [u, v] of edges) { + if(graph[u - 1] == null) graph[u - 1] = [] + if(graph[v - 1] == null) graph[v - 1] = [] + graph[u - 1].push(v - 1) + graph[v - 1].push(u - 1) + } + const res = Array(n - 1).fill(0) + + for(let i = 0, len = 2 ** n; i < len; i++) { + const dis = maxDistance(i) + if(dis > 0) res[dis - 1]++ + } + + return res + + function bfs(src, cities) { + const visited = new Set([src]) + let q = [[src, 0]] + let maxDist = 0 + while(q.length) { + const tmp = [] + const size = q.length + for(let i = 0; i < size; i++) { + const [u, d] = q[i] + maxDist = d + for(const v of (graph[u] || [])) { + if(cities.has(v) && !visited.has(v)) { + visited.add(v) + tmp.push([v, d + 1]) + } + } + } + + q = tmp + } + + return [maxDist, visited] + } + + function maxDistance(state) { + const cities = new Set() + for(let i = 0; i < n; i++) { + if(state & (1 << i)) cities.add(i) + } + + let res = 0 + for(const e of cities) { + const [maxDist, visited] = bfs(e, cities) + if(visited.size < cities.size) return 0 + res = Math.max(res, maxDist) + } + + return res + } +}; + + diff --git a/1619-mean-of-array-after-removing-some-elements.js b/1619-mean-of-array-after-removing-some-elements.js new file mode 100644 index 00000000..d5ad97c7 --- /dev/null +++ b/1619-mean-of-array-after-removing-some-elements.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const trimMean = function(arr) { + const n = arr.length + arr.sort((a, b) => a - b) + const idx = n / 20 + let tmp = arr.slice(idx, n - idx) + const sum = tmp.reduce((ac, cur) => ac + cur, 0) + return sum / (n -idx * 2) +}; diff --git a/162-find-peak-element.js b/162-find-peak-element.js new file mode 100644 index 00000000..c3c9bd07 --- /dev/null +++ b/162-find-peak-element.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const findPeakElement = function(nums) { + let low = 0; + let high = nums.length-1; + + while(low < high) { + let mid1 = low + ((high - low) >> 1); + let mid2 = mid1 + 1; + if(nums[mid1] < nums[mid2]) low = mid2; + else high = mid1; + } + return low; +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const findPeakElement = function(nums) { + if(nums == null) return -1 + const len = nums.length + if(len === 1) return 0 + for(let i = 1; i < len; i++) { + if(i === 1 && nums[i] < nums[i - 1]) return 0 + else if(i === len - 1 && nums[i] > nums[i - 1]) return len - 1 + else if(nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) return i + } + return -1 +}; diff --git a/1621-number-of-sets-of-k-non-overlapping-line-segments.js b/1621-number-of-sets-of-k-non-overlapping-line-segments.js new file mode 100644 index 00000000..58fca659 --- /dev/null +++ b/1621-number-of-sets-of-k-non-overlapping-line-segments.js @@ -0,0 +1,42 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const numberOfSets = function (n, k) { + let res = BigInt(1) + const mod = BigInt(10 ** 9 + 7) + for (let i = 1; i < k * 2 + 1; i++) { + res = res * BigInt(n + k - i) + res = res / BigInt(i) + } + res = res % mod + return res +} + +// another + +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const numberOfSets = function (n, k) { + // dp[i][k] as: the number of ways to generate + // k non-overlapping segments you can make using [0 ~ i]. + const dp = Array.from({ length: n }, () => Array(k + 1).fill(0)) + const MOD = 10 ** 9 + 7 + dp[1][1] = 1 + for (let i = 2; i < n; i++) dp[i][1] = ((i + 1) * i) / 2 + // sum[i][j] as: the number of ways to generate + // j - 1 segments from i - 1 points. + const sum = Array.from({ length: n }, () => Array(k + 1).fill(0)) + for (let i = 2; i < n; i++) { + for (let j = 2; j <= k; j++) { + if (j <= i) sum[i][j] = (sum[i - 1][j] + dp[i - 1][j - 1]) % MOD + dp[i][j] = (sum[i][j] + dp[i - 1][j]) % MOD + } + } + return dp[n - 1][k] +} + diff --git a/1622-fancy-sequence.js b/1622-fancy-sequence.js new file mode 100644 index 00000000..3b8577a0 --- /dev/null +++ b/1622-fancy-sequence.js @@ -0,0 +1,29 @@ +const mod = 10 ** 9 + 7; +const Fancy = function () { + this.seq = []; + this.mods = []; +}; +Fancy.prototype.append = function (val) { + this.seq.push(val); +}; +Fancy.prototype.addAll = function (inc) { + this.mods.push(["p", inc, this.seq.length]); +}; +Fancy.prototype.multAll = function (m) { + this.mods.push(["m", m, this.seq.length]); +}; +Fancy.prototype.getIndex = function (idx) { + if (idx >= this.seq.length) return -1; + let x = this.seq[idx]; + + for (let i = 0; i < this.mods.length; i++) { + if (this.mods[i][2] > idx) { + if ("m" === this.mods[i][0]) { + x = (x * this.mods[i][1]) % mod; + } else { + x = (x + this.mods[i][1]) % mod; + } + } + } + return x; +}; diff --git a/1623-all-valid-triplets-that-can-represent-a-country.sql b/1623-all-valid-triplets-that-can-represent-a-country.sql new file mode 100644 index 00000000..67b4af69 --- /dev/null +++ b/1623-all-valid-triplets-that-can-represent-a-country.sql @@ -0,0 +1,12 @@ +# Write your MySQL query statement below +SELECT sa.student_name AS member_a + , sb.student_name AS member_b + , sc.student_name AS member_c +FROM schoola sa CROSS JOIN schoolb sb + CROSS JOIN schoolc sc + WHERE sa.student_name != sb.student_name + AND sa.student_name != sc.student_name + AND sb.student_name != sc.student_name + AND sa.student_id != sc.student_id + AND sb.student_id != sc.student_id + AND sa.student_id != sb.student_id; diff --git a/1624-largest-substring-between-two-equal-characters.js b/1624-largest-substring-between-two-equal-characters.js new file mode 100644 index 00000000..5a163d44 --- /dev/null +++ b/1624-largest-substring-between-two-equal-characters.js @@ -0,0 +1,18 @@ +/** + * @param {string} s + * @return {number} + */ +const maxLengthBetweenEqualCharacters = function(s) { + const m = {} + if(s ==null || s.length <= 1) return -1 + let res = -1 + for(let i = 0, len = s.length; i< len;i++) { + if(m[s[i]] != null) { + res = Math.max(res, i - m[s[i]] - 1) + } else { + m[s[i]] = i + } + + } + return res +}; diff --git a/1625-lexicographically-smallest-string-after-applying-operations.js b/1625-lexicographically-smallest-string-after-applying-operations.js new file mode 100644 index 00000000..ec693a8b --- /dev/null +++ b/1625-lexicographically-smallest-string-after-applying-operations.js @@ -0,0 +1,200 @@ +/** + * @param {string} s + * @param {number} a + * @param {number} b + * @return {string} + */ +const findLexSmallestString = function(s, a, b) { + let res = s; + const n = s.length; + + let evenLimit = 10; + if (b % 2 === 0) evenLimit = 1; + + for (let i = 0; i < evenLimit; i++) { + for (let j = 0; j < 10; j++) { + let t = s.split(''); + + for (let k = 0; k < n; k += 2) { + t[k] = (parseInt(t[k]) + a * i) % 10; + } + for (let k = 1; k < n; k += 2) { + t[k] = (parseInt(t[k]) + a * j) % 10; + } + + t = t.join(''); + let p = t; + const gcdValue = gcd(n, b); + for (let k = 0; k <= n / gcdValue; k++) { + p = p.slice(n - b) + p.slice(0, n - b); + res = res < p ? res : p; + } + } + } + + return res; +}; + + +function gcd(x, y) { + while (y !== 0) { + let temp = y; + y = x % y; + x = temp; + } + return x; +} +// another + +/** + * @param {string} s + * @param {number} a + * @param {number} b + * @return {string} + */ +const findLexSmallestString = function(s, a, b) { + let res = s + const visited = new Set() + dfs(s) + return res + + function dfs(str) { + if(isVisited(str)) return + visit(str) + dfs(add(str)) + dfs(rotate(str)) + } + + function isVisited(str) { + return visited.has(str) + } + + function visit(str) { + if(str < res) res = str + visited.add(str) + } + + function add(str) { + const arr = str.split('').map(e => +e) + for(let i = 1; i < str.length; i += 2) { + arr[i] = (arr[i] + a) % 10 + } + return arr.join('') + } + + function rotate(str) { + const n = str.length + const len = b % str.length + const pre = str.slice(0,n - len), suf = str.slice(n - len) + return `${suf}${pre}` + } +}; + +// another + +/** + * @param {string} s + * @param {number} a + * @param {number} b + * @return {string} + */ +const findLexSmallestString = function(s, a, b) { + let res = s + const visited = new Set() + dfs(s) + return res + + function dfs(str) { + if(isVisited(str)) return + visit(str) + dfs(add(str)) + dfs(rotate(str)) + } + + function isVisited(str) { + return visited.has(str) + } + + function visit(str) { + if(str < res) res = str + visited.add(str) + } + + function add(str) { + const arr = str.split('').map(e => +e) + for(let i = 1; i < str.length; i += 2) { + arr[i] = (arr[i] + a) % 10 + } + return arr.join('') + } + + function rotate(str) { + const arr = str.split('') + arr.reverse() + let l = 0, r = b - 1 + while(l < r) { + swap(arr, l++, r--) + } + l = b + r = s.length - 1 + while(l < r) { + swap(arr, l++, r--) + } + return arr.join('') + } + + function swap(arr, i, j) { + ;[arr[i], arr[j]] = [arr[j], arr[i]] + } +}; + +// another + + +/** + * @param {string} s + * @param {number} a + * @param {number} b + * @return {string} + */ +const findLexSmallestString = function(s, a, b) { + let res = s + const set = new Set() + const q = [s] + set.add(res) + while(q.length) { + const len = q.length + for(let i = 0; i < len; i++) { + const tmp = q.shift() + const t1 = podd(tmp, a) + const t2 = rotate(tmp, b) + if(!set.has(t1)) { + set.add(t1) + q.push(t1) + } + if(!set.has(t2)) { + set.add(t2) + q.push(t2) + } + if(t1 < res) res = t1 + if(t2 < res) res = t2 + } + } + return res +}; + +function podd(s, num) { + const arr = s.split('') + for(let i = 1, len = s.length; i < len; i += 2) { + const tmp = (+s[i] + num) % 10 + arr[i] = tmp + } + return arr.join('') +} + +function rotate(s, num) { + const len = s.length + num = num % len + const idx = len - num + return s.slice(idx) + s.slice(0, idx) +} diff --git a/1626-best-team-with-no-conflicts.js b/1626-best-team-with-no-conflicts.js new file mode 100644 index 00000000..36b84702 --- /dev/null +++ b/1626-best-team-with-no-conflicts.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} scores + * @param {number[]} ages + * @return {number} + */ +const bestTeamScore = function(scores, ages) { + const len = ages.length + const arr = Array(len) + for(let i = 0; i < len; i++) { + arr[i] = [scores[i], ages[i]] + } + arr.sort((a, b) => { + if(a[1] > b[1]) return 1 + else if(a[1] === b[1]) return a[0] - b[0] + else return -1 + }) + const dp = Array(len) + let res = 0 + for(let i = 0; i < len; i++) { + dp[i] = arr[i][0] + for(let j = i - 1; j >= 0; j--) { + if(arr[j][0] > arr[i][0] && arr[j][1] < arr[i][1]) { + continue + } + dp[i] = Math.max(dp[i], dp[j] + arr[i][0]) + } + res = Math.max(res, dp[i]) + } + return res +}; + diff --git a/1627-graph-connectivity-with-threshold.js b/1627-graph-connectivity-with-threshold.js new file mode 100644 index 00000000..cafcb215 --- /dev/null +++ b/1627-graph-connectivity-with-threshold.js @@ -0,0 +1,107 @@ +/** + * @param {number} n + * @param {number} threshold + * @param {number[][]} queries + * @return {boolean[]} + */ +const areConnected = function(n, threshold, queries) { + const arr = [] + const uf = new UF(n) + setup(n, threshold, uf) + for(let i = 0, len = queries.length; i < len;i++) { + arr.push(uf.check(queries[i][0], queries[i][1])) + } + return arr +}; + +function setup(n, t, uf) { + for (let i = t + 1; i <= n; i++) { + let m = 1; + while (i * m <= n) { + uf.union(i, i * m); + m += 1; + } + } +} + + +class UF { + constructor(n) { + this.root = Array(n).fill(null).map((_, i) => i) + } + find(x) { + if (this.root[x] !== x) { + this.root[x] = this.find(this.root[x]) + } + return this.root[x] + } + union(x, y) { + const xr = this.find(x) + const yr = this.find(y) + this.root[yr] = xr + } + check(x, y) { + return this.find(x) === this.find(y) + } +} + + +// another + +/** + * @param {number} n + * @param {number} threshold + * @param {number[][]} queries + * @return {boolean[]} + */ +const areConnected = function (n, threshold, queries) { + const arr = [] + const uf = new UnionFind(n) + setup(n, threshold, uf) + for (let i = 0, len = queries.length; i < len; i++) { + arr.push(uf.check(queries[i][0], queries[i][1])) + } + return arr +} + +function setup(n, t, uf) { + t++ + for (let i = t; i <= n; i++) { + let m = 1 + while (i * m <= n) { + uf.union(i, i * m) + m += 1 + } + } +} +class UnionFind { + constructor(n) { + this.parents = Array(n + 1) + .fill(0) + .map((e, i) => i) + this.ranks = Array(n + 1).fill(0) + } + root(x) { + while (x !== this.parents[x]) { + this.parents[x] = this.parents[this.parents[x]] + x = this.parents[x] + } + return x + } + find(x) { + return this.root(x) + } + check(x, y) { + return this.root(x) === this.root(y) + } + union(x, y) { + const [rx, ry] = [this.find(x), this.find(y)] + if (this.ranks[rx] >= this.ranks[ry]) { + this.parents[ry] = rx + this.ranks[rx] += this.ranks[ry] + } else if (this.ranks[ry] > this.ranks[rx]) { + this.parents[rx] = ry + this.ranks[ry] += this.ranks[rx] + } + } +} diff --git a/1629-slowest-key.js b/1629-slowest-key.js new file mode 100644 index 00000000..206e906f --- /dev/null +++ b/1629-slowest-key.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} releaseTimes + * @param {string} keysPressed + * @return {character} + */ +const slowestKey = function(releaseTimes, keysPressed) { + const m = {} + const n = keysPressed.length + const set = new Set() + set.add(keysPressed[0]) + m[releaseTimes[0]] = set + for(let i = 1; i < n; i++) { + const k = releaseTimes[i] - releaseTimes[i - 1] + if(m[k] == null) m[k] = new Set() + m[k].add(keysPressed[i]) + } + const keys = Object.keys(m).sort((a, b) => a - b) + const last = keys[keys.length - 1] + const arr = Array.from(m[last]) + arr.sort() + return arr[arr.length - 1] +}; diff --git a/163-missing-ranges.js b/163-missing-ranges.js new file mode 100644 index 00000000..40aabd0a --- /dev/null +++ b/163-missing-ranges.js @@ -0,0 +1,46 @@ +/** + * @param {number[]} nums + * @param {number} lower + * @param {number} upper + * @return {string[]} + */ +const findMissingRanges = function(nums, lower, upper) { + const list = [] + for (let n of nums) { + let justBelow = n - 1 + if (lower === justBelow) list.push(lower + '') + else if (lower < justBelow) list.push(lower + '->' + justBelow) + lower = n + 1 + } + if (lower === upper) list.push(lower + '') + else if (lower < upper) list.push(lower + '->' + upper) + return list +} + +// another + +/** + * @param {number[]} nums + * @param {number} lower + * @param {number} upper + * @return {string[]} + */ +const findMissingRanges = function(nums, lower, upper) { + const res = []; + let next = lower; + for (let i = 0; i < nums.length; i++) { + if (nums[i] < next) continue; + if (nums[i] === next) { + next++; + continue; + } + range(next, nums[i] - 1, res); + next = nums[i] + 1; + } + if (next <= upper) range(next, upper, res); + return res; + function range(l, r, a) { + a.push(l < r ? `${l}->${r}` : `${l}`) + } +}; + diff --git a/1630-arithmetic-subarrays.js b/1630-arithmetic-subarrays.js new file mode 100644 index 00000000..8d02eda2 --- /dev/null +++ b/1630-arithmetic-subarrays.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @param {number[]} l + * @param {number[]} r + * @return {boolean[]} + */ +const checkArithmeticSubarrays = function(nums, l, r) { + const len = l.length + const res = [] + for(let i = 0; i < len; i++) { + res.push(chk(nums.slice(l[i], r[i] + 1))) + } + return res +}; + +function chk(arr) { + if(arr.length === 0 || arr.length === 1 || arr.length === 2) return true + arr.sort((a, b) => a - b) + const diff = arr[1] - arr[0] + for(let i = 2, len = arr.length; i < len; i++) { + if(arr[i] - arr[i - 1] !== diff) return false + } + return true +} diff --git a/1631-path-with-minimum-effort.js b/1631-path-with-minimum-effort.js new file mode 100644 index 00000000..76e5611d --- /dev/null +++ b/1631-path-with-minimum-effort.js @@ -0,0 +1,336 @@ +/** + * @param {number[][]} heights + * @return {number} + */ +const minimumEffortPath = function(heights) { + const m = heights.length, n = heights[0].length + const { abs, floor } = Math + let l = 0, r= 1e6 + + while(l < r) { + const mid = l + floor((r- l) /2) + if(valid(mid)) { + r = mid + } else { + l = mid + 1 + } + } + + return l + + function valid(effort) { + const visited = Array.from({length:m}, () => Array(n).fill(0)) + const dirs = [[1,0],[-1,0],[0,1],[0,-1]] + let q = [] + q.push([0, 0]) + visited[0][0] = 1 + while(q.length) { + const [x, y] = q.shift() + for(const [dx, dy] of dirs) { + const nx = x + dx, ny = y + dy + if(nx<0 || nx>=m || ny < 0 || ny >= n) continue + if(visited[nx][ny]) continue + if(abs(heights[nx][ny] - heights[x][y]) > effort) continue + q.push([nx,ny]) + visited[nx][ny] = 1 + } + } + + return visited[m - 1][n - 1] === 1 + } +}; + +// another + +/** + * @param {number[][]} heights + * @return {number} + */ +const minimumEffortPath = function(heights) { + const m = heights.length, n = heights[0].length + const dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]] + let l = 0, r = 1e6 - 1 + + while(l < r) { + const mid = ~~((l + r) / 2) + // console.log(l, r, mid) + if(valid(mid)) { + r = mid + } else { + l = mid + 1 + } + } + + return l + + function valid(limit) { + const visited = Array.from({ length: m }, () => Array(n).fill(false)) + return dfs(0, 0, limit, visited) + } + + function dfs(i, j, limit, visited) { + if(i === m - 1 && j === n - 1) return true + visited[i][j] = true + for(const [dx, dy] of dirs) { + const nx = i + dx, ny = j + dy + if(nx < 0 || nx >= m || ny < 0 || ny >= n) continue + if(visited[nx][ny]) continue + if(Math.abs(heights[i][j] - heights[nx][ny]) > limit) continue + if(dfs(nx, ny, limit, visited)) return true + } + // return false + } + +}; + +// another + + + +/** + * @param {number[][]} heights + * @return {number} + */ +const minimumEffortPath = function(heights) { + const m = heights.length, n = heights[0].length + const pq = new PriorityQueue() + const dist = Array.from({ length: m }, () => Array(n).fill(Infinity)) + pq.push([0, 0, 0]) + dist[0][0] = 0 + const dirs = [[-1, 0], [1, 0], [0, 1], [0, -1]] + while(!pq.isEmpty()) { + const [v, i, j] = pq.pop() + if(i === m - 1 && j === n - 1) return v + for(const [dx, dy] of dirs) { + const nx = i + dx, ny = j + dy + if(nx < 0 || nx >= m || ny < 0 || ny >= n) continue + const diff = Math.max(v, Math.abs(heights[nx][ny] - heights[i][j])) + if(dist[nx][ny] > diff) { + dist[nx][ny] = diff + pq.push([diff, nx, ny]) + } + } + } + return -1 +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a[0] < b[0]) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number[][]} heights + * @return {number} + */ +const minimumEffortPath = function (heights) { + const d = [0, 1, 0, -1, 0] + let lo = 0, + hi = 10 ** 6 + 1 + while (lo < hi) { + let effort = lo + ((hi - lo) >> 1) + if (isPath(heights, effort)) { + hi = effort + } else { + lo = effort + 1 + } + } + return lo + function isPath(h, effort) { + const m = h.length, + n = h[0].length + const q = [] + q.push([0, 0]) + const seen = new Set() + seen.add(0) + while (q.length) { + const cur = q.shift() + const x = cur[0], + y = cur[1] + if (x === m - 1 && y === n - 1) { + return true + } + for (let k = 0; k < 4; k++) { + const r = x + d[k], + c = y + d[k + 1] + if(seen.has(r * n + c)) continue + if ( + 0 <= r && + r < m && + 0 <= c && + c < n && + effort >= Math.abs(h[r][c] - h[x][y]) + ) { + seen.add(r * n + c) + q.push([r, c]) + } + } + } + return false + } +} + +// another + +/** + * @param {number[][]} heights + * @return {number} + */ +const minimumEffortPath = function(heights) { + const rows = heights.length + const cols = heights[0].length + const dirs = [[-1, 0], [1, 0], [0, 1], [0, -1]] + const dist = Array.from({ length: rows }, () => Array(cols).fill(Infinity)) + const pq = new PriorityQueue() + pq.push([0, 0, 0]) + dist[0][0] = 0 + while(pq.size) { + const cur = pq.pop() + if(cur[1] === rows - 1 && cur[2] === cols - 1) return cur[0] + for(let dir of dirs) { + const nr = cur[1] + dir[0] + const nc = cur[2] + dir[1] + if(nr < 0 || nr >= rows || nc < 0 || nc >= cols) continue + const diff = Math.max(cur[0], Math.abs(heights[nr][nc] - heights[cur[1]][cur[2]])) + if(dist[nr][nc] > diff) { + dist[nr][nc] = diff + pq.push([diff, nr, nc]) + } + } + } + return 0 +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a[0] < b[0]) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + diff --git a/1632-rank-transform-of-a-matrix.js b/1632-rank-transform-of-a-matrix.js new file mode 100644 index 00000000..6145eff0 --- /dev/null +++ b/1632-rank-transform-of-a-matrix.js @@ -0,0 +1,300 @@ +class UF { + constructor(n) { + this.parent = new Array(n + 1).fill(0).map((_, i) => i); + } + union(x, y) { + const rootX = this.find(x); + const rootY = this.find(y); + if (rootX !== rootY) { + this.parent[rootX] = rootY; + } + } + find(x) { + if (x !== this.parent[x]) { + this.parent[x] = this.find(this.parent[x]); + } + return this.parent[x]; + } +} + +// Update the matrixRankTransform function to use the union-find functions +var matrixRankTransform = function(matrix) { + const m = matrix.length + const n = matrix[0].length + const uf = new UF(m * n) + const res = Array.from({ length: m }, () => Array(n).fill(-1)) + + for (let i = 0; i < m; i++) { + const tmp = [] + for (let j = 0; j < n; j++) { + tmp.push([matrix[i][j], i * n + j]) + } + tmp.sort((a, b) => a[0] - b[0]) + for (let j = 1; j < n; j++) { + if (tmp[j][0] === tmp[j - 1][0] && uf.find(tmp[j][1]) !== uf.find(tmp[j - 1][1])) { + uf.union(tmp[j][1], tmp[j - 1][1]) + } + } + } + + for (let j = 0; j < n; j++) { + const tmp = [] + for (let i = 0; i < m; i++) { + tmp.push([matrix[i][j], i * n + j]) + } + tmp.sort((a, b) => a[0] - b[0]) + for (let i = 1; i < m; i++) { + if (tmp[i][0] === tmp[i - 1][0] && uf.find(tmp[i][1]) !== uf.find(tmp[i - 1][1])) { + uf.union(tmp[i][1], tmp[i - 1][1]) + } + } + } + + const nums = [], group = {} + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + const key = i * n + j + const root = uf.find(key) + if(group[root] == null) group[root] = [] + group[root].push(key) + nums.push([matrix[i][j], key]) + } + } + nums.sort((a, b) => a[0] - b[0]) + const rowMax = Array(m).fill(0) + const colMax = Array(n).fill(0) + for(const e of nums) { + const [val, key] = e + const [i, j] = [Math.floor(key / n), key % n] + if(res[i][j] !== -1) continue + let rank = 0 + for(const k of group[uf.find(key)]) { + const [x, y] = [Math.floor(k / n), k % n] + rank = Math.max(rank, rowMax[x], colMax[y]) + } + rank++ + for(const k of group[uf.find(key)]) { + const [x, y] = [Math.floor(k / n), k % n] + res[x][y] = rank + rowMax[x] = rank + colMax[y] = rank + } + } + + return res +}; + +// another + +/** + * @param {number[][]} matrix + * @return {number[][]} + */ +const matrixRankTransform = function (matrix) { + function find(UF, x) { + if (x !== UF.get(x)) UF.set(x, find(UF, UF.get(x))) + return UF.get(x) + } + function union(UF, x, y) { + if (!UF.has(x)) UF.set(x, x) + if (!UF.has(y)) UF.set(y, y) + UF.set(find(UF, x), find(UF, y)) + } + const m = matrix.length + const n = matrix[0].length + const UFs = new Map() + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + const v = matrix[i][j] + if (!UFs.has(v)) UFs.set(v, new Map()) + union(UFs.get(v), i, ~j) + } + } + const value2index = {} + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + let v = matrix[i][j] + if (!value2index.hasOwnProperty(v)) value2index[v] = new Map() + const indexes = value2index[v] + let f = find(UFs.get(v), i) + if (!indexes.has(f)) indexes.set(f, []) + indexes.get(f).push([i, j]) + } + } + const answer = Array.from({ length: m }, () => Array(n).fill(0)) + const rowMax = Array(m).fill(0), colMax = Array(n).fill(0) + const keys = Object.keys(value2index) + keys.sort((a, b) => a - b) + for (let v of keys) { + for (let points of value2index[v].values()) { + let rank = 1 + for (let point of points) { + rank = Math.max(rank, Math.max(rowMax[point[0]], colMax[point[1]]) + 1) + } + for (let point of points) { + answer[point[0]][point[1]] = rank + rowMax[point[0]] = Math.max(rowMax[point[0]], rank) + colMax[point[1]] = Math.max(colMax[point[1]], rank) + } + } + } + return answer +} + +// another + +/** + * @param {number[][]} matrix + * @return {number[][]} + */ +const matrixRankTransform = function (matrix) { + const m = matrix.length + const n = matrix[0].length + const rowIndex = Array.from({ length: m }, () => Array(n).fill(0)) + const colIndex = Array.from({ length: m }, () => Array(n).fill(0)) + for (let i = 0; i < m; i++) { + let row = [] + for (let j = 0; j < n; j++) { + row.push([matrix[i][j], j]) + } + + row.sort((a, b) => a[0] - b[0]) + for (let j = 0; j < n; j++) { + rowIndex[i][j] = row[j][1] + } + } + for (let i = 0; i < n; i++) { + const col = [] + for (let j = 0; j < m; j++) { + col.push([matrix[j][i], j]) + } + col.sort((a, b) => a[0] - b[0]) + for (let j = 0; j < m; j++) { + colIndex[j][i] = col[j][1] + } + } + const result = Array.from({ length: m }, () => Array(n).fill(0)) + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + result[i][j] = 1 + } + } + let changed = true + while (changed) { + changed = shakeRow(matrix, rowIndex, result) + changed = shakeCol(matrix, colIndex, result) || changed + } + return result +} + +function shakeCol(matrix, colIndex, result) { + let changed = false + for (let i = 0; i < matrix[0].length; i++) { + for (let j = 1; j < matrix.length; j++) { + if (matrix[colIndex[j][i]][i] == matrix[colIndex[j - 1][i]][i]) { + if (result[colIndex[j][i]][i] != result[colIndex[j - 1][i]][i]) + changed = true + result[colIndex[j][i]][i] = Math.max( + result[colIndex[j][i]][i], + result[colIndex[j - 1][i]][i] + ) + result[colIndex[j - 1][i]][i] = Math.max( + result[colIndex[j][i]][i], + result[colIndex[j - 1][i]][i] + ) + } else { + if (result[colIndex[j][i]][i] < result[colIndex[j - 1][i]][i] + 1) { + changed = true + result[colIndex[j][i]][i] = result[colIndex[j - 1][i]][i] + 1 + } + } + } + } + return changed +} + +function shakeRow(matrix, rowIndex, result) { + let changed = false + for (let i = 0; i < matrix.length; i++) { + let rowInd = rowIndex[i] + let resu = result[i] + for (let j = 1; j < matrix[0].length; j++) { + if (matrix[i][rowInd[j]] == matrix[i][rowInd[j - 1]]) { + if (resu[rowInd[j]] != resu[rowInd[j - 1]]) changed = true + resu[rowInd[j]] = Math.max(resu[rowInd[j - 1]], resu[rowInd[j]]) + resu[rowInd[j - 1]] = Math.max(resu[rowInd[j - 1]], resu[rowInd[j]]) + } else { + if (resu[rowInd[j]] < resu[rowInd[j - 1]] + 1) { + changed = true + resu[rowInd[j]] = resu[rowInd[j - 1]] + 1 + } + } + } + } + return changed +} + +// another + +/** + * @param {number[][]} matrix + * @return {number[][]} + */ +const matrixRankTransform = function (matrix) { + const r = matrix.length, + c = matrix[0].length; + const t = r * c; + const arr = Array(t); + const root = Array(t + 1); + const rk = Array(t + 1).fill(0); + const find = (a) => { + let ra = root[a]; + if (ra == a) return a; + return (root[a] = find(ra)); + }; + const union = (a, b) => { + let ra = find(a); + let rb = find(b); + if (ra !== rb) { + if (rk[ra] > rk[rb]) root[rb] = ra; + else root[ra] = rb; + } + }; + let k = 0; + const ans = Array(r) + .fill(0) + .map(() => Array(c)); + for (let i = 0; i < r; ++i) { + for (let j = 0; j < c; ++j) { + arr[k] = [matrix[i][j], i, j]; + root[k] = k; + ++k; + } + } + root[k] = k; + arr.sort((a, b) => a[0] - b[0]); + const X = Array(r) + .fill(0) + .map(() => [-Infinity, t]); + const Y = Array(c) + .fill(0) + .map(() => [-Infinity, t]); + for (let i = 0; i < t; ++i) { + const [v, x, y] = arr[i]; + const id = x * c + y; + const [xv, rx] = X[x], + [yv, ry] = Y[y]; + if (v > xv) rk[id] = rk[find(rx)] + 1; + else root[id] = rx; + if (v > yv) rk[find(id)] = Math.max(rk[find(id)], rk[find(ry)] + 1); + else union(id, ry); + X[x] = [v, id]; + Y[y] = [v, id]; + } + for (let i = 0; i < r; ++i) { + for (let j = 0; j < c; ++j) { + ans[i][j] = rk[find(i * c + j)]; + } + } + return ans; +}; diff --git a/1636-sort-array-by-increasing-frequency.js b/1636-sort-array-by-increasing-frequency.js new file mode 100644 index 00000000..eee5122f --- /dev/null +++ b/1636-sort-array-by-increasing-frequency.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const frequencySort = function(nums) { + const hash = {} + for(let e of nums) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + nums.sort((a, b) => hash[a] === hash[b] ? b - a : hash[a] - hash[b]) + return nums +}; diff --git a/1637-widest-vertical-area-between-two-points-containing-no-points.js b/1637-widest-vertical-area-between-two-points-containing-no-points.js new file mode 100644 index 00000000..d9df0f4a --- /dev/null +++ b/1637-widest-vertical-area-between-two-points-containing-no-points.js @@ -0,0 +1,13 @@ +/** + * @param {number[][]} points + * @return {number} + */ +const maxWidthOfVerticalArea = function(points) { + const arr = points.map(e => e[0]) + arr.sort((a, b) => a - b) + let res = -Infinity + for(let i = 1, len = arr.length; i < len; i++) { + if(arr[i] - arr[i - 1] > res) res = arr[i] - arr[i - 1] + } + return res +}; diff --git a/1638-count-substrings-that-differ-by-one-character.js b/1638-count-substrings-that-differ-by-one-character.js new file mode 100644 index 00000000..e1a9a64f --- /dev/null +++ b/1638-count-substrings-that-differ-by-one-character.js @@ -0,0 +1,54 @@ +/** + * @param {string} s + * @param {string} t + * @return {number} + */ +const countSubstrings = function (s, t) { + const m = s.length + const n = t.length + const matrix = (m, n, v) => Array.from({ length: m }, () => Array(n).fill(v)) + // number of exact same substrings ending at s[i] and t[j]. + const same = matrix(m + 1, n + 1, 0) + // number of substrings having 1 different character ending at s[i] and t[j]. + const one = matrix(m + 1, n + 1, 0) + let result = 0 + for (let i = 1; i <= m; ++i) { + for (let j = 1; j <= n; ++j) { + if (s[i - 1] == t[j - 1]) { + same[i][j] = same[i - 1][j - 1] + 1 + one[i][j] = one[i - 1][j - 1] + } else { + one[i][j] = same[i - 1][j - 1] + 1 + } + result += one[i][j] + } + } + return result +} + +// another + +/** + * @param {string} s + * @param {string} t + * @return {number} + */ +const countSubstrings = function(s, t) { + let res = 0 ; + for (let i = 0; i < s.length; ++i) res += helper(s, t, i, 0); + for (let j = 1; j < t.length; ++j) res += helper(s, t, 0, j); + return res; +}; + +function helper(s, t, i, j) { + let res = 0, pre = 0, cur = 0; + for (let n = s.length, m = t.length; i < n && j < m; ++i, ++j) { + cur++; + if (s.charAt(i) !== t.charAt(j)) { + pre = cur; + cur = 0; + } + res += pre; + } + return res; +} diff --git a/1639-number-of-ways-to-form-a-target-string-given-a-dictionary.js b/1639-number-of-ways-to-form-a-target-string-given-a-dictionary.js new file mode 100644 index 00000000..fa8bf975 --- /dev/null +++ b/1639-number-of-ways-to-form-a-target-string-given-a-dictionary.js @@ -0,0 +1,62 @@ +/** + * @param {string[]} words + * @param {string} target + * @return {number} + */ +const numWays = function (words, target) { + const m = words[0].length, len = words.length + const n = target.length, a = 'a'.charCodeAt(0) + const mod = 10 ** 9 + 7 + const dp = Array(n).fill(0) + for(let i = 0; i < m; i++) { + const freq = Array(26).fill(0) + for(let j = 0; j < len; j++) { + freq[words[j].charCodeAt(i) - a]++ + } + for(let j = Math.min(i, n - 1); j >= 0; j--) { + const code = target[j].charCodeAt(0) - a + if(freq[code] > 0) { + dp[j] += (j === 0 ? freq[code] : dp[j - 1] * freq[code]) + dp[j] %= mod + } + } + } + return dp[n - 1] +} + +// another + +/** + * @param {string[]} words + * @param {string} target + * @return {number} + */ +const numWays = function (words, target) { + const m = words[0].length + const n = target.length + const memo = Array.from({ length: m }, () => Array(n)) + const charAtIndexCnt = Array.from({ length: 128 }, () => Array(m).fill(0)) + const mod = 10 ** 9 + 7 + for (let word of words) { + for (let i = 0; i < m; i++) { + charAtIndexCnt[word.charCodeAt(i)][i] += 1 + } + } + + return dp(0, 0) + function dp(k, i) { + // found one + if (i == n) return 1 + // not found + if (k == m) return 0 + if (memo[k][i] != null) return memo[k][i] + const c = target.charCodeAt(i) + // skip k_th char + let ans = dp(k + 1, i) + if (charAtIndexCnt[c][k] > 0) { + ans += dp(k + 1, i + 1) * charAtIndexCnt[c][k] + ans %= mod + } + return (memo[k][i] = ans) + } +} diff --git a/164-maximum-gap.js b/164-maximum-gap.js new file mode 100644 index 00000000..cfdec7d7 --- /dev/null +++ b/164-maximum-gap.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maximumGap = function (nums) { + if (nums.length < 2) return + let max = 0 + nums = nums.sort(function (a, b) { + return a - b + }) + for (let i = 1; i < nums.length; i++) { + if (nums[i] - nums[i - 1] > max) max = nums[i] - nums[i - 1] + } + return max +} diff --git a/1640-check-array-formation-through-concatenation.js b/1640-check-array-formation-through-concatenation.js new file mode 100644 index 00000000..275e2323 --- /dev/null +++ b/1640-check-array-formation-through-concatenation.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} arr + * @param {number[][]} pieces + * @return {boolean} + */ +const canFormArray = function(arr, pieces) { + const m = new Map() + for(let i = 0, len = arr.length; i < len; i++) { + m.set(arr[i], i) + } + for(let p of pieces) { + let idx = m.get(p[0]) + if(idx == null) return false + for(let i = 1, len = p.length; i < len; i++) { + console.log(m.has(p[i])) + if(!m.has(p[i]) || arr[++idx] !== p[i]) return false + } + } + return true +}; diff --git a/1641-count-sorted-vowel-strings.js b/1641-count-sorted-vowel-strings.js new file mode 100644 index 00000000..b74ecc8d --- /dev/null +++ b/1641-count-sorted-vowel-strings.js @@ -0,0 +1,51 @@ +/** + * @param {number} n + * @return {number} + */ +const countVowelStrings = function (n) { + return (n + 4) * (n + 3) * (n + 2) * (n + 1) / 24 +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +const countVowelStrings = function (n) { + let mem = [1, 1, 1, 1, 1]; + for (let i = 1; i < n; ++i) { + const next = [0, 0, 0, 0, 0]; + let tmp = 0; + for (let j = 4; j >= 0; --j) { + tmp += mem[j]; + next[j] = tmp; + } + mem = next; + } + let sum = 0; + for (let i of mem) { + sum += i; + } + return sum; +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +const countVowelStrings = function (n) { + const dp = Array.from({ length: n + 1 }, () => Array(5)) + recur(n, 0) + return dp[n][0] + function recur(r, i) { + if(r === 0) return 1 + if(i === 5) return 0 + if(dp[r][i] != null) return dp[r][i] + let res = recur(r, i + 1) + res += recur(r - 1, i) + return dp[r][i] = res + } +}; diff --git a/1642-furthest-building-you-can-reach.js b/1642-furthest-building-you-can-reach.js new file mode 100644 index 00000000..4468d978 --- /dev/null +++ b/1642-furthest-building-you-can-reach.js @@ -0,0 +1,86 @@ +/** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ +const furthestBuilding = function(heights, bricks, ladders) { + const pq = new PriorityQueue((a, b) => a < b) + const len = heights.length + for(let i = 0; i < len - 1; i++) { + const diff = heights[i + 1] - heights[i] + if(diff > 0) pq.push(diff) + if(pq.size() > ladders) { + bricks -= pq.pop() + } + if(bricks < 0) return i + } + return len - 1 +}; +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1643-kth-smallest-instructions.js b/1643-kth-smallest-instructions.js new file mode 100644 index 00000000..23ccbacd --- /dev/null +++ b/1643-kth-smallest-instructions.js @@ -0,0 +1,89 @@ +/** + * @param {number[]} destination + * @param {number} k + * @return {string} + */ +const kthSmallestPath = function (destination, k) { + let v = destination[0], + h = destination[1] + const mu = (c, n) => { + let res = '' + for (let i = 0; i < n; i++) { + res += c + } + return res + } + + let res = '' + while (h > 0 && v > 0) { + let pre = comb(h + v - 1, v) + if (k <= pre) { + res += 'H' + h -= 1 + } else { + res += 'V' + v -= 1 + k -= pre + } + } + if (h == 0) res += mu('V', v) + if (v == 0) res += mu('H', h) + return res +} + +function product(a, b) { + let prd = a, + i = a + + while (i++ < b) { + prd *= i + } + return prd +} + +function comb(n, r) { + if (n == r) { + return 1 + } else { + r = r < n - r ? n - r : r + return product(r + 1, n) / product(1, n - r) + } +} + +// another + +/** + * @param {number[]} destination + * @param {number} k + * @return {string} + */ +const kthSmallestPath = function (destination, k) { + const [r, c] = destination; + const ret = []; + let remDown = r; + for (let i = 0; i < r + c; i++) { + const remSteps = r + c - (i + 1); + const com = comb(remSteps, remDown); + if (com >= k) ret.push("H"); + else { + remDown -= 1; + k -= com; + ret.push("V"); + } + } + return ret.join(""); +}; + +function comb(n, r) { + if (n < r) return 0; + let res = 1; + if (n - r < r) r = n - r; + for (let i = n, j = 1; i >= 1 && j <= r; --i, ++j) { + res = res * i; + } + for (let i = r; i >= 2; --i) { + res = res / i; + } + return res; +} + diff --git a/1644-lowest-common-ancestor-of-a-binary-tree-ii.js b/1644-lowest-common-ancestor-of-a-binary-tree-ii.js new file mode 100644 index 00000000..bd9407bb --- /dev/null +++ b/1644-lowest-common-ancestor-of-a-binary-tree-ii.js @@ -0,0 +1,73 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +const lowestCommonAncestor = function (root, p, q) { + let cn = null + const dfs = function (node) { + let mid = 0 + if (!node) return false + let left = dfs(node.left) + let right = dfs(node.right) + if (node === p || node === q) { + mid = 1 + } else { + mid = 0 + } + if (mid + left + right >= 2) { + cn = node + } else { + if (mid) return mid + return left || right + } + } + dfs(root) + return cn +} + +// another + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +const lowestCommonAncestor = function (root, p, q) { + let hasP = false, hasQ = false + const res = LCA(root, p, q) + return hasP && hasQ ? res : null + + function LCA(root, p, q) { + if(root == null) return root + const left = LCA(root.left, p, q) + const right = LCA(root.right, p, q) + if(root === p) { + hasP = true + return root + } + if(root === q) { + hasQ = true + return root + } + if(left && right) return root + return left || right + } +} + diff --git a/1646-get-maximum-in-generated-array.js b/1646-get-maximum-in-generated-array.js new file mode 100644 index 00000000..88ee56b2 --- /dev/null +++ b/1646-get-maximum-in-generated-array.js @@ -0,0 +1,17 @@ +const arr = [0, 1, 1] +/** + * @param {number} n + * @return {number} + */ +const getMaximumGenerated = function(n) { + if(arr[n] != null) return Math.max(...arr.slice(0, n + 1)) + const oddOrEven = num => num % 2 === 0 ? 'even' : 'odd' + const hi = arr.length - 1 + for(let i = hi + 1; i <= n; i++) { + let tmp, chk = oddOrEven(i) + if(chk === 'odd') tmp = arr[Math.floor(i / 2)] + arr[Math.floor(i / 2) + 1] + else tmp = arr[Math.floor(i / 2)] + arr[i] = tmp + } + return Math.max(...arr.slice(0, n + 1)) +}; diff --git a/1647-minimum-deletions-to-make-character-frequencies-unique.js b/1647-minimum-deletions-to-make-character-frequencies-unique.js new file mode 100644 index 00000000..a6af8c16 --- /dev/null +++ b/1647-minimum-deletions-to-make-character-frequencies-unique.js @@ -0,0 +1,38 @@ +/** + * @param {string} s + * @return {number} + */ +const minDeletions = function(s) { + if (s == null || s.length <= 1) { + return 0; + } + + const map = new Map(); + for (let ch of s) { + map.set(ch, (map.get(ch) || 0) + 1); + } + + + const frequencies = new Set(); + let minDeletions = 0; + + const vals = map.values() + for (let frequency of vals) { + if (!frequencies.has(frequency)) { + frequencies.add(frequency); + continue; + } + + let curr = frequency; + while (curr > 0 && frequencies.has(curr)) { + curr--; + minDeletions++; + } + + if (curr > 0) { + frequencies.add(curr); + } + } + + return minDeletions; +}; diff --git a/1648-sell-diminishing-valued-colored-balls.js b/1648-sell-diminishing-valued-colored-balls.js new file mode 100644 index 00000000..f38bf0b2 --- /dev/null +++ b/1648-sell-diminishing-valued-colored-balls.js @@ -0,0 +1,174 @@ +/** + * @param {number[]} inventory + * @param {number} orders + * @return {number} + */ +const maxProfit = function(inventory, orders) { + const bigIntMax = (...args) => args.reduce((m, e) => e > m ? e : m); + inventory = inventory.map(e => BigInt(e)) + orders = BigInt(orders) + let l = 0n, r = bigIntMax(...inventory) + while(l < r) { + const mid = l + (r - l) / 2n + if(valid(mid)) l = mid + 1n + else r = mid + } + + // console.log(l) + const mod = BigInt(1e9 + 7) + let t = l, res = 0n, cnt = 0n + for(const e of inventory) { + if(e <= t) continue + cnt += e - t + res = (res + (t + 1n + e) * (e - t) / 2n) % mod + } + + res = (res + (orders - cnt) * t) % mod + + return res + + function valid(mid) { + let res = 0n + for(const e of inventory) { + if(e > mid) res += e - mid + } + return res > orders + } +}; + +// another + +/** + * @param {number[]} inventory + * @param {number} orders + * @return {number} + */ +function maxProfit(inventory, orders) { + inventory.sort((a, b) => a - b) + inventory = inventory.map(e => BigInt(e)) + let ans = 0n, n = inventory.length - 1, count = 1n + const mod = BigInt(10 ** 9 + 7) + orders = BigInt(orders) + while(orders > 0n) { + if(n > 0 && inventory[n] > inventory[n - 1] && orders >= count * (inventory[n] - inventory[n - 1])) { + ans += count * sum(inventory[n - 1], inventory[n]) + orders -= count * (inventory[n] - inventory[n - 1]) + } else if(n === 0 || inventory[n] > inventory[n - 1]) { + const num = orders / count + ans += count * sum(inventory[n] - num, inventory[n]) + const remain = orders % count + ans += remain * (inventory[n] - num) + orders = 0n + } + ans %= mod + n-- + count++ + } + return ans +} + +function sum(lo, hi) { + return (hi - lo) * (lo + hi + 1n) / 2n +} + +// another + +/** + * @param {number[]} inventory + * @param {number} orders + * @return {number} + */ +const maxProfit = function (inventory, orders) { + let Max = 1e9 + 7, + Min = 0 + let mod = BigInt(1e9 + 7) + while (Max > Min + 1) { + let tot = 0 + let mid = ((Max + Min) >> 1) + for (let it of inventory) { + if (it > mid) tot += it - mid + } + if (tot > orders) Min = mid + else Max = mid + } + let sum = BigInt(0) + Max = BigInt(Max) + orders = BigInt(orders) + for (let it of inventory) { + it = BigInt(it) + if (it > Max) { + sum += ((it + Max + BigInt(1)) * (it - Max)) / BigInt(2) + orders -= it - Max + } + } + sum += orders * Max + + return sum % mod +} + +// another + +/** + * @param {number[]} inventory + * @param {number} orders + * @return {number} + */ +var maxProfit = function(inventory, orders) { + inventory.sort((a, b) => b - a) + const mod = BigInt(1e9 + 7), n = BigInt(inventory.length) + inventory = inventory.map(e => BigInt(e)) + orders = BigInt(orders) + let cur = BigInt(inventory[0]), res = 0n, i = 0n + const min = (a, b) => a > b ? b : a + while(orders) { + while(i < n && inventory[i] === cur) i++ + let next = i === n ? 0n : inventory[i] + let h = cur - next, r = 0n, cnt = min(orders, i * h) + if (orders < i * h) { + h = orders / i + r = orders % i + } + let val = cur - h + res = (res + (cur + val + 1n) * h / 2n * i + val * r) % mod + orders -= cnt + cur = next + } + + return res +}; + +// another + +/** + * @param {number[]} inventory + * @param {number} orders + * @return {number} + */ +const maxProfit = function (inventory, orders) { + inventory.sort((a, b) => b - a) + const mod = BigInt(1e9 + 7), + n = BigInt(inventory.length) + inventory = inventory.map((e) => BigInt(e)) + orders = BigInt(orders) + let cur = BigInt(inventory[0]), + res = 0n, + i = 0n + const min = (a, b) => (a > b ? b : a) + while (orders) { + while (i < n && inventory[i] === cur) i++ + let next = i === n ? 0n : inventory[i] + let h = cur - next, + r = 0n, + cnt = min(orders, i * h) + if (orders < i * h) { + h = orders / i + r = orders % i + } + let val = cur - h + res = (res + (((cur + val + 1n) * h) / 2n) * i + val * r) % mod + orders -= cnt + cur = next + } + + return res +} diff --git a/1649-create-sorted-array-through-instructions.js b/1649-create-sorted-array-through-instructions.js new file mode 100644 index 00000000..d186bcd8 --- /dev/null +++ b/1649-create-sorted-array-through-instructions.js @@ -0,0 +1,83 @@ +const lowBit = (x) => x & -x +class FenwickTree { + constructor(n) { + if (n < 1) return + this.sum = Array(n + 1).fill(0) + } + update(i, delta) { + if (i < 1) return + while (i < this.sum.length) { + this.sum[i] += delta + i += lowBit(i) + } + } + query(i) { + if (i < 1) return 0 + let sum = 0 + while (i > 0) { + sum += this.sum[i] + i -= lowBit(i) + } + return sum + } +} +/** + * @param {number[]} instructions + * @return {number} + */ +const createSortedArray = function(instructions) { + let res = 0, n = instructions.length, mod = 10 ** 9 + 7 + const bit = new FenwickTree(10 ** 5) + for(let i = 0; i < n; i++) { + res = (res + Math.min(bit.query(instructions[i] - 1), i - bit.query(instructions[i]))) % mod + bit.update(instructions[i], 1) + } + return res +}; + +// another + +/** + * @param {number[]} instructions + * @return {number} + */ +const createSortedArray = function (instructions) { + const ins = instructions, n = ins.length + let res = 0 + const mod = 1e9 + 7, { min } = Math + const bit = new BIT(1e5) + for(let i = 0; i < n; i++) { + const cur = ins[i] + res = (res + min(bit.query(cur - 1), i - bit.query(cur))) % mod + bit.update(cur, 1) + } + + return res +} + +function lowBit(x) { + return x & -x +} +class BIT { + constructor(n) { + this.arr = Array(n + 1).fill(0) + } + + update(i, delta) { + if(i < 1) return + while (i < this.arr.length) { + this.arr[i] += delta + i += lowBit(i) + } + } + + query(i) { + let res = 0 + if(i < 1) return res + while (i > 0) { + res += this.arr[i] + i -= lowBit(i) + } + return res + } +} diff --git a/1650-lowest-common-ancestor-of-a-binary-tree-iii.js b/1650-lowest-common-ancestor-of-a-binary-tree-iii.js new file mode 100644 index 00000000..2d0cf7b4 --- /dev/null +++ b/1650-lowest-common-ancestor-of-a-binary-tree-iii.js @@ -0,0 +1,55 @@ +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * }; + */ + +/** + * @param {Node} node + * @return {Node} + */ +const lowestCommonAncestor = function(p, q) { + const pa = [], qa = [] + if(up(p, q, pa)) return q + if(up(q, p, qa)) return p + const set = new Set(pa) + for(let i = 0; i < qa.length; i++) { + if(set.has(qa[i])) return qa[i] + } + + function up(node, target, arr) { + if(node == null) return null + if(node === target) return target + arr.push(node) + return up(node.parent, target, arr) + } +}; + +// another + +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * }; + */ + +/** + * @param {Node} node + * @return {Node} + */ +const lowestCommonAncestor = function(p, q) { + let a = p, b = q; + while (a !== b) { + a = a == null? q : a.parent; + b = b == null? p : b.parent; + } + return a; +}; diff --git a/1652-defuse-the-bomb.js b/1652-defuse-the-bomb.js new file mode 100644 index 00000000..2435e9cc --- /dev/null +++ b/1652-defuse-the-bomb.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} code + * @param {number} k + * @return {number[]} + */ +const decrypt = function(code, k) { + const res = new Array(code.length).fill(0); + if (k === 0) return res; + let start = 1, end = k, sum = 0; + if (k < 0) { + k = -k; + start = code.length - k; + end = code.length - 1; + } + for (let i = start; i <= end; i++) sum += code[i]; + for (let i = 0; i < code.length; i++) { + res[i] = sum; + sum -= code[(start++) % code.length]; + sum += code[(++end) % code.length]; + } + return res; +}; diff --git a/1653-minimum-deletions-to-make-string-balanced.js b/1653-minimum-deletions-to-make-string-balanced.js new file mode 100644 index 00000000..4cf12446 --- /dev/null +++ b/1653-minimum-deletions-to-make-string-balanced.js @@ -0,0 +1,81 @@ +/** + * @param {string} s + * @return {number} + */ +const minimumDeletions = function(s) { + let res = 0, b = 0 + for(const e of s) { + if(e === 'b') b++ + else if(b > 0) { + res++ + b-- + } + } + + return res +}; + +// another + + +/** + * @param {string} s + * @return {number} + */ +const minimumDeletions = function(s) { + let res = 0 + let cnt = 0 + for(let c of s) { + if(c === 'a' && cnt > 0) { + res++ + cnt-- + } else if(c === 'b') { + cnt++ + } + } + + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const minimumDeletions = function(s) { + const len = s.length + const dp = Array(len + 1).fill(0) + let bcount = 0 + for(let i = 1; i <= len; i++) { + if(s[i - 1] === 'a') { + dp[i] = Math.min(dp[i - 1] + 1, bcount) + } else { + dp[i] = dp[i - 1] + bcount++ + } + } + + return dp[len] +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const minimumDeletions = function(s) { + const len = s.length + const stack = [] + let res = 0 + for(let i = 0; i < len; i++) { + if(stack.length && stack[stack.length - 1] > s[i]) { + res++ + stack.pop() + } else { + stack.push(s[i]) + } + } + return res +}; diff --git a/1654-minimum-jumps-to-reach-home.js b/1654-minimum-jumps-to-reach-home.js new file mode 100644 index 00000000..11ce519d --- /dev/null +++ b/1654-minimum-jumps-to-reach-home.js @@ -0,0 +1,87 @@ +/** + * @param {number[]} forbidden + * @param {number} a + * @param {number} b + * @param {number} x + * @return {number} + */ +const minimumJumps = function (forbidden, a, b, x) { + const bad = new Set() + const set = new Set() + for (let i of forbidden) { + bad.add(i) + } + let q = [] + q.push([0, 0, 0]) + set.add('0,0') + while (q.length) { + const tmp = [] + const size = q.length + for(let i = 0; i < size; i++) { + const [pos, level, state] = q[i] + + if (pos === x) return level + if (state >= 0) { + if (pos <= 4000 && !set.has(pos + a + ',0') && !bad.has(pos + a)) { + set.add(pos + a + ',0') + tmp.push([pos + a, level + 1, 0]) + } + if (!set.has(pos - b + ',-1') && !bad.has(pos - b) && pos - b >= 0) { + set.add(pos - b + ',-1') + tmp.push([pos - b, level + 1, -1]) + } + } else if (state < 0) { + if (pos <= 4000 && !set.has(pos + a + ',0') && !bad.has(pos + a)) { + set.add(pos + a + ',0') + tmp.push([pos + a, level + 1, 0]) + } + } + } + + q = tmp + } + return -1 +} + +// another + +/** + * @param {number[]} forbidden + * @param {number} a + * @param {number} b + * @param {number} x + * @return {number} + */ +const minimumJumps = function (forbidden, a, b, x) { + const bad = new Set() + const set = new Set() + for (let i of forbidden) { + bad.add(i) + } + const q = [] + q.push([0, 0, 0]) + set.add('0,0') + while (q.length) { + const pair = q.shift() + let pos = pair[0], + level = pair[1], + state = pair[2] + if (pos == x) return level + if (state >= 0) { + if (pos <= 4000 && !set.has(pos + a + ',0') && !bad.has(pos + a)) { + set.add(pos + a + ',0') + q.push([pos + a, level + 1, 0]) + } + if (!set.has(pos - b + ',-1') && !bad.has(pos - b) && pos - b >= 0) { + set.add(pos - b + ',-1') + q.push([pos - b, level + 1, -1]) + } + } else if (state < 0) { + if (pos <= 4000 && !set.has(pos + a + ',0') && !bad.has(pos + a)) { + set.add(pos + a + ',0') + q.push([pos + a, level + 1, 0]) + } + } + } + return -1 +} diff --git a/1655-distribute-repeating-integers.js b/1655-distribute-repeating-integers.js new file mode 100644 index 00000000..201a7fad --- /dev/null +++ b/1655-distribute-repeating-integers.js @@ -0,0 +1,220 @@ + +/** + * @param {number[]} nums + * @param {number[]} quantity + * @return {boolean} + */ +const canDistribute = function(nums, quantity) { + const freq = new Map() + for(const e of nums) { + freq.set(e, (freq.get(e) || 0) + 1) + } + const cntArr = [...freq.values()] + const n = cntArr.length, m = quantity.length, limit = 1 << m + const dp = Array.from({ length: n + 1 }, () => Array(limit).fill(false)) + for(let i = 0; i < n; i++) { + dp[i][0] = true + } + cntArr.unshift(0) + const allMask = limit - 1 + + for(let i = 1; i <= n; i++) { + for(let mask = 1; mask <= allMask; mask++) { + if(dp[i - 1][mask]) { + dp[i][mask] = true + continue + } + for(let subset = mask; subset > 0; subset = (subset - 1) & mask) { + if(dp[i - 1][mask - subset] === false) continue + if(canSatisfySubset(cntArr[i], subset)) { + dp[i][mask] = true + break + } + } + } + } + + return dp[n][allMask] + + function canSatisfySubset(cnt, subset) { + let sum = 0 + for (let i = 0; i < m; i++) { + if(subset & (1 << i)) { + sum += quantity[i] + } + } + return cnt >= sum + } +}; + +// another + +/** + * @param {number[]} nums + * @param {number[]} quantity + * @return {boolean} + */ +const canDistribute = function (nums, quantity) { + const mp = {} + for (let x of nums) { + mp[x] = (mp[x] || 0) + 1 + } + const values = Object.values(mp) + quantity.sort((a, b) => b - a) + let res = false + dfs(0) + return res + + function dfs(idx) { + if(idx === quantity.length || res) { + res = true + return + } + for(let i = 0, len = values.length; i < len; i++) { + if(values[i] >= quantity[idx]) { + values[i] -= quantity[idx] + dfs(idx + 1) + values[i] += quantity[idx] + } + } + } +} + +// another + +/** + * @param {number[]} nums + * @param {number[]} quantity + * @return {boolean} + */ +const canDistribute = function (nums, quantity) { + const mp = {} + for (let x of nums) { + mp[x] = (mp[x] || 0) + 1 + } + const a = [] + for (let p in mp) a.push(mp[p]) + const b = quantity + const m = quantity.length + const n = a.length + const dp = Array.from({ length: n }, () => Array(1 << m).fill(-1)) + return solve(0, 0) + + function solve(idx, mask) { + if (mask === (1 << m) - 1) return 1 + if (idx === n) return 0 + if (dp[idx][mask] !== -1) return dp[idx][mask] + let ans = solve(idx + 1, mask) + for (let i = 0, up = 1 << m; i < up; i++) { + if (mask !== (mask & i)) continue + let nm = mask + let sum = 0 + for (let j = 0; j < m; j++) { + if (mask & (1 << j)) continue + if (i & (1 << j)) { + sum += b[j] + nm |= 1 << j + } + } + if (sum <= a[idx]) ans |= solve(idx + 1, nm) + } + return (dp[idx][mask] = ans) + } +} + +// another + +/** + * @param {number[]} nums + * @param {number[]} quantity + * @return {boolean} + */ +const canDistribute = function(nums, quantity) { + const freq = {} + for(let e of nums) freq[e] = (freq[e] || 0) + 1 + const fArr = Object.values(freq) + + const m = quantity.length, n = fArr.length + const dp = Array.from({ length: n }, () => Array(1 << m).fill(-1)) + + return solve(0, 0) + + function solve(idx, mask) { + if(mask === (1 << m) - 1) return 1 + if(idx === n) return 0 + if(dp[idx][mask] !== -1) return dp[idx][mask] + + let res = solve(idx + 1, mask) + for(let i = 0; i < (1 << m); i++) { + if(mask !== (mask & i)) continue + let tmp = mask + let sum = 0 + for(let j = 0; j < m; j++) { + if(mask & (1 << j)) continue + if(i & (1 << j)) { + sum += quantity[j] + tmp |= (1 << j) + } + } + if(sum <= fArr[idx]) res |= solve(idx + 1, tmp) + } + + return dp[idx][mask] = res + } +}; + +// another + +/** + * @param {number[]} nums + * @param {number[]} quantity + * @return {boolean} + */ +const canDistribute = function (nums, quantity) { + const hash = {} + for(const e of nums) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + const cnts = Object.values(hash), m = quantity.length, n = cnts.length + const dp = Array.from({ length: n }, () => Array(1 << m).fill(null)) + + return helper(0, 0) + + function helper(idx, mask) { + // mask are already selected candidates + if(mask == (1 << m) - 1) { + return true; + } + if(idx == n) { + return false; + } + if(dp[idx][mask] != null) { + return dp[idx][mask]; + } + let ans = helper(idx + 1, mask); + + for(let i = 1; i < (1 << m); ++i) { + // i are potential candidates in addition to already selected ones (from mask) + // if i == mask, we can skip as the candidate is selected already + // if mask != (mask & i) means that this candidate does not include selected ones e.g + // mask = 3 (i.e 2 elements 1,2 in binary) and i = 4 (the third element in binary as 4 does not include 1 & 2), there we skip + if(mask == i || mask != (mask & i)) continue; + let sum = 0; + for(let j = 0; j < m; ++j) { + // mask << ~j is just a fancy way to do: if(mask & (1 << j)) that i've learned from @Uwi and this way you don't have to use "(", ")" + // what it does is simply pushing the jth bit to the 2^31 bit which is negative + // thus if the jth bit is 1 then the value is less than zero and if its 0 then its greater or equal to zero + if(mask << ~j >= 0 && i << ~j < 0) { // check that mask does not contain the new candidate and that the candidate is part of the potential candidate i + sum += quantity[j]; + } + } + if(sum <= cnts[idx]) { + ans |= helper(idx + 1, i); + } + if(ans) break; // if ans is true, then a solution exists and no further computation is required + } + dp[idx][mask] = ans; + return ans; + } +} diff --git a/1656-design-an-ordered-stream.js b/1656-design-an-ordered-stream.js new file mode 100644 index 00000000..cc1587cd --- /dev/null +++ b/1656-design-an-ordered-stream.js @@ -0,0 +1,34 @@ +/** + * @param {number} n + */ +const OrderedStream = function(n) { + this.arr = Array(n + 1) + this.ptr = 1 +}; + +/** + * @param {number} id + * @param {string} value + * @return {string[]} + */ +OrderedStream.prototype.insert = function(id, value) { + + this.arr[id] = value + const res = [] + let i + for(i = this.ptr, len = this.arr.length; i < len; i++) { + if (this.arr[i] != null) res.push(this.arr[i]) + else { + break + } + } + this.ptr = i + + return res +}; + +/** + * Your OrderedStream object will be instantiated and called as such: + * var obj = new OrderedStream(n) + * var param_1 = obj.insert(id,value) + */ diff --git a/1657-determine-if-two-strings-are-close.js b/1657-determine-if-two-strings-are-close.js new file mode 100644 index 00000000..a6d92283 --- /dev/null +++ b/1657-determine-if-two-strings-are-close.js @@ -0,0 +1,30 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {boolean} + */ +const closeStrings = function(word1, word2) { + const len1 = word1.length, len2 = word2.length + if(len1 !== len2) return false + const a = ('a').charCodeAt(0) + const arr1 = Array(26).fill(0) + const arr2 = Array(26).fill(0) + for(let i = 0; i < len1; i++) { + arr1[word1.charCodeAt(i) - a]++ + arr2[word2.charCodeAt(i) - a]++ + } + return chk1(arr1, arr2) + function chk1(a1, a2) { + const a11 = a1.slice(0) + a11.sort() + const a22 = a2.slice(0) + a22.sort() + for(let i = 0, len = a1.length; i < len; i++) { + if((a1[i] !== 0 && a2[i] === 0) || (a1[i] === 0 && a2[i] !== 0) ) return false + } + for(let i = 0, len = a1.length; i < len; i++) { + if(a11[i] !== a22[i]) return false + } + return true + } +}; diff --git a/1658-minimum-operations-to-reduce-x-to-zero.js b/1658-minimum-operations-to-reduce-x-to-zero.js new file mode 100644 index 00000000..1e9fd1d6 --- /dev/null +++ b/1658-minimum-operations-to-reduce-x-to-zero.js @@ -0,0 +1,90 @@ +/** + * @param {number[]} nums + * @param {number} x + * @return {number} + */ +const minOperations = function(nums, x) { + const n = nums.length + const sum = nums.reduce((ac, e) => ac + e, 0) + const target = sum - x + if(target < 0) return -1 + if(target === 0) return n + const map = new Map() + map.set(0, -1) + let res = 0 + for(let i = 0, cur = 0; i < n; i++) { + cur += nums[i] + if(map.has(cur - target)) { + res = Math.max(res, i - map.get(cur - target)) + } + + if(!map.has(cur)) map.set(cur, i) + } + + return res === 0 ? -1 : n - res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} x + * @return {number} + */ +const minOperations = function(nums, x) { + const sum = nums.reduce((ac, e) => ac + e, 0) + const subArrSum = sum - x + if(subArrSum === 0) return nums.length + const n = nums.length, hash = {0: -1} + let ac = 0, res = -1 + for(let i = 0; i < n; i++) { + const cur = nums[i] + ac += cur + if(hash[ac - subArrSum] != null) { + res = Math.max(res, i - hash[ac - subArrSum]) + } + hash[ac] = i + } + + return res === -1 ? -1 : n - res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} x + * @return {number} + */ +const minOperations = function (nums, x) { + let l = 0, + r = nums.length - 1; + while (x >= 0 && r >= l) { + x -= nums[r]; + r -= 1; + } + if (r < 0 && x > 0) { + return -1; + } else if (r < 0 && x == 0) { + return nums.length; + } + + let ans = Number.MAX_VALUE; + while (r < nums.length) { + while (x <= 0 && r + 1 < nums.length) { + if (x == 0) ans = Math.min(ans, nums.length - (r - l + 1)); + x += nums[r + 1]; + r += 1; + } + if (r + 1 >= nums.length) { + if (x == 0) ans = Math.min(ans, nums.length - (r - l + 1)); + break; + } + while (x >= 0) { + if (x == 0) ans = Math.min(ans, nums.length - (r - l + 1)); + x -= nums[l]; + l += 1; + } + } + return ans != Number.MAX_VALUE ? ans : -1; +}; diff --git a/1659-maximize-grid-happiness.js b/1659-maximize-grid-happiness.js new file mode 100644 index 00000000..e6a97fe0 --- /dev/null +++ b/1659-maximize-grid-happiness.js @@ -0,0 +1,52 @@ +/** + * @param {number} m + * @param {number} n + * @param {number} introvertsCount + * @param {number} extrovertsCount + * @return {number} + */ +const getMaxGridHappiness = (m, n, introvertsCount, extrovertsCount) => { + const state = '0'.repeat(n) + const memo = new Map() + return helper(state, 0, n, m, introvertsCount, extrovertsCount, memo) +} +function helper(state, idx, n, m, inCount, exCount, memo) { + if ((inCount === 0 && exCount === 0) || idx === m * n) return 0 + let key = idx + state + inCount + exCount + if (memo.has(key)) return memo.get(key) + const r = (idx / n) >> 0, + c = idx % n + let best = 0 + if (inCount !== 0) { + let score = 120 + if (r > 0) score = calc(state.charAt(0) - '0', 1, score) + if (c !== 0) score = calc(state.charAt(state.length - 1) - '0', 1, score) + best = + score + + helper(state.slice(1) + '1', idx + 1, n, m, inCount - 1, exCount, memo) + } + if (exCount !== 0) { + let score = 40 + if (r > 0) score = calc(state.charAt(0) - '0', 2, score) + if (c !== 0) score = calc(state.charAt(state.length - 1) - '0', 2, score) + best = Math.max( + best, + score + + helper(state.slice(1) + '2', idx + 1, n, m, inCount, exCount - 1, memo) + ) + } + best = Math.max( + best, + helper(state.slice(1) + '0', idx + 1, n, m, inCount, exCount, memo) + ) + memo.set(key, best) + return best +} + +function calc(p1, p2, score) { + if (p1 === 1 && p2 === 1) return score - 60 + else if (p1 === 2 && p2 === 2) return score + 40 + else if (p1 === 1 && p2 === 2) return score - 10 + else if (p1 === 2 && p2 === 1) return score - 10 + return score +} diff --git a/166-fraction-to-recurring-decimal.js b/166-fraction-to-recurring-decimal.js new file mode 100644 index 00000000..df393a94 --- /dev/null +++ b/166-fraction-to-recurring-decimal.js @@ -0,0 +1,26 @@ +/** + * @param {number} numerator + * @param {number} denominator + * @return {string} + */ +const fractionToDecimal = function (numerator, denominator) { + if (numerator === 0) return '0' + let s = '' + if (Math.sign(numerator) !== Math.sign(denominator)) s += '-' + let n = Math.abs(numerator) + const d = Math.abs(denominator) + s += Math.floor(n / d) + n %= d + if (n === 0) return s + s += '.' + const map = {} + while (n !== 0) { + map[n] = s.length + n *= 10 + s += Math.floor(n / d) + n %= d + const i = map[n] // repeat starting index + if (i != null) return `${s.slice(0, i)}(${s.slice(i)})` + } + return s +} diff --git a/1660-correct-a-binary-tree.js b/1660-correct-a-binary-tree.js new file mode 100644 index 00000000..9c940f94 --- /dev/null +++ b/1660-correct-a-binary-tree.js @@ -0,0 +1,76 @@ +/** + * 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 + * @param {number} from + * @param {number} to + * @return {TreeNode} + */ +const correctBinaryTree = (root, seen = new Set(), found = false) => { + const go = (root) => { + seen.add(root) + if (root.right && seen.has(root.right)) { + found = true + return null + } + if (!found && root.right) root.right = go(root.right) + if (!found && root.left) root.left = go(root.left) + return root + } + return go(root) +} + +// another + +/** + * 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 + * @param {number} from + * @param {number} to + * @return {TreeNode} + */ +const correctBinaryTree = function(root) { + let q = [root] + let target + while(q.length) { + const size = q.length + const next = new Set() + const row = new Set() + for(let i = 0; i < size; i++) { + const cur = q.shift() + row.add(cur) + if(cur.left) next.add(cur.left) + if(cur.right) next.add(cur.right) + } + for(let e of next) { + if(next.has(e.right)) { + target = e + for(let el of row) { + if(el.left && el.left === target) { + el.left = null + return root + } + if(el.right && el.right === target) { + el.right = null + return root + } + } + } + } + q = Array.from(next) + } + return root +}; diff --git a/1661-average-time-of-process-per-machine.sql b/1661-average-time-of-process-per-machine.sql new file mode 100644 index 00000000..f1d3a735 --- /dev/null +++ b/1661-average-time-of-process-per-machine.sql @@ -0,0 +1,6 @@ +# Write your MySQL query statement below +SELECT s.machine_id, ROUND(AVG(e.timestamp-s.timestamp), 3) AS processing_time +FROM Activity s JOIN Activity e ON + s.machine_id = e.machine_id AND s.process_id = e.process_id AND + s.activity_type = 'start' AND e.activity_type = 'end' +GROUP BY s.machine_id; diff --git a/1662-check-if-two-string-arrays-are-equivalent.js b/1662-check-if-two-string-arrays-are-equivalent.js new file mode 100644 index 00000000..a551d68c --- /dev/null +++ b/1662-check-if-two-string-arrays-are-equivalent.js @@ -0,0 +1,8 @@ +/** + * @param {string[]} word1 + * @param {string[]} word2 + * @return {boolean} + */ +const arrayStringsAreEqual = function(word1, word2) { + return word1.join('') === word2.join('') +}; diff --git a/1663-smallest-string-with-a-given-numeric-value.js b/1663-smallest-string-with-a-given-numeric-value.js new file mode 100644 index 00000000..a651ac6a --- /dev/null +++ b/1663-smallest-string-with-a-given-numeric-value.js @@ -0,0 +1,31 @@ +/** + * @param {number} n + * @param {number} k + * @return {string} + */ +const getSmallestString = function(n, k) { + let arr = Array(n).fill(1) + k -= n + for(let i = n - 1; i >= 0; i--) { + if(k > 0) { + const delta = 26 - arr[i] + if(k >= delta) { + k -= delta + arr[i] = arr[i] + delta + } else { + arr[i] = arr[i] + k + k = 0 + } + } else break + } + const str = 'abcdefghijklmnopqrstuvwxyz' + const m = {} + for(let i = 0; i < 26; i++) { + m[i + 1] = str[i] + } + const res = [] + for(let i = 0; i < n; i++) { + res[i] = m[arr[i]] + } + return res.join('') +}; diff --git a/1664-ways-to-make-a-fair-array.js b/1664-ways-to-make-a-fair-array.js new file mode 100644 index 00000000..11e38596 --- /dev/null +++ b/1664-ways-to-make-a-fair-array.js @@ -0,0 +1,45 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const waysToMakeFair = function(nums) { + const n = nums.length, right = Array(2).fill(0), left = Array(2).fill(0) + let res = 0 + for(let i = 0; i < n; i++) right[i % 2] += nums[i] + for(let i = 0; i < n; i++) { + right[i % 2] -= nums[i] + if(left[0] + right[1] === left[1] + right[0]) res++ + left[i % 2] += nums[i] + } + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const waysToMakeFair = function (nums) { + const n = nums.length + const preOddSum = new Array(n + 1).fill(0) + const preEvenSum = new Array(n + 1).fill(0) + for (let i = 0; i < n; i++) { + if (i % 2 === 0) { + preEvenSum[i + 1] = nums[i] + preEvenSum[i] + preOddSum[i + 1] = preOddSum[i] + } else { + preOddSum[i + 1] = nums[i] + preOddSum[i] + preEvenSum[i + 1] = preEvenSum[i] + } + } + let ret = 0 + for (let i = 0; i < n; i++) { + if ( + preEvenSum[i] + preOddSum[n] - preOddSum[i + 1] === + preOddSum[i] + preEvenSum[n] - preEvenSum[i + 1] + ) + ret++ + } + return ret +} diff --git a/1665-minimum-initial-energy-to-finish-tasks.js b/1665-minimum-initial-energy-to-finish-tasks.js new file mode 100644 index 00000000..31746fc0 --- /dev/null +++ b/1665-minimum-initial-energy-to-finish-tasks.js @@ -0,0 +1,44 @@ +/** + * @param {number[][]} tasks + * @return {number} + */ +const minimumEffort = function (tasks) { + tasks.sort((a, b) => a[1] - a[0] > b[1] - b[0] ? 1 : -1) + let res = 0 + for(let e of tasks) { + res = Math.max(res + e[0], e[1]) + } + return res +} + +// another + +/** + * @param {number[][]} tasks + * @return {number} + */ +const minimumEffort = function (a) { + let low = 0, + high = 1e9 + for (let x of a) low = Math.max(low, x[1]) + a.sort((lhs, rhs) => (lhs[1] - lhs[0] > rhs[1] - rhs[0] ? -1 : 1)) + let n = a.length + while (low != high) { + let mid = low + ((high - low) >> 1) + let found = false + let rem = mid + for (let i = 0; i < n; ++i) { + if (rem < a[i][1]) { + found = true + break + } + rem -= a[i][0] + } + if (found) { + low = mid + 1 + } else { + high = mid + } + } + return high +} diff --git a/1666-change-the-root-of-a-binary-tree.js b/1666-change-the-root-of-a-binary-tree.js new file mode 100644 index 00000000..df2981f7 --- /dev/null +++ b/1666-change-the-root-of-a-binary-tree.js @@ -0,0 +1,33 @@ +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * }; + */ + +/** + * @param {Node} node + * @return {Node} + */ +const flipBinaryTree = function(root, leaf) { + function flip(node, from_node){ + // set and break pointers between node and from_node + const p = node.parent + node.parent = from_node + if (node.left === from_node) node.left = null + if (node.right === from_node) node.right = null + + // stopping condition + if (node === root) return node + + // set right child + if (node.left) node.right = node.left + // set left child + node.left = flip(p, node) + return node + } + return flip(leaf, null) +}; diff --git a/1667-fix-names-in-a-table.sql b/1667-fix-names-in-a-table.sql new file mode 100644 index 00000000..82902899 --- /dev/null +++ b/1667-fix-names-in-a-table.sql @@ -0,0 +1,6 @@ +# Write your MySQL query statement below +SELECT +user_id, +concat(upper(substr(name,1,1)),lower(substr(name,2))) as name +FROM Activity +ORDER BY 1 ASC; diff --git a/1668-maximum-repeating-substring.js b/1668-maximum-repeating-substring.js new file mode 100644 index 00000000..87467df4 --- /dev/null +++ b/1668-maximum-repeating-substring.js @@ -0,0 +1,40 @@ +/** + * @param {string} sequence + * @param {string} word + * @return {number} + */ +const maxRepeating = function(sequence, word) { + let count = 1; + while (sequence.includes(word.repeat(count))) count += 1 + return count - 1; +}; + +// another + +/** + * @param {string} sequence + * @param {string} word + * @return {number} + */ +const maxRepeating = function(sequence, word) { + const s = sequence.length, w = word.length + const max_repeat = (s / w) >> 0 + const failure = Array(w * max_repeat + 1).fill(0) + const repeat_words = word.repeat(max_repeat) + '$' + let result = 0, j = 0 + + for(let i = 1, hi = repeat_words.length; i < hi; i++) { + while(j > 0 && repeat_words[j] !== repeat_words[i]) j = failure[j - 1] + j += (repeat_words[j] === repeat_words[i] ? 1 : 0) + failure[i] = j + } + + j = 0 + for(let i = 0, len = sequence.length; i < len; i++) { + while(j > 0 && repeat_words[j] !== sequence[i]) j = failure[j - 1] + j += (repeat_words[j] === sequence[i] ? 1 : 0) + result = Math.max(result, (j / w) >> 0) + } + return result +}; + diff --git a/1669-merge-in-between-linked-lists.js b/1669-merge-in-between-linked-lists.js new file mode 100644 index 00000000..1bf4d09f --- /dev/null +++ b/1669-merge-in-between-linked-lists.js @@ -0,0 +1,57 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} list1 + * @param {number} a + * @param {number} b + * @param {ListNode} list2 + * @return {ListNode} + */ +const mergeInBetween = function(list1, a, b, list2) { + const dummy = new ListNode() + dummy.next = list1 + let cur = dummy + let tail + let idx = -1 + while(cur) { + if(cur.next && idx + 1 === a) { + tail = cur + const tmp = cur.next + cur.next = null + cur = tmp + idx++ + break + } + cur = cur.next + idx++ + } + let head + // console.log(idx) + while(cur) { + if(idx === b) { + head = cur.next + cur.next = null + break + } + cur = cur.next + idx++ + } + + tail.next = list2 + cur = list2 + while(cur) { + if(cur.next == null) { + cur.next = head + break + } + cur = cur.next + } + + + return dummy.next +}; diff --git a/1670-design-front-middle-back-queue.js b/1670-design-front-middle-back-queue.js new file mode 100644 index 00000000..05d29b66 --- /dev/null +++ b/1670-design-front-middle-back-queue.js @@ -0,0 +1,68 @@ + +const FrontMiddleBackQueue = function() { + this.arr = [] +}; + +/** + * @param {number} val + * @return {void} + */ +FrontMiddleBackQueue.prototype.pushFront = function(val) { + this.arr.unshift(val) +}; + +/** + * @param {number} val + * @return {void} + */ +FrontMiddleBackQueue.prototype.pushMiddle = function(val) { + const len = this.arr.length + const mid = Math.floor(len / 2) + this.arr.splice(mid, 0, val) +}; + +/** + * @param {number} val + * @return {void} + */ +FrontMiddleBackQueue.prototype.pushBack = function(val) { + this.arr.push(val) +}; + +/** + * @return {number} + */ +FrontMiddleBackQueue.prototype.popFront = function() { + const tmp = this.arr.shift() + return tmp == null ? -1 : tmp +}; + +/** + * @return {number} + */ +FrontMiddleBackQueue.prototype.popMiddle = function() { + const len = this.arr.length + const mid = len % 2 === 0 ? Math.floor(len / 2) - 1 : ((len / 2) >> 0) + if(len === 2) return this.arr.shift() + const [tmp] = this.arr.splice(mid, 1) + return tmp == null ? -1 : tmp +}; + +/** + * @return {number} + */ +FrontMiddleBackQueue.prototype.popBack = function() { + const tmp = this.arr.pop() + return tmp == null ? -1 : tmp +}; + +/** + * Your FrontMiddleBackQueue object will be instantiated and called as such: + * var obj = new FrontMiddleBackQueue() + * obj.pushFront(val) + * obj.pushMiddle(val) + * obj.pushBack(val) + * var param_4 = obj.popFront() + * var param_5 = obj.popMiddle() + * var param_6 = obj.popBack() + */ diff --git a/1671-minimum-number-of-removals-to-make-mountain-array.js b/1671-minimum-number-of-removals-to-make-mountain-array.js new file mode 100644 index 00000000..933532f3 --- /dev/null +++ b/1671-minimum-number-of-removals-to-make-mountain-array.js @@ -0,0 +1,64 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumMountainRemovals = function(nums) { + const inc = LIS(nums) + const dec = LIS(nums.slice().reverse()).reverse() + let res = 0 + for(let i = 0, len = nums.length; i < len; i++) { + if(inc[i] > 1 && dec[i] > 1) res = Math.max(res, inc[i] + dec[i] - 1) + } + return nums.length - res +}; + +function LIS(arr) { + const stack = [] + const res = [] + for(let e of arr) { + if((stack.length && e > stack[stack.length - 1]) || stack.length === 0) { + stack.push(e) + res.push(stack.length) + continue + } + let l = 0, r = stack.length - 1 + while(l < r) { + const mid = l + ((r - l) >> 1) + if(stack[mid] < e) l = mid + 1 + else r = mid + } + stack[l] = e + res.push(stack.length) + } + + return res +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const minimumMountainRemovals = function (nums) { + if (nums.length <= 3) return 0 + const n = nums.length + const inc = Array(n).fill(0) + const dec = Array(n).fill(0) + const { max, min } = Math + for (let i = 1; i < n; i++) { + for (let j = 0; j < i; j++) { + if (nums[i] > nums[j]) inc[i] = max(inc[i], inc[j] + 1) + } + } + for (let i = n - 2; i >= 0; i--) { + for (let j = n - 1; j > i; j--) { + if (nums[i] > nums[j]) dec[i] = max(dec[i], dec[j] + 1) + } + } + let res = 0 + for (let i = 0; i < n; i++) { + if (inc[i] > 0 && dec[i] > 0) res = max(res, inc[i] + dec[i]) + } + return n - res - 1 +} diff --git a/1672-richest-customer-wealth.js b/1672-richest-customer-wealth.js new file mode 100644 index 00000000..931ed126 --- /dev/null +++ b/1672-richest-customer-wealth.js @@ -0,0 +1,16 @@ +/** + * @param {number[][]} accounts + * @return {number} + */ +const maximumWealth = function(accounts) { + let max = -Infinity + const m = accounts.length, n = accounts[0].length + for(let i = 0; i < m; i++) { + let tmp = 0 + for(let j = 0; j < n; j++) { + tmp += accounts[i][j] + } + max = Math.max(max, tmp) + } + return max +}; diff --git a/1673-find-the-most-competitive-subsequence.js b/1673-find-the-most-competitive-subsequence.js new file mode 100644 index 00000000..bf913f46 --- /dev/null +++ b/1673-find-the-most-competitive-subsequence.js @@ -0,0 +1,69 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +const mostCompetitive = function (nums, k) { + const res = new Array(k).fill(0) + let start = -1 + let idx = 0 + for (let i = k; i > 0; i--) { + let min = Number.MAX_VALUE + for (let j = start + 1; j < nums.length - i + 1; j++) { + if (nums[j] < min) { + start = j + min = nums[j] + } + } + res[idx++] = min + } + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +const mostCompetitive = function (nums, k) { + const stack = [], + n = nums.length + let i = 0 + while (i < n) { + while ( + stack.length && + stack[stack.length - 1] > nums[i] && + n - i + stack.length > k + ) + stack.pop() + if (stack.length < k) stack.push(nums[i]) + i++ + } + return stack +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +const mostCompetitive = function (nums, k) { + const n = nums.length, stack = [] + for(let i = 0; i < n; i++) { + const ch = nums[i] + while( + stack.length && + ch < stack[stack.length - 1] && + stack.length + (n - 1 - i) >= k + ) { + stack.pop() + } + if(stack.length < k) stack.push(ch) + } + return stack +} + diff --git a/1674-minimum-moves-to-make-array-complementary.js b/1674-minimum-moves-to-make-array-complementary.js new file mode 100644 index 00000000..3c5243ef --- /dev/null +++ b/1674-minimum-moves-to-make-array-complementary.js @@ -0,0 +1,146 @@ +/** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ +const minMoves = function (nums, limit) { + const { min, max } = Math + const n = nums.length + const delta = Array(limit * 2 + 2).fill(0) + for (let i = 0; i < n / 2; i++) { + const lo = 1 + min(nums[i], nums[n - i - 1]) + const hi = limit + max(nums[i], nums[n - i - 1]) + const sum = nums[i] + nums[n - i - 1] + delta[lo]-- + delta[sum]-- + delta[sum + 1]++ + delta[hi + 1]++ + } + let now = n + let ans = n + for (let i = 2; i <= limit * 2; i++) { + now += delta[i] + ans = min(ans, now) + } + return ans +} + +// another + +/** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ +const minMoves = function (nums, limit) { + const n = nums.length, { max, min } = Math + const delta = Array(2 * limit + 2).fill(0) + for(let i = 0; i < n / 2; i++) { + const a = nums[i], b = nums[n - 1 - i] + // [2, min(a, b) + 1) + delta[2] += 2 + // [min(a, b) + 1, a + b) + delta[min(a, b) + 1] -= 1 + delta[a + b]-- + // [a + b + 1, max(a, b) + limit] + delta[a + b + 1] += 1 + // (max(a, b) + limit, 2 * limit] + delta[max(a, b) + limit + 1] +=1 + } + + let res = n, cur = 0 + for(let i = 2; i <= limit * 2; i++) { + cur += delta[i] + res = min(cur, res) + } + + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ +const minMoves = function (nums, limit) { + const n = nums.length, { min, max } = Math + const arr = Array(2 * limit + 2).fill(0) + for(let i = 0, r = n / 2; i < r; i++) { + const a = nums[i], b = nums[n - 1 - i] + arr[2] += 2 + arr[min(a, b) + 1]-- + arr[a + b]-- + arr[a + b + 1]++ + arr[max(a, b) + limit + 1]++ + } + let res = Infinity, cur = 0 + for(let i = 2, r = 2 * limit; i <= r; i++) { + cur += arr[i] + res = min(res, cur) + } + + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ +const minMoves = function (nums, limit) { + const n = nums.length, { min, max } = Math + const arr = Array(2 * limit + 2).fill(0) + for(let i = 0, r = n / 2; i < r; i++) { + const a = nums[i], b = nums[n - 1 - i] + // [2, 2 * limit] + arr[2] += 2 + arr[2 * limit + 1] -= 2 + // [min(a, b) + 1, max(a, b) + limit] + arr[min(a, b) + 1]-- + arr[max(a, b) + limit + 1]++ + // a + b + arr[a + b]-- + arr[a + b + 1]++ + + } + let res = Infinity, cur = 0 + for(let i = 2, r = 2 * limit; i <= r; i++) { + cur += arr[i] + res = min(res, cur) + } + + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ +const minMoves = function(nums, limit) { + const n = nums.length + const arr = Array(2 * limit + 2).fill(0) + for(let i = 0; i < n / 2; i++) { + const a = nums[i], b = nums[n - 1 - i] + const l = Math.min(a, b), r = Math.max(a, b) + arr[l + 1]-- + arr[l + r]-- + arr[l + r + 1]++ + arr[r + limit + 1]++ + } + let res = n, cur = n + for(let e of arr) { + cur += e + res = Math.min(res, cur) + } + + return res +}; + + diff --git a/1675-minimize-deviation-in-array.js b/1675-minimize-deviation-in-array.js new file mode 100644 index 00000000..f8fab346 --- /dev/null +++ b/1675-minimize-deviation-in-array.js @@ -0,0 +1,185 @@ +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} +/** + * @param {number[]} nums + * @return {number} + */ +const minimumDeviation = function(nums) { + const pq = new PQ((a, b) => a > b) + let min = Infinity + for(const e of nums) { + const tmp = e % 2 === 1 ? e * 2: e + pq.push(tmp) + min = Math.min(min, tmp) + } + let res = Infinity + while(pq.peek() % 2 === 0) { + const e = pq.pop() + res = Math.min(res, e - min) + min = Math.min(min, e / 2) + pq.push(e / 2) + } + if(pq.size()) { + res = Math.min(res, pq.peek() - min) + } + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const minimumDeviation = function (A) { + const pq = new PriorityQueue() + let n = A.length, + mi = Number.MAX_VALUE, + res = Number.MAX_VALUE + for (let a of A) { + if (a % 2 === 1) a *= 2 + pq.push(-a) + mi = Math.min(mi, a) + } + while (true) { + let a = -pq.pop() + res = Math.min(res, a - mi) + if (a % 2 === 1) break + mi = Math.min(mi, a / 2) + pq.push(-a / 2) + } + return res +} + +class PriorityQueue { + constructor(comparator = (a, b) => a < b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1676-lowest-common-ancestor-of-a-binary-tree-iv.js b/1676-lowest-common-ancestor-of-a-binary-tree-iv.js new file mode 100644 index 00000000..1057137e --- /dev/null +++ b/1676-lowest-common-ancestor-of-a-binary-tree-iv.js @@ -0,0 +1,51 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode[]} nodes + * @return {TreeNode} + */ +const lowestCommonAncestor = function(root, nodes) { + if (root == null) return root + for(let e of nodes) { + if(root === e) return root + } + const left = lowestCommonAncestor(root.left, nodes) + const right = lowestCommonAncestor(root.right, nodes) + if(left && right) return root + return left ? left : right +}; + +// another + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode[]} nodes + * @return {TreeNode} + */ + const lowestCommonAncestor = function(root, nodes) { + const set = new Set(nodes) + return dfs(root) + + function dfs(node) { + if(node == null) return node + const left = dfs(node.left) + const right = dfs(node.right) + + if(set.has(node)) return node + if(left && right) return node + return left || right + } +}; diff --git a/1678-goal-parser-interpretation.js b/1678-goal-parser-interpretation.js new file mode 100644 index 00000000..0453d266 --- /dev/null +++ b/1678-goal-parser-interpretation.js @@ -0,0 +1,31 @@ +/** + * @param {string} command + * @return {string} + */ +const interpret = function(c) { + const stack = [c[0]] + const n = c.length + let i = 1 + while(i < n) { + if(c[i] === ')') { + if(stack[stack.length - 1] === '(') { + stack.pop() + stack.push('o') + i++ + } else { + let res = '' + while(stack[stack.length - 1] !== '(') { + const tmp = stack.pop() + res = tmp + res + } + stack.pop() + stack.push(res) + i++ + } + } else { + stack.push(c[i]) + i++ + } + } + return stack.join('') +}; diff --git a/1679-max-number-of-k-sum-pairs.js b/1679-max-number-of-k-sum-pairs.js new file mode 100644 index 00000000..35cbe7d9 --- /dev/null +++ b/1679-max-number-of-k-sum-pairs.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxOperations = function(nums, k) { + const m = new Map() + let res = 0 + for(let e of nums) { + if(!m.has(e)) m.set(e, 0) + if(m.has(k - e) && m.get(k - e)) { + res++ + m.set(k - e, m.get(k - e) - 1) + } else { + m.set(e, m.get(e) + 1) + } + } + return res; +}; diff --git a/1680-concatenation-of-consecutive-binary-numbers.js b/1680-concatenation-of-consecutive-binary-numbers.js new file mode 100644 index 00000000..c2b7c069 --- /dev/null +++ b/1680-concatenation-of-consecutive-binary-numbers.js @@ -0,0 +1,35 @@ +/** + * @param {number} n + * @return {number} + */ +const concatenatedBinary = function(n) { + let res = '' + const mod = 10 ** 9 + 7 + for(let i = 1; i <= n; i++) { + res += dec2bin(i) + res = dec2bin(parseInt(res, 2) % mod) + } + return parseInt(res, 2) % mod +}; +function dec2bin(dec){ + return (dec >>> 0).toString(2); +} + +// another + +/** + * @param {number} n + * @return {number} + */ +const concatenatedBinary = function (n) { + const mod = BigInt(1e9 + 7) + let res = 0n + for (let i = 1n, shift = 0n; i <= n; i++) { + let singleBit = (i & (i - 1n)) == 0 + if (singleBit) shift++ + res <<= shift + res += i + res %= mod + } + return res +} diff --git a/1681-minimum-incompatibility.js b/1681-minimum-incompatibility.js new file mode 100644 index 00000000..255ef859 --- /dev/null +++ b/1681-minimum-incompatibility.js @@ -0,0 +1,182 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minimumIncompatibility = function(nums, k) { + const n = nums.length + const size = n / k + const mod = 1e9 + 7 + if(size === 1) return 0 + const limit = 1 << n + const dp = Array.from({ length: limit }, () => Array(16).fill(Infinity)) + for(let i = 0; i < n; i++) dp[1 << i][i] = 0 + + for(let mask = 0; mask < limit; mask++) { + for(let i = 0; i < n; i++) { + if((mask & (1 << i)) === 0) continue + for(let j = 0; j < n; j++) { + if((mask & (1 << j))) continue + const newMask = mask | (1 << j) + if(bitCnt(mask) % size === 0) { + dp[newMask][j] = Math.min(dp[newMask][j], dp[mask][i]) + } else if(nums[j] > nums[i]) { + dp[newMask][j] = Math.min(dp[newMask][j], dp[mask][i] + nums[j] - nums[i]) + } + } + } + } + + const candidate = Math.min(...dp.at(-1)) + + return candidate === Infinity ? -1 : candidate + + function bitCnt(num) { + let res = 0 + while(num) { + if(num & 1) res++ + num = num >> 1 + } + + return res + } +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minimumIncompatibility = function (nums, k) { + if (k === nums.length) { + return 0 + } + const counts = Array(nums.length + 1).fill(0) + for (let num of nums) { + counts[num]++ + if (counts[num] > k) { + return -1 + } + } + const size = nums.length / k + let ans = Number.MAX_VALUE + const backtracking = (groupIdx, index, sum, lowIndex, curIndex) => { + if (index === size) { + sum += curIndex - lowIndex + if (sum > ans) { + return + } + if (groupIdx === k - 1) { + ans = sum + return + } else { + groupIdx++ + index = 0 + } + } + if (index === 0) { + for (let i = 0; i < counts.length; i++) { + if (counts[i]) { + counts[i]-- + backtracking(groupIdx, index + 1, sum, i, i) + counts[i]++ + } + } + } else { + for (let i = curIndex + 1; i < counts.length; i++) { + if (counts[i]) { + counts[i]-- + backtracking(groupIdx, index + 1, sum, lowIndex, i) + counts[i]++ + } + } + } + } + backtracking(0, 0, 0, 0, 0) + return ans +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minimumIncompatibility = function (nums, k) { + if (nums.length === k) return 0 + const maxInBucket = nums.length / k + const freqCount = {} + for (const n of nums) { + if (freqCount[n]) { + if (freqCount[n] === k) { + return -1 + } else { + freqCount[n]++ + } + } else { + freqCount[n] = 1 + } + } + const cache = {} + const allIndiciesUsedMask = 2 ** nums.length - 1 + const dfs = (usedIndicesBitMask) => { + if (usedIndicesBitMask === allIndiciesUsedMask) { + return 0 + } + if (cache[usedIndicesBitMask]) { + return cache[usedIndicesBitMask] + } + const valsToIndices = {} + for (let i = 0; i < nums.length; i++) { + const indexMask = 1 << i + if (usedIndicesBitMask & indexMask) continue + const value = nums[i] + if (!valsToIndices.hasOwnProperty(value)) { + valsToIndices[value] = i + } + } + const indicesAvailable = Object.values(valsToIndices) + let minIncompatibilityCost = Infinity + const combinations = createCombinations(indicesAvailable, maxInBucket) + for (const indices of combinations) { + let nextMask = usedIndicesBitMask + let minVal = Infinity + let maxVal = -Infinity + for (const index of indices) { + minVal = Math.min(minVal, nums[index]) + maxVal = Math.max(maxVal, nums[index]) + nextMask = nextMask | (1 << index) + } + const incompatibilityCost = maxVal - minVal + minIncompatibilityCost = Math.min( + minIncompatibilityCost, + dfs(nextMask) + incompatibilityCost + ) + } + return (cache[usedIndicesBitMask] = minIncompatibilityCost) + } + return dfs(0) +} + +function createCombinations(indices, len) { + const combinations = [] + if (indices.length < len) { + return combinations + } + const stack = [[[], 0]] + while (stack.length > 0) { + let [combi, i] = stack.pop() + for (; i < indices.length; i++) { + const combination = [...combi, indices[i]] + if (combination.length === len) { + combinations.push(combination) + } else { + stack.push([combination, i + 1]) + } + } + } + return combinations +} diff --git a/1683-invalid-tweets.sql b/1683-invalid-tweets.sql new file mode 100644 index 00000000..04f5bbc4 --- /dev/null +++ b/1683-invalid-tweets.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +SELECT tweet_id +FROM Tweets +WHERE CHAR_LENGTH(content) > 15; diff --git a/1684-count-the-number-of-consistent-strings.js b/1684-count-the-number-of-consistent-strings.js new file mode 100644 index 00000000..02ff968a --- /dev/null +++ b/1684-count-the-number-of-consistent-strings.js @@ -0,0 +1,23 @@ +/** + * @param {string} allowed + * @param {string[]} words + * @return {number} + */ +var countConsistentStrings = function(allowed, words) { + const set = new Set() + for(let c of allowed) set.add(c) + let res = 0 + for(let i = 0, len = words.length; i < len; i++) { + const cur = words[i] + let b = true + for(let c of cur) { + if(!set.has(c)) { + b = false + break + } + } + if(b) res++ + } + + return res +}; diff --git a/1685-sum-of-absolute-differences-in-a-sorted-array.js b/1685-sum-of-absolute-differences-in-a-sorted-array.js new file mode 100644 index 00000000..a4273d0e --- /dev/null +++ b/1685-sum-of-absolute-differences-in-a-sorted-array.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const getSumAbsoluteDifferences = function(nums) { + const n = nums.length, { abs } = Math + const res = [] + let e0 = 0 + for(let i = 1; i < n; i++) { + e0 += abs(nums[i] - nums[0]) + } + res[0] = e0 + for(let i = 1; i < n; i++) { + const pre = res[i - 1], diff = nums[i] - nums[i - 1] + let cur = pre + diff * (i - 1) - diff * (n - 1 - i) + res.push(cur) + } + + return res +}; diff --git a/1686-stone-game-vi.js b/1686-stone-game-vi.js new file mode 100644 index 00000000..a57e8cd8 --- /dev/null +++ b/1686-stone-game-vi.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} aliceValues + * @param {number[]} bobValues + * @return {number} + */ +const stoneGameVI = function (aliceValues, bobValues) { + let data = [] + const length = aliceValues.length + for (let i = 0; i < length; i++) { + data.push([aliceValues[i] + bobValues[i], aliceValues[i], bobValues[i]]) + } + data.sort((a, b) => a[0] - b[0]) + data = data.reverse() + + let aScore = 0 + let bScore = 0 + for (let i = 0; i < length; i++) { + if (i % 2 == 0) aScore += data[i][1] + else bScore += data[i][2] + } + + if (aScore > bScore) return 1 + else if (aScore == bScore) return 0 + else return -1 +} diff --git a/1687-delivering-boxes-from-storage-to-ports.js b/1687-delivering-boxes-from-storage-to-ports.js new file mode 100644 index 00000000..46ef0a12 --- /dev/null +++ b/1687-delivering-boxes-from-storage-to-ports.js @@ -0,0 +1,39 @@ +/** + * @param {number[][]} boxes + * @param {number} portsCount + * @param {number} maxBoxes + * @param {number} maxWeight + * @return {number} + */ +var boxDelivering = function (boxes, portsCount, maxBoxes, maxWeight) { + const n = boxes.length + const diff = Array(n).fill(0) + for (let i = 0; i < n - 1; i++) { + if (boxes[i][0] != boxes[i + 1][0]) diff[i] = 1 + } + const dp = Array(n).fill(0) + let cur = 0 + let cbox = 0 + let start = 0 + for (let i = 0; i < n; i++) { + if (i - start == maxBoxes) { + cur -= boxes[start][1] + cbox -= diff[start] + start += 1 + } + cur += boxes[i][1] + if (i > 0) cbox += diff[i - 1] + while (cur > maxWeight) { + cur -= boxes[start][1] + cbox -= diff[start] + start += 1 + } + while (start < i && dp[start] == dp[start - 1]) { + cur -= boxes[start][1] + cbox -= diff[start] + start += 1 + } + dp[i] = (start == 0 ? 0 : dp[start - 1]) + cbox + 2 + } + return dp[n - 1] +} diff --git a/1688-count-of-matches-in-tournament.js b/1688-count-of-matches-in-tournament.js new file mode 100644 index 00000000..dd66cced --- /dev/null +++ b/1688-count-of-matches-in-tournament.js @@ -0,0 +1,23 @@ +/** + * @param {number} n + * @return {number} + */ +var numberOfMatches = function(n) { + const obj = { res: 0 } + helper(n, obj) + return obj.res +}; + +function helper(num, obj) { + if(num <= 1) return + const odd = num % 2 === 1 + if(odd) { + const tmp = Math.floor((num - 1) / 2) + obj.res += tmp + helper(tmp + 1, obj) + } else { + const tmp = Math.floor(num / 2) + obj.res += tmp + helper(tmp, obj) + } +} diff --git a/1689-partitioning-into-minimum-number-of-deci-binary-numbers.js b/1689-partitioning-into-minimum-number-of-deci-binary-numbers.js new file mode 100644 index 00000000..2e2ccec9 --- /dev/null +++ b/1689-partitioning-into-minimum-number-of-deci-binary-numbers.js @@ -0,0 +1,12 @@ +/** + * @param {string} n + * @return {number} + */ +var minPartitions = function(n) { + let res = 0 + const arr = n.split('').map(e => parseInt(e)) + for(let i = 0, len = arr.length; i < len; i++) { + res = Math.max(arr[i], res) + } + return res +}; diff --git a/169-majority-element.js b/169-majority-element.js index 857fce5c..927293c3 100755 --- a/169-majority-element.js +++ b/169-majority-element.js @@ -1,3 +1,48 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var majorityElement = function(nums) { + let el, cnt = 0 + for(let e of nums) { + if(cnt === 0) { + el = e + cnt++ + } else if(el === e) { + cnt++ + } else { + cnt-- + } + } + let tmp = 0 + for(const e of nums) { + if(e === el) tmp++ + } + return tmp > Math.floor(nums.length / 2) ? el : null +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const majorityElement = function(nums) { + let res = 0, cnt = 0 + + for(const e of nums) { + if(cnt === 0) { + res = e + } + if(res === e) cnt++ + else cnt-- + } + + return res +}; + +// another + /** * @param {number[]} nums * @return {number} @@ -16,3 +61,40 @@ const majorityElement = function(nums) { .map(el => +el[0]) .sort((a, b) => b - a)[0]; }; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const majorityElement = function(nums) { + let cnt = 1, candidate = nums[0] + for(let i = 1, n = nums.length; i < n; i++) { + if(candidate === nums[i]) cnt++ + else cnt-- + if(cnt === 0) { + cnt = 1 + candidate = nums[i] + } + } + return candidate +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const majorityElement = function(nums) { + let cnt = 1, candidate = nums[0] + for(let i = 1, n = nums.length; i < n; i++) { + if(cnt === 0) { + cnt = 1 + candidate = nums[i] + }else if(candidate === nums[i]) cnt++ + else cnt-- + } + return candidate +}; diff --git a/1690-stone-game-vii.js b/1690-stone-game-vii.js new file mode 100644 index 00000000..c79dbdc0 --- /dev/null +++ b/1690-stone-game-vii.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} stones + * @return {number} + */ +const stoneGameVII = function (stones) { + let len = stones.length + const dp = Array.from({ length: len }, () => Array(len).fill(0)) + for (let i = len - 2; i >= 0; i--) { + let sum = stones[i] + for (let j = i + 1; j < len; j++) { + sum += stones[j] + dp[i][j] = Math.max( + sum - stones[i] - dp[i + 1][j], + sum - stones[j] - dp[i][j - 1] + ) + } + } + return dp[0][len - 1] +} diff --git a/1691-maximum-height-by-stacking-cuboids.js b/1691-maximum-height-by-stacking-cuboids.js new file mode 100644 index 00000000..2dbc487d --- /dev/null +++ b/1691-maximum-height-by-stacking-cuboids.js @@ -0,0 +1,63 @@ +/** + * @param {number[][]} cuboids + * @return {number} + */ +var maxHeight = function (cuboids) { + let n = cuboids.length + for (let c of cuboids) { + c.sort((a, b) => a - b) + } + const { max } = Math + cuboids.sort(compare) + const f = Array(n) + let ans = 0 + for (let i = 0; i < n; i++) { + f[i] = cuboids[i][2] + for (let j = 0; j < i; j++) { + if ( + cuboids[i][0] <= cuboids[j][0] && + cuboids[i][1] <= cuboids[j][1] && + cuboids[i][2] <= cuboids[j][2] + ) + f[i] = max(f[i], f[j] + cuboids[i][2]) + } + ans = max(ans, f[i]) + } + return ans + function compare(a, b) { + if (a[0] != b[0]) return b[0] - a[0] + if (a[1] != b[1]) return b[1] - a[1] + return b[2] - a[2] + } +} + +// another + +/** + * @param {number[][]} cuboids + * @return {number} + */ +var maxHeight = function(cuboids) { + cuboids.forEach((cuboid) => cuboid.sort((a, b) => a - b)); + cuboids.sort((a, b) => { + if (a[0] !== b[0]) return b[0] - a[0]; + if (a[1] !== b[1]) return b[1] - a[1]; + return b[2] - a[2]; + }); + const n = cuboids.length; + const dp = Array(n).fill(0); + let res = 0; + for (let j = 0; j < n; ++j) { + dp[j] = cuboids[j][2]; + for (let i = 0; i < j; ++i) { + if (cuboids[i][0] >= cuboids[j][0] + && cuboids[i][1] >= cuboids[j][1] + && cuboids[i][2] >= cuboids[j][2] + ) { + dp[j] = Math.max(dp[j], dp[i] + cuboids[j][2]); + } + } + res = Math.max(res, dp[j]); + } + return res; +}; diff --git a/1693-daily-leads-and-partners.sql b/1693-daily-leads-and-partners.sql new file mode 100644 index 00000000..7daf685b --- /dev/null +++ b/1693-daily-leads-and-partners.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +SELECT date_id, make_name, COUNT(DISTINCT lead_id) AS unique_leads, COUNT(DISTINCT partner_id) AS unique_partners +FROM DailySales +GROUP BY 1, 2; diff --git a/1694-reformat-phone-number.js b/1694-reformat-phone-number.js new file mode 100644 index 00000000..33fab296 --- /dev/null +++ b/1694-reformat-phone-number.js @@ -0,0 +1,29 @@ +/** + * @param {string} number + * @return {string} + */ +const reformatNumber = function(number) { + let str = number.replace(/\-/g, '') + str = str.split(' ').join('') + const n = str.length + const re = n % 3 + let lo = 0, hi = 0 + let tmp = [] + if(re === 1) { + hi = n - 5 + tmp.push(str.slice(n - 4, n - 2), str.slice(n - 2)) + } else if(re === 2) { + hi = n - 3 + tmp.push(str.slice(n - 2)) + } else { + hi = n - 1 + } + const res = [] + for(let i = lo; i <= hi; i += 3) { + res.push(str.slice(i, i + 3)) + } + + res.push(...tmp) + + return res.join('-') +}; diff --git a/1695-maximum-erasure-value.js b/1695-maximum-erasure-value.js new file mode 100644 index 00000000..3913e80e --- /dev/null +++ b/1695-maximum-erasure-value.js @@ -0,0 +1,36 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maximumUniqueSubarray = function(nums) { + return maxSumSubarray(nums, nums.length) +}; + +function maxSumSubarray(arr, n) { + + let i = 0, j = 1; + const set = new Set(); + set.add(arr[0]); + + let sum = arr[0]; + let maxsum = sum; + let end = arr[0] + + while (i < n - 1 && j < n) { + const is_in = set.has(arr[j]) + if (!is_in) { + sum = sum + arr[j]; + maxsum = Math.max(sum, maxsum); + + set.add(arr[j++]); + } else { + sum -= arr[i]; + set.delete(arr[i++]); + } + } + return maxsum; +} + +function end(s) { + return Array.from(s).pop(); +} diff --git a/1696-jump-game-vi.js b/1696-jump-game-vi.js new file mode 100644 index 00000000..6a10c740 --- /dev/null +++ b/1696-jump-game-vi.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxResult = function (nums, k) { + const n = nums.length + const f = Array(n).fill(0) + f[0] = nums[0] + const q = [0] + for (let i = 1; i < n; ++i) { + while (i - q[0] > k) { + q.shift() + } + f[i] = f[q[0]] + nums[i] + while (q.length && f[i] >= f[q[q.length - 1]]) { + q.pop() + } + q.push(i) + } + return f[n - 1] +} diff --git a/1697-checking-existence-of-edge-length-limited-paths.js b/1697-checking-existence-of-edge-length-limited-paths.js new file mode 100644 index 00000000..72ef93c5 --- /dev/null +++ b/1697-checking-existence-of-edge-length-limited-paths.js @@ -0,0 +1,108 @@ +/** + * @param {number} n + * @param {number[][]} edgeList + * @param {number[][]} queries + * @return {boolean[]} + */ +const distanceLimitedPathsExist = function (n, edgeList, queries) { + edgeList.sort((a, b) => a[2] - b[2]) + const m = queries.length + const res = Array(m).fill(false) + const order = Array(m).fill(0) + for (let i = 0; i < m; ++i) order[i] = i + order.sort((i, j) => queries[i][2] - queries[j][2]) + const uf = new UF(n) + let idx = 0 + for (let i of order) { + const limit = queries[i][2] + while (idx < edgeList.length && edgeList[idx][2] < limit) { + const [u, v] = edgeList[idx] + uf.union(u, v) + idx++ + } + const [u0, v0] = queries[i] + if (uf.find(u0) === uf.find(v0)) res[i] = true + } + return res +} + +class UF { + constructor(n) { + this.root = Array(n) + .fill(null) + .map((_, i) => i) + } + find(x) { + if (this.root[x] !== x) { + this.root[x] = this.find(this.root[x]) + } + return this.root[x] + } + union(x, y) { + const xr = this.find(x) + const yr = this.find(y) + this.root[yr] = xr + } +} + + +// another + +/** + * @param {number} n + * @param {number[][]} edgeList + * @param {number[][]} queries + * @return {boolean[]} + */ +const distanceLimitedPathsExist = function (n, edgeList, queries) { + edgeList.sort((a, b) => a[2] - b[2]) + const m = queries.length + const ans = Array(m).fill(false) + const order = Array(m).fill(0) + for (let i = 0; i < m; ++i) order[i] = i + order.sort((i, j) => queries[i][2] - queries[j][2]) + const uf = new UnionFind(n) + let idx = 0 + for (let i of order) { + const limit = queries[i][2] + while (idx < edgeList.length && edgeList[idx][2] < limit) { + const [u, v] = edgeList[idx] + uf.union(u, v) + idx++ + } + const [u0, v0] = queries[i] + if (uf.find(u0) === uf.find(v0)) ans[i] = true + } + return ans +} +class UnionFind { + constructor(n) { + this.parents = Array(n) + .fill(0) + .map((e, i) => i) + this.ranks = Array(n).fill(0) + } + root(x) { + while (x !== this.parents[x]) { + this.parents[x] = this.parents[this.parents[x]] + x = this.parents[x] + } + return x + } + find(x) { + return this.root(x) + } + check(x, y) { + return this.root(x) === this.root(y) + } + union(x, y) { + const [rx, ry] = [this.find(x), this.find(y)] + if (this.ranks[rx] >= this.ranks[ry]) { + this.parents[ry] = rx + this.ranks[rx] += this.ranks[ry] + } else if (this.ranks[ry] > this.ranks[rx]) { + this.parents[rx] = ry + this.ranks[ry] += this.ranks[rx] + } + } +} diff --git a/1698-number-of-distinct-substrings-in-a-string.js b/1698-number-of-distinct-substrings-in-a-string.js new file mode 100644 index 00000000..f67060eb --- /dev/null +++ b/1698-number-of-distinct-substrings-in-a-string.js @@ -0,0 +1,42 @@ +/** + * @param {string} s + * @return {number} + */ +const countDistinct = function(s) { + const set = new Set() + for(let i = 0, len = s.length; i < len; i++) { + for(let j = i + 1; j <= len; j++) { + set.add(s.slice(i, j)) + } + } + + return set.size +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const countDistinct = function (s, count = 0) { + const root = new Trie() + const N = s.length + for (let i = 0; i < N; i++) { + let node = root + for (let j = i; j < N; j++) { + const c = s[j] + if (!node.children.has(c)) { + node.children.set(c, new Trie()) + count++ + } + node = node.children.get(c) + } + } + return count +} +class Trie { + constructor() { + this.children = new Map() + } +} diff --git a/170-two-sum-iii-data-structure-design.js b/170-two-sum-iii-data-structure-design.js new file mode 100644 index 00000000..3e478359 --- /dev/null +++ b/170-two-sum-iii-data-structure-design.js @@ -0,0 +1,37 @@ +/** + * Initialize your data structure here. + */ +const TwoSum = function() { + this.hm = new Map(); +}; + +/** + * Add the number to an internal data structure.. + * @param {number} number + * @return {void} + */ +TwoSum.prototype.add = function(number) { + this.hm.set(number, (this.hm.get(number) || 0) + 1); +}; + +/** + * Find if there exists any pair of numbers which sum is equal to the value. + * @param {number} value + * @return {boolean} + */ +TwoSum.prototype.find = function(value) { + for (let item of this.hm) { + let target = value - item[0]; + if (this.hm.has(target)) { + if (target !== item[0] || this.hm.get(target) > 1) return true; + } + } + return false; +}; + +/** + * Your TwoSum object will be instantiated and called as such: + * var obj = new TwoSum() + * obj.add(number) + * var param_2 = obj.find(value) + */ diff --git a/1700-number-of-students-unable-to-eat-lunch.js b/1700-number-of-students-unable-to-eat-lunch.js new file mode 100644 index 00000000..dfdac9b4 --- /dev/null +++ b/1700-number-of-students-unable-to-eat-lunch.js @@ -0,0 +1,35 @@ +/** + * @param {number[]} students + * @param {number[]} sandwiches + * @return {number} + */ +const countStudents = function(students, sandwiches) { + const n = students.length + let res = n + while(helper(students, sandwiches)) { + const len = students.length + for(let i = 0; i < len; i++) { + if (students[0] === sandwiches[0]) { + students.shift() + sandwiches.shift() + res-- + } else { + const tmp = students[0] + students.shift() + students.push(tmp) + } + } + } + return res +}; + +function helper(stu, san) { + const n = stu.length + let res = false + for(let i = 0; i < n; i++) { + if (stu[i] === san[0]) { + return true + } + } + return res +} diff --git a/1701-average-waiting-time.js b/1701-average-waiting-time.js new file mode 100644 index 00000000..a14dfc5f --- /dev/null +++ b/1701-average-waiting-time.js @@ -0,0 +1,17 @@ +/** + * @param {number[][]} customers + * @return {number} + */ +const averageWaitingTime = function(customers) { + const n = customers.length + let start = customers[0][0], end = start + customers[0][1] + let sum = end - start + for(let i = 1; i < n; i++) { + end = end > customers[i][0] ? end + customers[i][1] : customers[i][0] + customers[i][1] + sum += (end - customers[i][0]) + } + + let res = sum / n + + return res +}; diff --git a/1703-maximum-binary-string-after-change.js b/1703-maximum-binary-string-after-change.js new file mode 100644 index 00000000..903e97d4 --- /dev/null +++ b/1703-maximum-binary-string-after-change.js @@ -0,0 +1,66 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minMoves = function (nums, k) { + const pos = [], + pre = [] + const n = nums.length, + { min, floor: fl } = Math + for (let i = 0; i < n; i++) { + if (nums[i] === 1) pos.push(i) + } + let res = Infinity + + pre.push(0) + for (let i = 0, len = pos.length; i < len; i++) { + pre.push(pre[i] + pos[i]) + } + + for (let i = fl(k / 2), limit = pos.length - fl((k - 1) / 2); i > 0, + r = k - l - 1 + for (let i = 0; i + k <= n; ++i) { + const m = i + ((k / 2) >>> 0) + const cur = + pos[m] * l - + (sums[m - 1] - sums[i] + pos[i]) - + pos[m] * r + + sums[i + k - 1] - + sums[m] + res = Math.min(cur, res) + } + return res +} diff --git a/1704-determine-if-string-halves-are-alike.js b/1704-determine-if-string-halves-are-alike.js new file mode 100644 index 00000000..ec3a0a92 --- /dev/null +++ b/1704-determine-if-string-halves-are-alike.js @@ -0,0 +1,19 @@ +/** + * @param {string} s + * @return {boolean} + */ +const halvesAreAlike = function(s) { + const set = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']) + const n = s.length + const mid = n / 2 + const first = s.slice(0, mid), second = s.slice(mid) + return chk(first, set) === chk(second, set) +}; + +function chk(str, set) { + let res = 0 + for(let i = 0, len = str.length; i < len; i++) { + if(set.has(str[i])) res++ + } + return res +} diff --git a/1704-minimum-adjacent-swaps-for-k-consecutive-ones.js b/1704-minimum-adjacent-swaps-for-k-consecutive-ones.js new file mode 100644 index 00000000..8560b024 --- /dev/null +++ b/1704-minimum-adjacent-swaps-for-k-consecutive-ones.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minMoves = function(nums, k) { + if (k == 1) return 0; + let n = 0; + let pos = []; + for (let i = 0; i < nums.length; ++i) { + if (nums[i]) { + pos.push(i - (n++)); + } + } + let sums = []; + sums[0] = pos[0]; + for (let i = 1; i < n; ++i) { + sums[i] = pos[i] + sums[i - 1]; + } + let res = Number.MAX_VALUE; + let l = (k / 2) >> 0, r = k - l - 1; + for (let i = 0; i + k <= n; ++i) { + let m = i + ((k / 2) >>> 0); + let cur = pos[m] * l - (sums[m - 1] - sums[i] + pos[i]) - pos[m] * r + sums[i + k - 1] - sums[m]; + res = Math.min(cur, res); + } + return res; +}; + diff --git a/1705-maximum-number-of-eaten-apples.js b/1705-maximum-number-of-eaten-apples.js new file mode 100644 index 00000000..d6572bf6 --- /dev/null +++ b/1705-maximum-number-of-eaten-apples.js @@ -0,0 +1,90 @@ +/** + * @param {number[]} apples + * @param {number[]} days + * @return {number} + */ +const eatenApples = function (apples, days) { + const n = apples.length + let fin = 0, + i = 0 + const q = new PriorityQueue() + while (i < n || !q.isEmpty()) { + if (i < n && apples[i] > 0) q.push([i + days[i], apples[i]]) + while (!q.isEmpty() && (q.peek()[0] <= i || q.peek()[1] === 0)) q.pop() + if (!q.isEmpty()) { + q.peek()[1] -= 1 + if(q.peek()[1] <= 0) q.pop() + fin += 1 + } + i += 1 + } + return fin +} + +class PriorityQueue { + constructor(comparator = (a, b) => a[0] < b[0]) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1706-where-will-the-ball-fall.js b/1706-where-will-the-ball-fall.js new file mode 100644 index 00000000..1f497c6b --- /dev/null +++ b/1706-where-will-the-ball-fall.js @@ -0,0 +1,28 @@ +/** + * @param {number[][]} grid + * @return {number[]} + */ +const findBall = function (grid) { + const res = new Array(grid[0].length).fill(0) + for (let i = 0; i < res.length; i++) { + let start = i + let state = 1 + for (let j = 0; j < grid.length; j++) { + if (grid[j][start] === 1) { + if (start >= grid[0].length - 1 || grid[j][start + 1] === -1) { + state = -1 + break + } + start++ + } else { + if (start <= 0 || grid[j][start - 1] == 1) { + state = -1 + break + } + start-- + } + } + res[i] = state === -1 ? state : start + } + return res +} diff --git a/1707-maximum-xor-with-an-element-from-array.js b/1707-maximum-xor-with-an-element-from-array.js new file mode 100644 index 00000000..b7104d10 --- /dev/null +++ b/1707-maximum-xor-with-an-element-from-array.js @@ -0,0 +1,265 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +var maximizeXor = function(nums, queries) { + nums.sort((a, b) => a - b) + const n = nums.length + queries.forEach((query, index) => { + query.push(index) + }) + queries.sort((a, b) => a[1] - b[1]) + const trie = new Trie() + let i = 0 + const res = [] + queries.forEach(([x, m, index]) => { + while (i < n && nums[i] <= m) { + trie.insert(nums[i]) + i++ + } + + res[index] = trie.query(x) + + }) + return res +}; + +class Trie { + constructor() { + this.root = {} + } + insert(num) { + let node = this.root + for (let i = 31; i >= 0; i--) { + const bit = (num >> i) & 1 + if (!node[bit]) { + node[bit] = {} + } + node = node[bit] + } + } + query(num) { + let node = this.root + if (Object.keys(node).length === 0) return -1 + let res = 0 + for (let i = 31; i >= 0; i--) { + const bit = (num >> i) & 1 + if(node == null) break + if (node[1 - bit]) { + res |= 1 << i + node = node[1 - bit] + } else { + node = node[bit] + } + } + return res + } +} + +// another + + +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +const maximizeXor = function(nums, queries) { + nums.sort((a, b) => a - b) + queries.forEach((e, i) => e.push(i)) + queries.sort((a, b) => a[1] - b[1]) + const n = nums.length + let idx = 0 + const res = [] + const root = [null, null] + for(const [x, m, qi] of queries) { + while(idx < n && nums[idx] <= m) { + let cur = root, val = nums[idx] + for(let i = 29; i >= 0; i--) { + const tmp = (val >> i) & 1 + if(cur[tmp] == null) cur[tmp] = [null, null] + cur = cur[tmp] + } + idx++ + } + if(idx === 0) { + res[qi] = -1 + continue + } + + let tmp = 0, cur = root + for(let i = 29; i >= 0; i--) { + const val = 1 - ((x >> i) & 1) + if(cur[val] != null) { + tmp = tmp * 2 + 1 + cur = cur[val] + } else { + tmp = tmp * 2 + cur = cur[1 - val] + } + } + res[qi] = tmp + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +const maximizeXor = function (nums, queries) { + nums.sort((a, b) => a - b) + const numOfBits = 1 + Math.floor(Math.log2(nums[nums.length - 1])) + const maxMask = (1 << numOfBits) - 1 + return queries.map(([x, m]) => query(x, m)) + function query(x, m) { + if (m < nums[0]) return -1 + let l = 0, + r = nums.length + while (l < r) { + let mid = l + ((r - l) >> 1) + if (m < nums[mid])r = mid + else l = mid + 1 + } + r-- + l = 0 + let ans = x & ~maxMask + for (let bit = numOfBits - 1; bit >= 0; bit--) { + const mask = 1 << bit + if (x & mask) { + if ((nums[l] & mask) === 0) { + ans |= 1 << bit + r = search(l, r, mask) - 1 + } + } else { + if (nums[r] & mask) { + ans |= 1 << bit + l = search(l, r, mask) + } + } + } + return ans + } + function search(l, r, mask) { + while (l <= r) { + const m = l + ((r - l) >> 1) + if ((nums[m] & mask) === 0) l = m + 1 + else r = m - 1 + } + return l + } +} + + +// another + +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +const maximizeXor = function (nums, queries) { + const n = queries.length + const result = new Array(n) + const trie = [null, null] + for (let num of nums) { + let node = trie + for (let i = 30; i >= 0; i--) { + const b = 1 << i + if (b & num) { + if (!node[1]) node[1] = [null, null] + node = node[1] + } else { + if (!node[0]) node[0] = [null, null] + node = node[0] + } + } + } + const min = Math.min(...nums) + const dfs = (node, num, i, val, max) => { + if (!node || val > max) return -1 + if (i === -1) return val + const bit = 1 << i + i-- + if (bit > max) return dfs(node[0], num, i, val, max) + if (num & bit) { + let x = dfs(node[0], num, i, val, max) + if (x > -1) return x + return dfs(node[1], num, i, val | bit, max) + } else { + let y = dfs(node[1], num, i, val | bit, max) + if (y > -1) return y + return dfs(node[0], num, i, val, max) + } + } + + for (let i = 0; i < n; i++) { + const [num, max] = queries[i] + if (max < min) { + result[i] = -1 + continue + } + result[i] = dfs(trie, num, 30, 0, max) ^ num + } + return result +} + +// another +// though not enough memory, this method still provides a method to solve this kind of problem + +class Trie { + constructor() { + this.next = Array(2).fill(null) + } +} +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +const maximizeXor = function(nums, queries) { + nums.sort((a, b) => a - b) + queries.forEach((e, i) => e.push(i)) + queries.sort((a, b) => a[1] - b[1]) + const n = nums.length + let idx = 0 + const res = [] + const root = new Trie() + for(const [x, m, qi] of queries) { + + while(idx < n && nums[idx] <= m) { + let cur = root, val = nums[idx] + for(let i = 29; i >= 0; i--) { + const tmp = (val >> i) & 1 + if(cur.next[tmp] == null) cur.next[tmp] = new Trie() + cur = cur.next[tmp] + } + idx++ + } + if(idx === 0) { + res[qi] = -1 + continue + } + + let tmp = 0, cur = root + for(let i = 29; i >= 0; i--) { + const val = 1 - ((x >> i) & 1) + if(cur.next[val] != null) { + tmp = tmp * 2 + 1 + cur = cur.next[val] + } else { + tmp = tmp * 2 + cur = cur.next[1 - val] + } + + } + + res[qi] = tmp + } + return res +}; diff --git a/1708-largest-subarray-length-k.js b/1708-largest-subarray-length-k.js new file mode 100644 index 00000000..c3f26a8a --- /dev/null +++ b/1708-largest-subarray-length-k.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +const largestSubarray = function(nums, k) { + const n = nums.length + const hi = n - k + let start = Number.MIN_VALUE, idx = -1 + for(let i = 0; i <= hi; i++) { + if(nums[i] > start) { + start = nums[i] + idx = i + } + } + return nums.slice(idx, idx + k) +}; diff --git a/1709-biggest-window-between-visits.sql b/1709-biggest-window-between-visits.sql new file mode 100644 index 00000000..e5fb7829 --- /dev/null +++ b/1709-biggest-window-between-visits.sql @@ -0,0 +1,10 @@ +# Write your MySQL query statement below +SELECT user_id, MAX(diff) AS biggest_window +FROM +( + SELECT user_id, + DATEDIFF(COALESCE(LEAD(visit_date) OVER (PARTITION BY user_id ORDER BY visit_date), '2021-01-01'), visit_date) AS diff + FROM userVisits +) a +GROUP BY user_id +ORDER BY user_id; diff --git a/171-excel-sheet-column-number.js b/171-excel-sheet-column-number.js index 10c68858..2beff2fd 100755 --- a/171-excel-sheet-column-number.js +++ b/171-excel-sheet-column-number.js @@ -13,3 +13,16 @@ const titleToNumber = function(s) { console.log(titleToNumber("A")); console.log(titleToNumber("AA")); + +// another + +/** + * @param {string} s + * @return {number} + */ +const titleToNumber = function(s) { + let result = 0; + const A = 'A'.charCodeAt(0) + for (let i = 0; i < s.length; result = result * 26 + (s.charCodeAt(i) - A + 1), i++); + return result; +}; diff --git a/1710-maximum-units-on-a-truck.js b/1710-maximum-units-on-a-truck.js new file mode 100644 index 00000000..8a7d3bc0 --- /dev/null +++ b/1710-maximum-units-on-a-truck.js @@ -0,0 +1,16 @@ +/** + * @param {number[][]} boxTypes + * @param {number} truckSize + * @return {number} + */ +const maximumUnits = function (boxTypes, truckSize) { + boxTypes.sort((a, b) => b[1] - a[1]) + let res = 0 + + for (let i = 0; i < boxTypes.length && truckSize > 0; ++i) { + let used = Math.min(boxTypes[i][0], truckSize) + truckSize -= used + res += used * boxTypes[i][1] + } + return res +} diff --git a/1711-count-good-meals.js b/1711-count-good-meals.js new file mode 100644 index 00000000..3fb55787 --- /dev/null +++ b/1711-count-good-meals.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} deliciousness + * @return {number} + */ +const countPairs = function (deliciousness) { + const N = deliciousness.length + deliciousness.sort((a, b) => a - b) + const mp = {}, + mod = 10 ** 9 + 7 + let ret = 0 + for (let i = 0; i < N; i++) { + if (deliciousness[i] !== 0) { + let sum = 1 << (32 - __builtin_clz(deliciousness[i]) - 1) + ret += mp[sum - deliciousness[i]] || 0 + ret += mp[(sum << 1) - deliciousness[i]] || 0 + if (ret >= mod) ret -= mod + } + if (mp[deliciousness[i]] == null) mp[deliciousness[i]] = 0 + mp[deliciousness[i]]++ + } + return ret +} + +function __builtin_clz(num) { + if (num === 0) return 32 + return 32 - dec2bin(num).length +} + +function dec2bin(num) { + return (num >>> 0).toString(2) +} diff --git a/1712-ways-to-split-array-into-three-subarrays.js b/1712-ways-to-split-array-into-three-subarrays.js new file mode 100644 index 00000000..e1c4c3f7 --- /dev/null +++ b/1712-ways-to-split-array-into-three-subarrays.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const waysToSplit = function (nums) { + const N = nums.length + let ret = 0 + const presum = Array(N + 1).fill(0), MOD = 10 ** 9 + 7 + for (let i = 0; i < N; i++) presum[i + 1] = presum[i] + nums[i] + let avg = (presum[N] / 3 + 1) >> 0 + for (let l = 1, m = 2, r = 2; l < N - 1; l++) { + if (presum[l] > avg) break + while (m < N && presum[l] > presum[m] - presum[l]) m++ + m = Math.max(m, l + 1) + if (m > r) r = m + while (r < N && presum[N] - presum[r] >= presum[r] - presum[l]) r++ + ret += r - m + if (ret >= MOD) ret -= MOD + } + return ret +} diff --git a/1713-minimum-operations-to-make-a-subsequence.js b/1713-minimum-operations-to-make-a-subsequence.js new file mode 100644 index 00000000..72b75060 --- /dev/null +++ b/1713-minimum-operations-to-make-a-subsequence.js @@ -0,0 +1,141 @@ +/** + * @param {number[]} target + * @param {number[]} arr + * @return {number} + */ +const minOperations = function(target, arr) { + const hash = {} + for (let i = 0, n = target.length; i < n; i++) { + hash[target[i]] = i + } + const stk = [] + for(let e of arr) { + if(hash[e] == null) continue + let l = 0, r = stk.length + while(l < r) { + const mid = l + (~~((r - l) / 2)) + if(stk[mid] < hash[e]) l = mid + 1 + else r = mid + } + stk[l] = hash[e] + } + return target.length - stk.length +}; + +// another + +/** + * @param {number[]} target + * @param {number[]} arr + * @return {number} + */ +const minOperations = function (target, arr) { + let length1 = target.length, + length2 = arr.length + const targetMap = new Map() + for (let i = 0; i < length1; i++) targetMap.set(target[i], i) + const list = new Array() + for (let i = 0; i < length2; i++) { + let num = arr[i] + if (targetMap.has(num)) list.push(targetMap.get(num)) + } + let longestIncreasing = lengthOfLIS(list) + return target.length - longestIncreasing + + function lengthOfLIS(list) { + let length = 1, + size = list.length + if (size == 0) return 0 + const d = new Array(size + 1).fill(0) + d[length] = list[0] + for (let i = 1; i < size; ++i) { + if (list[i] > d[length]) { + d[++length] = list[i] + } else { + let left = 1, + right = length, + pos = 0 + while (left <= right) { + let mid = (left + right) >> 1 + if (d[mid] < list[i]) { + pos = mid + left = mid + 1 + } else { + right = mid - 1 + } + } + d[pos + 1] = list[i] + } + } + return length + } +} + +// another + +/** + * @param {number[]} target + * @param {number[]} arr + * @return {number} + */ +const minOperations = function(target, arr) { + const map = new Map() + for(let i = 0, len = target.length; i < len; i++) { + map.set(target[i], i) + } + const stack = [] + for(let a of arr) { + if(!map.has(a)) continue + if(stack.length === 0 || map.get(a) > stack[stack.length - 1]) { + stack.push(map.get(a)) + continue + } + let left = 0, right = stack.length - 1, mid + while(left < right) { + mid = left + ((right - left) >> 1) + if(stack[mid] < map.get(a)) left = mid + 1 + else right = mid + } + stack[left] = map.get(a) + } + + return target.length - stack.length +}; + +// another + +/** + * @param {number[]} target + * @param {number[]} arr + * @return {number} + */ +const minOperations = function(target, arr) { + const hash = {} + for(let i = 0, n = target.length; i < n; i++) { + hash[target[i]] = i + } + const stack = [] + + for(let e of arr) { + if(hash[e] == null) continue + const cur = hash[e] + if(stack.length && cur > stack[stack.length - 1]) { + stack.push(cur) + continue + } + + let l = 0, r = stack.length - 1 + + while(l < r) { + const mid = ~~((l + r) / 2) + if(stack[mid] < cur) { + l = mid + 1 + } else r = mid + } + + stack[l] = cur + + } + + return target.length - stack.length +}; diff --git a/1714-sum-of-special-evenly-spaced-elements-in-array.js b/1714-sum-of-special-evenly-spaced-elements-in-array.js new file mode 100644 index 00000000..0d60e731 --- /dev/null +++ b/1714-sum-of-special-evenly-spaced-elements-in-array.js @@ -0,0 +1,48 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +const solve = function (nums, queries) { + const n = nums.length + const dividingPoint = Math.floor(Math.sqrt(n)) + const mod = 1e9 + 7 + const prefix = new Map() + + const res = new Array(queries.length) + for (let i = 0; i < queries.length; i++) { + let x = queries[i][0], + y = queries[i][1] + if (y > dividingPoint) { + let sm = 0 + while (x < n) { + sm += nums[x] + sm %= mod + x += y + } + res[i] = sm + } else { + let startingPoint = x % y + if (!prefix.has(y)) { + prefix.set(y, new Map()) + } + if (!prefix.get(y).has(startingPoint)) { + const curPrefix = [] + curPrefix.push(0) + let cur = startingPoint, + sm = 0 + while (cur < n) { + sm += nums[cur] + sm %= mod + curPrefix.push(sm) + cur += y + } + prefix.get(y).set(startingPoint, curPrefix) + } + const curPrefix = prefix.get(y).get(startingPoint) + res[i] = + (curPrefix[curPrefix.length - 1] - curPrefix[~~(x / y)] + mod) % mod + } + } + return res +} diff --git a/1716-calculate-money-in-leetcode-bank.js b/1716-calculate-money-in-leetcode-bank.js new file mode 100644 index 00000000..ecc5700c --- /dev/null +++ b/1716-calculate-money-in-leetcode-bank.js @@ -0,0 +1,14 @@ +/** + * @param {number} n + * @return {number} + */ +const totalMoney = function(n) { + let total = 0 + for(let i = 0 ; i < n; i++) { + const base = (i / 7) >> 0 + const remain = i % 7 + 1 + total += base + remain + } + + return total +}; diff --git a/1717-maximum-score-from-removing-substrings.js b/1717-maximum-score-from-removing-substrings.js new file mode 100644 index 00000000..63030915 --- /dev/null +++ b/1717-maximum-score-from-removing-substrings.js @@ -0,0 +1,69 @@ +/** + * @param {string} s + * @param {number} x + * @param {number} y + * @return {number} + */ +const maximumGain = function (s, x, y) { + let sb = s.split('') + if (x > y) { + return remove(sb, 'ab', x) + remove(sb, 'ba', y) + } + return remove(sb, 'ba', y) + remove(sb, 'ab', x) + function remove(sb, pattern, point) { + let i = 0, + res = 0 + for (let j = 0; j < sb.length; j++) { + sb[i++] = sb[j] + if ( + i > 1 && + sb[i - 2] == pattern.charAt(0) && + sb[i - 1] == pattern.charAt(1) + ) { + i -= 2 + res += point + } + } + sb.splice(i) + return res + } +} + +// another + +/** + * @param {string} s + * @param {number} x + * @param {number} y + * @return {number} + */ +const maximumGain = function (s, x, y) { + return Math.max(go(s, x, y, 'a', 'b'), go(s, y, x, 'b', 'a')) +} + +function go(s, x, y, a, b) { + const n = s.length + const st = new Array(n) + let sc = 0 + let p = 0 + for (let c of s) { + if (p - 1 >= 0 && st[p - 1] === a && c === b) { + sc += x + p-- + } else { + st[p++] = c + } + } + const st2 = new Array(p) + let q = 0 + for (let u = 0; u < p; u++) { + let c = st[u] + if (q - 1 >= 0 && st2[q - 1] === b && c === a) { + sc += y + q-- + } else { + st2[q++] = c + } + } + return sc +} diff --git a/1718-construct-the-lexicographically-largest-valid-sequence.js b/1718-construct-the-lexicographically-largest-valid-sequence.js new file mode 100644 index 00000000..bba16bfc --- /dev/null +++ b/1718-construct-the-lexicographically-largest-valid-sequence.js @@ -0,0 +1,27 @@ +/** + * @param {number} n + * @return {number[]} + */ +const constructDistancedSequence = function(n) { + const ans = Array(2 * n - 1).fill(0) + const used = Array(n + 1).fill(0) + dfs(ans, 0) + return ans + + function dfs(ans, i) { + if(i === ans.length) return true + if(ans[i]) return dfs(ans, i + 1) + for(let j = used.length - 1; j > 0; j--) { + if(used[j]) continue + if(j !== 1 && (i + j >= ans.length || ans[i + j])) continue + used[j] = 1 + ans[i] = j + if(j !== 1) ans[i + j] = j + if(dfs(ans, i + 1)) return true + ans[i] = 0 + if(j !== 1) ans[i + j] = 0 + used[j] = 0 + } + return false + } +}; diff --git a/1719-number-of-ways-to-reconstruct-a-tree.js b/1719-number-of-ways-to-reconstruct-a-tree.js new file mode 100644 index 00000000..2b7e8d6e --- /dev/null +++ b/1719-number-of-ways-to-reconstruct-a-tree.js @@ -0,0 +1,132 @@ +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} +/** + * @param {number[][]} pairs + * @return {number} + */ +const checkWays = function (pairs) { + const adj = {} + for (let i = 0; i < pairs.length; i++) { + if (adj[pairs[i][0]] == null) adj[pairs[i][0]] = new Set() + if (adj[pairs[i][1]] == null) adj[pairs[i][1]] = new Set() + adj[pairs[i][0]].add(pairs[i][1]) + adj[pairs[i][1]].add(pairs[i][0]) + } + + const q = new PriorityQueue((a, b) => a[0] < b[0]) + Object.keys(adj).forEach((k) => { + q.push([-adj[k].size, +k]) + }) + + const n = q.size() + let multiple = false + const seen = new Set() + while (!q.isEmpty()) { + let [sz, v] = q.peek() + q.pop() + sz = -sz + let u = 0 + let usz = n + 1 + if (seen.size) { + for (let x of adj[v]) { + if (adj[x].size < usz && seen.has(x)) { + u = x + usz = adj[x].size + } + } + } + + seen.add(v) + if (u === 0) { + if (sz !== n - 1) { + return 0 + } + continue + } + + for (let x of adj[v]) { + if (x == u) { + continue + } + + if (!adj[u].has(x)) { + return 0 + } + } + + if (usz == sz) { + multiple = true + } + } + + if (multiple) { + return 2 + } + + return 1 +} diff --git a/1720-decode-xored-array.js b/1720-decode-xored-array.js new file mode 100644 index 00000000..cc368464 --- /dev/null +++ b/1720-decode-xored-array.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} encoded + * @param {number} first + * @return {number[]} + */ +const decode = function(encoded, first) { + const res = [first] + + for(let i = 0, len = encoded.length; i < len; i++) { + res[i + 1] = res[i] ^ encoded[i] + } + + return res +}; diff --git a/1721-swapping-nodes-in-a-linked-list.js b/1721-swapping-nodes-in-a-linked-list.js new file mode 100644 index 00000000..a5cffbd4 --- /dev/null +++ b/1721-swapping-nodes-in-a-linked-list.js @@ -0,0 +1,40 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ +const swapNodes = function(head, k) { + const dummy = new ListNode() + dummy.next = head + const arr = [] + let cur = head + while(cur) { + arr.push(cur) + cur = cur.next + } + const n = arr.length + if(k < 1 || k > n) return dummy.next + let first = arr[k - 1], second = arr[n - k] + + arr[k - 1] = second + arr[n - k] = first + + dummy.next = arr[0] + let pre = arr[0] + for(let i = 1, len = arr.length; i < len; i++) { + const tmp = arr[i] + pre.next = tmp + pre = tmp + } + + pre.next = null + + return dummy.next +}; diff --git a/1722-minimize-hamming-distance-after-swap-operations.js b/1722-minimize-hamming-distance-after-swap-operations.js new file mode 100644 index 00000000..e6349eec --- /dev/null +++ b/1722-minimize-hamming-distance-after-swap-operations.js @@ -0,0 +1,63 @@ +class UnionFind { + constructor(n) { + this.parents = Array(n) + .fill(0) + .map((e, i) => i) + this.ranks = Array(n).fill(0) + } + root(x) { + while (x !== this.parents[x]) { + this.parents[x] = this.parents[this.parents[x]] + x = this.parents[x] + } + return x + } + find(x) { + return this.root(x) + } + check(x, y) { + return this.root(x) === this.root(y) + } + union(x, y) { + const [rx, ry] = [this.find(x), this.find(y)] + if (this.ranks[rx] >= this.ranks[ry]) { + this.parents[ry] = rx + this.ranks[rx] += this.ranks[ry] + } else if (this.ranks[ry] > this.ranks[rx]) { + this.parents[rx] = ry + this.ranks[ry] += this.ranks[rx] + } + } +} +/** + * @param {number[]} source + * @param {number[]} target + * @param {number[][]} allowedSwaps + * @return {number} + */ +const minimumHammingDistance = function (source, target, allowedSwaps) { + const n = target.length + const uf = new UnionFind(n) + for (let A of allowedSwaps) { + const i = A[0], + j = A[1] + uf.union(i, j) + } + const M = {} + for (let i = 0; i < n; i++) { + const j = uf.find(i) + if (M[j] == null) M[j] = {} + if (M[j][source[i]] == null) M[j][source[i]] = 0 + M[j][source[i]]++ + } + let res = 0 + for (let i = 0; i < n; i++) { + const j = uf.find(i) + if (M[j][target[i]]) { + if (!--M[j][target[i]]) { + delete M[j][target[i]] + } + } else res++ + } + return res +} diff --git a/1723-find-minimum-time-to-finish-all-jobs.js b/1723-find-minimum-time-to-finish-all-jobs.js new file mode 100644 index 00000000..94a8c01b --- /dev/null +++ b/1723-find-minimum-time-to-finish-all-jobs.js @@ -0,0 +1,151 @@ +/** + * @param {number[]} jobs + * @param {number} k + * @return {number} + */ +const minimumTimeRequired = function(jobs, k) { + const n = jobs.length + const limit = 1 << n + const sum = Array(limit).fill(0) + const { min, max } = Math + + for(let mask = 0; mask < limit; mask++) { + for(let i = 0; i < n; i++) { + if((mask & (1 << i))) sum[mask] += jobs[i] + } + } + + const dp = Array.from({ length: k + 1 }, () => Array(limit).fill(0)) + for(let i = 0; i < limit; i++) dp[1][i] = sum[i] + + for(let i = 2; i <= k; i++) { + for(let mask = 0; mask < limit; mask++) { + dp[i][mask] = dp[i - 1][mask] + for(let sub = mask; sub; sub = (sub - 1) & mask) { + dp[i][mask] = min(dp[i][mask], max(dp[i - 1][mask - sub], sum[sub])) + } + } + } + + return dp[k][limit - 1] +}; + +// another + +/** + * @param {number[]} jobs + * @param {number} k + * @return {number} + */ +const minimumTimeRequired = function(jobs, k) { + const workers = Array(k).fill(0) + let res = Infinity + const n = jobs.length + + dfs(0) + + return res + + function dfs(idx) { + if(idx === n) { + res = Math.min(res, Math.max(...workers)) + return + } + const e = jobs[idx] + for(let i = 0; i < k; i++) { + if(workers[i] + e >= res) continue + workers[i] += e + dfs(idx + 1) + workers[i] -= e + if(workers[i] === 0) break + } + } +}; + +// another + +/** + * @param {number[]} jobs + * @param {number} k + * @return {number} + */ +const minimumTimeRequired = function (jobs, k) { + if (jobs.length <= k) { + return Math.max(...jobs) + } + + // create a store to hold the number of hours each worker worked + const workers = new Array(k).fill(0) + + let minLongestWorkingTime = Infinity + const dfs = (i) => { + if (i === jobs.length) { + // if we assigned all the jobs, see if we have a better result + minLongestWorkingTime = Math.min( + minLongestWorkingTime, + Math.max(...workers) + ) + return + } + const lengthOfWork = jobs[i] + + for (let worker = 0; worker < k; worker++) { + workers[worker] += lengthOfWork + + // if this combination is has a chance of decreasing our + // answer, try it, otherwise skip it to save on time. + if (workers[worker] <= minLongestWorkingTime) { + dfs(i + 1) + } + workers[worker] -= lengthOfWork + + // We want to minimize the width of the tree + // so if the worker has gotten their first job + // don't try any workers after this worker. + // All other workers after this worker will be 0 as well + // so the combination is exactly the same. + if (workers[worker] === 0) break + } + } + + dfs(0) + return minLongestWorkingTime +} + +// another + +/** + * @param {number[]} jobs + * @param {number} k + * @return {number} + */ +const minimumTimeRequired = function(jobs, k) { + return solution(jobs, k) +}; + +function solution(jobs, k) { + const n = jobs.length + let res = Infinity, arr = Array(k).fill(0) + + let start = 0 + bt(0) + return res + + function bt(idx) { + start++ + if(idx === n) { + res = Math.min(res, Math.max(...arr)) + return + } + const visited = new Set() + for(let j = start; j < start + k; j++) { + const i = j % k + if(visited.has(arr[i])) continue + if(arr[i] + jobs[idx] > res) continue + visited.add(arr[i]) + arr[i] += jobs[idx] + bt(idx + 1) + arr[i] -= jobs[idx] + } + } +} diff --git a/1724-checking-existence-of-edge-length-limited-paths-ii.js b/1724-checking-existence-of-edge-length-limited-paths-ii.js new file mode 100644 index 00000000..84e0cff5 --- /dev/null +++ b/1724-checking-existence-of-edge-length-limited-paths-ii.js @@ -0,0 +1,119 @@ +const DistanceLimitedPathsExist = function (n, edgeList) { + edgeList.sort((a, b) => a[2] - b[2]) + this.dis = [] + this.uf = new SnapshotUF(n) + let cur_dis = 0 + for (let e of edgeList) { + if (e[2] > cur_dis) { + this.dis.push(cur_dis) + cur_dis = e[2] + this.uf.snap() + } + this.uf.union(e[0], e[1]) + } + this.dis.push(cur_dis) + this.uf.snap() +} + +DistanceLimitedPathsExist.prototype.query = function (p, q, limit) { + let snap_id = lower_bound(this.dis, limit) - this.dis[0] - 1 + return this.uf.check(p, q, snap_id) +} + +class SnapshotArray { + constructor(length) { + this.tim = 0 + this.vec = Array.from({ length: length }, () => [0]) + this.ti = Array.from({ length: length }, () => [0]) + } + set(index, val) { + if (this.ti[index][this.ti.length - 1] === this.tim) { + this.vec[index][this.vec[index].length - 1] = val + } else { + this.ti[index].push(this.tim) + this.vec[index].push(val) + } + } + get(idx, snapId) { + const p = lower_bound(this.ti[idx], snapId + 1) - this.ti[idx][0] - 1 + return this.vec[idx][p] + } + snap() { + return this.tim++ + } +} + +class SnapshotUF extends SnapshotArray { + constructor(n) { + super(n) + for (let i = 0; i < n; i++) this.set(i, -1) + } + find(x, snap_id) { + let rep = this.get(x, snap_id) + if (rep < 0) return x + return this.find(rep, snap_id) + } + union(x, y) { + let px = this.find(x, this.tim) + let py = this.find(y, this.tim) + if (px == py) return + let sizepx = -1 * this.get(px, this.tim) + let sizepy = -1 * this.get(py, this.tim) + if (sizepx >= sizepy) { + this.set(px, -1 * sizepx + -1 * sizepy) + this.set(py, px) + } else { + this.set(py, -1 * sizepx + -1 * sizepy) + this.set(px, py) + } + } + check(x, y, snap_id) { + return this.find(x, snap_id) === this.find(y, snap_id) + } +} + +function lower_bound(array, arg1, arg2, arg3, arg4) { + let first + let last + let value + let less + if (arg3 === undefined) { + first = 0 + last = array.length + value = arg1 + less = arg2 + } else { + first = arg1 + last = arg2 + value = arg3 + less = arg4 + } + + if (less === undefined) { + less = function (a, b) { + return a < b + } + } + + let len = last - first + let middle + let step + while (len > 0) { + step = Math.floor(len / 2) + middle = first + step + if (less(array[middle], value, middle)) { + first = middle + first += 1 + len = len - step - 1 + } else { + len = step + } + } + return first +} + +/** + * Your DistanceLimitedPathsExist object will be instantiated and called as such: + * DistanceLimitedPathsExist* obj = new DistanceLimitedPathsExist(n, edgeList); + * bool param_1 = obj->query(p,q,limit); + */ diff --git a/1725-number-of-rectangles-that-can-form-the-largest-square.js b/1725-number-of-rectangles-that-can-form-the-largest-square.js new file mode 100644 index 00000000..dcd7f73c --- /dev/null +++ b/1725-number-of-rectangles-that-can-form-the-largest-square.js @@ -0,0 +1,18 @@ +/** + * @param {number[][]} rectangles + * @return {number} + */ +const countGoodRectangles = function(A) { + const arr = [] + let max = 0 + A.forEach(e => { + const tmp = Math.min(...e) + if(tmp > max) max=tmp + arr.push(tmp) + }) + let res = 0 + for(let e of arr) { + if(e >= max) res++ + } + return res +}; diff --git a/1726-tuple-with-same-product.js b/1726-tuple-with-same-product.js new file mode 100644 index 00000000..b948f581 --- /dev/null +++ b/1726-tuple-with-same-product.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const tupleSameProduct = function(nums) { + const m = {} + const len = nums.length + for(let i = 0; i < len - 1; i++) { + for(let j = i + 1; j < len; j++) { + const tmp = nums[i] * nums[j] + if(m[tmp] == null) m[tmp] = 0 + m[tmp]++ + } + } + let res = 0 + Object.keys(m).forEach(e => { + if(m[e] > 1) res += m[e] * (m[e] - 1) * 4 + }) + + return res +}; diff --git a/1727-largest-submatrix-with-rearrangements.js b/1727-largest-submatrix-with-rearrangements.js new file mode 100644 index 00000000..6323aed1 --- /dev/null +++ b/1727-largest-submatrix-with-rearrangements.js @@ -0,0 +1,22 @@ +/** + * @param {number[][]} matrix + * @return {number} + */ +const largestSubmatrix = function(matrix) { + const n = matrix.length; + const m = matrix[0].length; + const cols = Array(m).fill(0) + let res = 0 + for(let i = 0; i < n; i++) { + for(let j = 0; j < m; j++) { + cols[j] = matrix[i][j] === 1 ? cols[j] + 1 : 0 + } + const tmp = cols.slice() + tmp.sort((a, b) => b - a) + for(let j = 0; j < m; j++) { + res = Math.max(res, (j + 1) * tmp[j]) + } + } + return res +}; + diff --git a/1728-cat-and-mouse-ii.js b/1728-cat-and-mouse-ii.js new file mode 100644 index 00000000..0ced25b8 --- /dev/null +++ b/1728-cat-and-mouse-ii.js @@ -0,0 +1,88 @@ +/** + * @param {string[]} grid + * @param {number} catJump + * @param {number} mouseJump + * @return {boolean} + */ +const canMouseWin = function(grid, catJump, mouseJump) { + let n,m,k,lim,cache,mpos = -1, cpos = -1, fpos = -1 + n = grid.length + m = grid[0].length + for(let i = 0; i < n; i++) { + for(let j = 0; j < m; j++) { + if(grid[i][j] === 'M') mpos = i * m + j + else if(grid[i][j] === 'C') cpos = i * m + j + else if(grid[i][j] === 'F') fpos = i * m + j + } + } + mnei = Array(n * m), cnei = Array(n * m) + for(let i = 0; i < n; i++) { + for(let j = 0; j < m; j++) { + mnei[i * m + j] = traj(i, j, mouseJump) + } + } + for(let i = 0; i < n; i++) { + for(let j = 0; j < m; j++) { + cnei[i * m + j] = traj(i, j, catJump) + } + } + k = m * n + lim = 100 + cache = Array.from({ length: lim }, () => Array(k * k).fill(0)) + + for(let i = 0; i < lim; i++) { + for(let j = 0; j < k * k; j++) { + cache[i][j] = -1 + } + } + + return mouseWin(mpos, cpos, 0) + + function traj(i, j, d) { + if(grid[i][j] === '#') return [] + let pos = i * m + j + let change = [] + change.push(pos) + for(let k = 1; k < d + 1; k++) { + if(i + k >= n || grid[i + k][j] === '#') break + change.push(pos + k * m) + } + for(let k = 1; k < d + 1; k++) { + if(i - k < 0 || grid[i - k][j] === '#') break + change.push(pos - k * m) + } + for(let k = 1; k < d + 1; k++) { + if(j + k >= m || grid[i][j + k] === '#') break + change.push(pos + k) + } + for(let k = 1; k < d + 1; k++) { + if(j - k < 0 || grid[i][j - k] === '#') break + change.push(pos - k) + } + return change + } + + function mouseWin(mpos, cpos, turn) { + if(turn === lim) return false + let e = mpos * k + cpos + if(cache[turn][e] >= 0) return cache[turn][e] === 1 + if(cpos === fpos || cpos === mpos) return false + if(mpos === fpos) return true + if((turn & 1) !== 0) { + let b = 0 + for(let newCpos of cnei[cpos]) { + if(!mouseWin(mpos, newCpos, turn + 1)) b = 1 + } + if(b===0) cache[turn][e] = 1 + else cache[turn][e] = 0 + } else { + let b = 0 + for(let newMpos of mnei[mpos]) { + if(mouseWin(newMpos, cpos, turn + 1)) b = 1 + } + if(b === 1) cache[turn][e] = 1 + else cache[turn][e] = 0 + } + return cache[turn][e] === 1 + } +}; diff --git a/1729-find-followers-count.sql b/1729-find-followers-count.sql new file mode 100644 index 00000000..cfe38287 --- /dev/null +++ b/1729-find-followers-count.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +SELECT user_id, COUNT(follower_id) AS followers_count +FROM Followers +GROUP BY user_id +ORDER BY user_id; diff --git a/173-binary-search-tree-iterator.js b/173-binary-search-tree-iterator.js new file mode 100644 index 00000000..92044020 --- /dev/null +++ b/173-binary-search-tree-iterator.js @@ -0,0 +1,106 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + */ +const BSTIterator = function(root) { + this.root = root; + this.stack = []; +}; + +/** + * @return the next smallest number + * @return {number} + */ +BSTIterator.prototype.next = function() { + while (this.root) { + this.stack.push(this.root); + this.root = this.root.left; + } + this.root = this.stack.pop(); + const result = this.root.val; + this.root = this.root.right; + return result; +}; + +/** + * @return whether we have a next smallest number + * @return {boolean} + */ +BSTIterator.prototype.hasNext = function() { + return this.root || this.stack.length; +}; + +/** + * Your BSTIterator object will be instantiated and called as such: + * var obj = new BSTIterator(root) + * var param_1 = obj.next() + * var param_2 = obj.hasNext() + */ + +// another + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + */ +const BSTIterator = function(root) { + this.generator = dfsGenerator(root) + this.root = root + this.nextSmall = this.generator.next().value +} +function* dfsGenerator(root) { + if (root === null) return + const stack = [] + let current = root + while (true) { + if (current) { + stack.push(current) + current = current.left + } else if (stack.length) { + const top = stack.pop() + yield top.val + current = top.right + } else { + break + } + } +} + +/** + * @return the next smallest number + * @return {number} + */ +BSTIterator.prototype.next = function() { + const smallReturn = this.nextSmall + this.nextSmall = this.generator.next().value + return smallReturn +} + +/** + * @return whether we have a next smallest number + * @return {boolean} + */ +BSTIterator.prototype.hasNext = function() { + return this.nextSmall !== undefined ? true : false +} + +/** + * Your BSTIterator object will be instantiated and called as such: + * var obj = new BSTIterator(root) + * var param_1 = obj.next() + * var param_2 = obj.hasNext() + */ + + diff --git a/1732-find-the-highest-altitude.js b/1732-find-the-highest-altitude.js new file mode 100644 index 00000000..b3ed3097 --- /dev/null +++ b/1732-find-the-highest-altitude.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} gain + * @return {number} + */ +const largestAltitude = function(gain) { + const h = [0] + for(let e of gain) { + h.push(h[h.length - 1] + e) + } + let max = 0 + for(let e of h) { + max = Math.max(max, e) + } + return max +}; diff --git a/1733-minimum-number-of-people-to-teach.js b/1733-minimum-number-of-people-to-teach.js new file mode 100644 index 00000000..f17fb30f --- /dev/null +++ b/1733-minimum-number-of-people-to-teach.js @@ -0,0 +1,45 @@ +/** + * @param {number} n + * @param {number[][]} languages + * @param {number[][]} friendships + * @return {number} + */ +var minimumTeachings = function(n, languages, friendships) { + let cnt_people = languages.length; + + const knows = Array.from({length: cnt_people}, () => Array(n).fill(0)) + for(let who = 0; who < cnt_people; ++who) { + for(let x of languages[who]) { + knows[who][x-1] = true; + } + } + let req = Array(n).fill(0); + let s = new Set(); + for(let edge of friendships) { + let a = edge[0] - 1; + let b = edge[1] - 1; + let yes = false; + for(let x of languages[a]) { + if(knows[b][x-1]) { + yes = true; + } + } + if(yes) { + continue; + } + s.add(a); + s.add(b); + } + let best = Infinity; + for(let i = 0; i < n; ++i) { + let needed = 0; + for(let person of s) { + if(!knows[person][i]) { + needed++; + } + } + best = Math.min(best, needed); + } + return best; +}; + diff --git a/1734-decode-xored-permutation.js b/1734-decode-xored-permutation.js new file mode 100644 index 00000000..1ae0f396 --- /dev/null +++ b/1734-decode-xored-permutation.js @@ -0,0 +1,64 @@ +/** + * @param {number[]} encoded + * @return {number[]} + */ +const decode = function(encoded) { + const n = encoded.length + 1 + let xor = 0 + for(let i = 1; i <= n; i++) xor ^= i + for(let i = 1; i < n - 1; i += 2) xor ^= encoded[i] + const res = [xor] + let pre = xor + for(let i = 0; i < n - 1; i++) { + res.push(encoded[i] ^ pre) + pre = res[res.length - 1] + } + + return res +}; + +// another + +/** + * @param {number[]} encoded + * @return {number[]} + */ +const decode = function(encoded) { + let a = 0 + const n = encoded.length + 1 + for(let i = 0; i <= n; i++) { + a ^= i + if(i < n && i % 2 === 1) a ^= encoded[i] + } + const res = [a] + for(let i = 0; i < n - 1; i++) { + res[i + 1] = res[i] ^ encoded[i] + } + + return res +}; + +// another + +/** + * @param {number[]} encoded + * @return {number[]} + */ +const decode = function(A) { + let xor = 0 + const len = A.length + const permLen = len + 1 + for(let i = 1; i <= permLen; i++) { + xor ^= i + } + // except first + for(let i = 1; i < len; i += 2) xor ^= A[i] + const first = xor + const res = [xor] + let pre = xor + for(let i = 1; i < permLen; i++) { + res[i] = A[i - 1] ^ pre + pre = res[i] + } + return res; +}; diff --git a/1735-count-ways-to-make-array-with-product.js b/1735-count-ways-to-make-array-with-product.js new file mode 100644 index 00000000..b2d7829d --- /dev/null +++ b/1735-count-ways-to-make-array-with-product.js @@ -0,0 +1,44 @@ +/** + * @param {number[][]} queries + * @return {number[]} + */ +var waysToFillArray = function (queries) { + const nax = 10123 + const C = Array.from({ length: nax }, () => Array(15).fill(0n)) + const mod = BigInt(10 ** 9 + 7) + if (C[1][1] == 0n) { + for (let i = 0; i < nax; ++i) { + C[i][0] = 1n + if (i < 15) { + C[i][i] = 1n + } + for (let j = 1; j < i && j < 15; ++j) { + C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod + } + } + } + const answer = [] + for (let query of queries) { + let n = query[0] + let k = query[1] + let total = 1n + const consider = (cnt) => { + total = (total * C[n + cnt - 1][cnt]) % mod + } + for (let i = 2; i * i <= k; ++i) { + if (k % i == 0) { + let cnt = 0 + while (k % i == 0) { + k = (k / i) >> 0 + cnt++ + } + consider(cnt) + } + } + if (k != 1) { + consider(1) + } + answer.push(total) + } + return answer +} diff --git a/1736-latest-time-by-replacing-hidden-digits.js b/1736-latest-time-by-replacing-hidden-digits.js new file mode 100644 index 00000000..033ec30c --- /dev/null +++ b/1736-latest-time-by-replacing-hidden-digits.js @@ -0,0 +1,32 @@ +/** + * @param {string} time + * @return {string} + */ +var maximumTime = function(time) { + const arr = time.split('') + let idx = time.indexOf('?') + if(idx < 0) return time + while(arr.indexOf('?') >= 0) { + idx = arr.indexOf('?') + let e + if(idx === 0) { + if(time[1] === '?') e = 2 + else if(+time[1] < 4) e =2 + else e = 1 + arr[0] = '' + e + + } else if(idx === 1) { + if(+arr[0] > 1) e = 3 + else e = 9 + arr[1] = '' + e + } else if(idx === 3) { + e = 5 + arr[3] = '' + e + } else if(idx === 4) { + e = 9 + arr[4] = '' + e + } + } + + return arr.join('') +}; diff --git a/1737-change-minimum-characters-to-satisfy-one-of-three-conditions.js b/1737-change-minimum-characters-to-satisfy-one-of-three-conditions.js new file mode 100644 index 00000000..503c429e --- /dev/null +++ b/1737-change-minimum-characters-to-satisfy-one-of-three-conditions.js @@ -0,0 +1,148 @@ +/** + * @param {string} a + * @param {string} b + * @return {number} + */ +const minCharacters = function(a, b) { + const n = a.length, m = b.length; + const freqA = Array(26).fill(0), freqB = Array(26).fill(0); + const ac = 'a'.charCodeAt(0) + for(let i = 0; i < n; i++) { + freqA[a.charCodeAt(i) - ac]++ + } + for(let i = 0; i < m; i++) { + freqB[b.charCodeAt(i) - ac]++ + } + let res = Infinity + for(let i = 0; i < 26; i++) { + if(i > 0) { + let change = 0 + for(let j = 0; j < i; j++) { + change += freqA[j] + } + for(let j = i; j < 26; j++) { + change += freqB[j] + } + res = Math.min(res, change) + change = 0 + for(let j = 0; j < i; j++) { + change += freqB[j] + } + for(let j = i; j < 26; j++) { + change += freqA[j] + } + res = Math.min(res, change) + } + let change = 0 + for(let j = 0; j < 26; j++) { + if(j !== i) { + change += freqA[j] + change += freqB[j] + } + } + res = Math.min(res, change) + } + + return res +}; + + +// another + + +/** + * @param {string} a + * @param {string} b + * @return {number} + */ +const minCharacters = function (a, b) { + const n1 = a.length, + n2 = b.length + const cnt1 = Array(26).fill(0) + const cnt2 = Array(26).fill(0) + const aCode = 'a'.charCodeAt(0) + for (let c of a) ++cnt1[c.charCodeAt(0) - aCode] + for (let c of b) ++cnt2[c.charCodeAt(0) - aCode] + let res = n1 - Math.max(...cnt1) + n2 - Math.max(...cnt2) + for (let i = 0; i < 25; ++i) { + let cur1 = 0, + cur2 = 0 + for (let j = 0; j < 26; ++j) { + if (j <= i) { + cur1 += cnt2[j] + cur2 += cnt1[j] + } else { + cur1 += cnt1[j] + cur2 += cnt2[j] + } + } + res = Math.min(Math.min(cur1, cur2), res) + } + return res +} + +// another + +/** + * @param {string} a + * @param {string} b + * @return {number} + */ +const minCharacters = function(a, b) { + return Math.min(method1(a, b), method1(b, a), method3(a, b)) +}; + +function method1(str1, str2) { + let res = Infinity, a = 'a'.charCodeAt(0) + for(let i = 1; i < 26; i++) { + let cnt1 = 0, cnt2 = 0, mid = String.fromCharCode(a + i) + for(let ch of str1) { + if(ch >= mid) cnt1++ + } + for(let ch of str2) { + if(ch < mid) cnt2++ + } + res = Math.min(res, cnt1 + cnt2) + } + return res +} + +function method3(str1, str2) { + const a = 'a'.charCodeAt(0) + const cnt1 = Array(26).fill(0), cnt2 = Array(26).fill(0) + for(let ch of str1) cnt1[ch.charCodeAt(0) - a]++ + for(let ch of str2) cnt2[ch.charCodeAt(0) - a]++ + return str1.length + str2.length - Math.max(...cnt1) - Math.max(...cnt2) +} + +// another + +/** + * @param {string} a + * @param {string} b + * @return {number} + */ +const minCharacters = function (a, b) { + const m = a.length, n = b.length + let res = m + n + const cnt1 = Array(26).fill(0), cnt2 = Array(26).fill(0) + const ac = 'a'.charCodeAt(0) + for(let ch of a) cnt1[ch.charCodeAt(0) - ac]++ + for(let ch of b) cnt2[ch.charCodeAt(0) - ac]++ + const c3 = res - Math.max(...cnt1) - Math.max(...cnt2) + for(let i = 0; i < 26; i++) { + if(i > 0) { + cnt1[i] += cnt1[i - 1] + cnt2[i] += cnt2[i - 1] + } + + if(i < 25) { + res = Math.min(res, m - cnt1[i] + cnt2[i]) + res = Math.min(res, n - cnt2[i] + cnt1[i]) + } + } + + return Math.min(res, c3) +} + + diff --git a/1738-find-kth-largest-xor-coordinate-value.js b/1738-find-kth-largest-xor-coordinate-value.js new file mode 100644 index 00000000..b593d9f7 --- /dev/null +++ b/1738-find-kth-largest-xor-coordinate-value.js @@ -0,0 +1,165 @@ +/** + * @param {number[][]} matrix + * @param {number} k + * @return {number} + */ +var kthLargestValue = function(matrix, k) { + let m = matrix.length; + let n = matrix[0].length; + const v = [], d = Array(n).fill(0); + d[0] = matrix[0][0]; + v.push(d[0]); + for (let i = 1; i < n; ++i) { + d[i] = matrix[0][i] ^ d[i - 1]; + v.push(d[i]); + } + for (let i = 1; i < m; ++i) { + let cur = matrix[i][0]; + d[0] ^= cur; + v.push(d[0]); + for (let j = 1; j < n; ++j) { + cur ^= matrix[i][j]; + d[j] ^= cur; + v.push(d[j]); + } + } + v.sort((a, b) => b - a) + return v[k - 1]; +}; + +// another + +/** + * @param {number[][]} matrix + * @param {number} k + * @return {number} + */ +const kthLargestValue = function(matrix, k) { + const tmp = [] + const n = matrix.length, m = matrix[0].length + const dp = Array.from({ length: n }, () => Array(m).fill(0)) + dp[0][0] = matrix[0][0] + tmp.push(dp[0][0]) + for(let j = 1; j < m; j++) { + dp[0][j] = dp[0][j - 1] ^ matrix[0][j] + tmp.push(dp[0][j]) + } + for(let i = 1; i < n; i++) { + dp[i][0] = dp[i - 1][0] ^ matrix[i][0] + tmp.push(dp[i][0]) + } + for(let i = 1; i < n; i++) { + for(let j = 1; j < m; j++) { + dp[i][j] = dp[i][j - 1] ^ dp[i - 1][j] ^ matrix[i][j] ^ dp[i - 1][j - 1] + tmp.push(dp[i][j]) + } + } + tmp.sort((a, b) => b - a) + return tmp[k - 1] +}; + + +// another + +/** + * @param {number[][]} matrix + * @param {number} k + * @return {number} + */ +const kthLargestValue = function(matrix, k) { + if(matrix == null || matrix[0] == null) return 0 + const m = matrix.length, n = matrix[0].length + const res = Array.from({ length: m }, () => Array(n).fill(0)) + res[0][0] = matrix[0][0] + for(let i = 1; i < m; i++) { + res[i][0] = res[i - 1][0] ^ matrix[i][0] + } + for(let j = 1; j < n; j++) { + res[0][j] = res[0][j - 1] ^ matrix[0][j] + } + + for(let i = 1; i < m; i++) { + for(let j = 1; j < n; j++) { + res[i][j] = res[i][j - 1] ^ res[i - 1][j] ^ res[i - 1][j - 1] ^ matrix[i][j] + } + } + + const pq = new PriorityQueue((a, b) => a < b) + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + pq.push(res[i][j]) + if(pq.size() > k) pq.pop() + } + } + + return pq.pop() + +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1739-building-boxes.js b/1739-building-boxes.js new file mode 100644 index 00000000..420f84d6 --- /dev/null +++ b/1739-building-boxes.js @@ -0,0 +1,37 @@ +/** + * @param {number} n + * @return {number} + */ +const minimumBoxes = function(n) { + let i = 1, c = 1, s = 1 + while(s < n) { + i += 1, c += i, s += c + } + while(s - i >= n) { + s -= i, c -= 1, i -= 1 + } + return c +}; + +// another + + +/** + * @param {number} n + * @return {number} + */ +const minimumBoxes = function(n) { + let sum = 1n, base = 1n, row = 1n; + n = BigInt(n) + while (sum < n) { + base += (++row); + sum += base; + } + while (sum > n) { + --base; + sum -= (row--); + if (sum < n) return base + 1n; + } + return base; +}; + diff --git a/174-dungeon-game.js b/174-dungeon-game.js index 52c3d9d6..99988ffc 100644 --- a/174-dungeon-game.js +++ b/174-dungeon-game.js @@ -2,18 +2,43 @@ * @param {number[][]} dungeon * @return {number} */ -const calculateMinimumHP = function(dungeon) { - if(dungeon.length === 0) return 1 - const rows = dungeon.length - const cols = dungeon[0].length +const calculateMinimumHP = function (dungeon) { + const M = dungeon.length + const N = dungeon[0].length + // hp[i][j] represents the min hp needed at position (i, j) + // Add dummy row and column at bottom and right side + const hp = Array.from({ length: M + 1 }, () => + Array(N + 1).fill(Number.MAX_VALUE) + ) + hp[M][N - 1] = 1 + hp[M - 1][N] = 1 + for (let i = M - 1; i >= 0; i--) { + for (let j = N - 1; j >= 0; j--) { + const need = Math.min(hp[i + 1][j], hp[i][j + 1]) - dungeon[i][j] + hp[i][j] = need <= 0 ? 1 : need + } + } + return hp[0][0] +} + - for(let i = rows - 1 ; i >= 0; i--) { - for(let j = cols - 1; j >= 0; j--) { - if(i==rows-1 && j==cols-1) dungeon[i][j]=Math.max(1, 1-dungeon[i][j]); - else if(i==rows-1) dungeon[i][j]=Math.max(1, dungeon[i][j+1]-dungeon[i][j]); - else if(j==cols-1) dungeon[i][j]=Math.max(1, dungeon[i+1][j]-dungeon[i][j]); - else dungeon[i][j]=Math.max(1, Math.min(dungeon[i+1][j], dungeon[i][j+1])-dungeon[i][j]); +// another + +/** + * @param {number[][]} dungeon + * @return {number} + */ +const calculateMinimumHP = function (dungeon) { + const n = dungeon.length, + m = dungeon[0].length + const dp = Array(n + 1).fill(Number.MAX_VALUE) + dp[n - 1] = 1 + for (let j = m - 1; j >= 0; j--) { + for (let i = n - 1; i >= 0; i--) { + dp[i] = Math.min(dp[i], dp[i + 1]) - dungeon[i][j] + dp[i] = Math.max(1, dp[i]) } } - return dungeon[0][0] -}; + return dp[0] +} + diff --git a/1740-find-distance-in-a-binary-tree.js b/1740-find-distance-in-a-binary-tree.js new file mode 100644 index 00000000..97dae690 --- /dev/null +++ b/1740-find-distance-in-a-binary-tree.js @@ -0,0 +1,163 @@ +/** + * 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 + * @param {number} p + * @param {number} q + * @return {number} + */ +const findDistance = function(root, p, q) { + if(p === q) return 0 + return dfs(root, 0) + + function dfs(node, depth) { + let res = depth + if (node == null) { + res = 0 + } else if(node.val === p || node.val === q) { + let left = dfs(node.left, 1) + let right = dfs(node.right, 1) + res = (left > 0 || right > 0) ? Math.max(left, right) : res + } else { + let left = dfs(node.left, depth + 1) + let right = dfs(node.right, depth + 1) + res = left + right + if(left !== 0 && right !== 0) { + res -= 2 * depth + } + } + return res + } +}; + +// another + +/** + * 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 + * @param {number} p + * @param {number} q + * @return {number} + */ +const findDistance = function (root, p, q) { + if (p == q) return 0 + let result = -1 + dfs(root, p, q) + return result + + /** + The return value means the distance from root node to EITHER p OR q. If + neither p nor q are reachable from the root, return -1. + + It is either p or q but not both, because if the root node can reach both + p and q, it is a common ancestor of p and q and the answer should already + be available. + **/ + function dfs(root, p, q) { + if (root == null) return -1 + + let left = dfs(root.left, p, q) + let right = dfs(root.right, p, q) + + if (root.val == p || root.val == q) { + // root is p or q, but none of p or q is a descendent of root. + // The distance from root to one of p and q is 0 in this case. + if (left < 0 && right < 0) { + return 0 + } + + // root is p or q, and root is also the LCA of p and q. + result = 1 + (left >= 0 ? left : right) + return -1 + } + + // root is neither p nor q, but it is the LCA of p and q. + if (left >= 0 && right >= 0) { + result = left + right + 2 + return -1 + } + + if (left >= 0) { + return left + 1 + } + + if (right >= 0) { + return right + 1 + } + + return -1 + } +} + +// another + +/** + * 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 + * @param {number} p + * @param {number} q + * @return {number} + */ +const findDistance = function (root, p, q) { + let lca = lowestCommonAncestor(root, p, q) + + const queue = [] + queue.push(lca) + let dp = -1, + dq = -1 + let d = 0 + while (queue.length && (dp == -1 || dq == -1)) { + for (let k = queue.length; k > 0; k--) { + let node = queue.shift() + if (node.val == p) { + dp = d + } + + if (node.val == q) { + dq = d + } + + if (node.left != null) { + queue.push(node.left) + } + + if (node.right != null) { + queue.push(node.right) + } + } + d++ + } + + return dp + dq + + function lowestCommonAncestor(root, p, q) { + if (root == null || root.val == p || root.val == q) { + return root + } + let left = lowestCommonAncestor(root.left, p, q) + let right = lowestCommonAncestor(root.right, p, q) + + return left == null ? right : right == null ? left : root + } +} + diff --git a/1741-find-total-time-spent-by-each-employee.sql b/1741-find-total-time-spent-by-each-employee.sql new file mode 100644 index 00000000..02260b71 --- /dev/null +++ b/1741-find-total-time-spent-by-each-employee.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +SELECT event_day AS day, emp_id, SUM(out_time - in_time) AS total_time +FROM Employees +GROUP BY event_day, emp_id; diff --git a/1742-maximum-number-of-balls-in-a-box.js b/1742-maximum-number-of-balls-in-a-box.js new file mode 100644 index 00000000..acb7c9f8 --- /dev/null +++ b/1742-maximum-number-of-balls-in-a-box.js @@ -0,0 +1,16 @@ +/** + * @param {number} lowLimit + * @param {number} highLimit + * @return {number} + */ +const countBalls = function(lowLimit, highLimit) { + const m = {} + for(let i = lowLimit; i <= highLimit; i++) { + const tmp = (i + '').split('').map(e => +e).reduce((ac, e) => ac + e, 0) + if(m[tmp] == null) m[tmp] = 0 + m[tmp]++ + } + const arr = Object.values(m) + arr.sort((a, b) => b - a) + return arr[0] +}; diff --git a/1743-restore-the-array-from-adjacent-pairs.js b/1743-restore-the-array-from-adjacent-pairs.js new file mode 100644 index 00000000..d4255c5e --- /dev/null +++ b/1743-restore-the-array-from-adjacent-pairs.js @@ -0,0 +1,41 @@ +/** + * @param {number[][]} adjacentPairs + * @return {number[]} + */ +const restoreArray = function(pairs) { + const m = {} + for(let e of pairs) { + const [k, v] = e + if(m[k] == null) m[k] = new Set() + if(m[v] == null) m[v] = new Set() + m[k].add(v) + m[v].add(k) + } + const q = [pairs[0]] + let res = pairs[0] + m[res[0]].delete(res[1]) + m[res[1]].delete(res[0]) + let n = pairs.length + while(n) { + const front = res[0], rear = res[res.length - 1] + + if(m[front]) { + const newf = [...m[front].values()][0] + if(m[front].size) res.unshift(newf) + if(m[front]) m[front].delete(newf) + if(m[newf]) m[newf].delete(front) + if(m[front].size === 0) delete m[front] + } + + if(m[rear]) { + const newr = [...m[rear].values()][0] + if(m[rear].size) res.push(newr) + if(m[rear]) m[rear].delete(newr) + if(m[newr]) m[newr].delete(rear) + if(m[rear].size === 0) delete m[rear] + } + n-- + } + + return res +}; diff --git a/1744-can-you-eat-your-favorite-candy-on-your-favorite-day.js b/1744-can-you-eat-your-favorite-candy-on-your-favorite-day.js new file mode 100644 index 00000000..ee0251c3 --- /dev/null +++ b/1744-can-you-eat-your-favorite-candy-on-your-favorite-day.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} candiesCount + * @param {number[][]} queries + * @return {boolean[]} + */ +const canEat = function(candiesCount, queries) { + const n = candiesCount.length + const pre = Array(n).fill(0) + for(let i = 1; i < n; i++) { + pre[i] = pre[i - 1] + candiesCount[i - 1] + } + return queries.map((e, i) => { + const [t, d, c] = e + const num = candiesCount[t] + const min = d, max = (d + 1) * c + + if(pre[t] + num > min && pre[t] < max) { + return true + } else { + return false + } + }) +}; diff --git a/1745-palindrome-partitioning-iv.js b/1745-palindrome-partitioning-iv.js new file mode 100644 index 00000000..8576c981 --- /dev/null +++ b/1745-palindrome-partitioning-iv.js @@ -0,0 +1,100 @@ +/** + * @param {string} s + * @return {boolean} + */ +const checkPartitioning = function(s) { + const map = manacher(s); + return checkPartitioningDfs(map, s, 0); +}; + +function checkPartitioningDfs(map, word, i, path = []) { + if (path.length > 3) return false; + if (path.length == 3 && path.join('') == word) return true; + let found = false; + const length = map.get(i); + path.push(word.substr(i, length)); + found = found || checkPartitioningDfs(map, word, i + length, path); + path.pop(); + + path.push(word.substr(i, 1)); + found = found || checkPartitioningDfs(map, word, i + 1, path); + path.pop(); + + return found; +} + +function manacher(s) { + const t = '^#' + s.split('').join('#') + '#$'; + let r = 0; + let c = 0; + let maxC = 0; + const rad = new Array(t.length).fill(0); + for (let i = 1; i < t.length - 1; ++i) { + if (r > i) rad[i] = Math.min(rad[2 * c - i], r - i); + while (t[i - rad[i] - 1] == t[i + rad[i] + 1]) rad[i]++; + if (i + rad[i] > r) { + c = i; + r = i + rad[i]; + } + if (rad[c] > rad[maxC]) maxC = c; + } + const ans = new Map(); + for (let i = 0; i < rad.length; ++i) { + if (rad[i] > 0) { + ans.set((i - rad[i] - 1) >>> 1, rad[i]); + } + } + return ans; +} + +// another + +/** + * @param {string} s + * @return {boolean} + */ +const checkPartitioning = function (s) { + const n = s.length + const dp = Array.from({ length: n }, () => Array(n).fill(false)) + for(let i = n - 1; i >= 0; i--) { + for(let j = i; j < n; j++) { + if(s[i] === s[j]) { + dp[i][j] = i + 1 <= j - 1 ? dp[i + 1][j - 1] : true + } else dp[i][j] = false + } + } + for(let i = 1; i < n - 1; i++) { + for(let j = i; j < n - 1; j++) { + if(dp[0][i - 1] && dp[i][j] && dp[j + 1][n - 1]) return true + } + } + return false +} + + +// another + +/** + * @param {string} s + * @return {boolean} + */ +const checkPartitioning = function(s) { + for(let i = 1, len = s.length; i < len - 1; i++) { + for(let j = i + 1; j < len; j++) { + const s1 = s.slice(0, i), s2 = s.slice(i, j), s3 = s.slice(j) + if(chk(s1) && chk(s2) && chk(s3)) return true + } + } + return false +}; + +function chk(s) { + let l = 0, r = s.length - 1 + for(;l <= r;) { + if(s[l] === s[r]) { + l++ + r-- + } else return false + } + return true +} diff --git a/1746-maximum-subarray-sum-after-one-operation.js b/1746-maximum-subarray-sum-after-one-operation.js new file mode 100644 index 00000000..e2ae70ed --- /dev/null +++ b/1746-maximum-subarray-sum-after-one-operation.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxSumAfterOperation = function(nums) { + const n = nums.length + const dp = Array.from({ length: n }, () => Array(2).fill(0)) + dp[0][0] = nums[0], dp[0][1] = nums[0] * nums[0] + let res = dp[0][1] + for(let i = 1; i < n; i++) { + dp[i][0] = Math.max(nums[i], dp[i - 1][0] + nums[i]) + dp[i][1] = Math.max(nums[i] * nums[i], dp[i - 1][0] + nums[i] * nums[i], dp[i - 1][1] + nums[i]) + res = Math.max(res, dp[i][1]) + } + return res +}; diff --git a/1747-leetflex-banned-accounts.sql b/1747-leetflex-banned-accounts.sql new file mode 100644 index 00000000..6dd14d01 --- /dev/null +++ b/1747-leetflex-banned-accounts.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +SELECT DISTINCT L1.account_id FROM LogInfo L1 INNER JOIN LogInfo L2 +ON L1.account_id = L2.account_id +AND L1.ip_address <> L2.ip_address +AND (L1.login BETWEEN L2.login AND L2.logout OR L1.logout BETWEEN L2.login AND L2.logout); diff --git a/1748-sum-of-unique-elements.js b/1748-sum-of-unique-elements.js new file mode 100644 index 00000000..bb9ef416 --- /dev/null +++ b/1748-sum-of-unique-elements.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const sumOfUnique = function(nums) { + const m = {} + for(let e of nums) { + if(m[e] == null) m[e] = 0 + m[e]++ + } + let res = 0 + // console.log(m) + Object.entries(m).forEach(e => { + const [k, v] = e + if(v === 1) res += +k + }) + return res +}; diff --git a/1749-maximum-absolute-sum-of-any-subarray.js b/1749-maximum-absolute-sum-of-any-subarray.js new file mode 100644 index 00000000..503164e2 --- /dev/null +++ b/1749-maximum-absolute-sum-of-any-subarray.js @@ -0,0 +1,47 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxAbsoluteSum = function (nums) { + let min = 0, + max = 0, + sum = 0 + for(let e of nums) { + sum += e + min = Math.min(sum, min) + max = Math.max(sum, max) + } + return max - min +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxAbsoluteSum = function (nums) { + let min = Infinity, + max = -Infinity + let positiveSum = 0, + negativeSum = 0 + for (let num of nums) { + positiveSum += num + if (positiveSum > max) { + max = positiveSum + } + + if (positiveSum < 0) { + positiveSum = 0 + } + negativeSum += num + if (negativeSum < min) { + min = negativeSum + } + if (negativeSum > 0) { + negativeSum = 0 + } + } + + return Math.max(Math.abs(min), max) +} diff --git a/1750-minimum-length-of-string-after-deleting-similar-ends.js b/1750-minimum-length-of-string-after-deleting-similar-ends.js new file mode 100644 index 00000000..14f152cc --- /dev/null +++ b/1750-minimum-length-of-string-after-deleting-similar-ends.js @@ -0,0 +1,15 @@ +/** + * @param {string} s + * @return {number} + */ +const minimumLength = function(s) { + const n = s.length + let l = 0, r = n - 1 + while(l < r && s[l] === s[r]) { + while(l < r - 1 && s[r] === s[r - 1]) r-- + while(l + 1 < r && s[l] === s[l + 1]) l++ + l++ + r-- + } + return r - l + 1 +}; diff --git a/1751-maximum-number-of-events-that-can-be-attended-ii.js b/1751-maximum-number-of-events-that-can-be-attended-ii.js new file mode 100644 index 00000000..6f1ce829 --- /dev/null +++ b/1751-maximum-number-of-events-that-can-be-attended-ii.js @@ -0,0 +1,104 @@ +/** + * @param {number[][]} events + * @param {number} k + * @return {number} + */ +const maxValue = function (events, k) { + const n = events.length + const memo = Array.from({ length: n + 1 }, () => Array(k + 1).fill(-1)) + events.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) + return helper(memo, events, n, 0, k) +} + +function helper(memo, events, n, i, k) { + if(i === n || k === 0) return 0 + if(memo[i][k] !== -1) return memo[i][k] + let ni = i + 1 + for(; ni < n; ni++) { + if(events[ni][0] > events[i][1]) break + } + + return memo[i][k] = Math.max( + helper(memo, events, n, i + 1, k), + events[i][2] + helper(memo, events, n, ni, k - 1) + ) +} + +// another + +/** + * @param {number[][]} events + * @param {number} k + * @return {number} + */ +const maxValue = function (events, k) { + // d[i][j] 表示以 events[i]结尾的取最多j个最大值 + // d[i][j-1], Math.max( d[m][j-1] + v[i]) for m ending < start[i] + events.sort((a, b) => a[1] - b[1]) + const n = events.length + let d = [] + for (let j = 0; j <= k; j++) { + const newD = [] + for (let i = 0; i < n; i++) { + if (j === 0) { + newD[i] = 0 + } else if (j === 1) { + newD[i] = events[i][2] + } else if (i === 0) { + newD[i] = events[i][2] + } else { + newD[i] = d[i] // 以i结尾最多取j-1次的最大值 + const v = events[i][2] + const start = events[i][0] + for (let m = 0; m < i; m++) { + if (events[m][1] < start) { + if (d[m] + v > newD[i]) { + newD[i] = d[m] + v + } + } else { + break + } + } + } + } + d = [...newD] + } + return Math.max(...d) +} + + +// another + + +/** + * @param {number[][]} events + * @param {number} k + * @return {number} + */ +const maxValue = function(events, k) { + + cache = new Map(); + events.sort((a,b) => a[0] - b[0]); + return dfs(events, 0, -1, k); + + function dfs(events, idx, end, k){ + let key = idx + "," + end + "," + k; + if(cache.has(key)){ + return cache.get(key); + } + if(idx >= events.length){ + return 0; + } + if(k == 0) { + return 0; + } + let max = 0; + if(events[idx][0] > end){ + max = Math.max(max, dfs(events, idx+1, events[idx][1], k-1) + events[idx][2]); + } + + max = Math.max(max, dfs(events, idx+1, end, k)); + cache.set(key, max); + return max; + } +}; diff --git a/1752-check-if-array-is-sorted-and-rotated.js b/1752-check-if-array-is-sorted-and-rotated.js new file mode 100644 index 00000000..e634b954 --- /dev/null +++ b/1752-check-if-array-is-sorted-and-rotated.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +const check = function(nums) { + let prev = -1, mark = 0 + for(let e of nums) { + + if(e >= prev) prev = e + else { + mark++ + prev = e + } + if(mark > 1) return false + } + if(mark === 1 && nums[0] < nums[nums.length - 1]) { + return false + } + return true +}; diff --git a/1753-maximum-score-from-removing-stones.js b/1753-maximum-score-from-removing-stones.js new file mode 100644 index 00000000..fe93eed7 --- /dev/null +++ b/1753-maximum-score-from-removing-stones.js @@ -0,0 +1,18 @@ +/** + * @param {number} a + * @param {number} b + * @param {number} c + * @return {number} + */ +const maximumScore = function(a, b, c) { + const arr = [a, b, c] + arr.sort((a, b) => a - b) + + + if (arr[0] + arr[1] <= arr[2]) { + return arr[0] + arr[1]; + } else { + const min = Math.min(arr[0], Math.floor((arr[1] + arr[0] - arr[2]) / 2)); + return arr[2] + min; + } +}; diff --git a/1754-largest-merge-of-two-strings.js b/1754-largest-merge-of-two-strings.js new file mode 100644 index 00000000..f910ba72 --- /dev/null +++ b/1754-largest-merge-of-two-strings.js @@ -0,0 +1,73 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {string} + */ +var largestMerge = function(word1, word2) { + let merge = ""; + + while(word1.length && word2.length) { + if (word1[0] > word2[0]) { + merge += word1[0]; + word1 = word1.slice(1); + } else if (word1[0] < word2[0]) { + merge += word2[0]; + word2 = word2.slice(1); + } else { + if (word1 > word2) { + merge += word1[0]; + word1 = word1.slice(1); + } else { + merge += word2[0]; + word2 = word2.slice(1); + } + } + } + + if (word1.length) { + merge += word1; + } else if (word2.length) { + merge += word2; + } + + return merge; +}; + +// another + +/** + * @param {string} word1 + * @param {string} word2 + * @return {string} + */ +const largestMerge = function(word1, word2) { + const stack1 = word1.split(''), stack2 = word2.split('') + const arr = [] + + while(stack1.length && stack2.length) { + const c1 = stack1[0], c2 = stack2[0] + if(c1 > c2) { + stack1.shift() + arr.push(c1) + } else if(c1 < c2) { + stack2.shift() + arr.push(c2) + } else { + if(stack1.join('') > stack2.join('')) { + stack1.shift() + arr.push(c1) + } else { + stack2.shift() + arr.push(c2) + } + } + } + if(stack1.length) { + arr.push(...stack1) + } + if(stack2.length) { + arr.push(...stack2) + } + + return arr.join('') +}; diff --git a/1755-closest-subsequence-sum.js b/1755-closest-subsequence-sum.js new file mode 100644 index 00000000..f7fee8e8 --- /dev/null +++ b/1755-closest-subsequence-sum.js @@ -0,0 +1,130 @@ +/** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ +const minAbsDifference = function (nums, goal) { + let min = Math.abs(goal) + if (!nums.length) return min + const generateSums = (a) => { + let sums = [] + for (let i = 0; i < a.length; i++) { + const l = sums.length + for (let j = 0; j < l; j++) { + sums.push(sums[j] + a[i]) + min = Math.min(min, Math.abs(sums[j] + a[i] - goal)) + if (min === 0) return + } + sums.push(a[i]) + min = Math.min(min, Math.abs(a[i] - goal)) + if (min === 0) return + } + return sums + } + + const n1 = nums.slice(0, Math.ceil(nums.length / 2)) + const n2 = nums.slice(Math.ceil(nums.length / 2), nums.length) + const sums1 = generateSums(n1) + if (min === 0) return min + const sums2 = generateSums(n2) + if (min === 0) return min + + sums2.sort((a, b) => a - b) + for (let i = 0; i < sums1.length; i++) { + if (min === 0) return min + let l = 0 + let r = sums2.length + let sum + while (l < r) { + const h = Math.floor((l + r) / 2) + sum = sums1[i] + sums2[h] + min = Math.min(min, Math.abs(sum - goal)) + if (min === 0) return min + if (sum - goal < 0) { + l = h + 1 + } else { + r = h + } + } + } + return min +} + + +// another + +/** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ +var minAbsDifference = function(a, b) { + let n = a.length, m = (n / 2) >> 0, r = n - m; + let ans = 2e9; + const {max, min, abs} = Math + const va = [], vb = []; + for(let i=0;i<1<>j&1) tmp+=a[j]; + } + ans=min(ans,abs(tmp-b)); + va.push(tmp); + } + // sort(va.begin(), va.end()); + va.sort((a, b) => a - b) + for(let i=0;i<1<>j&1) tmp+=a[j+m]; + } + ans=min(ans,abs(tmp-b)); + let k=b-tmp; + let pos=lower_bound(va, k); + for(let j=pos-1;j<=pos+1;++j) { + if(j>=0 && j 0) { + step = Math.floor(len / 2); + middle = first + step; + if (less(array[middle], value, middle)) { + first = middle; + first += 1; + len = len - step - 1; + } else { + len = step; + } + } + return first; +}; + diff --git a/1757-recyclable-and-low-fat-products.sql b/1757-recyclable-and-low-fat-products.sql new file mode 100644 index 00000000..cec82c14 --- /dev/null +++ b/1757-recyclable-and-low-fat-products.sql @@ -0,0 +1,2 @@ +# Write your MySQL query statement below +SELECT product_id FROM Products WHERE low_fats = 'Y' AND recyclable = 'Y' ORDER BY 1 ASC; diff --git a/1758-minimum-changes-to-make-alternating-binary-string.js b/1758-minimum-changes-to-make-alternating-binary-string.js new file mode 100644 index 00000000..de91c4bb --- /dev/null +++ b/1758-minimum-changes-to-make-alternating-binary-string.js @@ -0,0 +1,14 @@ +/** + * @param {string} s + * @return {number} + */ +const minOperations = function(s) { + const arr = s.split('') + return Math.min(helper(arr, 0, '0'), helper(arr, 0, '1')) + + function helper(arr, idx, ch) { + if(idx === arr.length) return 0 + if(arr[idx] !== ch) return 1 + helper(arr, idx + 1, ch === '0' ? '1' : '0') + else return helper(arr, idx + 1, ch === '0' ? '1' : '0') + } +}; diff --git a/1759-count-number-of-homogenous-substrings.js b/1759-count-number-of-homogenous-substrings.js new file mode 100644 index 00000000..a60e7c32 --- /dev/null +++ b/1759-count-number-of-homogenous-substrings.js @@ -0,0 +1,25 @@ +/** + * @param {string} s + * @return {number} + */ +const countHomogenous = function(s) { + const mod = 10 ** 9 + 7 + let pre = s[0], res = 0, curL = 1 + for(let i = 1, len = s.length; i < len; i++) { + if(s[i] === pre) { + curL++ + } else { + res = (res + helper(curL)) % mod + pre = s[i] + curL = 1 + } + } + if(curL === 1) res = (res + 1) % mod + else res = (res + helper(curL)) % mod + return res + + function helper(num) { + return (num * (num + 1)) / 2 + } +}; + diff --git a/176-second-highest-salary.sql b/176-second-highest-salary.sql new file mode 100644 index 00000000..79b3dfac --- /dev/null +++ b/176-second-highest-salary.sql @@ -0,0 +1,14 @@ +# Write your MySQL query statement below +SELECT max(Salary) AS SecondHighestSalary +FROM Employee +WHERE Salary < (SELECT max(Salary) FROM Employee) + +# another + +# Write your MySQL query statement below +SELECT IFNULL( + (SELECT DISTINCT Salary + FROM Employee + ORDER BY Salary DESC + LIMIT 1 OFFSET 1) + , NULL) AS SecondHighestSalary diff --git a/1760-minimum-limit-of-balls-in-a-bag.js b/1760-minimum-limit-of-balls-in-a-bag.js new file mode 100644 index 00000000..fd3e868f --- /dev/null +++ b/1760-minimum-limit-of-balls-in-a-bag.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @param {number} maxOperations + * @return {number} + */ +const minimumSize = function(nums, maxOperations) { + let L = 1, R = 10 ** 9; + while(L < R){ + let M = (L + (R - L) / 2) >> 0, cnt = 0; + for(let x of nums) cnt += ((x + M - 1) / M - 1) >> 0; + if(cnt > maxOperations) L = M + 1; + else R = M; + } + return L; +}; + diff --git a/1761-minimum-degree-of-a-connected-trio-in-a-graph.js b/1761-minimum-degree-of-a-connected-trio-in-a-graph.js new file mode 100644 index 00000000..e752c0e5 --- /dev/null +++ b/1761-minimum-degree-of-a-connected-trio-in-a-graph.js @@ -0,0 +1,38 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +const minTrioDegree = function (n, edges) { + let ans = 10 ** 8 + const adj = [] + const deg = {} + + function incDeg(u) { + if (deg[u] == null) deg[u] = 0 + deg[u]++ + } + for (let i = 0; i < n; i++) { + adj.push(Array(n).fill(false)) + } + + for (let [u, v] of edges) { + adj[u - 1][v - 1] = true + adj[v - 1][u - 1] = true + incDeg(u - 1) + incDeg(v - 1) + } + for (let u1 = 0; u1 < n; u1++) { + for (let u2 = u1 + 1; u2 < n; u2++) { + for (let u3 = u2 + 1; u3 < n; u3++) { + if (adj[u1][u2] && adj[u2][u3] && adj[u3][u1]) { + let tmp = deg[u1] + deg[u2] + deg[u3] - 6 + ans = Math.min(ans, tmp) + } + } + } + } + + if (ans > 10000000) ans = -1 + return ans +} diff --git a/1762-buildings-with-an-ocean-view.js b/1762-buildings-with-an-ocean-view.js new file mode 100644 index 00000000..85122399 --- /dev/null +++ b/1762-buildings-with-an-ocean-view.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} heights + * @return {number[]} + */ +const findBuildings = function(heights) { + const n = heights.length, suffix = Array(n).fill(0) + let max = 0 + const res = [n - 1] + for(let i = n - 2; i >= 0; i--) { + max = Math.max(max, heights[i + 1]) + suffix[i] = max + if(max < heights[i]) res.push(i) + } + res.reverse() + return res +}; diff --git a/1763-longest-nice-substring.js b/1763-longest-nice-substring.js new file mode 100644 index 00000000..acdb1970 --- /dev/null +++ b/1763-longest-nice-substring.js @@ -0,0 +1,37 @@ +/** + * @param {string} s + * @return {string} + */ +const longestNiceSubstring = function(s) { + let res = '' + const n = s.length + + const arr = Array(26).fill(null) + for(let i = 0; i < n - 1; i++) { + for(let j = i + 1; j < n; j++) { + const tmp = s.slice(i, j + 1) + if(helper(tmp)) { + if(tmp.length > res.length) res = tmp + } + } + } + + + return res +}; + +function helper(s) { + const arr = Array(26).fill(null) + const a = 'a'.charCodeAt(0), A = 'A'.charCodeAt(0) + for(let e of s) { + const ecode = e.charCodeAt(0) + if(arr[ecode - a] === 0 || arr[ecode - A] === 0) continue + if(ecode - a < 26 && ecode - a >= 0) arr[ecode - a] = arr[ecode - a] === 1 ? 0 : -1 + if(ecode - A < 26 && ecode - A >= 0) arr[ecode - A] = arr[ecode - A] === -1 ? 0 : 1 + } + for(let e of arr) { + if(e === -1 || e === 1) return false + } + + return true +} diff --git a/1764-form-array-by-concatenating-subarrays-of-another-array.js b/1764-form-array-by-concatenating-subarrays-of-another-array.js new file mode 100644 index 00000000..c8013442 --- /dev/null +++ b/1764-form-array-by-concatenating-subarrays-of-another-array.js @@ -0,0 +1,137 @@ +/** + * @param {number[][]} groups + * @param {number[]} nums + * @return {boolean} + */ +const canChoose = function (groups, nums) { + const dp = new Array(1000).fill(0) + const lsps = preprocess(groups) + let cur = 0 + for (let i = 0; i < groups.length; i++) { + if (cur >= nums.length) return false + cur = find(nums, cur, groups[i], lsps[i]) + if (cur === -1) return false + cur += groups[i].length + } + return true + function find(nums, cur, p, lsp) { + const n = nums.length + dp[cur] = p[0] === nums[cur] ? 1 : 0 + if (lsp.length === 1 && dp[cur] === 1) { + return cur + } + for (let i = cur + 1; i < n; i++) { + let j = dp[i - 1] + while (j > 0 && p[j] !== nums[i]) { + j = lsp[j - 1] + } + dp[i] = j + (p[j] === nums[i]) + if (dp[i] === p.length) { + return i - p.length + 1 + } + } + return -1 + } + + function preprocess(groups) { + const rets = [] + for (let g of groups) { + const n = g.length + const dp = new Array(n) + dp[0] = 0 + for (let i = 1; i < n; i++) { + let j = dp[i - 1] + while (j > 0 && g[j] !== g[i]) { + j = dp[j - 1] + } + dp[i] = j + (g[j] === g[i] ? 1 : 0) + } + rets.push(dp) + } + return rets + } +} + +// another + +/** + * @param {number[][]} groups + * @param {number[]} nums + * @return {boolean} + */ +const canChoose = function (groups, nums) { + const m = nums.length + let index = 0 + for (let group of groups) { + const n = group.length + // Step-1 Generate LPS + const lps = Array(n).fill(0) + for (let i = 1; i < n; i++) { + let j = lps[i - 1] + while (j > 0 && group[i] !== group[j]) { + j = lps[j - 1] + } + if (group[i] === group[j]) { + j++ + } + lps[i] = j + } + + // Step-2 - Matching + let j = 0 + while (index < m) { + if (nums[index] === group[j]) { + j++ + index++ + } + if (j === n) break + else if (index < m && nums[index] != group[j]) { + if (j > 0) { + j = lps[j - 1] + } else { + index++ + } + } + } + if (j !== n) return false + } + return true +} + + +// another + + +/** + * @param {number[][]} groups + * @param {number[]} nums + * @return {boolean} + */ +const canChoose = function(groups, nums) { + let gi = 0, ni = 0 + const n = groups.length, m = nums.length + while(gi < n && ni < m) { + const len = groups[gi].length + let pass = true + if(nums[ni] !== groups[gi][0]) { + ni++ + continue + } + for(let i = 1; i < len; i++) { + if(nums[ni + i] !== groups[gi][i]) { + pass = false + break + } + } + if(pass) { + gi++ + ni += len + } else { + ni++ + } + } + if(gi >= n) return true + + return false + +}; diff --git a/1765-map-of-highest-peak.js b/1765-map-of-highest-peak.js new file mode 100644 index 00000000..d74a3e7c --- /dev/null +++ b/1765-map-of-highest-peak.js @@ -0,0 +1,40 @@ +/** + * @param {number[][]} isWater + * @return {number[][]} + */ +const highestPeak = function(isWater) { + let q = [] + const visited = new Set() + const m = isWater.length, n = isWater[0].length + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(isWater[i][j] === 1) { + q.push([i, j, 0]) + visited.add(`${i},${j}`) + } + } + } + const res = Array.from({ length: m }, () => Array(n).fill(0)) + const dirs = [[-1, 0], [1, 0], [0, 1], [0, -1]] + + while(q.length) { + const size = q.length + const next = [] + // Array.shift time complexity: O(n) + for(let i = 0; i < size; i++) { + const cur = q[i] + const [row, col, val] = cur + for(let dir of dirs) { + const newRow = row + dir[0], newCol = col + dir[1] + const key = `${newRow},${newCol}` + if(newRow < 0 || newRow >= m || newCol < 0 || newCol >= n || visited.has(key) || res[newRow][newCol] !== 0) continue + next.push([newRow, newCol, val + 1]) + res[newRow][newCol] = val + 1 + visited.add(key) + } + } + q = next + + } + return res +}; diff --git a/1766-tree-of-coprimes.js b/1766-tree-of-coprimes.js new file mode 100644 index 00000000..32324162 --- /dev/null +++ b/1766-tree-of-coprimes.js @@ -0,0 +1,44 @@ +/** + * @param {number[]} nums + * @param {number[][]} edges + * @return {number[]} + */ +const getCoprimes = function (nums, edges) { + const output = Array(nums.length).fill(null) + const graph = new Map() + for (let [u, v] of edges) { + if (!graph.has(u)) graph.set(u, []) + if (!graph.has(v)) graph.set(v, []) + graph.get(u).push(v) + graph.get(v).push(u) + } + + function getGCD(a, b) { + if (!b) return a + return getGCD(b, a % b) + } + + // ancestors is an array of unique ancestors from the recent to the farthest + // indices maps the index of each ancestor + function dfs(i, ancestors, indices) { + for (let num of ancestors) { + const gcd = getGCD(nums[i], num) + if (gcd === 1) { + output[i] = indices[num] + break + } + } + + if (output[i] === null) output[i] = -1 + ancestors = [nums[i], ...ancestors.filter((x) => x !== nums[i])] + indices[nums[i]] = i + for (let next of graph.get(i)) { + if (output[next] === null) { + dfs(next, ancestors, [...indices]) + } + } + } + + dfs(0, [], Array(51)) + return output +} diff --git a/1768-merge-strings-alternately.js b/1768-merge-strings-alternately.js new file mode 100644 index 00000000..d93be80c --- /dev/null +++ b/1768-merge-strings-alternately.js @@ -0,0 +1,21 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {string} + */ +var mergeAlternately = function(word1, word2) { + let res = '', mark = 0, i = 0, j = 0 + while(i < word1.length && j < word2.length) { + if(mark === 0) { + res += word1[i++] + mark = 1 + } else { + res += word2[j++] + mark = 0 + } + } + while(i < word1.length) res += word1[i++] + while(j < word2.length) res += word2[j++] + + return res +}; diff --git a/1769-minimum-number-of-operations-to-move-all-balls-to-each-box.js b/1769-minimum-number-of-operations-to-move-all-balls-to-each-box.js new file mode 100644 index 00000000..11f47aa6 --- /dev/null +++ b/1769-minimum-number-of-operations-to-move-all-balls-to-each-box.js @@ -0,0 +1,71 @@ +/** + * @param {string} boxes + * @return {number[]} + */ +const minOperations = function(boxes) { + const n = boxes.length + const res = Array(n).fill(0) + let cum = 0, sum = 0 + for(let i = 0; i < n; i++) { + res[i] += sum + cum += +boxes[i] + sum += cum + } + cum = 0, sum = 0 + for(let i = n - 1; i >= 0; i--) { + res[i] += sum + cum += +boxes[i] + sum += cum + } + return res +}; + + +// another + + +/** + * @param {string} boxes + * @return {number[]} + */ +const minOperations = function(boxes) { + const res = [] + for(let i = 0, len = boxes.length; i < len; i++) { + res[i] = helper(boxes, i) + } + + return res +}; + +function helper(str, idx) { + let res = 0 + for(let i = 0, len = str.length; i < len; i++) { + if(i === idx || str[i] === '0') continue + res += Math.abs(i - idx) + } + return res +} + +// another + +/** + * @param {string} boxes + * @return {number[]} + */ + const minOperations = function(boxes) { + const n = boxes.length + const res = Array(n).fill(0) + let cnt = 0, sum = 0 + for(let i = 0; i < n; i++) { + res[i] = sum + cnt += boxes[i] === '1' ? 1 : 0 + sum += cnt + } + cnt = 0, sum = 0 + for(let i = n - 1; i >= 0; i--) { + res[i] += sum + cnt += boxes[i] === '1' ? 1 : 0 + sum += cnt + } + return res +}; diff --git a/1770-maximum-score-from-performing-multiplication-operations.js b/1770-maximum-score-from-performing-multiplication-operations.js new file mode 100644 index 00000000..fb4efcc0 --- /dev/null +++ b/1770-maximum-score-from-performing-multiplication-operations.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @param {number[]} multipliers + * @return {number} + */ +const maximumScore = function(nums, multipliers) { + const n = nums.length, m = multipliers.length + const { max } = Math + const dp = Array.from({ length: m + 1 }, () => Array(m + 1).fill(-Infinity)) + return helper(0, 0) + function helper(l, i) { + if(i === m) return 0 + if(dp[l][i] !== -Infinity) return dp[l][i] + const pickLeft = helper(l + 1, i + 1) + nums[l] * multipliers[i] + const pickRight = helper(l, i + 1) + nums[n - (i - l) - 1] * multipliers[i] + return dp[l][i] = max(pickLeft, pickRight) + } + +}; diff --git a/1771-maximize-palindrome-length-from-subsequences.js b/1771-maximize-palindrome-length-from-subsequences.js new file mode 100644 index 00000000..fd093aa0 --- /dev/null +++ b/1771-maximize-palindrome-length-from-subsequences.js @@ -0,0 +1,64 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const longestPalindrome = function(word1, word2) { + const str = word1 + word2 + const len = str.length, m = word1.length, n = word2.length + const dp = LPS(str) + let res = 0 + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(word1[i] !== word2[j]) continue + res = Math.max(res, 2 + dp[i + 1][j + m - 1]) + } + } + return res +} + +function LPS(str) { + const n = str.length + const dp = Array.from({ length: n }, () => Array(n).fill(0)) + for(let i = n - 1; i >= 0; i--) { + dp[i][i] = 1 + for(let j = i + 1; j < n; j++) { + if(str[i] === str[j]) dp[i][j] = 2 + dp[i + 1][j - 1] + else dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]) + } + } + return dp +} + + +// another + +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const longestPalindrome = function(word1, word2) { + const sz = word1.length + word2.length + let res = 0; + const dp = Array.from({ length: sz + 1 }, () => Array(sz + 1).fill(0)) + longestPalindromeSubseq(word1 + word2, dp); + for (let i = 0; i < word1.length; ++i) + for (let j = word2.length - 1; j >= 0; --j) + if (word1[i] == word2[j]) { + res = Math.max(res, dp[i][word1.length + j + 1]); + break; + } + return res; + +} +function longestPalindromeSubseq( s, dp) { + for (let len = 1; len <= s.length; ++len) + for (let i = 0; i + len <= s.length; ++i) + dp[i][i + len] = s[i] == s[i + len - 1] ? + dp[i + 1][i + len - 1] + (len == 1 ? 1 : 2) : + Math.max(dp[i][i + len - 1], dp[i + 1][i + len]); + return dp[0][s.length]; +} + + diff --git a/1773-count-items-matching-a-rule.js b/1773-count-items-matching-a-rule.js new file mode 100644 index 00000000..b761bf79 --- /dev/null +++ b/1773-count-items-matching-a-rule.js @@ -0,0 +1,27 @@ +/** + * @param {string[][]} items + * @param {string} ruleKey + * @param {string} ruleValue + * @return {number} + */ +const countMatches = function(items, ruleKey, ruleValue) { + let res = 0 + for(let e of items) { + if(helper(e, ruleKey, ruleValue)) res++ + } + return res +}; + +function helper(e, k, v) { + const [t, c, n] = e + if(k === 'type' && v === t) { + return true + } else if(k === 'color' && v === c) { + return true + } else if(k === 'name' && v === n) { + return true + } + + return false + +} diff --git a/1774-closest-dessert-cost.js b/1774-closest-dessert-cost.js new file mode 100644 index 00000000..6d918079 --- /dev/null +++ b/1774-closest-dessert-cost.js @@ -0,0 +1,57 @@ +/** + * @param {number[]} baseCosts + * @param {number[]} toppingCosts + * @param {number} target + * @return {number} + */ +const closestCost = function(baseCosts, toppingCosts, target) { + let res = baseCosts[0], n = baseCosts.length, m = toppingCosts.length + const { abs } = Math + for (let i = 0; i < n; i++) { + helper(0, baseCosts[i]) + } + return res + function helper(i, cur) { + if( + abs(cur - target) < abs(res - target) + || (abs(cur - target) === abs(res - target) && cur < res) + ) { + res = cur + } + if(i === m || cur > target) return + helper(i + 1, cur) + helper(i + 1, cur + toppingCosts[i]) + helper(i + 1, cur + toppingCosts[i] * 2) + } +}; + +// another + + +/** + * @param {number[]} baseCosts + * @param {number[]} toppingCosts + * @param {number} target + * @return {number} + */ +const closestCost = function(baseCosts, toppingCosts, target) { + let n = baseCosts.length, m = toppingCosts.length; + const { abs } = Math + const costs = new Set(); + for (let i = 0; i < n; i++) { + dfs(toppingCosts, 0, m, baseCosts[i], costs); + } + const nums = []; + for (let x of costs) nums.push(x); + nums.sort((a, b) => abs(a - target) == abs(b - target) ? a - b : abs(a - target) - abs(b - target)) + return nums[0]; + +}; + +function dfs(toppingCosts, ind, m, cost, costs) { + costs.add(cost); + if (ind >= m) return; + dfs(toppingCosts, ind + 1, m, cost, costs); + dfs(toppingCosts, ind + 1, m, cost + toppingCosts[ind], costs); + dfs(toppingCosts, ind + 1, m, cost + toppingCosts[ind] * 2, costs); +} diff --git a/1775-equal-sum-arrays-with-minimum-number-of-operations.js b/1775-equal-sum-arrays-with-minimum-number-of-operations.js new file mode 100644 index 00000000..4f723a5a --- /dev/null +++ b/1775-equal-sum-arrays-with-minimum-number-of-operations.js @@ -0,0 +1,103 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minOperations = function(nums1, nums2) { + const m = nums1.length, n = nums2.length + if(m > n * 6 || n > m * 6) return -1 + let sum1 = sum(nums1), sum2 = sum(nums2) + if(sum1 > sum2) return minOperations(nums2, nums1) + + const arr = Array(6).fill(0) + nums1.forEach(e => arr[6 - e]++) + nums2.forEach(e => arr[e - 1]++) + + let res = 0, i = 5 + while(sum1 < sum2) { + while(arr[i] === 0) i-- + sum1 += i + res++ + arr[i]-- + } + + return res +}; + +function sum(arr) { + return arr.reduce((ac, e) => ac + e, 0) +} + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minOperations = function(nums1, nums2) { + const m = nums1.length, n = nums2.length + if(m > n * 6 || n > m * 6) return -1 + const sum1 = nums1.reduce((ac, e) => ac + e, 0) + const sum2 = nums2.reduce((ac, e) => ac + e, 0) + let largerArr, smallerArr + if(sum1 === sum2) return 0 + if(sum1 > sum2) { + largerArr = nums1 + smallerArr = nums2 + } else { + largerArr = nums2 + smallerArr = nums1 + } + + const gain = [] + for(let e of largerArr) gain.push(e - 1) + for(let e of smallerArr) gain.push(6 - e) + gain.sort((a, b) => b - a) + let diff = Math.abs(sum2 - sum1) + let cnt = 0 + for(let e of gain) { + diff -= e + cnt++ + if(diff <= 0) return cnt + } + return -1 +}; + + + + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minOperations = function(nums1, nums2) { + const len1 = nums1.length, len2 = nums2.length; + if (len1 > 6 * len2 || len2 > 6 * len1) return -1; + let sum1 = 0, sum2 = 0; + for (let x of nums1) sum1 += x; + for (let x of nums2) sum2 += x; + if (sum1 === sum2) return 0; + nums1.sort((a, b) => a - b) + nums2.sort((a, b) => a - b) + let cnt = 0; + if (sum1 > sum2) { + let ind1 = len1 - 1, ind2 = 0; + while (sum1 > sum2) { + if (ind2 === len2 || nums1[ind1] - 1 > 6 - nums2[ind2]) sum1 -= nums1[ind1--] - 1; + else sum2 += 6 - nums2[ind2++]; + cnt++; + } + return cnt; + } + let ind1 = 0, ind2 = len2 - 1; + while (sum1 < sum2) { + if (ind1 === len1 || nums2[ind2] - 1 > 6 - nums1[ind1]) sum2 -= nums2[ind2--] - 1; + else sum1 += 6 - nums1[ind1++]; + cnt++; + } + return cnt; +}; diff --git a/1776-car-fleet-ii.js b/1776-car-fleet-ii.js new file mode 100644 index 00000000..34d81e53 --- /dev/null +++ b/1776-car-fleet-ii.js @@ -0,0 +1,98 @@ +/** + * @param {number[][]} cars + * @return {number[]} + */ +const getCollisionTimes = function(cars) { + const n = cars.length; + const stack = []; + const res = Array(n) + for(let i = n - 1; i >= 0; i--) { + const [p, s] = cars[i] + res[i] = -1 + while(stack.length) { + const j = stack[stack.length - 1] + const [p2, s2] = cars[j] + if(s2 >= s || res[j] > 0 && (p2 - p) / (s - s2) >= res[j]) stack.pop() + else break + } + if(stack.length) { + const j = stack[stack.length - 1] + const [p2, s2] = cars[j] + res[i] = (p2 - p) / (s - s2) + } + stack.push(i) + } + + return res +}; + +// another + + +/** + * @param {number[][]} cars + * @return {number[]} + */ +var getCollisionTimes = function(cars) { + //这道题必须想清楚一点,那就是如果ans[i]有正值,那么一定是cars[i]和某个cars[j](j>i且speed[j]= 0; i--) { + while(stack.length) { + //如果栈顶比我快,我追不上它,可以考虑等它消失之后我去撞它前面的,所以将它pop + if(cars[stack[stack.length - 1]][1] >= cars[i][1]) stack.pop() + //如果栈顶比我慢,我就决定去碰它了 + else { + //如果它不会消失,那我肯定能碰它,break + if(ans[stack[stack.length - 1]] < 0) break + //如果它会消失,我需要计算一下在它消失之前能否追上它 + const d = ans[stack[stack.length - 1]] * (cars[i][1] - cars[stack[stack.length - 1]][1]) + //能追上,那我肯定碰它,break + if(d > cars[stack[stack.length - 1]][0] - cars[i][0]) break + //追不上,那算了,追它前面的车 + else stack.pop() + } + } + if(stack.length === 0) ans[i] = -1 + else { + //相对距离除以相对速度 + const t = (cars[stack[stack.length - 1]][0]-cars[i][0])/(cars[i][1]-cars[stack[stack.length - 1]][1]) + ans[i] = t + } + stack.push(i) + } + return ans +}; + + +// another + +/** + * @param {number[][]} cars + * @return {number[]} + */ +var getCollisionTimes = function (cars) { + let n = cars.length, + t = 0, + i + const ans = Array(n) + for (let i = 0; i < n; i++) ans[i] = -1 + const s = [] + s[++t] = n - 1 + for (let i = n - 2; ~i; i--) { + while (t && cars[s[t]][1] >= cars[i][1]) t-- + while ( + t > 1 && + (cars[s[t]][0] - cars[i][0]) * (cars[i][1] - cars[s[t - 1]][1]) > + (cars[s[t - 1]][0] - cars[i][0]) * (cars[i][1] - cars[s[t]][1]) + ) + t-- + if (t) ans[i] = (cars[s[t]][0] - cars[i][0]) / (cars[i][1] - cars[s[t]][1]) + s[++t] = i + } + return ans +} diff --git a/1779-find-nearest-point-that-has-the-same-x-or-y-coordinate.js b/1779-find-nearest-point-that-has-the-same-x-or-y-coordinate.js new file mode 100644 index 00000000..9a8c5230 --- /dev/null +++ b/1779-find-nearest-point-that-has-the-same-x-or-y-coordinate.js @@ -0,0 +1,23 @@ +/** + * @param {number} x + * @param {number} y + * @param {number[][]} points + * @return {number} + */ +const nearestValidPoint = function(x, y, points) { + let idx = -1, dis = Infinity + const {min, max, abs} = Math + for(let i = 0; i < points.length; i++) { + const e = points[i] + const [tx, ty] = e + if(tx === x || ty === y) { + const tmp = abs(tx - x) + abs(ty - y) + if(tmp < dis) { + idx = i + dis = tmp + } + } + } + + return idx === -1 ? -1 : idx +}; diff --git a/1780-check-if-number-is-a-sum-of-powers-of-three.js b/1780-check-if-number-is-a-sum-of-powers-of-three.js new file mode 100644 index 00000000..72083886 --- /dev/null +++ b/1780-check-if-number-is-a-sum-of-powers-of-three.js @@ -0,0 +1,11 @@ +/** + * @param {number} n + * @return {boolean} + */ +const checkPowersOfThree = function(n) { + const num = ~~(n / 3) + const rem = n % 3 + if(num === 0 && rem === 1) return true + if(rem === 2) return false + return checkPowersOfThree(num) +}; diff --git a/1781-sum-of-beauty-of-all-substrings.js b/1781-sum-of-beauty-of-all-substrings.js new file mode 100644 index 00000000..6926fff3 --- /dev/null +++ b/1781-sum-of-beauty-of-all-substrings.js @@ -0,0 +1,23 @@ +/** + * @param {string} s + * @return {number} + */ +const beautySum = function(s) { + let ans = 0 + const a = 'a'.charCodeAt(0) + const min = arr => { + let res = Infinity + for(let e of arr) { + if(e !== 0) res = Math.min(e, res) + } + return res + } + for(let i = 0, n = s.length; i < n; i++) { + let freq = Array(26).fill(0) + for(let j = i; j < n; j++) { + freq[s.charCodeAt(j) - a]++ + ans += Math.max(...freq) - min(freq) + } + } + return ans +}; diff --git a/1783-grand-slam-titles.sql b/1783-grand-slam-titles.sql new file mode 100644 index 00000000..5107ee09 --- /dev/null +++ b/1783-grand-slam-titles.sql @@ -0,0 +1,8 @@ +# Write your MySQL query statement below +SELECT player_id,player_name, +SUM(player_id=Wimbledon)+SUM(player_id=Fr_open)+SUM(player_id=US_open)+SUM(player_id=Au_open) +as grand_slams_count +FROM Players +JOIN Championships +ON player_id=Wimbledon or player_id=Fr_open or player_id=US_open or player_id=Au_open +GROUP BY player_id; diff --git a/1784-check-if-binary-string-has-at-most-one-segment-of-ones.js b/1784-check-if-binary-string-has-at-most-one-segment-of-ones.js new file mode 100644 index 00000000..25300c32 --- /dev/null +++ b/1784-check-if-binary-string-has-at-most-one-segment-of-ones.js @@ -0,0 +1,12 @@ +/** + * @param {string} s + * @return {boolean} + */ +const checkOnesSegment = function(s) { + let res = 1 + for(let i = 1, len = s.length; i < len; i++) { + if(s[i] === '1' && s[i - 1] === '0') res++ + if(s[i] === '1' && s[i - 1] === '1') continue + } + return res <= 1 +}; diff --git a/1785-minimum-elements-to-add-to-form-a-given-sum.js b/1785-minimum-elements-to-add-to-form-a-given-sum.js new file mode 100644 index 00000000..ea8518bd --- /dev/null +++ b/1785-minimum-elements-to-add-to-form-a-given-sum.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @param {number} limit + * @param {number} goal + * @return {number} + */ +const minElements = function(nums, limit, goal) { + const sum = nums.reduce((ac, e) => ac + e, 0) + let delta = goal - sum + if(delta === 0) return 0 + const op = delta > 0 ? '+' : '-' + let res = 0 + delta = Math.abs(delta) + return Math.floor(delta / limit) + (delta % limit > 0 ? 1 : 0) +}; diff --git a/1786-number-of-restricted-paths-from-first-to-last-node.js b/1786-number-of-restricted-paths-from-first-to-last-node.js new file mode 100644 index 00000000..511174a9 --- /dev/null +++ b/1786-number-of-restricted-paths-from-first-to-last-node.js @@ -0,0 +1,286 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +const countRestrictedPaths = function(n, edges) { + const g = {} + for (let [u, v, w] of edges) { + g[u] = g[u] || [] + g[u].push([v, w]) + g[v] = g[v] || [] + g[v].push([u, w]) + } + const dist = Array(n + 1).fill(Infinity) + dist[n] = 0 + const pq = new PQ((a, b) => a[0] < b[0]) + pq.push([0, n]) + while(!pq.isEmpty()) { + const [d, u] = pq.pop() + if (d !== dist[u]) continue + for (let [v, w] of (g[u] || [])) { + if (dist[v] > dist[u] + w) { + dist[v] = dist[u] + w + pq.push([dist[v], v]) + } + } + } + const mod = 1e9 + 7 + const memo = Array(n + 1).fill(null) + const dfs = (src) => { + if (memo[src] !== null) return memo[src] + if (src === n) return 1 + let res = 0 + for (let [v, w] of (g[src] || [])) { + if (dist[src] > dist[v]) { + res = (res + dfs(v)) % mod + } + } + return memo[src] = res + } + return dfs(1) +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } + } + +// another + + +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +const countRestrictedPaths = function(n, edges) { + const adj = {} + const MOD = 10 ** 9 + 7 + for(let edge of edges) { + const [u,v,d] = edge + if(adj[u] == null) adj[u] = [] + if(adj[v] == null) adj[v] = [] + adj[u].push([v, d]) + adj[v].push([u, d]) + } + const dist = Array(n + 1).fill(Infinity) + dist[n] = 0 + const pq = new PriorityQueue((a, b) => a[0] < b[0]) + pq.push([0, n]) + while(!pq.isEmpty()) { + const [d, u] = pq.peek() + pq.pop() + if(d > dist[u]) continue + for(let [v, c] of adj[u]) { + if(d + c < dist[v]) { + dist[v] = d + c + pq.push([dist[v], v]) + } + } + } + + const order = Array(n).fill(0) + for(let i = 0; i < n; i++) { + order[i] = i + 1 + } + + order.sort((u, v) => dist[u] - dist[v]) + const ans = Array(n + 1).fill(0) + ans[n] = 1 + for(let u of order) { + for(let [v, c] of adj[u]) { + if(dist[v] > dist[u]) { + ans[v] = (ans[v] + ans[u]) % MOD + } + } + } + + return ans[1] +}; + + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +const countRestrictedPaths = function(n, edges) { + if (n === 1) return 0 + const graph = {} + for(const [u, v, t] of edges) { + if(graph[u] == null) graph[u] = {} + if(graph[v] == null) graph[v] = {} + graph[u][v] = t + graph[v][u] = t + } + const dist = dijkstra(n, graph) + const memo = Array(n + 1).fill(null) + const res = dfs(1) + return res + + function dijkstra(n, graph) { + const dist = Array(n + 1).fill(Infinity) + dist[n] = 0 + const pq = new PriorityQueue((a, b) => a[0] < b[0]) + pq.push([0, n]) + while(!pq.isEmpty()) { + const [d, cur] = pq.pop() + if(d !== dist[cur]) continue + for(const next of Object.keys(graph[cur] || {})) { + const delta = graph[cur][next] + if(dist[next] > d + delta) { + dist[next] = d + delta + pq.push([d + delta, next]) + } + } + } + return dist + } + + function dfs(src) { + if(memo[src] != null) return memo[src] + if(src === n) return 1 + let res = 0 + for(let next of Object.keys(graph[src] || {})) { + next = +next + if(dist[src] > dist[next]) { + res = ((res + dfs(next)) % (1e9 + 7)) + } + } + return memo[src] = res + } +} diff --git a/1787-make-the-xor-of-all-segments-equal-to-zero.js b/1787-make-the-xor-of-all-segments-equal-to-zero.js new file mode 100644 index 00000000..db715bc4 --- /dev/null +++ b/1787-make-the-xor-of-all-segments-equal-to-zero.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const L = 2 ** 10; +const MAX = Number.MAX_SAFE_INTEGER; +const mi = Math.min; +const minChanges = (a, k) => { + let n = a.length; + let dp = Array(L).fill(MAX); + dp[0] = 0; + for (let i = 0; i < k; i++) { + let tmp = Array(L).fill(0); + let tot = 0; + for (let j = i; j < n; j += k) { + tmp[a[j]]++; // frequency count of starting points from each kth continuous subarray + tot++; // total count of starting points from each kth continuous subarray + } + let ndp = Array(L).fill(0); + let min = MAX; + for (let j = 0; j < L; j++) { + min = mi(min, dp[j]); + } + min += tot; + ndp = ndp.map(x => x = min); // updated nested dp array with min value + for (let j = 0; j < L; j++) { + if (tmp[j] != 0) { + for (let m = 0; m < L; m++) { + ndp[m ^ j] = mi(ndp[m ^ j], dp[m] + tot - tmp[j]); + } + } + } + dp = ndp; // reset dp + } + return dp[0]; +}; diff --git a/179-largest-number.js b/179-largest-number.js new file mode 100644 index 00000000..07b1fab7 --- /dev/null +++ b/179-largest-number.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} nums + * @return {string} + */ +const largestNumber = function(nums) { + const arr = nums + .map(v => v.toString()) + .sort((a, b) => (a + b < b + a ? 1 : -1)) + .join(""); + + return arr[0] === "0" ? "0" : arr; +}; diff --git a/1790-check-if-one-string-swap-can-make-strings-equal.js b/1790-check-if-one-string-swap-can-make-strings-equal.js new file mode 100644 index 00000000..1612d9b9 --- /dev/null +++ b/1790-check-if-one-string-swap-can-make-strings-equal.js @@ -0,0 +1,19 @@ +/** + * @param {string} s1 + * @param {string} s2 + * @return {boolean} + */ +const areAlmostEqual = function(s1, s2) { + if (s1 === s2) return true + let arr = [] + for(let i = 0, len = s1.length; i < len; i++) { + if(s1[i] !== s2[i]) arr.push(i) + + if(arr.length > 2) return false + } + + if(arr.length === 1) return false + const [i1, i2] = arr + if(s1[i2] === s2[i1] && s1[i1] === s2[i2]) return true + return false +}; diff --git a/1791-find-center-of-star-graph.js b/1791-find-center-of-star-graph.js new file mode 100644 index 00000000..b57647b9 --- /dev/null +++ b/1791-find-center-of-star-graph.js @@ -0,0 +1,36 @@ +/** + * @param {number[][]} edges + * @return {number} + */ +const findCenter = function(edges) { + return edges[0][0] === edges[1][0] || edges[0][0] === edges[1][1] ? edges[0][0] : edges[0][1] +}; + +// another + +/** + * @param {number[][]} edges + * @return {number} + */ +const findCenter = function(edges) { + const map = {} + for(let e of edges) { + const [u, v] = e + if(map[u] == null) map[u] = [] + if(map[v] == null) map[v] = [] + map[u].push(v) + map[v].push(u) + } + + const keys = Object.keys(map) + let res, max = -Infinity + keys.forEach(e => { + if(map[e].length > max) { + res = e + max = map[e].length + } + }) + + return res + +}; diff --git a/1792-maximum-average-pass-ratio.js b/1792-maximum-average-pass-ratio.js new file mode 100644 index 00000000..58573af6 --- /dev/null +++ b/1792-maximum-average-pass-ratio.js @@ -0,0 +1,211 @@ +/** + * @param {number[][]} classes + * @param {number} extraStudents + * @return {number} + */ +const maxAverageRatio = function (classes, extraStudents) { + const pq = new PriorityQueue((a, b) => a.delta > b.delta) + const n = classes.length + for (let e of classes) { + pq.push({ + pass: e[0], + total: e[1], + ratio: e[0] / e[1], + delta: (e[0] + 1) / (e[1] + 1) - e[0] / e[1], + }) + } + + while (extraStudents) { + const tmp = pq.pop() + tmp.pass++ + tmp.total++ + tmp.ratio = tmp.pass / tmp.total + tmp.delta = (tmp.pass + 1) / (tmp.total + 1) - tmp.ratio + pq.push(tmp) + extraStudents-- + } + + let res = 0 + while (!pq.isEmpty()) { + const tmp = pq.pop() + res += tmp.ratio + } + + return res / n +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + + + +// another + +/** + * @param {number[][]} classes + * @param {number} extraStudents + * @return {number} + */ +const maxAverageRatio = function(classes, extraStudents) { + const pq = new PriorityQueue((a, b) => a.up > b.up); + for (let x of classes) pq.push(new Node(x[0], x[1])); + while (extraStudents--) { + let temp = pq.peek(); + pq.pop(); + temp.pass++, temp.total++; + temp.calUp(); + pq.push(temp); + } + let total = 0.0; + let n = classes.length; + while (!pq.isEmpty()) { + let temp = pq.peek(); + pq.pop(); + total += temp.pass / temp.total; + } + return total / n; +}; + +class Node { + constructor(pass, total) { + this.pass = pass + this.total = total + this.calUp() + } + calUp() { + this.up = (this.pass + 1) / (this.total + 1) - this.pass / this.total + } +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1793-maximum-score-of-a-good-subarray.js b/1793-maximum-score-of-a-good-subarray.js new file mode 100644 index 00000000..980891cc --- /dev/null +++ b/1793-maximum-score-of-a-good-subarray.js @@ -0,0 +1,48 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumScore = function(nums, k) { + const n = nums.length, {min, max} = Math + let mini = nums[k]; + let ans = mini; + let i = k; + let j = k; + + while (i > 0 || j < n - 1) { + if (i === 0 || (j + 1 < n && nums[i - 1] <= nums[j + 1])) { + j++; + mini = min(mini, nums[j]); + } else { + i--; + mini = min(mini, nums[i]); + } + ans = max(ans, mini * (j - i + 1)); + } + + return ans; +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumScore = function(nums, k) { + const n = nums.length, { max, min } = Math + let l = k, r = k, mi = nums[k] + let res = nums[k] + while(l > 0 || r < n - 1) { + if(l === 0) r++ + else if(r === n - 1) l-- + else if(nums[l - 1] < nums[r + 1]) r++ + else l-- + mi = min(mi, nums[l], nums[r]) + res = max(res, mi * (r - l + 1)) + } + + return res +}; diff --git a/1795-rearrange-products-table.sql b/1795-rearrange-products-table.sql new file mode 100644 index 00000000..6a135447 --- /dev/null +++ b/1795-rearrange-products-table.sql @@ -0,0 +1,8 @@ +# Write your MySQL query statement below +SELECT product_id, 'store1' AS store, store1 AS price FROM Products WHERE store1 IS NOT NULL +UNION +SELECT product_id, 'store2' AS store, store2 AS price FROM Products WHERE store2 IS NOT NULL +UNION +SELECT product_id, 'store3' AS store, store3 AS price FROM Products WHERE store3 IS NOT NULL + +ORDER BY 1,2 ASC; diff --git a/1798-maximum-number-of-consecutive-values-you-can-make.js b/1798-maximum-number-of-consecutive-values-you-can-make.js new file mode 100644 index 00000000..2aee0b58 --- /dev/null +++ b/1798-maximum-number-of-consecutive-values-you-can-make.js @@ -0,0 +1,36 @@ +/** + * @param {number[]} coins + * @return {number} + */ +const getMaximumConsecutive = function(coins) { + coins.sort((a, b) => a - b); + let res = 1; + for (let a of coins) { + if (a > res) break; + res += a; + } + return res; +}; + +// another + +/** + * @param {number[]} coins + * @return {number} + */ +const getMaximumConsecutive = function(coins) { + coins.sort((a, b) => a - b) + let sum = 1, res = 1, i = 0 + while(true) { + const e = coins[i] + if(i >= coins.length) break + if(e <= sum) { + sum += e + i++ + } else { + break + } + } + + return sum +}; diff --git a/1799-maximize-score-after-n-operations.js b/1799-maximize-score-after-n-operations.js new file mode 100644 index 00000000..4e4ec0cf --- /dev/null +++ b/1799-maximize-score-after-n-operations.js @@ -0,0 +1,73 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxScore = function (nums) { + const len = nums.length + const n = len / 2 + const allMask = 2 ** 14 - 1 + const memo = Array.from({ length: n + 1 }, () => Array()) + + return helper(1, 0) + + function helper(op, mask) { + if(op > n) return 0 + if(memo[op][mask]) return memo[op][mask] + + let res = 0 + for(let i = 0; i < len; i++) { + const a = nums[i] + for(let j = i + 1; j < len; j++) { + const b = nums[j] + const newMask = (1 << i) + (1 << j) + if((mask & newMask) === 0) { + res = Math.max(res, op * gcd(a, b) + helper(op + 1, mask | newMask)) + } + } + } + // console.log(res) + memo[op][mask] = res + + return memo[op][mask] + } +} + +function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxScore = function (nums) { + const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b)) + const n = nums.length / 2 + const memo = {} + const traverse = (op, mask) => { + if (op > n) { + return 0 + } + const idx = op * 100000 + mask + if (memo[idx] === undefined) { + let res = 0 + for (let i = 0; i < 2 * n - 1; i++) { + if (mask & (1 << i)) continue + for (let j = i + 1; j < 2 * n; j++) { + if (mask & (1 << j)) continue + const newMask = mask | (1 << i) | (1 << j) + res = Math.max( + res, + traverse(op + 1, newMask) + op * gcd(nums[i], nums[j]) + ) + } + } + memo[idx] = res + } + return memo[idx] + } + const res = traverse(1, 0) + return res +} diff --git a/18-4sum.js b/18-4sum.js index a006b9e1..fd34cdf7 100644 --- a/18-4sum.js +++ b/18-4sum.js @@ -1,3 +1,49 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[][]} + */ +const fourSum = function (nums, target) { + nums.sort((a, b) => a - b) + const results = [] + kSum(nums, target, 4, 0, [], results) + return results +} + +function kSum(nums, target, k, i, acc, results) { + if (nums[i] * k > target || nums[nums.length - 1] * k < target) return + if (k > 2) { + for (let j = i; j <= nums.length - k; j++) { + if (j == i || nums[j] > nums[j - 1]) + kSum(nums, target - nums[j], k - 1, j + 1, [...acc, nums[j]], results) + } + } else { + twoSum(nums, target, i, acc, results) + } +} + +function twoSum(nums, target, i, acc, results) { + let lo = i + let hi = nums.length - 1 + while (lo < hi) { + const sum = nums[lo] + nums[hi] + if (sum == target) { + results.push([...acc, nums[lo], nums[hi]]) + while (nums[lo] == nums[lo + 1]) lo++ + while (nums[hi] == nums[hi - 1]) hi-- + lo++ + hi-- + } else if (sum < target) { + lo++ + } else { + hi-- + } + } +} + + +// another + /** * @param {number[]} nums * @param {number} target @@ -42,3 +88,39 @@ function nSum(nums, target, k, start) { } return res; } + + +// another + +/** + * @param {number[]} nums + * @param {number} target + * @return {number[][]} + */ +const fourSum = function(nums, target) { + const res = [], n = nums.length + nums.sort((a, b) => a - b) + for(let a = 0; a < n - 3; a++) { + if(a > 0 && nums[a] === nums[a - 1]) continue + for(let b = a + 1; b < n - 2; b++) { + if(b > a + 1 && nums[b] === nums[a + 1]) continue + if(b > a + 1 && nums[b] === nums[b - 1]) continue + const t = target - nums[a] - nums[b] + let l = b + 1, r = n - 1 + while(l < r) { + const sum = nums[l] + nums[r] + if(sum < t) l++ + else if(sum > t) r-- + else { + res.push([nums[a], nums[b], nums[l], nums[r]]) + l++ + r-- + while(l < r && nums[l] === nums[l - 1]) l++ + while(l < r && nums[r] === nums[r + 1]) r-- + } + } + } + } + + return res +}; diff --git a/1800-maximum-ascending-subarray-sum.js b/1800-maximum-ascending-subarray-sum.js new file mode 100644 index 00000000..b7a91bd4 --- /dev/null +++ b/1800-maximum-ascending-subarray-sum.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxAscendingSum = function(nums) { + let res = -Infinity + + const n = nums.length + let cur = 0 + for(let i = 0; i < n; i++) { + if(i === 0) cur = nums[i] + if(i > 0) { + if(nums[i] > nums[i - 1]) { + cur += nums[i] + res = Math.max(res, cur) + } else { + res = Math.max(res, cur) + cur = nums[i] + } + } + } + res = Math.max(res, cur) + return res +}; diff --git a/1801-number-of-orders-in-the-backlog.js b/1801-number-of-orders-in-the-backlog.js new file mode 100644 index 00000000..8e95f7ce --- /dev/null +++ b/1801-number-of-orders-in-the-backlog.js @@ -0,0 +1,139 @@ +/** + * @param {number[][]} orders + * @return {number} + */ +const getNumberOfBacklogOrders = function(orders) { + const buyPQ = new PQ((a, b) => a[0] > b[0]) + const sellPQ = new PQ((a, b) => a[0] < b[0]) + const mod = 1e9 + 7 + + for(const e of orders) { + const [p, a, o] = e + if(o === 0) { + // buy order + if(sellPQ.isEmpty() || sellPQ.peek()[0] > p) { + buyPQ.push(e) + continue + } + while(!sellPQ.isEmpty() && sellPQ.peek()[0] <= p && e[1]) { + const tmp = sellPQ.peek() + if(e[1] <= tmp[1]) { + tmp[1] -= e[1] + e[1] = 0 + if(tmp[1] === 0) { + sellPQ.pop() + } + } else { + // e[1] > tmp[1] + sellPQ.pop() + e[1] -= tmp[1] + } + } + if(e[1]) { + buyPQ.push(e) + } + } else if(o === 1) { + // sell order + if(buyPQ.isEmpty() || buyPQ.peek()[0] < p) { + sellPQ.push(e) + continue + } + while(!buyPQ.isEmpty() && buyPQ.peek()[0] >= p && e[1]) { + const tmp = buyPQ.peek() + if(e[1] <= tmp[1]) { + tmp[1] -= e[1] + e[1] = 0 + if(tmp[1] === 0) { + buyPQ.pop() + } + } else { + // e[1] > tmp[1] + buyPQ.pop() + e[1] -= tmp[1] + } + } + if(e[1]) { + sellPQ.push(e) + } + } + } + + let res = 0 + + while(!buyPQ.isEmpty()) { + res = (res + buyPQ.pop()[1]) % mod + } + while(!sellPQ.isEmpty()) { + res = (res + sellPQ.pop()[1]) % mod + } + + return res % mod +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1802-maximum-value-at-a-given-index-in-a-bounded-array.js b/1802-maximum-value-at-a-given-index-in-a-bounded-array.js new file mode 100644 index 00000000..64d18833 --- /dev/null +++ b/1802-maximum-value-at-a-given-index-in-a-bounded-array.js @@ -0,0 +1,133 @@ +/** + * @param {number} n + * @param {number} index + * @param {number} maxSum + * @return {number} + */ +const maxValue = function (n, index, maxSum) { + maxSum -= n; + let left = 0, right = maxSum, mid; + while (left < right) { + const mid = right - Math.floor((right - left) / 2); + if (valid(mid))left = mid; + else right = mid - 1; + } + return left + 1; + + function valid(mid) { + let b = Math.max(mid - index, 0); + let res = (mid + b) * (mid - b + 1) / 2; + b = Math.max(mid - ((n - 1) - index), 0); + res += (mid + b) * (mid - b + 1) / 2; + return res - mid <= maxSum; + } +} + +// another + + +/** + * @param {number} n + * @param {number} index + * @param {number} maxSum + * @return {number} + */ +const maxValue = function(n, index, maxSum) { + let res = 1, l = index, r = index + maxSum -= n + + while(l > 0 || r < n - 1) { + const len = r - l + 1 + if(maxSum >= len) { + maxSum -= len + res++ + } else break + if(l > 0) l-- + if(r < n - 1) r++ + } + res += ~~(maxSum / n) + + return res +} + +// another + + +/** + * @param {number} n + * @param {number} index + * @param {number} maxSum + * @return {number} + */ +const maxValue = function(n, index, maxSum) { + maxSum -= n; + let level = 1; + let left = index; + let right = index; + + while (maxSum - (right - left + 1) >= 0) { + if (left === 0 && right === n - 1) break + maxSum -= right - left + 1; + if (left - 1 >= 0) left-- + if (right + 1 <= n - 1) right++; + level++; + } + + if (maxSum) level += ~~(maxSum / n) + + return level; +} + +// another + + +/** + * @param {number} n + * @param {number} index + * @param {number} maxSum + * @return {number} + */ +const maxValue = function(n, index, maxSum) { + const { floor, sqrt } = Math + maxSum -= n + if(index < Math.floor(n / 2)) index = n - 1 - index + let left = index // number of element to the left of the index + let right = n - 1 - index // number of element to the right of the index + // the triangle area for the left side if not hitting the boundary + let leftSum = floor((left * (left + 1)) / 2) + // the triangle area for the right side if not hitting the boundary + let rightSum = floor((right * (right + 1)) / 2) + // case: perfect pyramid + if (maxSum <= (rightSum * 2 + right + 1)) return floor(sqrt(maxSum) + 1) + // case: right side hits the boundary + if (maxSum <= (leftSum + rightSum + (left - right) * right + left + 1)) { + const b = 3 + 2 * right + return floor((-b + sqrt(b * b - 8 * (rightSum + 1 - right * right - maxSum))) / 2) + 1 + 1 + } + // case: both sides hit boundaries + maxSum -= (leftSum + rightSum + (left - right) * right + left + 1) + return left + 1 + 1 + floor(maxSum / n) +}; + +// another + +/** + * @param {number} n + * @param {number} index + * @param {number} maxSum + * @return {number} + */ +const maxValue = function (n, index, maxSum) { + let ret = 0 + const { max } = Math + for (let i = 30; i >= 0; i--) { + const tmp = ret + (1 << i) + const L = max(0, tmp - index) + let sum = ((L + tmp) * (tmp - L + 1)) / 2 + const R = max(0, tmp - (n - 1 - index)) + sum += ((R + tmp) * (tmp - R + 1)) / 2 - tmp + + if (sum <= maxSum - n) ret += 1 << i + } + return ret + 1 +} diff --git a/1803-count-pairs-with-xor-in-a-range.js b/1803-count-pairs-with-xor-in-a-range.js new file mode 100644 index 00000000..03ee2ffe --- /dev/null +++ b/1803-count-pairs-with-xor-in-a-range.js @@ -0,0 +1,94 @@ +/** + * @param {number[]} nums + * @param {number} low + * @param {number} high + * @return {number} + */ +const countPairs = function (nums, low, high) { + const trie = new Trie() + + let ans = 0 + for (let x of nums) { + ans += trie.count(x, high + 1) - trie.count(x, low) + trie.insert(x) + } + return ans +} + +class Trie { + constructor() { + this.root = {} + } + insert(val) { + let node = this.root + for (let i = 14; i >= 0; i--) { + let bit = (val >> i) & 1 + if (!(bit in node)) node[bit] = { cnt: 1 } + else node[bit]['cnt'] += 1 + node = node[bit] + } + } + count(val, high) { + let ans = 0 + let node = this.root + for (let i = 14; i >= 0; i--) { + if (!node) break + const bit = (val >> i) & 1 + const cmp = (high >> i) & 1 + if (cmp) { + if (node[bit]) ans += node[bit]['cnt'] + node = node[1 ^ bit] + } else node = node[bit] + } + + return ans + } +} + + +// another + +/** + * @param {number[]} nums + * @param {number} low + * @param {number} high + * @return {number} + */ +const countPairs = function(nums, low, high) { + let res = 0, n = nums.length, trie = { cnt: 0 } + for(const e of nums) { + res += helper(e, high + 1) - helper(e, low) + insert(e) + } + return res + + function helper(e, limit) { + let res = 0, cur = trie + for(let i = 14; i >= 0; i--) { + const a = (e >> i) & 1 + const b = (limit >> i) & 1 + if(cur == null) break + if(b === 0) { + cur = cur[a] + continue + } + if(cur[a]) { + res += cur[a].cnt + } + cur = cur[1 - a] + } + + return res + } + + function insert(e) { + let cur = trie + for(let i = 14; i >= 0; i--) { + const tmp = (e >> i) & 1 + if(!(tmp in cur)) cur[tmp] = {cnt:0} + cur[tmp].cnt++ + cur = cur[tmp] + } + } + +}; diff --git a/1804-implement-trie-ii-prefix-tree.js b/1804-implement-trie-ii-prefix-tree.js new file mode 100644 index 00000000..2e2ecc84 --- /dev/null +++ b/1804-implement-trie-ii-prefix-tree.js @@ -0,0 +1,75 @@ +class Node { + constructor(val) { + this.val = val + this.cnt = 0 + this.children = {} + this.wordCnt = 0 + } +} + +const Trie = function () { + this.root = new Node(null) +} + +/** + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function (word) { + let cur = this.root + for(const ch of word) { + if(cur.children[ch] == null) cur.children[ch] = new Node(ch) + cur.children[ch].cnt++ + cur = cur.children[ch] + } + cur.wordCnt++ +} + +/** + * @param {string} word + * @return {number} + */ +Trie.prototype.countWordsEqualTo = function (word) { + let cur = this.root + for(const ch of word) { + if(cur.children[ch] == null) return 0 + cur = cur.children[ch] + } + return cur.wordCnt +} + +/** + * @param {string} prefix + * @return {number} + */ +Trie.prototype.countWordsStartingWith = function (prefix) { + let cur = this.root + for(const ch of prefix) { + if(cur.children[ch] == null) return 0 + cur = cur.children[ch] + } + return cur.cnt +} + +/** + * @param {string} word + * @return {void} + */ +Trie.prototype.erase = function (word) { + let cur = this.root + for(const ch of word) { + if(cur.children[ch] == null) break + cur.children[ch].cnt-- + cur = cur.children[ch] + } + cur.wordCnt-- +} + +/** + * Your Trie object will be instantiated and called as such: + * var obj = new Trie() + * obj.insert(word) + * var param_2 = obj.countWordsEqualTo(word) + * var param_3 = obj.countWordsStartingWith(prefix) + * obj.erase(word) + */ diff --git a/1805-number-of-different-integers-in-a-string.js b/1805-number-of-different-integers-in-a-string.js new file mode 100644 index 00000000..ef4477eb --- /dev/null +++ b/1805-number-of-different-integers-in-a-string.js @@ -0,0 +1,19 @@ +/** + * @param {string} word + * @return {number} + */ +const numDifferentIntegers = function(word) { + let cur = '' + const n = word.length + const set = new Set() + for(let i = 0; i < n; i++ ) { + if(word[i] >= '0' && word[i] <= '9') cur += word[i] + else { + if(cur) set.add(+cur) + cur = '' + } + if(i === n - 1 && cur) set.add(+cur) + } + + return set.size +}; diff --git a/1806-minimum-number-of-operations-to-reinitialize-a-permutation.js b/1806-minimum-number-of-operations-to-reinitialize-a-permutation.js new file mode 100644 index 00000000..3176daf4 --- /dev/null +++ b/1806-minimum-number-of-operations-to-reinitialize-a-permutation.js @@ -0,0 +1,68 @@ +/** + * @param {number} n + * @return {number} + */ +const reinitializePermutation = function(n) { + let perm = [] + for(let i = 0; i < n; i++) { + perm[i] = i + } + let clone = perm.slice() + let res = 0 + + while(true) { + res++ + let arr = clone.slice() + for(let i = 0; i < clone.length; i++) { + if(i % 2 === 0) arr[i] = clone[i / 2] + else arr[i] = clone[n / 2 + (i - 1) / 2] + } + + if(chk(perm, arr)) break + clone = arr + } + + + return res + + function chk(a1, a2) { + for(let i = 0, len = a1.length; i < len; i++) { + if(a1[i] !== a2[i]) return false + } + return true + } +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +const reinitializePermutation = function(n) { + let res = 0, i = 1; + while (res === 0 || i > 1) { + i = i * 2 % (n - 1); + res++; + } + return res; +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +const reinitializePermutation = function(n) { + if (n === 2) return 1 + const mod = n - 1 + let curr_power = 2 + let cnt = 1 + // Find multiplicative order modulo n-1 + while (curr_power !== 1) { + curr_power = (2 * curr_power) % mod + cnt++ + } + return cnt +}; diff --git a/1807-evaluate-the-bracket-pairs-of-a-string.js b/1807-evaluate-the-bracket-pairs-of-a-string.js new file mode 100644 index 00000000..8d14fdfc --- /dev/null +++ b/1807-evaluate-the-bracket-pairs-of-a-string.js @@ -0,0 +1,41 @@ +/** + * @param {string} s + * @param {string[][]} knowledge + * @return {string} + */ +const evaluate = function(s, knowledge) { + const map = {} + for(let e of knowledge) { + const [k, v] = e + map[k] = v + } + const n = s.length + let start = -1, end = 0 + let cur = '' + const arr = [] + for(let i = 0; i < n; i++) { + if(s[i] === '(') { + start = i + if(cur) { + arr.push(cur) + cur = '' + } + continue + } + else if(start !== -1 && s[i] !== ')') { + cur += s[i] + } + else if(s[i] === ')') { + if(cur in map) arr.push(map[cur]) + else arr.push('?') + start = -1 + cur = '' + } else { + cur += s[i] + } + if(i === n - 1 && cur) arr.push(cur) + } + + return arr.join('') + +}; diff --git a/1808-maximize-number-of-nice-divisors.js b/1808-maximize-number-of-nice-divisors.js new file mode 100644 index 00000000..a5674ff3 --- /dev/null +++ b/1808-maximize-number-of-nice-divisors.js @@ -0,0 +1,28 @@ +/** + * @param {number} primeFactors + * @return {number} + */ +const MOD = BigInt(1e9 + 7) +const maxNiceDivisors = (pf) => { + if (pf == 1) return 1 + let bpf = BigInt(pf) + let res + if (pf % 3 == 0) { + res = powmod(3n, bpf / 3n, MOD) + } else if (pf % 3 == 1) { + res = (powmod(3n, bpf / 3n - 1n, MOD) * 4n) % MOD + } else { + res = (powmod(3n, bpf / 3n, MOD) * 2n) % MOD + } + return Number(res) +} + +const powmod = (a, b, mod) => { + let r = 1n + while (b > 0n) { + if (b % 2n == 1) r = (r * a) % mod + b >>= 1n + a = (a * a) % mod + } + return r +} diff --git a/181-employees-earning-more-than-their-managers.sql b/181-employees-earning-more-than-their-managers.sql new file mode 100644 index 00000000..3c0407bc --- /dev/null +++ b/181-employees-earning-more-than-their-managers.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +SELECT Name AS Employee FROM Employee AS E, +(SELECT DISTINCT Id, Salary FROM Employee) AS M +WHERE E.ManagerId = M.Id AND E.Salary > M.Salary diff --git a/1815-maximum-number-of-groups-getting-fresh-donuts.js b/1815-maximum-number-of-groups-getting-fresh-donuts.js new file mode 100644 index 00000000..84b25e27 --- /dev/null +++ b/1815-maximum-number-of-groups-getting-fresh-donuts.js @@ -0,0 +1,53 @@ +/** + * @param {number} batchSize + * @param {number[]} groups + * @return {number} + */ +const maxHappyGroups = function (batchSize, groups) { + const arr = new Array(batchSize + 1).fill(0) + let result = 0 + // reduce group to groups of size group%n + for (let gSize of groups) { + arr[gSize % batchSize]++ + } + + // Only need 1 step + result += arr[0] + arr[0] = 0 + + // Only need 2 step + for (let i = 1; i < batchSize / 2; i++) { + let min = Math.min(arr[i], arr[batchSize - i]) + arr[i] -= min + arr[batchSize - i] -= min + result += min + } + result += dfs(arr, 0, new Map()) + return result +} + +function dfs(arr, remain, cache) { + let n = arr.length - 1 + const key = arr.join(',') + if (cache.has(key)) return cache.get(key) + let result = 0 + // greedy and short cut when we can finish the current round + if (remain > 0 && arr[n - remain] > 0) { + arr[n - remain]-- + result = dfs(arr, 0, cache) + arr[n - remain]++ + } else { + for (let i = 1; i < arr.length; i++) { + if (arr[i] > 0) { + arr[i]-- + result = Math.max( + result, + dfs(arr, (remain + i) % n, cache) + (remain == 0 ? 1 : 0) + ) + arr[i]++ + } + } + } + cache.set(key, result) + return result +} diff --git a/1816-truncate-sentence.js b/1816-truncate-sentence.js new file mode 100644 index 00000000..0a73bce1 --- /dev/null +++ b/1816-truncate-sentence.js @@ -0,0 +1,10 @@ +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const truncateSentence = function(s, k) { + const arr = s.split(' ') + const sli = arr.slice(0, k) + return sli.join(' ') +}; diff --git a/1817-finding-the-users-active-minutes.js b/1817-finding-the-users-active-minutes.js new file mode 100644 index 00000000..df7e2e20 --- /dev/null +++ b/1817-finding-the-users-active-minutes.js @@ -0,0 +1,24 @@ +/** + * @param {number[][]} logs + * @param {number} k + * @return {number[]} + */ +const findingUsersActiveMinutes = function(logs, k) { + const hash = {}, map = {} + logs.forEach(l => { + const [id, mi] = l + if(hash[mi] == null) hash[mi] = new Set() + if(map[id] == null) map[id] = new Set() + hash[mi].add(id) + map[id].add(mi) + }) + + const res = Array(k).fill(0) + Object.keys(map).forEach(k => { + const num = map[k].size + res[num - 1]++ + }) + + return res + +}; diff --git a/1818-minimum-absolute-sum-difference.js b/1818-minimum-absolute-sum-difference.js new file mode 100644 index 00000000..c46574c0 --- /dev/null +++ b/1818-minimum-absolute-sum-difference.js @@ -0,0 +1,39 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minAbsoluteSumDiff = function (A, B) { + const mod = 10 ** 9 + 7 + const sA = [...A].sort((a, b) => a - b) + let res = 0 + let gain = 0 + + for (let i = 0; i < A.length; i++) { + const delta = Math.abs(A[i] - B[i]) + res += delta + // if delta <= gain, delta - newDelta is not possbile to be better than gain + if (delta <= gain) continue + // Find closest to B[i] in A + const idx = binaryS(sA, B[i]) + // Double check l, l + 1, l - 1 + const newDelta = Math.min( + Math.abs(sA[idx] - B[i]), + idx >= 1 ? Math.abs(sA[idx - 1] - B[i]) : Infinity, + idx + 1 < A.length ? Math.abs(sA[idx + 1] - B[i]) : Infinity + ) + gain = Math.max(gain, delta - newDelta) + } + return (res - gain) % mod +} +function binaryS(A, b) { + let [l, r] = [0, A.length - 1] + while (l < r) { + const mid = l + ((r - l) >> 1) + const midV = A[mid] + if (midV === b) return mid + if (midV < b) l = mid + 1 + else r = mid - 1 + } + return l +} diff --git a/1819-number-of-different-subsequences-gcds.js b/1819-number-of-different-subsequences-gcds.js new file mode 100644 index 00000000..cc6aa6c6 --- /dev/null +++ b/1819-number-of-different-subsequences-gcds.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const countDifferentSubsequenceGCDs = function(nums) { + const MAX = 2e5 + 1; + const cnt = Array(MAX).fill(0) + for (let x of nums) cnt[x] = true; + let ret = 0; + for (let x=1; x 0) pos++ + else if(e < 0) neg++ + else zero++ + } + if(zero > 0) return 0 + if(neg % 2 === 1) return -1 + else return 1 +}; diff --git a/1823-find-the-winner-of-the-circular-game.js b/1823-find-the-winner-of-the-circular-game.js new file mode 100644 index 00000000..706a3fd1 --- /dev/null +++ b/1823-find-the-winner-of-the-circular-game.js @@ -0,0 +1,16 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const findTheWinner = function(n, k) { + const arr = Array(n).fill(0) + for(let i = 0; i < n; i++) arr[i] = i + 1 + let idx = 0 + while(arr.length > 1) { + idx = (idx + k - 1) % arr.length + arr.splice(idx, 1) + } + return arr.length ? arr[0] : -1 +}; + diff --git a/1824-minimum-sideway-jumps.js b/1824-minimum-sideway-jumps.js new file mode 100644 index 00000000..b96a62e7 --- /dev/null +++ b/1824-minimum-sideway-jumps.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} obstacles + * @return {number} + */ +const minSideJumps = function(obstacles) { + const n = obstacles.length + const { max, min } = Math + const dp = [10000000, 1, 0, 1]; + for (let i of obstacles) { + dp[i] = dp[0]; + for (let j = 1; j <= 3; ++j) + if (i !== j) + dp[j] = min(dp[1] + (j != 1 ? 1 : 0), dp[2] + (j != 2 ? 1 : 0), dp[3] + (j != 3 ? 1 : 0)); + } + return min(dp[1], dp[2], dp[3]); +}; + diff --git a/1825-finding-mk-average.js b/1825-finding-mk-average.js new file mode 100644 index 00000000..8ef45ae2 --- /dev/null +++ b/1825-finding-mk-average.js @@ -0,0 +1,185 @@ +class BIT { + constructor(n) { + this.arr = new Array(n + 1).fill(0) + } + + update(i, v) { + while (i < this.arr.length) { + this.arr[i] += v + i += i & -i + } + } + + prefixSum(i) { + let res = 0 + while (i > 0) { + res += this.arr[i] + i -= i & -i + } + return res + } + + upper_bound(v) { + const n = Math.floor(Math.log2(this.arr.length)) + let pos = 0 + let s = 0 + for (let i = n; i >= 0; i--) { + if ( + pos + (1 << i) < this.arr.length && + s + this.arr[pos + (1 << i)] <= v + ) { + pos += 1 << i + s += this.arr[pos] + } + } + return pos + 1 + } +} + +class MKAverage { + constructor(m, k) { + this.m = m + this.k = k + this.cnt = new BIT(10 ** 5) + this.bit = new BIT(10 ** 5) + this.q = [] + } + + addElement(num) { + this.q.push(num) + this.cnt.update(num, 1) + this.bit.update(num, num) + if (this.q.length > this.m) { + const x = this.q.shift() + this.cnt.update(x, -1) + this.bit.update(x, -x) + } + } + + calculateMKAverage() { + if (this.q.length < this.m) { + return -1 + } + const l = this.k + const r = this.m - this.k + const i = this.cnt.upper_bound(l) + const j = this.cnt.upper_bound(r) + let ans = this.bit.prefixSum(j) - this.bit.prefixSum(i) + ans += (this.cnt.prefixSum(i) - l) * i + ans -= (this.cnt.prefixSum(j) - r) * j + return Math.floor(ans / (this.m - 2 * this.k)) + } +} + +// another + + +/** + * @param {number} m + * @param {number} k + */ +const MKAverage = function (m, k) { + this.sum = 0 + this.dataBuff = [] + this.dataM = [] + this.m = m + this.k = k + this.count = m - k - k +} +/** + * @param {number} num + * @return {void} + */ +MKAverage.prototype.addElement = function (num) { + const total = this.dataBuff.length + this.dataBuff.push(num) + if (total >= this.m) { + let index = binarySearch( + this.dataBuff, + this.dataM, + this.dataBuff[total - this.m] + ) + this.dataM[index] = this.dataBuff.length - 1 + if (index === 0 || num > this.dataBuff[this.dataM[index - 1]]) { + move2End(this.dataBuff, this.dataM, index) + } else if ( + index === this.m - 1 || + num < this.dataBuff[this.dataM[index - 1]] + ) { + move2Start(this.dataBuff, this.dataM, index) + } + + this.sum = 0 + } else { + this.dataM.push(this.dataBuff.length - 1) + move2Start(this.dataBuff, this.dataM, this.dataBuff.length - 1) + } +} + +/** + * @return {number} + */ +MKAverage.prototype.calculateMKAverage = function () { + if (this.dataM.length < this.m) { + return -1 + } else { + if (!this.sum) { + this.sum = calcSum(this.dataBuff, this.dataM, this.k, this.count) + } + return Math.floor(this.sum / this.count) + } +} + +/** + * Your MKAverage object will be instantiated and called as such: + * var obj = new MKAverage(m, k) + * obj.addElement(num) + * var param_2 = obj.calculateMKAverage() + */ +function binarySearch(numArr, indexArr, tar) { + let left = 0 + let right = indexArr.length - 1 + + while (left <= right) { + let mid = (left + right) >>> 1 + + if (numArr[indexArr[mid]] > tar) { + right = mid - 1 + } else if (numArr[indexArr[mid]] < tar) { + left = mid + 1 + } else { + return mid + } + } +} +function move2Start(numArr, indexArr, index) { + let tmp + + while (index > 0 && numArr[indexArr[index]] < numArr[indexArr[index - 1]]) { + tmp = indexArr[index] + indexArr[index] = indexArr[index - 1] + indexArr[index - 1] = tmp + index-- + } +} +function move2End(numArr, indexArr, index) { + let tmp + + while ( + index < indexArr.length - 1 && + numArr[indexArr[index]] > numArr[indexArr[index + 1]] + ) { + tmp = indexArr[index] + indexArr[index] = indexArr[index + 1] + indexArr[index + 1] = tmp + index++ + } +} + +function calcSum(numArr, indexArr, start, count) { + let sum = 0 + for (let i = 0; i < count; i++) { + sum += numArr[indexArr[i + start]] + } + return sum +} diff --git a/1827-minimum-operations-to-make-the-array-increasing.js b/1827-minimum-operations-to-make-the-array-increasing.js new file mode 100644 index 00000000..d5c31859 --- /dev/null +++ b/1827-minimum-operations-to-make-the-array-increasing.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minOperations = function(nums) { + let res = 0 + let pre = nums[0] + for(let i = 1, n = nums.length; i < n; i++) { + const e = nums[i] + if(e <= pre) { + res += pre - e + 1 + pre++ + } else { + pre = e + } + } + return res +}; diff --git a/1828-queries-on-number-of-points-inside-a-circle.js b/1828-queries-on-number-of-points-inside-a-circle.js new file mode 100644 index 00000000..f4a8176d --- /dev/null +++ b/1828-queries-on-number-of-points-inside-a-circle.js @@ -0,0 +1,26 @@ +/** + * @param {number[][]} points + * @param {number[][]} queries + * @return {number[]} + */ +var countPoints = function(points, queries) { + const res = [] + + for(const [x, y, r] of queries) { + const square = r ** 2 + const center = [x, y] + let cnt = 0 + for(const d of points) { + if(disSquare(d, center) <= square) { + cnt++ + } + } + res.push(cnt) + } + + return res + + function disSquare(a, b) { + return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 + } +}; diff --git a/1829-maximum-xor-for-each-query.js b/1829-maximum-xor-for-each-query.js new file mode 100644 index 00000000..18bb6c49 --- /dev/null +++ b/1829-maximum-xor-for-each-query.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @param {number} maximumBit + * @return {number[]} + */ +const getMaximumXor = function(nums, maximumBit) { + const n = nums.length + let xor = nums.reduce((ac, e) => ac ^ e, 0) + let limit = 2 ** maximumBit - 1 + const res = [] + for(let i = n - 1; i >= 0; i--) { + const tmp = limit ^ xor + res.push(tmp) + xor ^= nums[i] + } + + return res +}; diff --git a/1830-minimum-number-of-operations-to-make-string-sorted.js b/1830-minimum-number-of-operations-to-make-string-sorted.js new file mode 100644 index 00000000..702e0c27 --- /dev/null +++ b/1830-minimum-number-of-operations-to-make-string-sorted.js @@ -0,0 +1,103 @@ +/** + * @param {string} s + * @return {number} + */ +const makeStringSorted = function (s) { + const mod = 1e9 + 7, + n = s.length + const a = 'a'.charCodeAt(0) + let res = 0 + const freq = Array(26).fill(0) + for (let c of s) { + freq[c.charCodeAt(0) - a]++ + } + const fact = Array(n + 1).fill(1) + getfact() + let l = n + for (let c of s) { + l-- + let t = 0, + rev = 1 + for (let i = 0; i < 26; i++) { + if (i < c.charCodeAt(0) - a) t += freq[i] + rev = modmul(rev, fact[freq[i]]) + } + res += modmul(modmul(t, fact[l]), binExpo(rev, mod - 2)) + res %= mod + freq[c.charCodeAt(0) - a]-- + } + return res + + function modmul(a, b) { + const big = BigInt + return Number(((big(a) % big(mod)) * (big(b) % big(mod))) % big(mod)) + } + + function binExpo(a, b) { + if (b === 0) return 1 + let res = binExpo(a, Math.floor(b / 2)) + if (b & 1) { + return modmul(a, modmul(res, res)) + } else { + return modmul(res, res) + } + } + + function modmulinv(a) { + return binExpo(a, mod - 2) + } + + function getfact() { + fact[0] = 1 + for (let i = 1; i <= 3000; i++) { + fact[i] = modmul(fact[i - 1], i) + } + } + +} + + +// another + + + +/** + * @param {string} s + * @return {number} + */ +const makeStringSorted = function (s) { + const mod = BigInt(10 ** 9 + 7), + n = s.length + const a = 'a'.charCodeAt(0) + let ans = 0n + const freq = Array(26).fill(0n) + for (let c of s) { + freq[c.charCodeAt(0) - a]++ + } + const fact = Array(n + 1).fill(1n) + for (let i = 1n; i <= n; i++) { + fact[i] = (fact[i - 1n] * i) % mod + } + let l = n + for (let c of s) { + l-- + let t = 0n, + rev = 1n + for (let i = 0; i < 26; i++) { + if (i < c.charCodeAt(0) - a) t += freq[i] + rev = (rev * fact[freq[i]]) % mod + } + ans += ((t * fact[l]) % mod) * modpow(rev, mod - 2n) + ans %= mod + freq[c.charCodeAt(0) - a]-- + } + return Number(ans) + function modpow(b, p) { + let ans = 1n + for (; p; p >>= 1n) { + if (p & 1n) ans = (ans * b) % mod + b = (b * b) % mod + } + return ans + } +} diff --git a/1832-check-if-the-sentence-is-pangram.js b/1832-check-if-the-sentence-is-pangram.js new file mode 100644 index 00000000..d52d6e67 --- /dev/null +++ b/1832-check-if-the-sentence-is-pangram.js @@ -0,0 +1,12 @@ +/** + * @param {string} sentence + * @return {boolean} + */ +const checkIfPangram = function(sentence) { + const hash = new Map() + for(let ch of sentence) { + if(!hash.has(ch)) hash.set(ch, 0) + hash.set(ch, hash.get(ch) + 1) + } + return hash.size >= 26 +}; diff --git a/1833-maximum-ice-cream-bars.js b/1833-maximum-ice-cream-bars.js new file mode 100644 index 00000000..1b6d789b --- /dev/null +++ b/1833-maximum-ice-cream-bars.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} costs + * @param {number} coins + * @return {number} + */ +const maxIceCream = function(costs, coins) { + costs.sort((a, b) => a - b) + let res = 0, idx = 0 + while(coins >= costs[idx]) { + res++ + coins -= costs[idx++] + } + + return res +}; diff --git a/1834-single-threaded-cpu.js b/1834-single-threaded-cpu.js new file mode 100644 index 00000000..192aedec --- /dev/null +++ b/1834-single-threaded-cpu.js @@ -0,0 +1,284 @@ +/** + * @param {number[][]} tasks + * @return {number[]} + */ +const getOrder = function(tasks) { + const pq = new PriorityQueue(compare), n = tasks.length + const res = [] + let time = 0, i = 0 + for(let i = 0; i < n; i++) tasks[i].push(i) + tasks.sort((a, b) => a[0] - b[0]) + + time = tasks[0][0] + while(i < n || !pq.isEmpty()) { + while ((i < n) && (tasks[i][0] <= time)) { + pq.push([tasks[i][1], tasks[i][2]]) + i++ + } + if(!pq.isEmpty()) { + const [dur, idx] = pq.pop() + time += dur + res.push(idx) + } else if(i < n) { + time = tasks[i][0] + } + + } + + return res +}; + +function compare(a, b) { + if(a[0] < b[0]) return true + else if (a[0] > b[0]) return false + else { + return a[1] < b[1] + } +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + + +// another + +/** + * @param {number[][]} tasks + * @return {number[]} + */ +const getOrder = function(tasks) { + const pq = new PriorityQueue(compare), n = tasks.length + const res = [] + let time = 0, i = 0 + for(let i = 0; i < n; i++) tasks[i].push(i) + tasks.sort((a, b) => a[0] - b[0]) + + while(i < n || !pq.isEmpty()) { + if(pq.isEmpty()) { + time = Math.max(time, tasks[i][0]) + } + while(i < n && time >= tasks[i][0]) { + pq.push([tasks[i][1], tasks[i][2]]) + i++ + } + const [dur, idx] = pq.pop() + time += dur + res.push(idx) + } + + return res +}; + +function compare(a, b) { + if(a[0] < b[0]) return true + else if (a[0] > b[0]) return false + else { + return a[1] < b[1] + } +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another +/** + * @param {number[][]} tasks + * @return {number[]} + */ +const getOrder = function(tasks) { + const n = tasks.length + const pq = new PriorityQueue((a, b) => a[0] === b[0] ? a[1] < b[1] : a[0] < b[0]) + tasks.forEach((e, i) => e.push(i)) + tasks.sort((a, b) => a[0] - b[0]) + let idx = 0, time = 0 + const res = [] + + while(idx < n || !pq.isEmpty()) { + while(idx < n && tasks[idx][0] <= time) { + pq.push([tasks[idx][1], task[idx][2]]) + idx++ + } + if(!pq.isEmpty()) { + const tmp = pq.pop() + time += tmp[0] + res.push(tmp[1]) + } else if(idx < n) { + time = tasks[idx][0] + } + } + return res + +}; + +// another + +/** + * @param {number[][]} tasks + * @return {number[]} + */ +const getOrder = function (tasks) { + tasks = tasks.map((e, idx) => [e[0], e[1], idx]) + tasks.sort((a, b) => a[0] - b[0]) + const pq = new PriorityQueue(compare) + const res = [] + let i = 0, + t = 0 + while (i < tasks.length) { + while (i < tasks.length && tasks[i][0] <= t) { + let [ent, pt, ind] = tasks[i] + i += 1 + pq.push([pt, ind]) + } + if (pq.size() == 0) { + if (i < tasks.length) t = tasks[i][0] + continue + } + let [pt, ind] = pq.pop() + res.push(ind) + t += pt + } + while (pq.size()) { + let [pt, index] = pq.pop() + res.push(index) + } + return res +} + +function compare(a, b) { + if (a[0] < b[0]) return true + else if (a[0] > b[0]) return false + else { + return a[1] < b[1] + } +} + diff --git a/1835-find-xor-sum-of-all-pairs-bitwise-and.js b/1835-find-xor-sum-of-all-pairs-bitwise-and.js new file mode 100644 index 00000000..795a8fcf --- /dev/null +++ b/1835-find-xor-sum-of-all-pairs-bitwise-and.js @@ -0,0 +1,71 @@ +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number} + */ +const getXORSum = function(arr1, arr2) { + let a = 0, b = 0 + for(const e of arr1) a ^= e + for(const e of arr2) b ^= e + + return a & b +}; + + +// another + +// On every bit XOR acts as modulo 2 addition and AND acts as modulo 2 multiplication. +// The set {0,1} with modulo 2 addition and multiplication is the field GF(2) and the distributive property holds in every field. + +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number} + */ +const getXORSum = function(arr1, arr2) { + const bits = Array(32).fill(0) + for (let v of arr2) { + let pos = 0; + while (v > 0) { + if (v & 1) { + bits[pos]++; + } + v = v >> 1; + pos++; + } + } + + let res = 0; + + for (let v of arr1) { + let pos = 0; + let tmp = 0; + while (v > 0) { + if (v & 1) { + if (bits[pos] % 2 == 1) { + tmp |= (1 << pos); + } + } + v = v >> 1; + pos++; + } + + res ^= tmp; + } + + return res; +}; + +// another + +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number} + */ +const getXORSum = function(arr1, arr2) { + let x1 = arr1[0], x2 = arr2[0] + for(let i = 1; i < arr1.length; i++) x1 ^= arr1[i] + for(let i = 1; i < arr2.length; i++) x2 ^= arr2[i] + return x1 & x2 +}; diff --git a/1836-remove-duplicates-from-an-unsorted-linked-list.js b/1836-remove-duplicates-from-an-unsorted-linked-list.js new file mode 100644 index 00000000..62bb0226 --- /dev/null +++ b/1836-remove-duplicates-from-an-unsorted-linked-list.js @@ -0,0 +1,44 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const deleteDuplicatesUnsorted = function(head) { + const set = new Set() + const del = new Set() + let cur = head + + while(cur) { + if(set.has(cur.val)) { + del.add(cur.val) + } else { + set.add(cur.val) + + } + cur = cur.next + } + + const dummy = new ListNode() + dummy.next = head + cur = dummy + + while(cur) { + if(cur.next) { + if(del.has(cur.next.val)) { + cur.next = cur.next.next + } else { + cur = cur.next + } + } else { + cur = cur.next + } + } + + return dummy.next +}; diff --git a/1837-sum-of-digits-in-base-k.js b/1837-sum-of-digits-in-base-k.js new file mode 100644 index 00000000..403174c6 --- /dev/null +++ b/1837-sum-of-digits-in-base-k.js @@ -0,0 +1,12 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const sumBase = function(n, k) { + let str = n.toString(k) + let res = 0 + for(let ch of str) res += +ch + + return res +}; diff --git a/1838-frequency-of-the-most-frequent-element.js b/1838-frequency-of-the-most-frequent-element.js new file mode 100644 index 00000000..1be16f31 --- /dev/null +++ b/1838-frequency-of-the-most-frequent-element.js @@ -0,0 +1,68 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxFrequency = function(nums, k) { + nums.sort((a, b) => a - b) + let res = 1 + const n = nums.length + let i = 0, sum = 0 + for(let j = 1; j < n; j++) { + const e = nums[j] + const delta = e - nums[j - 1] + sum += (j - i) * delta + while(sum > k) { + sum -= e - nums[i] + i++ + } + res = Math.max(res, j - i + 1) + } + + + return res +}; + +// another + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxFrequency = function(nums, k) { + let res = 1, i = 0, j = 0, sum = 0 + const n = nums.length + nums.sort((a, b) => a - b) + for(j = 0; j < n; j++) { + sum += nums[j] + while(sum + k < (j - i + 1) * nums[j]) { + sum -= nums[i] + i++ + } + res = Math.max(res, j - i + 1) + } + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxFrequency = function(nums, k) { + nums.sort((a, b) => a - b) + let i = 0, sum = 0, res = 1 + for(let j = 0; j < nums.length; j++) { + sum += nums[j] + while(sum + k < (j - i + 1) * nums[j]) { + sum -= nums[i] + i++ + } + res = Math.max(res, j - i + 1) + } + return res +}; diff --git a/1839-longest-substring-of-all-vowels-in-order.js b/1839-longest-substring-of-all-vowels-in-order.js new file mode 100644 index 00000000..d5d78f94 --- /dev/null +++ b/1839-longest-substring-of-all-vowels-in-order.js @@ -0,0 +1,84 @@ +/** + * @param {string} word + * @return {number} + */ +function longestBeautifulSubstring(word) { + let res = 0, cur = 'a', cnt = 0 + const set = new Set() + for(let ch of word) { + if(ch < cur) { + set.clear() + cnt = 0 + cur = 'a' + if(ch === cur) { + cnt++ + set.add(cur) + } + } else { + cnt++ + set.add(ch) + cur = ch + if(set.size === 5) res = Math.max(res, cnt) + } + } + return res +} + +// another + +/** + * @param {string} word + * @return {number} + */ +function longestBeautifulSubstring(word) { + let res = 0, cur = 'a', cnt = 0 + const set = new Set() + for (let ch of word) { + if (ch >= cur) { + cnt++ + cur = ch + set.add(ch) + } else { + set.clear() + cnt = 0 + cur = 'a' + if(ch === cur) { + set.add(ch) + cnt++ + } + } + if (set.size === 5) { + res = Math.max(res, cnt) + } + } + + return res +} + +// another + +/** + * @param {string} word + * @return {number} + */ +function longestBeautifulSubstring(word) { + let result = 0, + current = 0 + let currentVowel = "a" + const set = new Set() + for (let i = 0; i < word.length; i++) + if (word.charAt(i) < currentVowel) { + set.clear() + if (word.charAt(i) == "a") { + set.add("a") + current = 1 + } else current = 0 + currentVowel = "a" + } else { + current++ + currentVowel = word.charAt(i) + set.add(currentVowel) + if (set.size == 5) result = Math.max(result, current) + } + return result +} diff --git a/1840-maximum-building-height.js b/1840-maximum-building-height.js new file mode 100644 index 00000000..f88b1e2f --- /dev/null +++ b/1840-maximum-building-height.js @@ -0,0 +1,46 @@ +/** + * @param {number} n + * @param {number[][]} restrictions + * @return {number} + */ +var maxBuilding = function (n, restrictions) { + restrictions.sort((a, b) => a[0] - b[0]); + let prevInd = 1, + prevH = 0; + for (let i = 0; i < restrictions.length; i++) { + restrictions[i][1] = Math.min( + restrictions[i][1], + prevH + (restrictions[i][0] - prevInd) + ); + prevInd = restrictions[i][0]; + prevH = restrictions[i][1]; + } + + for (let i = restrictions.length - 2; i >= 0; i--) { + restrictions[i][1] = Math.min( + restrictions[i][1], + restrictions[i + 1][1] + (restrictions[i + 1][0] - restrictions[i][0]) + ); + } + + let ph = 0, + pInd = 1, + highest = 0; + for (let i = 0; i < restrictions.length; i++) { + let ind = restrictions[i][0]; + let h = restrictions[i][1]; + if (ph < h) { + h = Math.min(h, ph + (ind - pInd)); + + let remains = Math.max(0, ind - pInd - (h - ph)); + highest = Math.max(highest, h + ~~(remains / 2)); + } else { + let remains = ind - pInd - (ph - h); + highest = Math.max(highest, ph + ~~(remains / 2)); + } + ph = h; + pInd = ind; + } + highest = Math.max(highest, ph + (n - pInd)); + return highest; +}; diff --git a/1844-replace-all-digits-with-characters.js b/1844-replace-all-digits-with-characters.js new file mode 100644 index 00000000..af554d97 --- /dev/null +++ b/1844-replace-all-digits-with-characters.js @@ -0,0 +1,16 @@ +/** + * @param {string} s + * @return {string} + */ +const replaceDigits = function(s) { + let arr = s.split('') + for(let i = 1; i < s.length; i += 2) { + arr[i] = shift(s[i - 1], +s[i]) + } + + return arr.join('') + + function shift(ch, x) { + return String.fromCharCode(ch.charCodeAt(0) + x) + } +}; diff --git a/1846-maximum-element-after-decreasing-and-rearranging.js b/1846-maximum-element-after-decreasing-and-rearranging.js new file mode 100644 index 00000000..70d6be66 --- /dev/null +++ b/1846-maximum-element-after-decreasing-and-rearranging.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const maximumElementAfterDecrementingAndRearranging = function(arr) { + arr.sort((a, b) => a - b); + arr[0] = 1; + for(let i = 1; i < arr.length; i++) { + if(arr[i] <= arr[i - 1] + 1) continue; + arr[i] = arr[i - 1] + 1; + } + return arr[arr.length - 1]; +}; diff --git a/1847-closest-room.js b/1847-closest-room.js new file mode 100644 index 00000000..f23d4cf2 --- /dev/null +++ b/1847-closest-room.js @@ -0,0 +1,179 @@ +/** + * @param {number[][]} rooms + * @param {number[][]} queries + * @return {number[]} + */ +var closestRoom = function (rooms, queries) { + const n = rooms.length + const k = queries.length + const indexes = new Array(k) + for (let i = 0; i < k; i++) { + indexes[i] = i + } + rooms.sort((a, b) => b[1] - a[1]) // Sort by decreasing order of room size + indexes.sort((a, b) => queries[b][1] - queries[a][1]) // Sort by decreasing order of query minSize + const roomIdsSoFar = new Set() + const ans = new Array(k) + let i = 0 + for (const index of indexes) { + while (i < n && rooms[i][1] >= queries[index][1]) { + // Add id of the room which its size >= query minSize + roomIdsSoFar.add(rooms[i++][0]) + } + ans[index] = searchClosetRoomId(roomIdsSoFar, queries[index][0]) + if (ans[index] == Infinity || ans[index] == -Infinity) ans[index] = -1 + } + return ans + + function searchClosetRoomId(treeSet, preferredId) { + let floor = -Infinity + let ceiling = Infinity + for (const id of treeSet) { + if (id <= preferredId) { + floor = Math.max(floor, id) + } else { + ceiling = Math.min(ceiling, id) + } + } + if (floor === -Infinity) { + return ceiling + } else if (ceiling === Infinity) { + return floor + } else if (preferredId - floor <= ceiling - preferredId) { + return floor + } else { + return ceiling + } + } +} + +// another + +/** + * @param {number[][]} rooms + * @param {number[][]} queries + * @return {number[]} + */ +const closestRoom = function (rooms, queries) { + const n = rooms.length + const m = queries.length + const idxArr = Array.from({ length: m }, (_, i) => i) + const res = [] + rooms.sort((a, b) => b[1] - a[1]) + idxArr.sort((a, b) => queries[b][1] - queries[a][1]) + const set = new Set() + let j = 0 + for (let i = 0; i < m; i++) { + const q = queries[idxArr[i]] + while (j < n && rooms[j][1] >= q[1]) { + set.add(rooms[j][0]) + j++ + } + res[idxArr[i]] = helper(q[0]) + } + + return res + + function helper(preferedId) { + let floor = -Infinity, + ceil = Infinity + for (const roomId of set) { + if (roomId < preferedId && roomId > floor) { + floor = roomId + } + if (roomId >= preferedId && roomId < ceil) { + ceil = roomId + } + } + let res = -1 + if (floor === -Infinity) { + res = ceil + } else if (ceil === Infinity) { + res = floor + } else { + if (preferedId - floor === ceil - preferedId) { + res = floor + } else if (preferedId - floor < ceil - preferedId) { + res = floor + } else { + res = ceil + } + } + + return res === Infinity || res === -Infinity ? -1 : res + } +} + + +// another + +/** + * @param {number[][]} rooms + * @param {number[][]} queries + * @return {number[]} + */ + const closestRoom = function (rooms, queries) { + rooms.sort((a, b) => b[1] - a[1]) + const n = queries.length + const minSize = Array(n).fill(0).map((_, i) => i) + .sort((a, b) => queries[b][1] - queries[a][1]) + + const res = new Array(queries.length).fill(-1) + const bst = new BinarySearchTree() + let currentRoom = 0 + + minSize.forEach((query) => { + const [preferredRoom, minimumSize] = queries[query] + if (rooms[0][1] < minimumSize) return + + while (currentRoom < rooms.length && rooms[currentRoom][1] >= minimumSize) { + bst.add(rooms[currentRoom][0]) + currentRoom++ + } + + res[query] = bst.search(preferredRoom) + }) + + return res +} + +class BinarySearchTree { + constructor() { + this.root = null + } + + add(val) { + this.root = this.insert(this.root, val) + } + + insert(node, val) { + if (!node) return new TreeNode(val) + if (node.val < val) { + node.right = this.insert(node.right, val) + } else { + node.left = this.insert(node.left, val) + } + return node + } + + search(val, node = this.root) { + if (node.val === val) return val + const currentDistance = Math.abs(node.val - val) + const nextChild = node.val < val ? node.right : node.left + if (!nextChild) return node.val + const closestChild = this.search(val, nextChild) + const childDistance = Math.abs(closestChild - val) + if (childDistance < currentDistance) return closestChild + if (childDistance === currentDistance) + return Math.min(closestChild, node.val) + return node.val + } +} + +class TreeNode { + constructor(val) { + this.val = val + this.left = null + this.right = null + } +} diff --git a/1848-minimum-distance-to-the-target-element.js b/1848-minimum-distance-to-the-target-element.js new file mode 100644 index 00000000..440d4340 --- /dev/null +++ b/1848-minimum-distance-to-the-target-element.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @param {number} target + * @param {number} start + * @return {number} + */ +const getMinDistance = function(nums, target, start) { + let min = Infinity, res = -1 + for(let i = 0; i < nums.length; i++) { + if(nums[i] === target) { + if(min > Math.abs(i - start)) { + res = i + min = Math.abs(i - start) + } + } + } + + return min + +}; diff --git a/1849-splitting-a-string-into-descending-consecutive-values.js b/1849-splitting-a-string-into-descending-consecutive-values.js new file mode 100644 index 00000000..48e25d46 --- /dev/null +++ b/1849-splitting-a-string-into-descending-consecutive-values.js @@ -0,0 +1,45 @@ +/** + * @param {string} s + * @return {boolean} + */ +const splitString = function(s) { + return helper(s, null) +}; + +function helper(str, previous) { + for(let i = 0, n = str.length; i < n; i++) { + const tmp = +(str.slice(0, i + 1)) + if(previous == null) { + if(helper(str.slice(i + 1), tmp)) return true + } else if(previous - tmp === 1 && (i === n - 1 || helper(str.slice(i + 1), tmp))) return true + } + + return false +} + + +// another + + +/** + * @param {string} s + * @return {boolean} + */ +const splitString = function(s) { + return dfs(s, 0, [Infinity]) +}; + +function dfs(str, idx, arr) { + if(idx >= str.length && arr.length > 2) return true + for(let i = idx; i < str.length; i++) { + const tmp = str.slice(idx, i + 1) + const num = parseInt(tmp, 10) + const pre = arr[arr.length - 1] + if(num < pre && (pre === Infinity || pre - num === 1)) { + arr.push(num) + if(dfs(str, i + 1, arr)) return true + arr.pop() + } + } + return false +} diff --git a/1850-minimum-adjacent-swaps-to-reach-the-kth-smallest-number.js b/1850-minimum-adjacent-swaps-to-reach-the-kth-smallest-number.js new file mode 100644 index 00000000..4fa860fe --- /dev/null +++ b/1850-minimum-adjacent-swaps-to-reach-the-kth-smallest-number.js @@ -0,0 +1,57 @@ +/** + * @param {string} num + * @param {number} k + * @return {number} + */ + const getMinSwaps = function (num, k) { + const temp = num.split('') + for (let i = 0; i < k; i++) nextPermutation(temp) + return count(num.split(''), temp, temp.length) +} + +function nextPermutation(a) { + let i = a.length - 2 + //Find the first element which isn't in increasing order fom behind + while (i >= 0 && a[i] >= a[i + 1]) i-- + //If we found an element + if (i >= 0) { + // Find the rightmost element such that a[j] > a[i] + const j = bSearch(a, i + 1, a.length - 1, a[i]) + // swap a[i] and a[j] + a[i] = a[i] ^ a[j] ^ (a[j] = a[i]) + } + //reverse array from i + 1 till end + reverse(a, i + 1, a.length - 1) +} + +function bSearch(a, i, j, key) { + while (i <= j) { + const mid = (i + j) >>> 1 + if (key < a[mid]) i = mid + 1 + else j = mid - 1 + } + return i - 1 +} + +function reverse(a, i, j) { + while (i < j) a[i] = a[i] ^ a[j] ^ (a[j--] = a[i++]) +} + +function count(s1, s2, n) { + let i = 0, + j = 0, + res = 0 + + while (i < n) { + j = i + while (s1[j] != s2[i]) j++ + while (i < j) { + const temp = s1[j] + s1[j] = s1[j - 1] + s1[j-- - 1] = temp + ++res + } + ++i + } + return res +} diff --git a/1851-minimum-interval-to-include-each-query.js b/1851-minimum-interval-to-include-each-query.js new file mode 100644 index 00000000..b2a0f7f3 --- /dev/null +++ b/1851-minimum-interval-to-include-each-query.js @@ -0,0 +1,447 @@ +/** + * @param {number[][]} intervals + * @param {number[]} queries + * @return {number[]} + */ +const minInterval = function (intervals, queries) { + const n = intervals.length + const m = queries.length + const sortedQueryIdx = [...Array(m).keys()].sort( + (a, b) => queries[a] - queries[b] + ) + intervals.sort((a, b) => a[0] - b[0]) // sort by start & ascending + const minHeap = new BinaryHeap((c, p) => c.size >= p.size) + const res = Array(m).fill(0) + let i = 0 + for (const idx of sortedQueryIdx) { + const query = queries[idx] + while (i < n && intervals[i][0] <= query) { + minHeap.push({ + size: intervals[i][1] - intervals[i][0] + 1, + start: intervals[i][0], + end: intervals[i][1], + }) + i++ + } + while (!minHeap.isEmpty() && minHeap.peek().end < query) { + minHeap.pop() + } + res[idx] = minHeap.isEmpty() ? -1 : minHeap.peek().size + } + return res +} + +class BinaryHeap { + /** + * @param {compareFunction} compareFn + */ + constructor(compareFn) { + this.content = [] + this.compareFn = compareFn // Min-Heap: (c, p) => c > p + } + + /** + * @return {number} - Current heap size. + */ + size() { + return this.content.length + } + + /** + * @return {boolean} - True if heap size is empty. + */ + isEmpty() { + return this.size() === 0 + } + + /** + * @return {*} - Root node of the heap. + */ + peek() { + return this.size() > 0 ? this.content[0] : null + } + + /** + * @param {*} node - New node to add. + */ + push(node) { + this.content.push(node) + this._bubbleUp(this.content.length - 1) + } + + /** + * @return {*} - Root node of the heap. + */ + pop() { + if (this.content.length === 0) return null + const root = this.content[0] + const last = this.content.pop() + if (this.content.length > 0) { + this.content[0] = last + this._sinkDown(0) + } + return root + } + + /** + * @param {*} node - Node to delete. + */ + remove(node) { + const length = this.content.length + for (let i = 0; i < length; i++) { + if (this.content[i] !== node) continue + const last = this.content.pop() + if (i === length - 1) break + this.content[i] = last + this._bubbleUp(i) + this._sinkDown(i) + break + } + } + + /** + * @param {number} idx - Index of the node to bubble up + */ + _bubbleUp(idx) { + const node = this.content[idx] + while (idx > 0) { + const parentIdx = Math.floor((idx + 1) / 2) - 1 + const parent = this.content[parentIdx] + if (this.compareFn(node, parent)) break + this.content[parentIdx] = node + this.content[idx] = parent + idx = parentIdx + } + } + + /** + * @param {number} idx - Index of the node to sink down + */ + _sinkDown(idx) { + const node = this.content[idx] + while (true) { + const child2Idx = (idx + 1) * 2 + const child1Idx = child2Idx - 1 + let swapIdx = -1 + if (child1Idx < this.content.length) { + const child1 = this.content[child1Idx] + if (!this.compareFn(child1, node)) swapIdx = child1Idx + } + if (child2Idx < this.content.length) { + const child2 = this.content[child2Idx] + const compareNode = swapIdx === -1 ? node : this.content[child1Idx] + if (!this.compareFn(child2, compareNode)) swapIdx = child2Idx + } + if (swapIdx === -1) break + this.content[idx] = this.content[swapIdx] + this.content[swapIdx] = node + idx = swapIdx + } + } +} + + +// another + +/** + * @param {number[][]} intervals + * @param {number[]} queries + * @return {number[]} + */ +const minInterval = function (A, Q) { + const QQ = [] + for (let idx = 0; idx < Q.length; idx++) QQ.push([Q[idx], idx]) + QQ.sort((a, b) => a[0] - b[0]) + A.sort((a, b) => a[0] - b[0]) + let i = 0, + N = A.length + const ans = Array(Q.length).fill(-1) + const m = new TreeMap() + const pq = new PriorityQueue((a, b) => a[0] < b[0]) + for (let [q, index] of QQ) { + for (; i < N && A[i][0] <= q; i++) { + let len = A[i][1] - A[i][0] + 1 + if (m.get(len) == null) m.set(len, 0) + m.set(len, m.get(len) + 1) + pq.push([A[i][1], len]) + } + while (pq.size() > 0 && pq.peek()[0] < q) { + let [right, len] = pq.peek() + m.set(len, m.get(len) - 1) + if (m.get(len) === 0) m.remove(len) + pq.pop() + } + const first = m.getMinKey() + if (m.getLength()) ans[index] = first + } + return ans +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +function TreeMap() { + var root = null + var keyType = void 0 + var length = 0 + + return { + each: each, + set: set, + get: get, + getTree: getTree, + getLength: getLength, + getMaxKey: getMaxKey, + getMinKey: getMinKey, + remove: remove, + } + + function checkKey(key, checkKeyType) { + var localKeyType = typeof key + + if ( + localKeyType !== 'number' && + localKeyType !== 'string' && + localKeyType !== 'boolean' + ) { + throw new Error("'key' must be a number, a string or a boolean") + } + + if (checkKeyType === true && localKeyType !== keyType) { + throw new Error('All keys must be of the same type') + } + + return localKeyType + } + + function call(callback) { + var args = Array.prototype.slice.call(arguments, 1) + + if (typeof callback === 'function') { + callback.apply(void 0, args) + } + } + + function getTree() { + return root + } + + function getLength() { + return length + } + + function each(callback) { + internalEach(root, callback) + } + + function internalEach(node, callback, internalCallback) { + if (node === null) { + return call(internalCallback) + } + + internalEach(node.left, callback, function () { + call(callback, node.value, node.key) + + internalEach(node.right, callback, function () { + call(internalCallback) + }) + }) + } + + function get(key) { + checkKey(key) + + return internalGet(key, root) + } + + function internalGet(key, node) { + if (node === null) { + return void 0 + } + + if (key < node.key) { + return internalGet(key, node.left) + } else if (key > node.key) { + return internalGet(key, node.right) + } else { + return node.value + } + } + + function set(key, value) { + if (root === null) { + keyType = checkKey(key) + } else { + checkKey(key, true) + } + + root = internalSet(key, value, root) + } + + function internalSet(key, value, node) { + if (node === null) { + length++ + + return { + key: key, + value: value, + left: null, + right: null, + } + } + + if (key < node.key) { + node.left = internalSet(key, value, node.left) + } else if (key > node.key) { + node.right = internalSet(key, value, node.right) + } else { + node.value = value + } + + return node + } + + function getMaxKey() { + var maxNode = getMaxNode(root) + + if (maxNode !== null) { + return maxNode.key + } + + return maxNode + } + + function getMinKey() { + var minNode = getMinNode(root) + + if (minNode !== null) { + return minNode.key + } + + return minNode + } + + function getMaxNode(node) { + while (node !== null && node.right !== null) { + node = node.right + } + + return node + } + + function getMinNode(node) { + while (node !== null && node.left !== null) { + node = node.left + } + + return node + } + + function remove(key) { + checkKey(key) + + root = internalRemove(key, root) + } + + function internalRemove(key, node) { + if (node === null) { + return null + } + + if (key < node.key) { + node.left = internalRemove(key, node.left) + } else if (key > node.key) { + node.right = internalRemove(key, node.right) + } else { + if (node.left !== null && node.right !== null) { + var maxNode = getMaxNode(node.left) + + var maxNodeKey = maxNode.key + var maxNodeValue = maxNode.value + + maxNode.key = node.key + maxNode.value = node.value + node.key = maxNodeKey + node.value = maxNodeValue + + node.left = internalRemove(key, node.left) + } else if (node.left !== null) { + length-- + return node.left + } else if (node.right !== null) { + length-- + return node.right + } else { + length-- + return null + } + } + + return node + } +} diff --git a/1854-maximum-population-year.js b/1854-maximum-population-year.js new file mode 100644 index 00000000..c8a1f739 --- /dev/null +++ b/1854-maximum-population-year.js @@ -0,0 +1,89 @@ +/** + * @param {number[][]} logs + * @return {number} + */ +const maximumPopulation = function(logs) { + const n = logs.length + const arr = Array(101).fill(0) + const base = 1950 + for(let log of logs) { + const [start, end] = log + arr[start - base]++ + arr[end - base]-- + } + + let res = 0, tmp = -Infinity + for(let i = 1; i < 101; i++) { + arr[i] += arr[i - 1] + } + for(let i = 0; i < 101; i++) { + if(arr[i] > tmp) { + res = i + tmp = arr[i] + } + } + return res + base +}; + + +// another + +/** + * @param {number[][]} logs + * @return {number} + */ +const maximumPopulation = function(logs) { + logs.sort((a, b) => { + if(a[0] === b[0]) return a[1] - b[1] + return a[0] - b[0] + }) + const arr = Array(101).fill(0) + const bit = new FenwickTree(101) + for(let i = 0, len = logs.length; i < len; i++) { + const [start, end] = logs[i] + const idx = start - 1950 + bit.update(idx + 1, 1) + } + for(let i = 0, len = logs.length; i < len; i++) { + const [start, end] = logs[i] + const idx = end - 1950 + bit.update(idx + 1, -1) + } + let max = 0 + for(let i = 1; i <= 101; i++) { + max = Math.max(max, bit.query(i)) + } + let tmp + for(let i = 1; i <= 101; i++) { + if(bit.query(i) === max) { + tmp = i + break + } + } + + return 1950 + tmp - 1 +}; + +const lowBit = (x) => x & -x +class FenwickTree { + constructor(n) { + if (n < 1) return + this.sum = Array(n + 1).fill(0) + } + update(i, delta) { + if (i < 1) return + while (i < this.sum.length) { + this.sum[i] += delta + i += lowBit(i) + } + } + query(i) { + if (i < 1) return + let sum = 0 + while (i > 0) { + sum += this.sum[i] + i -= lowBit(i) + } + return sum + } +} diff --git a/1855-maximum-distance-between-a-pair-of-values.js b/1855-maximum-distance-between-a-pair-of-values.js new file mode 100644 index 00000000..ff799df6 --- /dev/null +++ b/1855-maximum-distance-between-a-pair-of-values.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const maxDistance = function(nums1, nums2) { + let res = 0 + const m = nums1.length, n = nums2.length + for(let i = 0; i < m; i++) { + const idx = bSearch(nums2, i, n - 1, nums1[i]) + res = Math.max(res, idx - i) + } + return res +}; + +function bSearch(a, i, j, key) { + while (i <= j) { + let mid = (i + j) >>> 1 + if (key <= a[mid]) i = mid + 1 + else if(key > a[mid]) j = mid - 1 + } + return i - 1 +} diff --git a/1856-maximum-subarray-min-product.js b/1856-maximum-subarray-min-product.js new file mode 100644 index 00000000..aef4a778 --- /dev/null +++ b/1856-maximum-subarray-min-product.js @@ -0,0 +1,140 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxSumMinProduct = function(nums) { + const n = nums.length, left = Array(n).fill(0), right = Array(n).fill(n - 1) + const mod = BigInt(1e9 + 7) + let res = 0n + let stk = [] + for(let i = 0; i < n; i++) { + while(stk.length && nums[stk[stk.length - 1]] >= nums[i]) { + stk.pop() + } + left[i] = stk.length ? stk[stk.length - 1] + 1 : 0 + stk.push(i) + } + + stk = [] + for(let i = n - 1; i >= 0; i--) { + while(stk.length && nums[stk[stk.length - 1]] >= nums[i]) { + stk.pop() + } + right[i] = stk.length ? stk[stk.length - 1] - 1 : n - 1 + stk.push(i) + } + + const preSum = [] + for(let i = 0; i < n; i++) { + preSum[i] = (i === 0 ? 0n : preSum[i - 1]) + BigInt(nums[i]) + } + for(let i = 0; i < n; i++) { + res = max(res, fn(nums[i], left[i], right[i])) + } + + return res % mod + + function max(a, b) { + return a > b ? a : b + } + function fn(v, l, r) { + return BigInt(v) * (l === 0 ? preSum[r] : preSum[r] - preSum[l - 1]) + } +}; + +// another + + +/** + * @param {number[]} nums + * @return {number} + */ +const maxSumMinProduct = function (nums) { + const n = nums.length + const mod = BigInt(10 ** 9 + 7) + const preSum = Array(n + 1).fill(0n) + for (let i = 0; i < n; i++) { + preSum[i + 1] = preSum[i] + BigInt(nums[i]) + } + const l = Array(n).fill(0) // l[i] stores index of farthest element greater or equal to nums[i] + const r = Array(n).fill(0) // r[i] stores index of farthest element greater or equal to nums[i] + let st = [] + + for (let i = 0; i < n; i++) { + while (st.length && nums[st[st.length - 1]] >= nums[i]) st.pop() + if (st.length) l[i] = st[st.length - 1] + 1 + else l[i] = 0 + st.push(i) + } + + st = [] + for (let i = n - 1; i >= 0; i--) { + while (st.length && nums[st[st.length - 1]] >= nums[i]) st.pop() + if (st.length) r[i] = st[st.length - 1] - 1 + else r[i] = n - 1 + st.push(i) + } + function getSum(left, right) { + // inclusive + return preSum[right + 1] - preSum[left] + } + + let maxProduct = 0n + for (let i = 0; i < n; i++) { + maxProduct = bigint_max(maxProduct, BigInt(nums[i]) * getSum(l[i], r[i])) + } + return maxProduct % mod +} +function bigint_max(...args){ + if (args.length < 1){ throw 'Max of empty list'; } + m = args[0]; + args.forEach(a=>{if (a > m) {m = a}}); + return m; +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxSumMinProduct = function(nums) { + const n = nums.length, s1 = [], s2 = [], + left = Array(n), right = Array(n), mod = BigInt(1e9 + 7) + for(let i = 0; i < n; i++) { + while(s1.length && nums[s1[s1.length - 1]] >= nums[i]) s1.pop() + if(s1.length) left[i] = s1[s1.length - 1] + 1 + else left[i] = 0 + s1.push(i) + } + + for(let i = n - 1; i >= 0; i--) { + while(s2.length && nums[s2[s2.length - 1]] >= nums[i]) s2.pop() + if(s2.length) right[i] = s2[s2.length - 1] - 1 + else right[i] = n - 1 + s2.push(i) + } + + const preSum = Array(n) + for(let i = 0; i < n; i++) { + preSum[i] = (i === 0 ? 0n : preSum[i - 1]) + BigInt(nums[i]) + } + let res = 0n + for(let i = 0; i < n; i++) { + res = max(res, getSum(preSum, left[i], right[i]) * BigInt(nums[i])) + } + return res % mod + +}; + +function getSum(arr, l, r) { + return arr[r] - (l === 0 ? 0n : arr[l - 1]) +} + +function max(...args) { + let res = -Infinity + for(let e of args) { + if(e > res) res = e + } + return res +} diff --git a/1857-largest-color-value-in-a-directed-graph.js b/1857-largest-color-value-in-a-directed-graph.js new file mode 100644 index 00000000..670144e8 --- /dev/null +++ b/1857-largest-color-value-in-a-directed-graph.js @@ -0,0 +1,202 @@ +/** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ +const largestPathValue = function(colors, edges) { + const n = colors.length; + const m = edges.length; + const adj = Array(n).fill(0).map(() => []); + const inDegree = Array(n).fill(0); + for (const [u, v] of edges) { + adj[u].push(v); + inDegree[v]++; + } + let res = 1 + const colorSet = new Set(colors); + const a = 'a'.charCodeAt(0); + for(const e of colorSet) { + const tmp = helper(e.charCodeAt(0) - a); + if(tmp === -1) return -1; + res = Math.max(res, tmp); + } + + return res + + function code(ch) { + return ch.charCodeAt(0) - 'a'.charCodeAt(0); + } + function helper(k) { + const ind = [...inDegree]; + const count = Array(n).fill(0); + let nodes = 0 + let res = 0 + let q = [] + for(let i = 0; i < n; i++) { + if(ind[i] === 0) { + q.push(i); + nodes++ + count[i] = code(colors[i]) === k ? 1 : 0; + } + } + + while(q.length) { + const size = q.length; + const tmp = [] + for(let i = 0; i < size; i++) { + const e = q[i]; + for(const v of adj[e]) { + count[v] = Math.max(count[v], count[e] + (code(colors[v]) === k ? 1 : 0)); + res = Math.max(res, count[v]); + ind[v]--; + if(ind[v] === 0) { + tmp.push(v); + nodes++ + } + } + } + + q = tmp + } + + return nodes === n ? res : -1 + } +}; + +// another + +/** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ +const largestPathValue = function (colors, edges) { + const graph = {} + const n = colors.length, + a = 'a'.charCodeAt(0) + const indegree = Array(colors.length).fill(0) + for (let e of edges) { + if (graph[e[0]] == null) graph[e[0]] = [] + graph[e[0]].push(e[1]) + indegree[e[1]]++ + } + // cnt[i][j] is the maximum count of j-th color from the ancester nodes to node i. + const cnt = Array.from({ length: n }, () => Array(26).fill(0)) + const q = [] + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + q.push(i) + cnt[i][colors.charCodeAt(i) - a] = 1 + } + } + let res = 0, + seen = 0 + while (q.length) { + const u = q[0] + q.shift() + const val = Math.max(...cnt[u]) + res = Math.max(res, val) + seen++ + for (let v of (graph[u] || [])) { + for (let i = 0; i < 26; i++) { + cnt[v][i] = Math.max( + cnt[v][i], + cnt[u][i] + (i === colors.charCodeAt(v) - a) + ) + } + if (--indegree[v] === 0) q.push(v) + } + } + return seen < colors.length ? -1 : res +} + +// another + +/** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ + const largestPathValue = function(colors, edges) { + const graph = {}, n = colors.length, a = 'a'.charCodeAt(0) + const indegree = Array(n).fill(0) + for (const [from, to] of edges) { + if (graph[from] == null) graph[from] = [] + graph[from].push(to) + indegree[to]++ + } + const cnt = Array.from({ length: n }, () => Array(26).fill(0)) + const code = idx => colors.charCodeAt(idx) - a + const q = [] + for (let i = 0; i < n; i++) { + if(indegree[i] === 0) { + q.push(i) + cnt[i][code(i)] = 1 + } + } + let res = 0, seen = 0 + + while(q.length) { + const u = q.pop() + const val = cnt[u][code(u)] + res = Math.max(res, val) + seen++ + for(const next of (graph[u] || [])) { + for(let i = 0; i < 26; i++) { + cnt[next][i] = Math.max(cnt[next][i], cnt[u][i] + (i === code(next) ? 1 : 0)) + } + if(--indegree[next] === 0) { + q.push(next) + } + } + } + return seen < n ? -1 : res +}; + +// another + + +/** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ +const largestPathValue = function (colors, edges) { + const graph = {} + const n = colors.length, + a = 'a'.charCodeAt(0) + const indegree = Array(colors.length).fill(0) + for (let e of edges) { + if (graph[e[0]] == null) graph[e[0]] = [] + graph[e[0]].push(e[1]) + indegree[e[1]]++ + } + const cnt = Array.from({ length: n }, () => Array(26).fill(0)) + const q = [] + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + q.push(i) + cnt[i][colors.charCodeAt(i) - a] = 1 + } + } + let res = 0, + seen = 0 + while (q.length) { + const u = q[0] + q.shift() + const val = Math.max(...cnt[u]) + res = Math.max(res, val) + seen++ + if (graph[u] == null) continue + for (let v of graph[u]) { + for (let i = 0; i < 26; i++) { + cnt[v][i] = Math.max( + cnt[v][i], + cnt[u][i] + (i === colors.charCodeAt(v) - a) + ) + } + if (--indegree[v] === 0) q.push(v) + } + } + return seen < colors.length ? -1 : res +} diff --git a/1859-sorting-the-sentence.js b/1859-sorting-the-sentence.js new file mode 100644 index 00000000..8da3d884 --- /dev/null +++ b/1859-sorting-the-sentence.js @@ -0,0 +1,13 @@ +/** + * @param {string} s + * @return {string} + */ +const sortSentence = function(s) { + const arr = s.split(' ') + const n = arr.length, res = Array(n) + for(let e of arr) { + const idx = +e[e.length - 1] + res[idx - 1] = e.slice(0, e.length - 1) + } + return res.join(' ') +}; diff --git a/186-reverse-words-in-a-string-ii.js b/186-reverse-words-in-a-string-ii.js new file mode 100644 index 00000000..bc2b78c0 --- /dev/null +++ b/186-reverse-words-in-a-string-ii.js @@ -0,0 +1,22 @@ +/** + * @param {character[]} s + * @return {void} Do not return anything, modify s in-place instead. + */ +const reverseWords = function(s) { + reverse(s, 0, s.length - 1) + for (let i = 0, j = 0; i <= s.length; i++) { + if (i == s.length || s[i] == ' ') { + reverse(s, j, i - 1) + j = i + 1 + } + } +} +function reverse(s, begin, end) { + while (begin < end) { + let c = s[begin] + s[begin] = s[end] + s[end] = c + begin++ + end-- + } +} diff --git a/1860-incremental-memory-leak.js b/1860-incremental-memory-leak.js new file mode 100644 index 00000000..2eaf5bbd --- /dev/null +++ b/1860-incremental-memory-leak.js @@ -0,0 +1,34 @@ +/** + * @param {number} memory1 + * @param {number} memory2 + * @return {number[]} + */ +const memLeak = function(memory1, memory2) { + let i = 1 + const res = Array(3).fill(0) + res[0] = 1 + res[1] = memory1 + res[2] = memory2 + while(true) { + if(res[1] >= i || res[2] >= i) { + if(res[1] >= i && res[2] >= i) { + if(res[1] === res[2]) { + res[1] -= i + } else if(res[1] > res[2]) { + res[1] -= i + } else { + res[2] -= i + } + } else if(res[1] >= i) { + res[1] -= i + } else if(res[2] >= i){ + res[2] -= i + } + } else { + res[0] = i + return res + } + + i++ + } +}; diff --git a/1861-rotating-the-box.js b/1861-rotating-the-box.js new file mode 100644 index 00000000..dcd137ee --- /dev/null +++ b/1861-rotating-the-box.js @@ -0,0 +1,50 @@ +/** + * @param {character[][]} box + * @return {character[][]} + */ +const rotateTheBox = function(box) { + const m = box.length, n = box[0].length + const res = Array.from({ length: n }, () => Array(m).fill('.')) + for(let i = 0; i < m; i++) { + for(let j = n - 1, pos = n - 1; j >= 0; j--) { + if(box[i][j] === '.') continue + if(box[i][j] === '#') { + res[pos][m - 1 - i] = '#' + pos-- + } else { + res[j][m - 1 - i] = '*' + pos = j - 1 + } + } + } + return res +}; + +// another + +/** + * @param {character[][]} box + * @return {character[][]} + */ +const rotateTheBox = function(box) { + const m = box.length, n = box[0].length + const res = Array.from({ length: n }, () => Array(m).fill('.')) + for(let i = 0; i < m; i++) { + let j = n - 1 + let pos = j + while(j >= 0) { + if(box[i][j] === '*') { + pos = j - 1 + } else if(box[i][j] === '#') { + box[i][j] = '.' + box[i][pos] = '#' + res[pos][m - 1 - i] = '#' + pos-- + } + res[j][m - 1 - i] = box[i][j] + j-- + } + + } + return res +}; diff --git a/1862-sum-of-floored-pairs.js b/1862-sum-of-floored-pairs.js new file mode 100644 index 00000000..bd6ac4f7 --- /dev/null +++ b/1862-sum-of-floored-pairs.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const sumOfFlooredPairs = function (nums) { + const MAX = Math.max(...nums) + const countsGreaterOrEqualTo = new Array(MAX + 1).fill(0) + const numCounts = new Map() + const MOD = 1e9 + 7 + nums.forEach((num) => { + countsGreaterOrEqualTo[num]++ + numCounts.set(num, (numCounts.get(num) || 0) + 1) + }) + + for (let num = MAX - 1; num >= 0; num--) { + countsGreaterOrEqualTo[num] += countsGreaterOrEqualTo[num + 1] + } + + let totalCount = 0 + numCounts.forEach((count, num) => { + let current = num + while (current <= MAX) { + totalCount = (totalCount + countsGreaterOrEqualTo[current] * count) % MOD + current += num + } + }) + + return totalCount +} diff --git a/1863-sum-of-all-subset-xor-totals.js b/1863-sum-of-all-subset-xor-totals.js new file mode 100644 index 00000000..1597b8b1 --- /dev/null +++ b/1863-sum-of-all-subset-xor-totals.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const subsetXORSum = function(nums) { + let res = {sum: 0} + + helper(nums, 0, [], res) + return res.sum +}; + +function helper(arr, idx, cur, res) { + if(idx === arr.length) { + res.sum += calc(cur) + return + } + const clone = cur.slice() + helper(arr, idx + 1, clone, res) + const c2 = cur.slice() + c2.push(arr[idx]) + helper(arr, idx + 1, c2, res) +} + +function calc(arr) { + let res = 0 + for(let e of arr) res ^= e + return res +} diff --git a/1864-minimum-number-of-swaps-to-make-the-binary-string-alternating.js b/1864-minimum-number-of-swaps-to-make-the-binary-string-alternating.js new file mode 100644 index 00000000..86d29d67 --- /dev/null +++ b/1864-minimum-number-of-swaps-to-make-the-binary-string-alternating.js @@ -0,0 +1,53 @@ +/** + * @param {string} s + * @return {number} + */ +const minSwaps = function(s) { + const valid = chk(s) + if(valid === -1) return -1 + const [zeroNum, oneNum] = valid + let res = Infinity + if(zeroNum === oneNum) { + // zero start + let tmpZero = 0 + let cur = '0' + for(let i = 0; i < s.length; i++) { + if(i % 2 === 0 && s[i] !== '0') tmpZero++ + } + + res = Math.min(tmpZero, res) + // one start + let tmpOne = 0 + cur = '1' + for(let i = 0; i < s.length; i++) { + if(i % 2 === 0 && s[i] !== '1') tmpOne++ + } + res = Math.min(tmpOne, res) + } else if(zeroNum > oneNum) { + let tmpZero = 0 + let cur = '0' + for(let i = 0; i < s.length; i++) { + if(i % 2 === 0 && s[i] !== '0') tmpZero++ + } + + res = Math.min(tmpZero, res) + } else { + let tmpOne = 0 + cur = '1' + for(let i = 0; i < s.length; i++) { + if(i % 2 === 0 && s[i] !== '1') tmpOne++ + } + res = Math.min(tmpOne, res) + } + return res +}; + +function chk(str) { + let oneNum = 0, zeroNum = 0 + for(let ch of str) { + if(ch === '0') zeroNum++ + else oneNum++ + } + return Math.abs(zeroNum - oneNum) <= 1 ? [zeroNum, oneNum] : -1 +} + diff --git a/1865-finding-pairs-with-a-certain-sum.js b/1865-finding-pairs-with-a-certain-sum.js new file mode 100644 index 00000000..984fd296 --- /dev/null +++ b/1865-finding-pairs-with-a-certain-sum.js @@ -0,0 +1,50 @@ + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + */ +const FindSumPairs = function(nums1, nums2) { + this.nums1 = nums1 + this.nums2 = nums2 + const m = nums1.length, n = nums2.length + this.mp = {} + for(let x of nums2) { + if(this.mp[x] == null) this.mp[x] = 0 + this.mp[x]++ + } +}; + +/** + * @param {number} index + * @param {number} val + * @return {void} + */ +FindSumPairs.prototype.add = function(index, val) { + if(val !== 0) { + if(!(--this.mp[this.nums2[index]])) delete this.mp[this.nums2[index]] + } + this.nums2[index] += val + if(this.mp[this.nums2[index]] == null) this.mp[this.nums2[index]] = 0 + if(val !== 0)this.mp[this.nums2[index]]++ +}; + +/** + * @param {number} tot + * @return {number} + */ +FindSumPairs.prototype.count = function(tot) { + let ans = 0; + for (let x of this.nums1) { + let res = tot - x; + if (!this.mp[res]) continue; + ans += this.mp[res]; + } + return ans; +}; + +/** + * Your FindSumPairs object will be instantiated and called as such: + * var obj = new FindSumPairs(nums1, nums2) + * obj.add(index,val) + * var param_2 = obj.count(tot) + */ diff --git a/1866-number-of-ways-to-rearrange-sticks-with-k-sticks-visible.js b/1866-number-of-ways-to-rearrange-sticks-with-k-sticks-visible.js new file mode 100644 index 00000000..e652838e --- /dev/null +++ b/1866-number-of-ways-to-rearrange-sticks-with-k-sticks-visible.js @@ -0,0 +1,41 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const rearrangeSticks = function(n, k) { + const mod = BigInt(1e9 + 7) + const g = Array.from({ length: 1001 }, () => Array(1001).fill(0n)) + g[1][1] = 1n + for(let i = 2; i <= 1000; i++) { + for(let j = 1; j <= i; j++ ) { + g[i][j] = (g[i - 1][j - 1] + BigInt(i - 1) * g[i - 1][j] % mod) % mod + } + } + return g[n][k] +}; + +// another + +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const rearrangeSticks = function(n, k) { + const MOD = 1e9 + 7; + // first # can be smallest # in which case we recurse for (n - 1, k - 1) + // or it can not be and smallest can be in any of n - 1 otehr positions for recursed(n - 1, k) + const dp = new Array(n + 1).fill().map( _ => new Array(k + 1).fill(0) ); + for (let i = 1; i <= n; ++i) { + for (let j = 1; j <= k; ++j) { + if (j === i) { + dp[i][j] = 1; + } else if (j < i) { + dp[i][j] = (dp[i - 1][j - 1] + (i - 1) * dp[i - 1][j]) % MOD; + } + } + } + return dp[n][k] % MOD; + +}; diff --git a/1867-orders-with-maximum-quantity-above-average.sql b/1867-orders-with-maximum-quantity-above-average.sql new file mode 100644 index 00000000..744035ce --- /dev/null +++ b/1867-orders-with-maximum-quantity-above-average.sql @@ -0,0 +1,10 @@ +# Write your MySQL query statement below +select order_id from OrdersDetails +group by order_id +having max(quantity) > ( + select max(avg_quantity) from + (select order_id, sum(quantity) / count(product_id) as avg_quantity + from OrdersDetails + group by order_id + ) t +); diff --git a/1869-longer-contiguous-segments-of-ones-than-zeros.js b/1869-longer-contiguous-segments-of-ones-than-zeros.js new file mode 100644 index 00000000..8fbceb89 --- /dev/null +++ b/1869-longer-contiguous-segments-of-ones-than-zeros.js @@ -0,0 +1,25 @@ +/** + * @param {string} s + * @return {boolean} + */ +const checkZeroOnes = function(s) { + const stack = [] + let zl = 0, ol = 0 + for(let e of s) { + let tmp = 0, zo = '' + while(stack.length && stack[stack.length - 1] !== e) { + if(zo === '') zo = stack[stack.length - 1] + tmp++ + stack.pop() + } + if(zo === '1') ol = Math.max(tmp, ol) + if(zo === '0') zl = Math.max(tmp, zl) + stack.push(e) + } + if(stack.length) { + let zo = stack[stack.length - 1] + if(zo === '1') ol = Math.max(stack.length, ol) + if(zo === '0') zl = Math.max(stack.length, zl) + } + return ol > zl +}; diff --git a/1870-minimum-speed-to-arrive-on-time.js b/1870-minimum-speed-to-arrive-on-time.js new file mode 100644 index 00000000..9eebca9b --- /dev/null +++ b/1870-minimum-speed-to-arrive-on-time.js @@ -0,0 +1,102 @@ +/** + * @param {number[]} dist + * @param {number} hour + * @return {number} + */ +const minSpeedOnTime = function(dist, hour) { + let n = dist.length, l = 1, r = 1e7 + 1 + while(l < r) { + const mid = l + ((r - l) >> 1) + let time = 0 + for(let i = 0; i < n - 1; i++) time += Math.ceil(dist[i] / mid) + time += dist[dist.length - 1] / mid + if(time > hour) l = mid + 1 + else r = mid + } + return l > 1e7 ? -1 : l +}; + +// another + +/** + * @param {number[]} dist + * @param {number} hour + * @return {number} + */ +const minSpeedOnTime = function(dist, hour) { + let l = 1, r = 1e7 + while(l <= r) { + let mid = (l + r) >> 1 + if(valid(mid)) r = mid -1 + else l = mid + 1 + } + return l > 1e7 ? -1 : l + + function valid(speed) { + let sum = 0 + for(let e of dist) { + sum = Math.ceil(sum) + sum += e / speed + if(sum > hour) return + } + + return true + } +}; + +// another + +/** + * @param {number[]} dist + * @param {number} hour + * @return {number} + */ +const minSpeedOnTime = function(dist, hour) { + const sum = dist.reduce((ac, e) => ac + e, 0) + let l = 1, r = 10 ** 7 + while(l < r) { + let mid = l + ((r - l) >> 1) + if(chk(mid)) r = mid + else l = mid + 1 + } + + return chk(l) ? l : -1 + + function chk(speed) { + let res = 0 + for(let i = 0, len = dist.length; i < len - 1; i++) { + res += Math.ceil(dist[i] / speed) + } + if (dist.length) res += dist[dist.length - 1] / speed + return res <= hour + } + +}; + +// another + +/** + * @param {number[]} dist + * @param {number} hour + * @return {number} + */ +const minSpeedOnTime = function(dist, hour) { + let l = 1, r = 1e7 + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if(!valid(mid)) l = mid + 1 + else r = mid + } + // console.log(l) + return valid(l) ? l : -1 + + function valid(mid) { + let res = 0 + for(let i = 0, n = dist.length; i < n; i++) { + const d = dist[i] + res += (i === n - 1 ? d / mid : Math.ceil(d / mid)) + } + return res <= hour + } +}; + diff --git a/1871-jump-game-vii.js b/1871-jump-game-vii.js new file mode 100644 index 00000000..55fd6fcf --- /dev/null +++ b/1871-jump-game-vii.js @@ -0,0 +1,99 @@ +/** + * @param {string} s + * @param {number} minJump + * @param {number} maxJump + * @return {boolean} + */ +const canReach = function(s, minJump, maxJump) { + const n = s.length + const queue = [0] + let mx = 0 + const { max, min } = Math + while(queue.length) { + const i = queue.shift() + for(let j = max(i + minJump, mx + 1); j < min(s.length, i + maxJump + 1); j++) { + if(s[j] === '0') { + if(j === n - 1) return true + queue.push(j) + } + } + mx = i + maxJump + } + + return false +}; + + +// another + +/** + * @param {string} s + * @param {number} minJump + * @param {number} maxJump + * @return {boolean} + */ +const canReach = function(s, minJump, maxJump) { + let n = s.length; + const {max, min} = Math + if (s[n - 1] != '0') return false; + const pre_sum = Array(n + 1).fill(0); + const check = Array(n + 1).fill(0); + check[1] = 1; + pre_sum[1] = 1; + for (let i = 1; i < n; i++) { + pre_sum[i + 1] = pre_sum[i]; + if (s[i] == '1') continue; + if (i < minJump) continue; + let r = i - minJump; + let l = max(0, i - maxJump); + if (pre_sum[r + 1] - pre_sum[l] == 0) continue; + check[i + 1] = true; + pre_sum[i + 1]++; + } + return check[n]; +}; + +// another + +/** + * @param {string} s + * @param {number} minJump + * @param {number} maxJump + * @return {boolean} + */ +const canReach = function(s, minJump, maxJump) { + const n = s.length, dp = Array(n).fill(0) + dp[0] = 1 + let pre = 0 + for(let i = 1; i < n; i++) { + if(i >= minJump) { + pre += dp[i - minJump] + } + if(i > maxJump) pre -= dp[i - maxJump - 1] + dp[i] = pre > 0 && s[i] === '0' ? 1 : 0 + } + return dp[n - 1] +}; + +// another + +/** + * @param {string} s + * @param {number} minJump + * @param {number} maxJump + * @return {boolean} + */ +const canReach = function(s, minJump, maxJump) { + const n = s.length + const dp = Array(n).fill(0) + dp[0] = 1 + let pre = 0 + for(let i = 1; i < n; i++) { + if(i < minJump) continue + if(i >= minJump) pre += dp[i - minJump] + if(i > maxJump) pre -= dp[i - maxJump - 1] + dp[i] = pre > 0 && s[i] === '0' ? 1 : 0 + } + + return dp[n - 1] ? true : false +}; diff --git a/1872-stone-game-viii.js b/1872-stone-game-viii.js new file mode 100644 index 00000000..e6067265 --- /dev/null +++ b/1872-stone-game-viii.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} stones + * @return {number} + */ +const stoneGameVIII = function (A) { + let N = A.length, + ans = -Infinity + for (let i = 1; i < N; ++i) A[i] += A[i - 1] // now A[i] becomes prefix[i] + let mx = A[N - 1] // dp[N - 1] = prefix[N - 1] + for (let i = N - 2; i >= 0; --i) { + ans = Math.max(ans, mx) // since dp[i] = mx, we try to use dp[i] to update ans. + mx = Math.max(mx, A[i] - mx) // try to update mx using prefix[i] - dp[i] + } + return ans +} diff --git a/1873-calculate-special-bonus.sql b/1873-calculate-special-bonus.sql new file mode 100644 index 00000000..9f6862d0 --- /dev/null +++ b/1873-calculate-special-bonus.sql @@ -0,0 +1,2 @@ +# Write your MySQL query statement below +select employee_id, if(employee_id%2=1 and name not like'M%', salary,0) as bonus from Employees; diff --git a/1874-minimize-product-sum-of-two-arrays.js b/1874-minimize-product-sum-of-two-arrays.js new file mode 100644 index 00000000..556095cb --- /dev/null +++ b/1874-minimize-product-sum-of-two-arrays.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minProductSum = function(nums1, nums2) { + nums1.sort((a, b) => a - b) + nums2.sort((a, b) => b - a) + + const n = nums1.length + let res = 0 + for(let i = 0; i < n; i++) { + res += nums1[i] * nums2[i] + } + + return res +}; diff --git a/1876-substrings-of-size-three-with-distinct-characters.js b/1876-substrings-of-size-three-with-distinct-characters.js new file mode 100644 index 00000000..fb8d6fb0 --- /dev/null +++ b/1876-substrings-of-size-three-with-distinct-characters.js @@ -0,0 +1,18 @@ +/** + * @param {string} s + * @return {number} + */ + const countGoodSubstrings = function(s) { + let res = 0 + for(let i = 2; i < s.length; i++) { + if(chk(s, i)) res++ + } + + return res +}; + +function chk(s, i) { + return s[i - 2] !== s[i - 1] && + s[i - 2] !== s[i] && + s[i - 1] !== s[i] +} diff --git a/1877-minimize-maximum-pair-sum-in-array.js b/1877-minimize-maximum-pair-sum-in-array.js new file mode 100644 index 00000000..1c27a9d4 --- /dev/null +++ b/1877-minimize-maximum-pair-sum-in-array.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minPairSum = function(nums) { + nums.sort((a, b) => a - b) + let res = 0 + for(let i = 0, limit = nums.length / 2; i < limit; i++) { + res = Math.max(res, nums[i] + nums[nums.length - 1 - i]) + } + + return res +}; diff --git a/1878-get-biggest-three-rhombus-sums-in-a-grid.js b/1878-get-biggest-three-rhombus-sums-in-a-grid.js new file mode 100644 index 00000000..357876ca --- /dev/null +++ b/1878-get-biggest-three-rhombus-sums-in-a-grid.js @@ -0,0 +1,29 @@ +/** + * @param {number[][]} grid + * @return {number[]} + */ +const getBiggestThree = function (grid) { + const rows = grid.length + const cols = grid[0].length + const res = [] + for(let i = 0; i < rows; i++) { + for(let j = 0; j < cols; j++) { + for(let size = 0; i - size >= 0 && i + size < rows && j + size * 2 < cols; size++) { + let tmp = 0, r = i, c = j + do {tmp += grid[r++][c++]} while(r < rows && c < cols && r < i + size) + if(size > 0) { + do {tmp += grid[r--][c++]} while(c < cols && c < j + 2 * size) + do {tmp += grid[r--][c--]} while(r > 0 && r > i - size) + do {tmp += grid[r++][c--]} while(c > 0 && r < i) + } + if(res.indexOf(tmp) === -1) res.push(tmp) + if(res.length > 3) { + res.sort((a, b) => b - a) + res.splice(3) + } + } + } + } + res.sort((a, b) => b - a) + return res +} diff --git a/1879-minimum-xor-sum-of-two-arrays.js b/1879-minimum-xor-sum-of-two-arrays.js new file mode 100644 index 00000000..31c752c9 --- /dev/null +++ b/1879-minimum-xor-sum-of-two-arrays.js @@ -0,0 +1,129 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minimumXORSum = function (nums1, nums2) { + const n = nums1.length + const limit = 1 << n + const dp = Array(limit).fill(Infinity) + dp[0] = 0 + for (let mask = 1; mask < limit; ++mask) { + for (let i = 0; i < n; ++i) { + if ((mask >> i) & 1) { + dp[mask] = Math.min( + dp[mask], + dp[mask ^ (1 << i)] + (nums1[bitCnt(mask) - 1] ^ nums2[i]) + ) + } + } + } + return dp[limit - 1] +} + +function bitCnt(num) { + let res = 0 + while (num) { + res++ + num = num & (num - 1) + } + + return res +} + + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minimumXORSum = function (nums1, nums2) { + const n = nums1.length, dp = Array(1 << n).fill(Infinity) + return dfs(0, 0) + function dfs(i, mask) { + if(i === n) return 0 + if(dp[mask] !== Infinity) return dp[mask] + for(let j = 0; j < n; j++) { + if((mask & (1 << j)) === 0) { + dp[mask] = Math.min( + dp[mask], + (nums1[i] ^ nums2[j]) + dfs(i + 1, mask | (1 << j)) + ) + } + } + return dp[mask] + } +} + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minimumXORSum = function(nums1, nums2) { + const dp = Array(1 << nums2.length).fill(Infinity) + return dfs(dp, nums1, nums2, 0, 0) +}; + +function dfs(dp, a, b, i, mask) { + if(i >= a.length) return 0 + if(dp[mask] === Infinity) { + for(let j = 0; j < b.length; j++) { + if((mask & (1 << j)) === 0) { + dp[mask] = Math.min(dp[mask], (a[i] ^ b[j]) + dfs(dp, a, b, i + 1, mask + (1 << j))) + } + } + } + return dp[mask] +} + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minimumXORSum = function (nums1, nums2) { + const dp = Array(1 << nums2.length).fill(Infinity) + return dfs(0, 0) + + function dfs(i, mask) { + if(i >= nums2.length) return 0 + if(dp[mask] != Infinity) return dp[mask] + for(let j = 0; j < nums2.length; j++) { + if((mask & (1 << j)) === 0) { + dp[mask] = Math.min(dp[mask], (nums1[i] ^ nums2[j]) + dfs(i + 1, mask + (1 << j)) ) + } + } + return dp[mask] + } +} + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const minimumXORSum = function (nums1, nums2) { + const n = nums1.length, dp = Array(1 << n).fill(Infinity) + return dfs(0, 0) + + function dfs(i, mask) { + if(i >= n) return 0 + if(dp[mask] !== Infinity) return dp[mask] + for(let j = 0; j < n; j++) { + if((mask & (1 << j)) === 0) { + dp[mask] = Math.min(dp[mask], (nums1[i] ^ nums2[j]) + dfs(i + 1, mask | (1 << j))) + } + } + return dp[mask] + } +} + diff --git a/188-best-time-to-buy-and-sell-stock-iv.js b/188-best-time-to-buy-and-sell-stock-iv.js index 4800dc89..35de229f 100644 --- a/188-best-time-to-buy-and-sell-stock-iv.js +++ b/188-best-time-to-buy-and-sell-stock-iv.js @@ -25,6 +25,36 @@ const maxProfit = function(k, prices) { return sell[k] } +// another + +/** + * @param {number} k + * @param {number[]} prices + * @return {number} + */ +const maxProfit = function(k, prices) { + if(prices.length === 0) return 0 + + if(k > (prices.length/2)) { + let profit = 0 + for(let i = 1; i < prices.length; i++) { + if(prices[i] > prices[i-1]) profit += prices[i] - prices[i-1] + } + return profit + } else { + let dp = new Array(prices.length).fill(0) + let length = prices.length + for(let j = 0; j < k; j++) { + let min = prices[0], max = 0 + for(let i = 0; i < length; i++) { + min = Math.min(min, prices[i] - dp[i]) + max = Math.max(max, prices[i] - min) + dp[i] = max + } + } + return dp.pop() + } +} // another diff --git a/1880-check-if-word-equals-summation-of-two-words.js b/1880-check-if-word-equals-summation-of-two-words.js new file mode 100644 index 00000000..54703af5 --- /dev/null +++ b/1880-check-if-word-equals-summation-of-two-words.js @@ -0,0 +1,44 @@ +/** + * @param {string} firstWord + * @param {string} secondWord + * @param {string} targetWord + * @return {boolean} + */ +const isSumEqual = function(firstWord, secondWord, targetWord) { + let str = 'abcdefghij' + const hash = {}, reverse = {} + for(let i = 0; i < str.length; i++) { + hash[str[i]] = i + reverse[i] = str[i] + } + let len1 = firstWord.length, len2 = secondWord.length + if (len1 < len2) return isSumEqual(secondWord, firstWord, targetWord) + // len1 >= len2 + if (len1 > len2) { + for(let i = len1 - len2; i > 0; i--) { + secondWord = 'a' + secondWord + } + } + let res = '', inc = 0 + for(let i = len1 - 1; i >= 0; i--) { + const tmp = hash[firstWord[i]] + hash[secondWord[i]] + inc + if (tmp > 9) { + inc = 1 + } else { + inc = 0 + } + const cur = tmp % 10 + res = reverse[cur] + res + } + + if(inc) res = 'b' + res + // console.log(res) + let r1 = '', r2 = '' + for(let i = 0; i < targetWord.length; i++) { + r1 = r1 + hash[targetWord[i]] + } + for(let i = 0; i < res.length; i++) { + r2 = r2 + hash[res[i]] + } + return (+r1) === (+r2) +}; diff --git a/1881-maximum-value-after-insertion.js b/1881-maximum-value-after-insertion.js new file mode 100644 index 00000000..fe1983f1 --- /dev/null +++ b/1881-maximum-value-after-insertion.js @@ -0,0 +1,24 @@ +/** + * @param {string} n + * @param {number} x + * @return {string} + */ +const maxValue = function(n, x) { + const neg = n[0] === '-' + if (neg) { + for(let i = 1; i < n.length; i++) { + if(+n[i] > x) { + return n.slice(0, i) + x + n.slice(i) + } + } + return n + x + } else { + for(let i = 0; i < n.length; i++) { + if(+n[i] < x) { + + return n.slice(0, i) + x + n.slice(i) + } + } + return n + x + } +}; diff --git a/1882-process-tasks-using-servers.js b/1882-process-tasks-using-servers.js new file mode 100644 index 00000000..db62a07e --- /dev/null +++ b/1882-process-tasks-using-servers.js @@ -0,0 +1,434 @@ +/** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ +const assignTasks = function(servers, tasks) { + const avail = new PQ((a, b) => a[0] === b[0] ? a[1] < b[1] : a[0] < b[0]) + const busy = new PQ((a, b) => a[2] < b[2]) + const res = [] + const { max } = Math + // init + for(let i = 0, len = servers.length; i < len; i++) { + avail.push([servers[i], i, 0]) + } + + for(let i = 0, len = tasks.length; i < len; i++) { + while(!busy.isEmpty() && busy.peek()[2] <= i) { + const s = busy.pop() + s[2] = i + avail.push(s) + } + if(!avail.isEmpty()) { + const s = avail.pop() + res.push(s[1]) + busy.push([s[0], s[1], max(i, s[2]) + tasks[i]]) + } else { + const tmp = busy.peek() + while(!busy.isEmpty() && busy.peek()[2] === tmp[2]) { + avail.push(busy.pop()) + } + const s = avail.pop() + res.push(s[1]) + busy.push([s[0], s[1], max(i, s[2]) + tasks[i]]) + } + } + + return res +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ +const assignTasks = function (servers, tasks) { + const available = new PriorityQueue((a, b) => + a[0] === b[0] ? a[1] < b[1] : a[0] < b[0] + ) + const occupied = new PriorityQueue((a, b) => + a[0] === b[0] ? (a[1] === b[1] ? a[2] < b[2] : a[1] < b[1]) : a[0] < b[0] + ) + + const res = [], + m = tasks.length, + n = servers.length + for (let i = 0; i < n; i++) { + const w = servers[i] + available.push([w, i]) + } + let now = 0 + for (let i = 0; i < m; i++) { + const t = tasks[i] + + while (!occupied.isEmpty() && occupied.peek()[0] <= now) { + const [end, weight, index] = occupied.pop() + available.push([weight, index]) + } + + let idx + if (!available.isEmpty()) { + const [weight, index] = available.pop() + idx = index + occupied.push([now + t, weight, index]) + if(i >= now) now++ + } else { + let [endTime, weight, index] = occupied.pop() + idx = index + occupied.push([endTime + t, weight, index]) + now = endTime + } + + res.push(idx) + } + + return res +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + + +/** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ +const assignTasks = function(servers, tasks) { + const freePQ = new PriorityQueue((a, b) => a.w === b.w ? a.i < b.i : a.w < b.w) + const runningPQ = new PriorityQueue((a, b) => a.e === b.e ? (a.w === b.w ? a.i < b.i : a.w < b.w) : a.e < b.e) + const m = servers.length, n = tasks.length + for(let i = 0; i < m; i++) freePQ.push({w: servers[i], i, e: 0}) + const res = [] + for(let i = 0; i < n; i++) { + const cur = tasks[i] + while(!runningPQ.isEmpty() && runningPQ.peek().e <= i) { + const tmp = runningPQ.pop() + tmp.e = i + freePQ.push(tmp) + } + if(freePQ.isEmpty()) { + const tmp = runningPQ.pop() + res[i] = tmp.i + tmp.e += cur + runningPQ.push(tmp) + } else { + const tmp = freePQ.pop() + res[i] = tmp.i + tmp.e = i + cur + runningPQ.push(tmp) + } + } + return res +}; + +// another + +/** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ +const assignTasks = function(servers, tasks) { + let i = 0 + const freePQ = new PriorityQueue((a, b) => { + if(a.w < b.w) return true + else if(a.w > b.w) return false + else { + if(a.idx < b.idx) return true + return false + } + }) + const runningPQ = new PriorityQueue((a, b) => { + return a.end < b.end + }) + const res = [] + for(let i = 0; i < servers.length; i++) { + freePQ.push({ + w: servers[i], + idx: i + }) + } + let taskIdx = 0 + while(taskIdx < tasks.length) { + while(!runningPQ.isEmpty() && runningPQ.peek().end <= i) { + let server = runningPQ.pop() + freePQ.push({ + w: server.w, + idx: server.idx + }) + } + + while(taskIdx <= i && !freePQ.isEmpty() && taskIdx < tasks.length) { + const server = freePQ.pop() + res[taskIdx] = server.idx + runningPQ.push({ + end: i + tasks[taskIdx], + w: server.w, + idx: server.idx + }) + taskIdx++ + } + if(i < tasks.length || !freePQ.isEmpty()) i++ + else i = Math.max(i + 1, runningPQ.peek().end) + } + return res +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ +const assignTasks = function(servers, tasks) { + const freePQ = new PriorityQueue((a, b) => { + if(a.w < b.w) return true + else if(a.w > b.w) return false + else { + if(a.idx < b.idx) return true + return false + } + }) + const runningPQ = new PriorityQueue((a, b) => { + return a.end === b.end ? (a.w === b.w ? a.idx < b.idx : a.w < b.w) : a.end < b.end + }) + const res = [] + for(let i = 0; i < servers.length; i++) { + freePQ.push({ + w: servers[i], + idx: i + }) + } + for(let i = 0, n = tasks.length; i < n; i++) { + const cur = tasks[i] + while(runningPQ.size() && runningPQ.peek().end <= i) { + const el = runningPQ.pop() + freePQ.push({ + w: el.w, + idx: el.idx, + }) + } + + if(freePQ.isEmpty()) { + const el = runningPQ.pop() + res[i] = el.idx + el.end += cur + runningPQ.push(el) + } else { + const el = freePQ.pop() + res[i] = el.idx + el.end = i + cur + runningPQ.push(el) + } + } + + return res +}; + diff --git a/1883-minimum-skips-to-arrive-at-meeting-on-time.js b/1883-minimum-skips-to-arrive-at-meeting-on-time.js new file mode 100644 index 00000000..5349fc76 --- /dev/null +++ b/1883-minimum-skips-to-arrive-at-meeting-on-time.js @@ -0,0 +1,41 @@ +/** + * @param {number[]} dist + * @param {number} speed + * @param {number} hoursBefore + * @return {number} + */ +const minSkips = function (dist, speed, hoursBefore) { + let left = 0 + let right = dist.length + + while (left < right) { + let mid = ~~(left + (right - left) / 2) + if (dfs(dist, speed, mid) > 1.0 * hoursBefore) { + left = mid + 1 + } else { + right = mid + } + } + return dfs(dist, speed, left) <= 1.0 * hoursBefore ? left : -1 + function dfs(dist, speed, skips) { + const dp = Array.from({ length: dist.length }, () => + Array(skips + 1).fill(0) + ) + let eps = 1e-9 + for (let i = 0; i <= skips; i++) { + dp[0][i] = (dist[0] * 1.0) / speed - eps + } + + for (let i = 1; i < dist.length; i++) { + dp[i][0] = Math.ceil(dp[i - 1][0]) + (dist[i] * 1.0) / speed - eps + for (let j = 1; j <= skips; j++) { + let time = dp[i - 1][j - 1] + (dist[i] * 1.0) / speed - eps + dp[i][j] = Math.min( + time, + Math.ceil(dp[i - 1][j]) + (dist[i] * 1.0) / speed - eps + ) + } + } + return dp[dist.length - 1][skips] + } +} diff --git a/1884-egg-drop-with-2-eggs-and-n-floors.js b/1884-egg-drop-with-2-eggs-and-n-floors.js new file mode 100644 index 00000000..09c729a1 --- /dev/null +++ b/1884-egg-drop-with-2-eggs-and-n-floors.js @@ -0,0 +1,24 @@ +/** + * @param {number} n + * @return {number} + */ +const twoEggDrop = function (n) { + const dp = Array(n + 1).fill(0) + + helper(n) +// console.log(dp) + return dp[n] + + function helper(k) { + if(k === 0) return 0 + if (dp[k] === 0) { + for (let i = 1; i <= k; i++) { + dp[k] = Math.min( + dp[k] === 0 ? k : dp[k], + 1 + Math.max(i - 1, helper(k - i)) + ) + } + } + return dp[k] + } +} diff --git a/1885-count-pairs-in-two-arrays.js b/1885-count-pairs-in-two-arrays.js new file mode 100644 index 00000000..ecc04f11 --- /dev/null +++ b/1885-count-pairs-in-two-arrays.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const countPairs = function(nums1, nums2) { + const n = nums1.length + const arr = Array(n) + for(let i = 0; i < n; i++) { + arr[i] = nums1[i] - nums2[i] + } + // console.log(arr) + arr.sort((a, b) => a - b) + // console.log(arr) + let res = 0 + for(let i = 0; i < n - 1; i++) { + const e = arr[i] + const target = -e + 1 + let l = i + 1, r = n + while(l < r) { + const mid = ((l + r) >> 1) + if(valid(mid, target)) r = mid + else l = mid + 1 + } + // console.log(l) + res += n - l + } + + return res + + function valid(mid, t) { + return arr[mid] >= t + } +}; diff --git a/1886-determine-whether-matrix-can-be-obtained-by-rotation.js b/1886-determine-whether-matrix-can-be-obtained-by-rotation.js new file mode 100644 index 00000000..785367a5 --- /dev/null +++ b/1886-determine-whether-matrix-can-be-obtained-by-rotation.js @@ -0,0 +1,35 @@ +/** + * @param {number[][]} mat + * @param {number[][]} target + * @return {boolean} + */ +const findRotation = function(mat, target) { + if(chk(mat, target)) return true + for(let i = 0; i < 3; i++) { + rotate(mat) + if(chk(mat, target)) return true + } + return false +}; + +function chk(m1, m2) { + for(let i = 0; i < m1.length; i++) { + for(let j = 0; j < m1.length; j++) { + if(m1[i][j] !== m2[i][j]) return false + } + } + return true +} + +function rotate(matrix) { + matrix.reverse() + for (let i = 0; i < matrix.length; ++i) { + for (let j = matrix[i].length - 1; j > i; j--) swap(matrix, i, j) + } +} + +function swap(matrix, i, j) { + const tmp = matrix[j][i] + matrix[j][i] = matrix[i][j] + matrix[i][j] = tmp +} diff --git a/1887-reduction-operations-to-make-the-array-elements-equal.js b/1887-reduction-operations-to-make-the-array-elements-equal.js new file mode 100644 index 00000000..63db3c46 --- /dev/null +++ b/1887-reduction-operations-to-make-the-array-elements-equal.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const reductionOperations = function(nums) { + nums.sort((a, b) => a - b) + const n = nums.length + const arr = Array(n).fill(0) + for(let i = 1; i < n; i++) { + if(nums[i] > nums[i - 1]) arr[i] = 1 + } + let res = 0, pre = 0 + + for(let i = 1; i < n; i++) { + if(arr[i] === 0) arr[i] = arr[i - 1] + else arr[i] += arr[i - 1] + } + + for(let e of arr) { + res += e + } + return res +}; diff --git a/1888-minimum-number-of-flips-to-make-the-binary-string-alternating.js b/1888-minimum-number-of-flips-to-make-the-binary-string-alternating.js new file mode 100644 index 00000000..0255d212 --- /dev/null +++ b/1888-minimum-number-of-flips-to-make-the-binary-string-alternating.js @@ -0,0 +1,115 @@ +/** + * @param {string} s + * @return {number} + */ +const minFlips = function (s) { + let n = s.length + let t = s + s + let a0 = 0 + let a1 = 0 + let b0 = 0 + let b1 = 0 + let ans = Infinity + for (let i = 0; i < t.length; i++) { + if (t[i] == '0') { + if (i % 2 == 0) { + a0++ + } else { + b0++ + } + } else { + if (i % 2 == 0) { + a1++ + } else { + b1++ + } + } + + if (i >= n) { + if (t[i - n] == '0') { + if ((i - n) % 2 == 0) { + a0-- + } else { + b0-- + } + } else { + if ((i - n) % 2 == 0) { + a1-- + } else { + b1-- + } + } + } + ans = Math.min(ans, Math.min(n - a0 - b1, n - a1 - b0)) + } + + return ans +} + +// another + +/** + * @param {string} s + * @return {number} + */ +const minFlips = function (s) { + const n = s.length + s += s + let s1 = '', s2 = '' + for(let i = 0;i < s.length; i++) { + s1 += i % 2 === 0 ? '0' : '1' + s2 += i % 2 === 0 ? '1' : '0' + } + let res1 = 0, res2 = 0, res = Infinity + for(let i = 0; i < s.length; i++) { + if(s1[i] !== s[i]) res1++ + if(s2[i] !== s[i]) res2++ + if(i >= n) { + if(s1[i - n] !== s[i - n]) res1-- + if(s2[i - n] !== s[i - n]) res2-- + } + if(i >= n - 1) { + res = Math.min(res, res1, res2) + } + } + + return res +} + +// another + +/** + * @param {string} s + * @return {number} + */ +const minFlips = function (s) { + const n = s.length + const ss = s + s + let s1 = '', s2 = '' + for(let i = 0; i < 2 * n; i++) { + if(i % 2 === 0) { + s1 += '0' + s2 += '1' + }else{ + s1 += '1' + s2 += '0' + } + } + + let res = Infinity, res1 = 0, res2 = 0 + + for (let i = 0; i < 2 * n; i++) { + if(ss[i] !== s1[i]) res1++ + if(ss[i] !== s2[i]) res2++ + if(i >= n) { + if(ss[i - n] !== s1[i - n]) res1-- + if(ss[i - n] !== s2[i - n]) res2-- + } + if(i >= n - 1) { + res = Math.min(res, res1, res2) + } + } + + return res +} + diff --git a/1889-minimum-space-wasted-from-packaging.js b/1889-minimum-space-wasted-from-packaging.js new file mode 100644 index 00000000..1e733c58 --- /dev/null +++ b/1889-minimum-space-wasted-from-packaging.js @@ -0,0 +1,103 @@ +/** + * @param {number[]} packages + * @param {number[][]} boxes + * @return {number} + */ +const minWastedSpace = function (packages, boxes) { + const mod = 1e9 + 7 + const n = packages.length + packages.sort((a, b) => a - b) + const preSum = packages.reduce( + (acc, cur) => { + acc.push(acc[acc.length - 1] + cur) + return acc + }, + [0] + ) + + const upperBound = (target) => { + let lo = 0, + hi = n + while (lo < hi) { + const mi = (lo + hi) >> 1 + const val = packages[mi] + if (val <= target) { + lo = mi + 1 + } else { + hi = mi + } + } + return lo + } + + let res = Infinity + for (const bs of boxes) { + bs.sort((a, b) => b - a) + if (bs[0] < packages[n - 1]) continue + let wastes = bs[0] * n - preSum[n] + let last = bs[0] + for (let i = 1; i < bs.length; i++) { + const b = bs[i] + const j = upperBound(b) + if (j <= 0) { + break + } + wastes -= (last - b) * j + last = b + } + res = Math.min(res, wastes) + } + return res === Infinity ? -1 : res % mod +} + +// another + +/** + * @param {number[]} packages + * @param {number[][]} boxes + * @return {number} + */ +var minWastedSpace = function (packages, boxes) { + packages.sort(function (a, b) { + return a - b + }) + let count = 0, + b, + wastage, + minWastage = Number.MAX_SAFE_INTEGER, + flag = false + for (let i = 0; i < boxes.length; i++) { + boxes[i].sort(function (a, b) { + return a - b + }) + b = 0 + wastage = 0 + count = 0 + if (boxes[i][boxes[i].length - 1] < packages[packages.length - 1]) { + //This supplier's largest box is smaller than our larget package, this supplier can't be used + continue + } + while (count < packages.length && b < boxes[i].length) { + if (packages[count] <= boxes[i][b]) { + wastage += boxes[i][b] - packages[count] + if (wastage > minWastage) { + //Need not to porcess this supplier if wastage has already been more than minWastage + break + } + count++ + } else { + b++ + } + } + if (count === packages.length) { + flag = true //We have found atleas 1 answer + if (wastage < minWastage) { + minWastage = wastage + } + } + } + if (flag === false) { + return -1 + } + return minWastage % 1000000007 +} diff --git a/189-rotate-array.js b/189-rotate-array.js new file mode 100644 index 00000000..f6017a19 --- /dev/null +++ b/189-rotate-array.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {void} Do not return anything, modify nums in-place instead. + */ +const rotate = function(nums, k) { + nums.unshift(...nums.splice(nums.length - k)) +}; + +// another + +const rotate = function(nums, k) { + let i = k + while (i > 0) { + nums.unshift(nums.pop()) + i-- + } +}; + +// another + +const rotate = function(nums, k) { + k %= nums.length + reverse(nums, 0, nums.length - 1) + reverse(nums, 0, k - 1) + reverse(nums, k, nums.length - 1) +} + +function reverse(nums, start, end) { + while (start < end) { + var temp = nums[start] + nums[start] = nums[end] + nums[end] = temp + start++ + end-- + } +} diff --git a/1891-cutting-ribbons.js b/1891-cutting-ribbons.js new file mode 100644 index 00000000..23cd8b8c --- /dev/null +++ b/1891-cutting-ribbons.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} ribbons + * @param {number} k + * @return {number} + */ +const maxLength = function(ribbons, k) { + let l = 0, r = Math.max(...ribbons) + while(l < r) { + const mid = r - Math.floor((r - l) / 2) + if(valid(mid)) { + l = mid + } else r = mid - 1 + } + return l + + function valid(mid) { + let res = 0 + for(let e of ribbons) { + res += ~~(e / mid) + } + return res >= k + } +}; diff --git a/1893-check-if-all-the-integers-in-a-range-are-covered.js b/1893-check-if-all-the-integers-in-a-range-are-covered.js new file mode 100644 index 00000000..34d23efe --- /dev/null +++ b/1893-check-if-all-the-integers-in-a-range-are-covered.js @@ -0,0 +1,65 @@ +/** + * @param {number[][]} ranges + * @param {number} left + * @param {number} right + * @return {boolean} + */ +const isCovered = function(ranges, left, right) { + const arr = Array(52).fill(0) + for(let [s, e] of ranges) { + arr[s]++ + arr[e + 1]-- + } + for(let i = 1; i < 52; i++) { + arr[i] += arr[i - 1] + } + for(let i = left; i <= right; i++) { + if(arr[i] === 0) return false + } + + return true +}; + +// another + +/** + * @param {number[][]} ranges + * @param {number} left + * @param {number} right + * @return {boolean} + */ +const isCovered = function(ranges, left, right) { + for(let i = left; i <= right; i++) { + let seen = false; + for(let j = 0; j < ranges.length && !seen; j++) + if(i >= ranges[j][0] && i <= ranges[j][1]) + seen = true; + if(!seen) return false; + } + return true; +}; + +// another + +/** + * @param {number[][]} ranges + * @param {number} left + * @param {number} right + * @return {boolean} + */ +const isCovered = function(ranges, left, right) { + const arr = Array(52).fill(0) + for(let [s, e] of ranges) { + arr[s]++ + arr[e + 1]-- + } + + let overlaps = 0 + for(let i = 1; i <= right; i++) { + overlaps += arr[i]; + if (i >= left && overlaps == 0) return false; + } + + return true +}; + diff --git a/1896-minimum-cost-to-change-the-final-value-of-expression.js b/1896-minimum-cost-to-change-the-final-value-of-expression.js new file mode 100644 index 00000000..a5600719 --- /dev/null +++ b/1896-minimum-cost-to-change-the-final-value-of-expression.js @@ -0,0 +1,89 @@ +/** + * @param {string} expression + * @return {number} + */ +function minOperationsToFlip (s) { + const nums = [] + const ops = [] + for (let i = 0; i < s.length; i++) { + if (s[i] === '0') nums.push([0, 0, 1]) + else if (s[i] === '1') nums.push([1, 1, 0]) + else if (s[i] === '(') ops.push('(') + else if (s[i] === ')') { + while (ops.length && ops[ops.length - 1] !== '(') { + const op = ops.pop() + calc(op) + } + if (ops.length) ops.pop() + } else { + while (ops.length && grade(ops[ops.length - 1]) >= grade(s[i])) { + const op = ops.pop() + calc(op) + } + ops.push(s[i]) + } + } + + while (ops.length && nums.length >= 2) { + const op = ops.pop() + calc(op) + } + const val = nums[0][0] + return nums[0][2 - val] + + function calc (op) { + const [x, y] = [nums.pop(), nums.pop()] + let [z, a0, a1] = [0, 0, 0] + switch (op) { + case '&': + z = x[0] & y[0] + if (x[0] === 0 && y[0] === 0) { + a0 = 0 + a1 = Math.min(x[2] + 1, y[2] + 1) + } + if (x[0] === 0 && y[0] === 1) { + a0 = 0 + a1 = 1 + } + if (x[0] === 1 && y[0] === 0) { + a0 = 0 + a1 = 1 + } + if (x[0] === 1 && y[0] === 1) { + a0 = Math.min(x[1], y[1]) + a1 = 0 + } + break + case '|': + z = x[0] | y[0] + if (x[0] === 0 && y[0] === 0) { + a0 = 0 + a1 = Math.min(x[2], y[2]) + } + if (x[0] === 0 && y[0] === 1) { + a0 = 1 + a1 = 0 + } + if (x[0] === 1 && y[0] === 0) { + a0 = 1 + a1 = 0 + } + if (x[0] === 1 && y[0] === 1) { + a0 = Math.min(x[1] + 1, y[1] + 1) + a1 = 0 + } + break + } + nums.push([z, a0, a1]) + } + function grade (op) { + switch (op) { + case '(': + return 1 + case '&': + case '|': + return 2 + } + return 0 + } +}; diff --git a/1897-redistribute-characters-to-make-all-strings-equal.js b/1897-redistribute-characters-to-make-all-strings-equal.js new file mode 100644 index 00000000..9ca9a384 --- /dev/null +++ b/1897-redistribute-characters-to-make-all-strings-equal.js @@ -0,0 +1,18 @@ +/** + * @param {string[]} words + * @return {boolean} + */ +const makeEqual = function(words) { + const arr = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for(let w of words) { + for(let ch of w) { + arr[ch.charCodeAt(0) - a]++ + } + } + const n = words.length + for(let i = 0; i < 26; i++) { + if(arr[i] % n !== 0) return false + } + return true +}; diff --git a/1898-maximum-number-of-removable-characters.js b/1898-maximum-number-of-removable-characters.js new file mode 100644 index 00000000..043796cc --- /dev/null +++ b/1898-maximum-number-of-removable-characters.js @@ -0,0 +1,65 @@ +/** + * @param {string} s + * @param {string} p + * @param {number[]} removable + * @return {number} + */ +const maximumRemovals = function (s, p, removable) { + const n = removable.length + let l = 0, + r = n + while (l < r) { + let mid = (l + r + 1) >> 1 + if (is_valid(s, p, removable, mid)) l = mid + else r = mid - 1 + } + return l +} + +function is_valid(s, p, removable, cnt) { + let len1 = s.length, + len2 = p.length + const check = Array(len1).fill(0) + for (let i = 0; i < cnt; i++) check[removable[i]] = 1 + let ind1 = 0, + ind2 = 0 + while (ind1 < len1 && ind2 < len2) { + if (s[ind1] != p[ind2] || check[ind1]) { + ind1++ + continue + } + ind1++, ind2++ + } + return ind2 == len2 +} + +// another + +/** + * @param {string} s + * @param {string} p + * @param {number[]} removable + * @return {number} + */ +const maximumRemovals = function(s, p, removable) { + let l = 0, r = removable.length + while(l < r) { + const mid = r - Math.floor((r - l) / 2) + if(valid(mid)) l = mid + else r = mid - 1 + } + return l + + function valid(mid) { + let arr = s.split('') + for (let i = 0; i < mid; i++) arr[removable[i]] = null + arr = arr.filter(e => e !== null) + + for(let i = 0, j = 0; i < arr.length && j < p.length;) { + if(arr[i] === p[j]) i++, j++ + else i++ + if(j === p.length) return true + } + return false + } +}; diff --git a/1899-merge-triplets-to-form-target-triplet.js b/1899-merge-triplets-to-form-target-triplet.js new file mode 100644 index 00000000..3b147614 --- /dev/null +++ b/1899-merge-triplets-to-form-target-triplet.js @@ -0,0 +1,22 @@ +/** + * @param {number[][]} triplets + * @param {number[]} target + * @return {boolean} + */ +const mergeTriplets = function (triplets, target) { + let n = triplets.length + const ans = Array(3).fill(0) + const { max } = Math + for (let i = 0; i < n; i++) { + if ( + triplets[i][0] <= target[0] && + triplets[i][1] <= target[1] && + triplets[i][2] <= target[2] + ) { + ans[0] = max(ans[0], triplets[i][0]) + ans[1] = max(ans[1], triplets[i][1]) + ans[2] = max(ans[2], triplets[i][2]) + } + } + return ans[0] == target[0] && ans[1] == target[1] && ans[2] == target[2] +} diff --git a/190-reverse-bits.js b/190-reverse-bits.js index 13e24388..afa6c0b6 100644 --- a/190-reverse-bits.js +++ b/190-reverse-bits.js @@ -1,3 +1,23 @@ +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +const reverseBits = function(n) { + let r = 0; + for (let i = 0; i < 32; i++) { + if (n & 1) { + r = r | 1; + } + if (i !== 31) { + r = r << 1; + n = n >> 1; + } + } + return r >>> 0; +}; + +// another + /** * @param {number} n - a positive integer * @return {number} - a positive integer @@ -13,3 +33,17 @@ const reverseBits = function(n) { } return count; }; + +// another + +/** + * @param {number} n - a positive integer + * @return {number} - a positive integer + */ +const reverseBits = function(n) { + const b = n.toString(2) + const leadingZeroes = b.padStart(32,'0') + const rev = leadingZeroes.split('') + rev.reverse() + return parseInt(rev.join(''), 2) +}; diff --git a/1900-the-earliest-and-latest-rounds-where-players-compete.js b/1900-the-earliest-and-latest-rounds-where-players-compete.js new file mode 100644 index 00000000..2836f4ee --- /dev/null +++ b/1900-the-earliest-and-latest-rounds-where-players-compete.js @@ -0,0 +1,34 @@ +/** + * @param {number} n + * @param {number} firstPlayer + * @param {number} secondPlayer + * @return {number[]} + */ +const earliestAndLatest = function (n, firstPlayer, secondPlayer) { + const { max, min } = Math + const hash = {} + function dp(l, r, m) { + const key = `${l}${r}${m}` + if (hash[key] != null) return hash[key] + if (l > r) return dp(r, l, m) + if (l === r) return [1, 1] + let nxt_m = (m + 1) >> 1 + let ans = [n, 0] + for (let i = 1; i < l + 1; i++) { + let l_win = i - 1, + l_lose = l - i + for ( + let j = max(r - ~~(m / 2) - 1, 0) + l_lose + 1; + j < min(r - 1 - l_win, nxt_m - i) + 1; + j++ + ) { + let tmp = dp(i, j, nxt_m) + ans = [min(ans[0], tmp[0]), max(ans[1], tmp[1])] + } + } + hash[key] = [ans[0] + 1, ans[1] + 1] + return hash[key] + } + + return dp(firstPlayer, n - secondPlayer + 1, n) +} diff --git a/1901-find-a-peak-element-ii.js b/1901-find-a-peak-element-ii.js new file mode 100644 index 00000000..882df7c7 --- /dev/null +++ b/1901-find-a-peak-element-ii.js @@ -0,0 +1,28 @@ +/** + * @param {number[][]} mat + * @return {number[]} + */ +const findPeakGrid = function(mat) { + let lowCol = 0; + let highCol = mat[0].length - 1; + + while(lowCol <= highCol) { + let midCol = lowCol + ~~((highCol - lowCol) / 2); + let maxRow = 0; + for(let i = 0; i < mat.length; i++) { + maxRow = mat[i][midCol] > mat[maxRow][midCol] ? i : maxRow; + } + + let isLeftElementBig = midCol - 1 >= lowCol && mat[maxRow][midCol - 1] > mat[maxRow][midCol]; + let isRightElementBig = midCol + 1 <= highCol && mat[maxRow][midCol + 1] > mat[maxRow][midCol]; + + if(!isLeftElementBig && !isRightElementBig) { + return [maxRow, midCol]; + } else if(isRightElementBig) { + lowCol = midCol + 1; + } else { + highCol = midCol - 1; + } + } + return null; +}; diff --git a/1903-largest-odd-number-in-string.js b/1903-largest-odd-number-in-string.js new file mode 100644 index 00000000..097f1cb7 --- /dev/null +++ b/1903-largest-odd-number-in-string.js @@ -0,0 +1,11 @@ +/** + * @param {string} num + * @return {string} + */ +const largestOddNumber = function(num) { + let idx= -1 + for(let i = 0, n = num.length; i < n; i++) { + if((+num[i]) % 2 === 1) idx = i + } + return num.slice(0, idx+1) +}; diff --git a/1904-the-number-of-full-rounds-you-have-played.js b/1904-the-number-of-full-rounds-you-have-played.js new file mode 100644 index 00000000..d53993e3 --- /dev/null +++ b/1904-the-number-of-full-rounds-you-have-played.js @@ -0,0 +1,45 @@ +/** + * @param {string} startTime + * @param {string} finishTime + * @return {number} + */ +const numberOfRounds = function(startTime, finishTime) { + let start = 60 * parseInt(startTime.slice(0, 2)) + parseInt(startTime.slice(3)) + let finish = 60 * parseInt(finishTime.slice(0, 2)) + parseInt(finishTime.slice(3)); + if (start > finish) finish += 60 * 24; // If `finishTime` is earlier than `startTime`, add 24 hours to `finishTime`. + return Math.max(0, Math.floor(finish / 15) - Math.ceil(start / 15)); // floor(finish / 15) - ceil(start / 15) +}; + +// another + +/** + * @param {string} startTime + * @param {string} finishTime + * @return {number} + */ +const numberOfRounds = function(startTime, finishTime) { + const { ceil, floor } = Math + const start = new Node(startTime), finish = new Node(finishTime) + if(finish.compare(start)) finish.hour += 24 + let cnt = 0 + if(start.hour === finish.hour) { + const r = floor(finish.minute / 15) + const l = ceil(start.minute / 15) + if(l >= r) return 0 + return r - l + } + cnt += 4 - ceil(start.minute / 15) + floor(finish.minute / 15) + start.hour++ + cnt += (finish.hour - start.hour) * 4 + return cnt +}; + +class Node { + constructor(str) { + this.hour = +str.slice(0, 2) + this.minute = +str.slice(3) + } + compare(node) { + return this.hour === node.hour ? this.minute < node.minute : this.hour < node.hour + } +} diff --git a/1905-count-sub-islands.js b/1905-count-sub-islands.js new file mode 100644 index 00000000..b89e0a5e --- /dev/null +++ b/1905-count-sub-islands.js @@ -0,0 +1,25 @@ +/** + * @param {number[][]} grid1 + * @param {number[][]} grid2 + * @return {number} + */ +const countSubIslands = function(grid1, grid2) { + let m = grid2.length, n = grid2[0].length, res = 0; + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (grid2[i][j] === 1) res += dfs(grid1, grid2, i, j); + } + } + return res; +}; + +function dfs(B, A, i, j) { + let m = A.length, n = A[0].length, res = 1; + if (i < 0 || i == m || j < 0 || j == n || A[i][j] == 0) return 1; + A[i][j] = 0; + res &= dfs(B, A, i - 1, j); + res &= dfs(B, A, i + 1, j); + res &= dfs(B, A, i, j - 1); + res &= dfs(B, A, i, j + 1); + return res & B[i][j]; +} diff --git a/1906-minimum-absolute-difference-queries.js b/1906-minimum-absolute-difference-queries.js new file mode 100644 index 00000000..0b153a62 --- /dev/null +++ b/1906-minimum-absolute-difference-queries.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +const minDifference = function (nums, queries) { + const res = [], + cnt = Array.from({ length: nums.length + 1 }, () => Array(101).fill(0)) + + for (let i = 0; i < nums.length; ++i) { + for (let j = 1; j <= 100; ++j) { + cnt[i + 1][j] = cnt[i][j] + (nums[i] == j) + } + } + + for (let i = 0; i < queries.length; ++i) { + let prev = 0, + delta = Infinity + for (let j = 1; j <= 100; ++j) + if (cnt[queries[i][1] + 1][j] - cnt[queries[i][0]][j]) { + delta = Math.min(delta, prev == 0 ? Infinity : j - prev) + prev = j + } + res.push(delta == Infinity ? -1 : delta) + } + return res +} diff --git a/1909-remove-one-element-to-make-the-array-strictly-increasing.js b/1909-remove-one-element-to-make-the-array-strictly-increasing.js new file mode 100644 index 00000000..9446fc73 --- /dev/null +++ b/1909-remove-one-element-to-make-the-array-strictly-increasing.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +const canBeIncreasing = function(nums) { + let previous = nums[0]; + let used = false; + for (let i = 1; i < nums.length; i++){ + if (nums[i] <= previous) { + if (used) return false; + used = true; + if (i === 1 || nums[i] > nums[i - 2]) previous = nums[i]; + } else previous = nums[i]; + } + return true; +}; diff --git a/191-number-of-1-bits.js b/191-number-of-1-bits.js index a20625e2..8395aae6 100644 --- a/191-number-of-1-bits.js +++ b/191-number-of-1-bits.js @@ -3,12 +3,25 @@ * @return {number} */ const hammingWeight = function(n) { - let str = (n >>> 0).toString(2) - let count = 0 - for(let i = 0; i < str.length; i++) { - if(str.charAt(i) === '1') { - count += 1 - } - } - return count + let res = 0 + while(n > 0) { + if(n & 1) res++ + n = n >>> 1 + } + return res +}; + +// another + +/** + * @param {number} n - a positive integer + * @return {number} + */ +const hammingWeight = function(n) { + const str = (n >>> 0).toString(2) + let res = 0 + for(let c of str) { + if(c === '1') res++ + } + return res }; diff --git a/1910-remove-all-occurrences-of-a-substring.js b/1910-remove-all-occurrences-of-a-substring.js new file mode 100644 index 00000000..97b46c74 --- /dev/null +++ b/1910-remove-all-occurrences-of-a-substring.js @@ -0,0 +1,13 @@ +/** + * @param {string} s + * @param {string} part + * @return {string} + */ +var removeOccurrences = function(s, part) { + while(s.indexOf(part) !== -1) { + const idx = s.indexOf(part) + s = s.slice(0, idx) + s.slice(idx + part.length) + // console.log(s) + } + return s +}; diff --git a/1911-maximum-alternating-subsequence-sum.js b/1911-maximum-alternating-subsequence-sum.js new file mode 100644 index 00000000..555eefb8 --- /dev/null +++ b/1911-maximum-alternating-subsequence-sum.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxAlternatingSum = function(nums) { + let odd = 0, even = 0; + for (let a of nums) { + even = Math.max(even, odd + a); + odd = even - a; + } + return even; +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxAlternatingSum = function(nums) { + let res = nums[0] + for(let i = 1; i < nums.length; i++) { + res += Math.max(nums[i] - nums[i - 1], 0) + } + return res +}; diff --git a/1913-maximum-product-difference-between-two-pairs.js b/1913-maximum-product-difference-between-two-pairs.js new file mode 100644 index 00000000..1786d953 --- /dev/null +++ b/1913-maximum-product-difference-between-two-pairs.js @@ -0,0 +1,9 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxProductDifference = function(nums) { + nums.sort((a, b) => a - b) + const n = nums.length + return nums[n - 1] * nums[n - 2] - nums[0] * nums[1] +}; diff --git a/1914-cyclically-rotating-a-gridsubmissions.js b/1914-cyclically-rotating-a-gridsubmissions.js new file mode 100644 index 00000000..056a22c3 --- /dev/null +++ b/1914-cyclically-rotating-a-gridsubmissions.js @@ -0,0 +1,107 @@ +/** + * @param {number[][]} grid + * @param {number} k + * @return {number[][]} + */ +const rotateGrid = function(grid, k) { + const m = grid.length, n = grid[0].length + let top = 0, left = 0, right = n - 1, bottom = m - 1 + while(top < bottom && left < right) { + const num = (right - left + 1) * 2 + (bottom - top + 1) * 2 - 4 + let rem = k % num + while(rem) { + const tmp = grid[top][left] + // top + for(let i = left; i < right; i++) { + grid[top][i] = grid[top][i + 1] + } + // right + for(let i = top; i < bottom; i++) { + grid[i][right] = grid[i + 1][right] + } + // bottom + for(let i = right; i > left; i--) { + grid[bottom][i] = grid[bottom][i - 1] + } + // left + for(let i = bottom; i > top; i--) { + grid[i][left] = grid[i - 1][left] + } + grid[top + 1][left] = tmp + rem-- + } + left++ + top++ + right-- + bottom-- + } + return grid +}; + +// another + +/** + * @param {number[][]} grid + * @param {number} k + * @return {number[][]} + */ +var rotateGrid = function(grid, k) { + var m = grid.length; + var n = grid[0].length; + + // step1: loop each layer + var layer = Math.min(n/2, m/2); + for(l = 0; l=l; j--) + { + cur.push(grid[m-l-1][j]); + } + // left + for(var i = m-l-2; i>l; i--) + { + cur.push(grid[i][l]); + } + + // step3: rotation (k%len) on one-dimension array + var d = cur.length; + var offset = k % d; + cur = [...cur.slice(offset, d), ...cur.slice(0, offset)]; + + // step4: refill rotated array back to 2D array at current layer + var index = 0; + // top + for(var j = l; j=l; j--) + { + grid[m-l-1][j] = cur[index++]; + } + // left + for(var i = m-l-2; i>l; i--) + { + grid[i][l] = cur[index++]; + } + } + return grid; +}; diff --git a/1915-number-of-wonderful-substrings.js b/1915-number-of-wonderful-substrings.js new file mode 100644 index 00000000..800696e7 --- /dev/null +++ b/1915-number-of-wonderful-substrings.js @@ -0,0 +1,100 @@ +/** + * @param {string} word + * @return {number} + */ +const wonderfulSubstrings = function(word) { + const n = word.length; + let mask = 0 + const hash = {0: 1}, a = 'a'.charCodeAt(0) + let res = 0 + + for(let i = 0; i < n; i++) { + const idx = word.charCodeAt(i) - a + mask ^= (1 << idx) + + res += hash[mask] || 0 + for(let j = 0; j < 10; j++) { + const newMask = mask ^ (1 << j) + res += hash[newMask] || 0 + } + + if(hash[mask] == null) hash[mask] = 0 + hash[mask]++ + } + + return res +}; + +// another + +/** + * @param {string} word + * @return {number} + */ +const wonderfulSubstrings = function (word) { + const n = word.length, + a = 'a'.charCodeAt(0) + const map = new Map() + map.set(0, 1) + let res = 0 + for (let i = 0, mask = 0; i < n; i++) { + const idx = word[i].charCodeAt(0) - a + mask ^= 1 << idx + res += (map.get(mask) || 0) + for (let j = 0; j < 10; j++) { + const tmp = mask ^ (1 << j) + res += map.get(tmp) || 0 + } + + map.set(mask, (map.get(mask) || 0) + 1) + } + return res +} + +// another + + +/** + * @param {string} word + * @return {number} + */ +const wonderfulSubstrings = (word) => { + let res = 0, count = Array(1024).fill(0); + let cur = 0; + count[0] = 1; + for (let i = 0; i < word.length; ++i) { + const num = word[i].charCodeAt() - 97; + cur ^= 1 << (num); + res += count[cur]; + ++count[cur]; + + for (let j = 0; j < 10; ++j) { + res += count[cur ^ (1 << j)]; + } + } + + return res; +}; + +// another + +/** + * @param {string} word + * @return {number} + */ +const asi = (c) => c.charCodeAt(); +const wonderfulSubstrings = (s) => { + let res = 0; + let f = Array(2 ** 10).fill(0); + f[0] = 1; // count array + let cur = res = 0; + for (const c of s) { + cur ^= 1 << asi(c) - 97; // get Hash (the set bit for a character.), update prefix parity + res += f[cur]; + for (let i = 0; i < 10; i++) { // a ~ j + res += f[cur ^ 1 << i]; // 1 << i get Hash + } + f[cur]++; + } + return res; +}; diff --git a/1916-count-ways-to-build-rooms-in-an-ant-colony.js b/1916-count-ways-to-build-rooms-in-an-ant-colony.js new file mode 100644 index 00000000..4c4a6d4f --- /dev/null +++ b/1916-count-ways-to-build-rooms-in-an-ant-colony.js @@ -0,0 +1,60 @@ +/** + * @param {number[]} prevRoom + * @return {number} + */ +const waysToBuildRooms = function (prevRoom) { + return brute(prevRoom); +}; +function brute(prevRoom) { + const power = function (a, b, n) { + a = a % n; + let result = 1n; + let x = a; + while (b > 0) { + let leastSignificantBit = b % 2n; + b = b / 2n; + if (leastSignificantBit == 1n) { + result = result * x; + result = result % n; + } + x = x * x; + x = x % n; + } + return result; + }; + const modInverse = function (aa, mm) { + return power(BigInt(aa), BigInt(mm - 2), BigInt(mm)); + }; + const mod = Math.pow(10, 9) + 7; + let nodes = {}; + for (let i = 0; i < prevRoom.length; i++) { + nodes[i] = { val: i, edges: {} }; + } + for (let i = 1; i < prevRoom.length; i++) { + nodes[prevRoom[i]].edges[i] = true; + } + let memo = {}; + const numNodes = function (root) { + var key = root.val; + if (memo[key] !== undefined) { + return memo[key]; + } + var res = 1; + for (var x in root.edges) { + res += numNodes(nodes[x]); + } + memo[key] = res; + return res; + }; + let den = 1; + for (let x in nodes) { + let size = numNodes(nodes[x]); + den = (den * size) % mod; + } + let numerator = 1; + for (let i = 1; i < prevRoom.length; i++) { + numerator = (numerator * (i + 1)) % mod; + } + let denInverse = modInverse(den, mod); + return (BigInt(numerator) * denInverse) % BigInt(mod); +} diff --git a/1918-kth-smallest-subarray-sum.js b/1918-kth-smallest-subarray-sum.js new file mode 100644 index 00000000..cea6e615 --- /dev/null +++ b/1918-kth-smallest-subarray-sum.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const kthSmallestSubarraySum = function(nums, k) { + const sum = nums.reduce((ac, e) => ac + e, 0), n = nums.length + let l = 0, r = sum + while(l < r) { + const mid = l + ((r - l) >> 1) + let cnt = 0 + for(let i = 0, j = 0, tmp = 0; i < n; i++) { + tmp += nums[i] + while(tmp > mid) tmp -= nums[j++] + cnt += i - (j - 1) + } + if (cnt < k) l = mid + 1 + else r = mid + } + return l +}; diff --git a/1920-build-array-from-permutation.js b/1920-build-array-from-permutation.js new file mode 100644 index 00000000..50dda790 --- /dev/null +++ b/1920-build-array-from-permutation.js @@ -0,0 +1,11 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const buildArray = function(nums) { + const res = [] + for(let i = 0, n = nums.length; i < n; i++) { + res[i] = nums[nums[i]] + } + return res +}; diff --git a/1921-eliminate-maximum-number-of-monsters.js b/1921-eliminate-maximum-number-of-monsters.js new file mode 100644 index 00000000..e21fbe7b --- /dev/null +++ b/1921-eliminate-maximum-number-of-monsters.js @@ -0,0 +1,90 @@ +/** + * @param {number[]} dist + * @param {number[]} speed + * @return {number} + */ +const eliminateMaximum = function(dist, speed) { + const pq = new PriorityQueue((a, b) => a[0] / a[1] < b[0] / b[1]) + const n = dist.length + for(let i = 0; i < n; i++) { + pq.push([dist[i], speed[i]]) + } + let res = 0 + while(true) { + if(pq.isEmpty()) break + if(pq.peek()[0] < 0) break + const tmp = pq.pop() + if(tmp[0] <= res * tmp[1]) break + res++ + } + + return res +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1922-count-good-numbers.js b/1922-count-good-numbers.js new file mode 100644 index 00000000..28813aaa --- /dev/null +++ b/1922-count-good-numbers.js @@ -0,0 +1,23 @@ +/** + * @param {number} n + * @return {number} + */ +const countGoodNumbers = function (n) { + n = BigInt(n) + const MOD = BigInt(10 ** 9 + 7) + let res = + quick_pow(5n, (n + 1n) / 2n ) * quick_pow(4n, n / 2n) + res %= MOD + return res + + function quick_pow(b, m) { + let ans = 1n + while (m) { + if (m % 2n === 1n) ans = (ans * b) % MOD + m = m / 2n + b = (b * b) % MOD + } + return ans + } +} + diff --git a/1923-longest-common-subpath.js b/1923-longest-common-subpath.js new file mode 100644 index 00000000..b87890ea --- /dev/null +++ b/1923-longest-common-subpath.js @@ -0,0 +1,98 @@ +/** + * @param {number} n + * @param {number[][]} paths + * @return {number} + */ +const longestCommonSubpath = function(n, paths) { + if (!paths.length) return 0 + let arr = paths[0] + for (const path of paths) if (path.length < arr.length) arr = path + return new Sam(arr).longestCommonSubpath(paths) +}; + +class State { + constructor(len, link, next) { + this.len = len + this.link = link + this.next = new Map(next) + this.ans = len + this.revLink = [] + this.max = 0 + } +} + +/** + * @param p {State} + * @return boolean + */ +function dfs(p) { + let hasNext = false + for (const q of p.revLink) { + hasNext = dfs(q) || hasNext + } + if (hasNext) p.max = p.len + return p.max > 0 +} + +class Sam { + newState(len, link, next) { + const state = new State(len, link, next) + this.container.push(state) + return state + } + + constructor(path) { + this.container = [] + const root = this.newState(0, null) + let last = root + for (const x of path) { + const cur = this.newState(last.len + 1, root) + for (let p = last; p; p = p.link) { + const q = p.next.get(x) + if (!q) { + p.next.set(x, cur) + continue + } + if (q.len === p.len + 1) { + cur.link = q + } else { + const clone = this.newState(p.len + 1, q.link, q.next) + for (; p && p.next.get(x) === q; p = p.link) p.next.set(x, clone) + cur.link = q.link = clone + } + break + } + last = cur + } + for (const state of this.container) + if (state.link) state.link.revLink.push(state) + } + + visit(path) { + for (const state of this.container) state.max = 0 + const root = this.container[0] + let p = root + let len = 0 + for (const x of path) { + for (; ; p = p.link, len = p.len) { + const q = p.next.get(x) + if (q) { + p = q + p.max = Math.max(p.max, ++len) + break + } + if (!p.link) break + } + } + dfs(root) + for (const state of this.container) + state.ans = Math.min(state.ans, state.max) + } + + longestCommonSubpath(paths) { + for (const path of paths) this.visit(path) + let ans = 0 + for (const state of this.container) ans = Math.max(ans, state.ans) + return ans + } +} diff --git a/1925-count-square-sum-triples.js b/1925-count-square-sum-triples.js new file mode 100644 index 00000000..dbc871df --- /dev/null +++ b/1925-count-square-sum-triples.js @@ -0,0 +1,19 @@ +/** + * @param {number} n + * @return {number} + */ +const countTriples = function(n) { + let res = 0 + const hash = {} + for(let i = 1; i<= n; i++) { + hash[i * i] = 1 + } + + for(let i = 1; i <= n; i++) { + for(let j = i; i * i + j * j <= n * n; j++) { + res += (hash[i * i + j * j] || 0) * 2 + } + } + + return res +}; diff --git a/1928-minimum-cost-to-reach-destination-in-time.js b/1928-minimum-cost-to-reach-destination-in-time.js new file mode 100644 index 00000000..db1a7339 --- /dev/null +++ b/1928-minimum-cost-to-reach-destination-in-time.js @@ -0,0 +1,105 @@ +/** + * @param {number} maxTime + * @param {number[][]} edges + * @param {number[]} passingFees + * @return {number} + */ +const minCost = function(maxTime, edges, passingFees) { + const n = passingFees.length + const pq = new PriorityQueue((a, b) => a[0] < b[0]) + const graph = {} + for(let [s, e, t] of edges) { + if(graph[s] == null) graph[s] = [] + if(graph[e] == null) graph[e] = [] + graph[s].push([e, t]) + graph[e].push([s, t]) + } + + const times = {} + + pq.push([passingFees[0], 0, 0]) + while(!pq.isEmpty()) { + const [cost, node, time] = pq.pop() + + if(time > maxTime) continue + if(node === n - 1) return cost + + if(times[node] == null || times[node] > time) { + times[node] = time + for(let [nxt, ext] of graph[node]) { + pq.push([cost + passingFees[nxt], nxt, time + ext]) + } + } + + } + + return -1 +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1929-concatenation-of-array.js b/1929-concatenation-of-array.js new file mode 100644 index 00000000..58d03269 --- /dev/null +++ b/1929-concatenation-of-array.js @@ -0,0 +1,7 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const getConcatenation = function(nums) { + return nums.concat(nums) +}; diff --git a/193-valid-phone-numbers.sh b/193-valid-phone-numbers.sh new file mode 100644 index 00000000..5ab758c2 --- /dev/null +++ b/193-valid-phone-numbers.sh @@ -0,0 +1,10 @@ +# Read from the file file.txt and output all valid phone numbers to stdout. +awk '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/' file.txt + +# another + +grep -P '^(\(\d{3}\) |\d{3}-)\d{3}-\d{4}$' file.txt + +# another + +sed -n -r '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/p' file.txt diff --git a/1930-unique-length-3-palindromic-subsequences.js b/1930-unique-length-3-palindromic-subsequences.js new file mode 100644 index 00000000..d615b832 --- /dev/null +++ b/1930-unique-length-3-palindromic-subsequences.js @@ -0,0 +1,53 @@ +/** + * @param {string} s + * @return {number} + */ +const countPalindromicSubsequence = function(s) { + const first = Array(26).fill(Infinity), last = Array(26).fill(0) + let res = 0 + const n = s.length, a = 'a'.charCodeAt(0) + for(let i = 0; i < n; i++) { + const code = s[i].charCodeAt(0) + first[code - a] = Math.min(i, first[code - a]) + last[code - a] = i + } + + for(let i = 0; i < 26; i++) { + if(last[i] - 1 > first[i]) { + const tmp = s.slice(first[i] + 1, last[i]) + const set = new Set() + for(let ch of tmp) set.add(ch) + res += set.size + } + } + + return res +}; + +// another + + +/** + * @param {string} s + * @return {number} + */ +const countPalindromicSubsequence = (s) => { + let res = 0; + for (let i = 0; i < 26; i++) { + for (let j = 0; j < 26; j++) { + let len = 0; + for (const c of s) { + if(len === 3) break + if (len == 0) { + if (c.charCodeAt() - 97 == i) len++; // first char + } else if (len == 1) { + if (c.charCodeAt() - 97 == j) len++; // second char + } else if (len == 2) { + if (c.charCodeAt() - 97 == i) len++; // third char + } + } + if (len == 3) res++; + } + } + return res; +}; diff --git a/1931-painting-a-grid-with-three-different-colors.js b/1931-painting-a-grid-with-three-different-colors.js new file mode 100644 index 00000000..2e3cec5a --- /dev/null +++ b/1931-painting-a-grid-with-three-different-colors.js @@ -0,0 +1,149 @@ +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +const colorTheGrid = function(m, n) { + // Get color of the `mask` at `pos`, 2 bit store 1 color + function getColor(mask, pos) { + return (mask >> (2 * pos)) & 3 + } + // Set `color` to the `mask` at `pos`, 2 bit store 1 color + function setColor(mask, pos, color) { + return mask | (color << (2 * pos)) + } + function dfs(r, curColMask, prevColMask, out) { + // Filled full color for a row + if(r === m) { + out.push(curColMask) + return + } + // Try colors i in [1=RED, 2=GREEN, 3=BLUE] + for(let i = 1; i <= 3; i++) { + if(getColor(prevColMask, r) !== i && (r === 0 || getColor(curColMask, r - 1) !== i)) { + dfs(r + 1, setColor(curColMask, r, i), prevColMask, out) + } + } + } + // Generate all possible columns we can draw, if the previous col is `prevColMask` + function neighbor(prevColMask) { + let out = [] + dfs(0, 0, prevColMask, out) + return out + } + const mod = 10 ** 9 + 7 + const memo = {} + function dp(c, prevColMask) { + // Found a valid way + if(c === n) return 1 + if(memo[`${c},${prevColMask}`] != null) return memo[`${c},${prevColMask}`] + let res = 0 + const arr = neighbor(prevColMask) + for(let e of arr) { + res = (res + dp(c + 1, e)) % mod + } + memo[`${c},${prevColMask}`] = res + return res + } + + return dp(0, 0) + +}; + +// another + +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +const colorTheGrid = function(m, n) { + const mod = 10 ** 9 + 7 + const colors = [1, 2, 3] + const memoDp = {}, memoOpts = {} + function getColor(pos, preMask) { + return (preMask >> (pos * 2)) & 3 + } + function setColor(pos, color, curMask) { + return curMask | (color << (pos * 2)) + } + function dfs(pos, curMask, preMask, res) { + if(pos === m) { + res.push(curMask) + return + } + for(let c of colors) { + if(getColor(pos, preMask) !== c && (pos === 0 || getColor(pos - 1, curMask) !== c)) { + dfs(pos + 1, setColor(pos, c, curMask), preMask, res) + } + } + } + function curOpts(preMask) { + if (memoOpts[preMask]) return memoOpts[preMask] + const res = [] + dfs(0, 0, preMask, res) + memoOpts[preMask] = res + return res + } + function dp(col, preMask) { + const k = `${col},${preMask}` + if(col === n) return 1 + if(memoDp[k]) return memoDp[k] + let res = 0 + const cur = curOpts(preMask) + for(let mask of cur) { + res = (res + dp(col + 1, mask)) % mod + } + memoDp[k] = res + return res + } + + return dp(0, 0) +}; + +// another + +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +const colorTheGrid = function(m, n) { + const mod = 1e9 + 7 + const limit = 1 << (2 * m) + const memo = Array.from({ length: n }, () => Array(limit)) + + return dp(0, 0) + + function dp(col, preColMask) { + if(col === n) return 1 + let res = 0 + + if(memo[col][preColMask] != null) return memo[col][preColMask] + const curColMasks = [] + dfs(preColMask, 0, 0, curColMasks) + for(const colMask of curColMasks) { + res = (res + dp(col + 1, colMask)) % mod + } + return memo[col][preColMask] = res + } + + function dfs(preColMask, curColMask, row, res) { + if(row === m) { + res.push(curColMask) + return + } + for(let i = 1; i <= 3; i++) { + if(getColor(preColMask, row) !== i && (row === 0 || getColor(curColMask, row - 1) !== i)) { + dfs(preColMask, setColor(curColMask, row, i) ,row + 1, res) + } + } + } + + function getColor(mask, row) { + return (mask >> (2 * row)) & 3 + } + function setColor(mask, row, val) { + return mask | (val << (2 * row)) + } +}; diff --git a/1932-merge-bsts-to-create-single-bst.js b/1932-merge-bsts-to-create-single-bst.js new file mode 100644 index 00000000..9a3040db --- /dev/null +++ b/1932-merge-bsts-to-create-single-bst.js @@ -0,0 +1,86 @@ +/** + * 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[]} trees + * @return {TreeNode} + */ +const canMerge = function (trees) { + const mapRoots = {} + const mapLeaves = {} + let prev + + //check all trees and hashMap all available roots and leaves + for (let node of trees) { + mapRoots[node.val] = node + if (node.left != null) { + if (mapLeaves[node.left.val] != null) + //different nodes can't refer to the same node -> abnormal BST + return null + mapLeaves[node.left.val] = node.left + } + if (node.right != null) { + if (mapLeaves[node.right.val] != null) + //different nodes can't refer to the same node -> abnormal BST + return null + mapLeaves[node.right.val] = node.right + } + } + + let rootRes = null + let count = trees.length + + //find potential root-result of the merged entire tree + //that is node without any references from the parent leaf nodes + for (let node of trees) { + if (mapLeaves[node.val] == null) { + rootRes = node + break + } + } + + //if there are no nodes like that -> abnormal BST + if (rootRes == null) return rootRes + + const q = [] + + //put root-result leaves into queue + if (rootRes.left != null) q.push(rootRes.left) + if (rootRes.right != null) q.push(rootRes.right) + count-- + + while (q.length) { + //get leaf from the queue and check if there is correponding available root + let leaf = q.pop() + let root = mapRoots[leaf.val] + if (root != null) { + //there is root matched to leaf, so let's merge it + count-- + leaf.left = root.left + leaf.right = root.right + //add new leaves into the queue + if (root.left != null) q.push(root.left) + if (root.right != null) q.push(root.right) + } + } + + prev = 0 + //if we have merged all inputed trees and that is valid BST by values, then return rootRes + return count == 0 && recSanity(rootRes) ? rootRes : null + + function recSanity(node) { + if (node == null) return true + + if (!recSanity(node.left)) return false + + if (prev >= node.val) return false + prev = node.val + + return recSanity(node.right) + } +} diff --git a/1935-maximum-number-of-words-you-can-type.js b/1935-maximum-number-of-words-you-can-type.js new file mode 100644 index 00000000..ccbd27c8 --- /dev/null +++ b/1935-maximum-number-of-words-you-can-type.js @@ -0,0 +1,22 @@ +/** + * @param {string} text + * @param {string} brokenLetters + * @return {number} + */ +const canBeTypedWords = function(text, brokenLetters) { + const set = new Set(brokenLetters.split('')) + const arr = text.split(' ') + let res = 0 + for(let e of arr) { + let ok = true + for(let c of e) { + if(set.has(c)) { + ok = false + break + } + } + if(ok) res++ + } + + return res +}; diff --git a/1936-add-minimum-number-of-rungs.js b/1936-add-minimum-number-of-rungs.js new file mode 100644 index 00000000..07eb14bc --- /dev/null +++ b/1936-add-minimum-number-of-rungs.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} rungs + * @param {number} dist + * @return {number} + */ +const addRungs = function(rungs, dist) { + let res = 0 + let pre = 0 + const { floor, ceil } = Math + for(let r of rungs) { + if(r - pre > dist) { + // console.log(r, pre) + res += ceil((r - pre) / dist) - 1 + } + pre = r + } + return res +}; diff --git a/1937-maximum-number-of-points-with-cost.js b/1937-maximum-number-of-points-with-cost.js new file mode 100644 index 00000000..83e5caf7 --- /dev/null +++ b/1937-maximum-number-of-points-with-cost.js @@ -0,0 +1,71 @@ +/** + * @param {number[][]} points + * @return {number} + */ +const maxPoints = function(points) { + const m = points.length, n = points[0].length + let prev = points[0].slice() + for(let i = 1; i < m; i++) { + const left = [] + left[0] = prev[0] + // left to right + for(let j = 1; j < n; j++) { + left[j] = Math.max(prev[j], left[j - 1] - 1) + } + const right = [] + right[n - 1] = prev[n - 1] + // right to left + for(let j = n - 2; j >= 0; j--) { + right[j] = Math.max(prev[j], right[j + 1] - 1) + } + + const cur = [] + for(let j = 0; j < n; j++) { + cur[j] = Math.max(left[j], right[j]) + points[i][j] + } + prev = cur + } + + return Math.max(...prev) +}; + +// another + +/** + * @param {number[][]} points + * @return {number} + */ +const maxPoints = function(points) { + let m = points.length, n = points[0].length; + let result = 0; + // dp + const dp = Array.from({ length: m }, () => Array(n).fill(0)); + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (i == 0) { + dp[i][j] = points[i][j]; + } else { + dp[i][j] = Math.max(points[i][j] + dp[i - 1][j], dp[i][j]); + } + } + for (let j = 0; j < n; j++) { + // right + for (let k = 1; k < n - j; k++) { + if (dp[i][j + k] >= dp[i][j] - k) { + break; + } + dp[i][j + k] = dp[i][j] - k; + } + for (let k = 1; k <= j; k++) { + if (dp[i][j - k] >= dp[i][j] - k) { + break; + } + dp[i][j - k] = dp[i][j] - k; + } + } + } + for (let j = 0; j < n; j++) { + result = Math.max(result, dp[m - 1][j]); + } + return result; +}; diff --git a/1938-maximum-genetic-difference-query.js b/1938-maximum-genetic-difference-query.js new file mode 100644 index 00000000..f90fe783 --- /dev/null +++ b/1938-maximum-genetic-difference-query.js @@ -0,0 +1,62 @@ +/** + * @param {number[]} parents + * @param {number[][]} queries + * @return {number[]} + */ +const maxGeneticDifference = function (parents, queries) { + let pn = parents.length, + qn = queries.length + let root = parents.indexOf(-1) + let children = initializeGraph(pn) + for (let i = 0; i < pn; i++) { + if (i != root) { + children[parents[i]].push(i) + } + } + let freq = Array(1 << 20).fill(0) + let queriesByNode = initializeGraph(pn) + for (let i = 0; i < qn; i++) { + let query = queries[i] + queriesByNode[query[0]].push(new Query(i, query[1])) + } + + let res = Array(qn).fill(0) + const dfs = (idx) => { + let y = (1 << 19) + idx + while (y > 0) { + freq[y]++ + y >>= 1 + } + for (const qnode of queriesByNode[idx]) { + let j = qnode.index, + x = qnode.val + let cum = 0 + let bit = 1 << 18 + while (bit > 0) { + let ii = (((1 << 19) ^ cum ^ x ^ bit) / bit) >> 0 + if (freq[ii] > 0) cum += bit + bit >>= 1 + } + res[j] = cum + } + for (const child of children[idx]) dfs(child) + y = (1 << 19) + idx + while (y > 0) { + freq[y]-- + y >>= 1 + } + } + dfs(root) + return res +} + +const initializeGraph = (n) => { + let G = [] + for (let i = 0; i < n; i++) G.push([]) + return G +} + +function Query(index, val) { + this.index = index + this.val = val +} diff --git a/1941-check-if-all-characters-have-equal-number-of-occurrences.js b/1941-check-if-all-characters-have-equal-number-of-occurrences.js new file mode 100644 index 00000000..dfc28545 --- /dev/null +++ b/1941-check-if-all-characters-have-equal-number-of-occurrences.js @@ -0,0 +1,17 @@ +/** + * @param {string} s + * @return {boolean} + */ +var areOccurrencesEqual = function(s) { + const n = s.length + const arr = Array(26).fill(0), a = 'a'.charCodeAt(0) + for(const ch of s) { + arr[ch.charCodeAt(0) - a]++ + } + const set = new Set() + for(const e of arr) { + if(e !== 0) set.add(e) + if(set.size > 1) return false + } + return true +}; diff --git a/1942-the-number-of-the-smallest-unoccupied-chair.js b/1942-the-number-of-the-smallest-unoccupied-chair.js new file mode 100644 index 00000000..643058c6 --- /dev/null +++ b/1942-the-number-of-the-smallest-unoccupied-chair.js @@ -0,0 +1,359 @@ +/** + * @param {number[][]} times + * @param {number} targetFriend + * @return {number} + */ +const smallestChair = function(times, targetFriend) { + times.forEach((e, i) => e[2] = i) + times.sort((a, b) => a[0] - b[0]) + const pq = new PQ((a, b) => a[1] < b[1]) + const available = new PQ((a, b) => a < b) + const n = times.length + for(let i = 0; i < n; i++) { + available.push(i) + } + const seat = available.pop() + times[0].push(seat) + pq.push(times[0]) + if(times[0][2] === targetFriend) return seat + for(let i = 1; i < n; i++) { + const el = times[i] + const [s, e, idx] = el + while(!pq.isEmpty() && pq.peek()[1] <= s) { + const tmp = pq.pop() + available.push(tmp[3]) + } + const seat = available.pop() + if(targetFriend === idx) return seat + el.push(seat) + pq.push(el) + } + +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number[][]} times + * @param {number} targetFriend + * @return {number} + */ +const smallestChair = function(times, targetFriend) { + const avail = new PQ((a, b) => a[0] < b[0]) + const occupied = new PQ((a, b) => a[1] < b[1]) + const n = times.length + for(let i = 0; i < n; i++) { + avail.push([i, 0]) + } + times.forEach((e, i) => e.push(i)) + times.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) + + for(let i = 0; i < n; i++) { + let res = -1 + const [s, e, idx] = times[i] + while(!occupied.isEmpty() && occupied.peek()[1] <= s) { + avail.push(occupied.pop()) + } + + const c = avail.pop() + res = c[0] + c[1] = e + occupied.push(c) + + if(idx === targetFriend) { + return res + } + } +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number[][]} times + * @param {number} targetFriend + * @return {number} + */ +const smallestChair = function (times, targetFriend) { + const targetArrival = times[targetFriend][0] + let seatNum = 0 + let res = 0 + const n = times.length + + times.sort((a, b) => a[0] - b[0]) + + const occupied = new PriorityQueue((a, b) => a[0] < b[0]) + const available = new PriorityQueue((a, b) => a < b) + + for(let i = 0; i < n; i++) { + const [arrival, leaving] = times[i] + while(!occupied.isEmpty() && occupied.peek()[0] <= arrival) { + available.push(occupied.pop()[1]) + } + let seat + if(!available.isEmpty()) { + seat = available.pop() + } else { + seat = seatNum + seatNum++ + } + occupied.push([leaving, seat]) + if(arrival === targetArrival) { + res = seat + break + } + } + + return res +} +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + + +/** + * @param {number[][]} times + * @param {number} targetFriend + * @return {number} + */ +var smallestChair = function (times, targetFriend) { + const [targetArrival] = times[targetFriend] + const arrivalQueue = times + const leavingQueue = [...times] + arrivalQueue.sort((a, b) => a[0] - b[0]) + leavingQueue.sort((a, b) => a[1] - b[1] || a[0] - b[0]) + const chairsByLeaveTime = new Map() + let chairsCount = 0 + let arriving = 0, + leaving = 0 + + while (arriving < arrivalQueue.length) { + let chairIdx + const arrival = arrivalQueue[arriving][0] + const leave = leavingQueue[leaving][1] + if (arrival < leave) { + chairIdx = chairsCount++ + } else { + let freeChairIdx = leaving + chairIdx = chairsByLeaveTime.get(leavingQueue[freeChairIdx++][0]) + while (arrival >= leavingQueue[freeChairIdx][1]) { + const nextChair = chairsByLeaveTime.get(leavingQueue[freeChairIdx][0]) + if (chairIdx > nextChair) { + ;[leavingQueue[leaving], leavingQueue[freeChairIdx]] = [ + leavingQueue[freeChairIdx], + leavingQueue[leaving], + ] + chairIdx = nextChair + } + ++freeChairIdx + } + ++leaving + } + if (targetArrival === arrival) { + return chairIdx + } + chairsByLeaveTime.set(arrival, chairIdx) + arriving++ + } +} diff --git a/1943-describe-the-painting.js b/1943-describe-the-painting.js new file mode 100644 index 00000000..59191bb1 --- /dev/null +++ b/1943-describe-the-painting.js @@ -0,0 +1,55 @@ +/** + * @param {number[][]} segments + * @return {number[][]} + */ +const splitPainting = function(segments) { + const hash = {} + for(let [s, e, c] of segments) { + if(hash[s] == null) hash[s] = 0 + if(hash[e] == null) hash[e] = 0 + hash[s] += c + hash[e] -= c + } + const keys = Object.keys(hash) + keys.sort((a, b) => a - b) + let prev, color = 0 + const res = [] + for(let k of keys) { + if(prev != null && color !== 0) res.push([prev,k,color]) + + prev = k + color += hash[k] + } + return res +}; + +// another + +/** + * @param {number[][]} segments + * @return {number[][]} + */ +const splitPainting = function(segments) { + const sum = {} + for(const [s, e, v] of segments) { + if(sum[s] == null) sum[s] = 0 + if(sum[e] == null) sum[e] = 0 + sum[s] += v + sum[e] -= v + } + const keys = Object.keys(sum).map(e => +e) + keys.sort((a, b) => a - b) + const res = [] + let pre = 0, s = 0, n = keys.length + for(let i = 0; i < n; i++) { + const k = keys[i] + + if(s) { + res.push([pre, k, s]) + } + s += sum[k] + pre = k + } + + return res +}; diff --git a/1944-number-of-visible-people-in-a-queue.js b/1944-number-of-visible-people-in-a-queue.js new file mode 100644 index 00000000..b2864dfc --- /dev/null +++ b/1944-number-of-visible-people-in-a-queue.js @@ -0,0 +1,95 @@ +/** + * @param {number[]} heights + * @return {number[]} + */ +const canSeePersonsCount = function(heights) { + const n = heights.length + const res = Array(n).fill(0) + const stk = [] + for(let i = n - 1; i >= 0; i--) { + const cur = heights[i] + let del = 0 + while(stk.length && cur > heights[stk.at(-1)]) { + del++ + stk.pop() + } + res[i] = del + (stk.length ? 1 : 0) + stk.push(i) + } + + return res +}; + +// another + +/** + * @param {number[]} heights + * @return {number[]} + */ +const canSeePersonsCount = function(heights) { + const res = [] + if(heights.length === 0) return res + + const n = heights.length + const stk = [] + for(let i = n - 1; i >= 0; i--) { + let del = 0 + while(stk.length && heights[i] > heights[stk[stk.length - 1]]) { + stk.pop() + del++ + } + res.push(del + (stk.length ? 1 : 0)) + stk.push(i) + } + + return res.reverse() +}; + +// another + + +/** + * @param {number[]} heights + * @return {number[]} + */ +const canSeePersonsCount = function(heights) { + const ans = new Uint32Array(heights.length); + + const stack = []; + for (let i = heights.length - 1; i >= 0; i--) { + const h = heights[i]; + + let del = 0; + while (stack.length && stack[stack.length - 1] <= h) { + del++; + stack.pop(); + } + + ans[i] = del + (stack.length ? 1 : 0); + stack.push(h); + } + + return ans; +}; + +// another + +/** + * @param {number[]} heights + * @return {number[]} + */ +const canSeePersonsCount = function(heights) { + const stack = [], n = heights.length, res = Array(n) + for(let i = n - 1; i >= 0; i--) { + const h = heights[i] + let del = 0 + while(stack.length && stack[stack.length - 1] <= h) { + stack.pop() + del++ + } + res[i] = stack.length ? del + 1 : del + stack.push(h) + } + + return res +}; diff --git a/1945-sum-of-digits-of-string-after-convert.js b/1945-sum-of-digits-of-string-after-convert.js new file mode 100644 index 00000000..138ea154 --- /dev/null +++ b/1945-sum-of-digits-of-string-after-convert.js @@ -0,0 +1,25 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const getLucky = function(s, k) { + let res = 0 + const a = 'a'.charCodeAt(0) + const arr = [] + for(let ch of s) { + arr.push(ch.charCodeAt(0) - a + 1) + } + let str = arr.join('').split('').map(e => +e) + let prev = str, sum = 0 + while(k > 0) { + // let tmp = 0 + let tmp = prev.reduce((ac, e) => ac + e, 0) + // console.log(tmp) + prev = `${tmp}`.split('').map(e => +e) + sum = tmp + k-- + } + + return sum +}; diff --git a/1946-largest-number-after-mutating-substring.js b/1946-largest-number-after-mutating-substring.js new file mode 100644 index 00000000..8c6ed631 --- /dev/null +++ b/1946-largest-number-after-mutating-substring.js @@ -0,0 +1,24 @@ +/** + * @param {string} num + * @param {number[]} change + * @return {string} + */ +const maximumNumber = function(num, change) { + let res = '' + const arr = num.split('') + let prev = false, cnt = 0 + for(let i = 0, n = num.length; i < n; i++) { + const cur = +num[i] + if(change[cur] > cur) { + cnt++ + prev = true + arr[i] = change[cur] + } + if(change[cur] < cur) { + if(cnt <= 0) continue + else break + } + } + + return arr.join('') +}; diff --git a/1947-maximum-compatibility-score-sum.js b/1947-maximum-compatibility-score-sum.js new file mode 100644 index 00000000..7debdc44 --- /dev/null +++ b/1947-maximum-compatibility-score-sum.js @@ -0,0 +1,120 @@ +/** + * @param {number[][]} students + * @param {number[][]} mentors + * @return {number} + */ +const maxCompatibilitySum = function(students, mentors) { + const m = students.length, n = students[0].length + const limit = 1 << m + const dp = Array(limit).fill(0) + for(let mask = 1; mask < limit; mask++) { + for(let i = 0; i < m; i++) { + if(mask & (1 << i)) { + dp[mask] = Math.max( + dp[mask], + dp[mask ^ (1 << i)] + calc(bitCnt(mask) - 1, i) + ) + } + } + } + + + return dp[limit - 1] + + function bitCnt(num) { + let res = 0 + while(num) { + num = num & (num - 1) + res++ + } + + return res + } + // student, mentor + function calc(i, j) { + let res = 0 + for(let k = 0; k < n; k++) { + if(students[i][k] === mentors[j][k]) { + res++ + } + } + + return res + } +}; + +// another + +/** + * @param {number[][]} students + * @param {number[][]} mentors + * @return {number} + */ +const maxCompatibilitySum = function(students, mentors) { + const n = students.length, dp = Array(1 << n).fill(-Infinity) + const m = students[0].length + return dfs(0, 0) + + function dfs(i, mask) { + if(i === n) return 0 + if(dp[mask] !== -Infinity) return dp[mask] + for(let j = 0; j < n; j++) { + if((mask & (1 << j)) === 0) { + dp[mask] = Math.max(dp[mask], calc(i, j) + dfs(i + 1, mask | (1 << j))) + } + } + + return dp[mask] + } + + function calc(i, j) { + let res = 0 + const a = students[i], b = mentors[j] + for(let k = 0; k < m; k++) { + if(a[k] === b[k]) res++ + } + return res + } +}; + + +// another + +/** + * @param {number[][]} students + * @param {number[][]} mentors + * @return {number} + */ +const maxCompatibilitySum = function(students, mentors) { + const obj = { res: 0 }, hash = {} + bt(students, mentors, 0, 0, obj, hash) + + return obj.res +}; + +function bt(stu, men, i, score, obj, hash) { + + if(i === stu.length) { + if(score > obj.res) { + obj.res = score + } + return + } + + for(let j = 0; j < men.length; j++) { + const k = `${j}` + if(hash[k] === 1) continue + hash[k] = 1 + bt(stu, men, i + 1, score + calc(stu[i], men[j]), obj, hash) + delete hash[k] + } +} + +function calc(a1, a2) { + const n = a1.length + let res = 0 + for(let i = 0; i < n; i++) { + if(a1[i] === a2[i]) res++ + } + return res +} diff --git a/1948-delete-duplicate-folders-in-system.js b/1948-delete-duplicate-folders-in-system.js new file mode 100644 index 00000000..e68d27a4 --- /dev/null +++ b/1948-delete-duplicate-folders-in-system.js @@ -0,0 +1,134 @@ +/** + * @param {string[][]} paths + * @return {string[][]} + */ +const deleteDuplicateFolder = function(paths) { + const trie = new Trie() + for (const path of paths) { + let cur = trie.trie + cur.countPrefix++ + for (const name of path) { + if(cur.children[name] == null) cur.children[name] = new TrieNode(name) + cur = cur.children[name] + cur.countPrefix++ + } + } + const folders = new Map() + dfs1(trie.trie) + for (const value of folders.values()) { + if (value.length > 1) { + // found the same dir, mark as to be deleted + for (const node of value) { + node.countPrefix = 0 + } + } + } + const ans = [] + // traverse un-deleted dir, put them to result + dfs2(trie.trie, []) + return ans + function dfs1 (node) { + if (Object.keys(node.children).length === 0) { + return `(${node.char})` + } + const childrenExp = [] + for (const key in node.children) { + childrenExp.push(dfs1(node.children[key])) + } + const exp = childrenExp.sort((a, b) => a.localeCompare(b)).join('') + if (!folders.has(exp)) { + folders.set(exp, []) + } + folders.get(exp).push(node) + return `(${node.char}${childrenExp.join('')})` + } + function dfs2 (node, path) { + // already deleted, no need go further + if (node.countPrefix === 0) { + return + } + if (node.char !== '/') { path.push(node.char) } + if (path.length) ans.push([...path]) + for (const key in node.children) { + dfs2(node.children[key], path) + } + path.pop() + } +}; +class TrieNode { + constructor (char) { + this.char = char + this.count = 0 + this.countPrefix = 0 + this.children = {} + } +}; +class Trie { + /** + * @description Initialize the trie + */ + constructor () { + this.trie = new TrieNode('/') + } + + /** + * @description Insert strings into the trie + * @param str the string to be inserted + * @param count number of `str` to be inserted, can be negative for deleting x from the trie + */ + insert (str, count = 1) { + let cur = this.trie + for (const char of str) { + cur.children[char] ??= new TrieNode(char) + cur = cur.children[char] + cur.countPrefix += count + } + cur.count += count + } + + /** + * Traverse the trie with a callback function + * @param str An input string + * @param callbackfn A callback function. traverse calls the callbackfn function one time for each char in `str`, however it may skip ending chars in str if the trie has no children to go deeper, the returned char from callbackfn will be used as the direction of traversing + * @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value + */ + traverse (str, callbackfn, thisArg) { + let cur = this.trie + for (let i = 0; i < str.length; i++) { + const retChar = callbackfn.call(thisArg, str[i], i, cur) + const tmp = cur.children[retChar] + if (!tmp || tmp.countPrefix <= 0) return + cur = tmp + } + } + + /** + * @description Search a string in the trie + * @returns Number of `str` in the trie + */ + count (str) { + let ans = 0 + this.traverse(str, (char, idx, node) => { + const nextNode = node.children[char] + if (idx === str.length - 1 && nextNode) { + ans = nextNode.count + } + return char + }) + return ans + } + + /** + * @description Search a string in the trie + * @returns Number of prefix of `str` in the trie + */ + countPrefix (str) { + let ans = 0 + this.traverse(str, (char, idx, node) => { + const nextNode = node.children[char] + ans += nextNode?.countPrefix ?? 0 + return char + }) + return ans + } +}; diff --git a/1952-three-divisors.js b/1952-three-divisors.js new file mode 100644 index 00000000..54dd076d --- /dev/null +++ b/1952-three-divisors.js @@ -0,0 +1,14 @@ +/** + * @param {number} n + * @return {boolean} + */ +const isThree = function(n) { + if(n == 1) return false; + let a = ~~Math.sqrt(n); + if(n != a * a) return false; + for(let i = 2; i < a; i++) { + if (n % i == 0) + return false; + } + return true; +}; diff --git a/1953-maximum-number-of-weeks-for-which-you-can-work.js b/1953-maximum-number-of-weeks-for-which-you-can-work.js new file mode 100644 index 00000000..c981ef69 --- /dev/null +++ b/1953-maximum-number-of-weeks-for-which-you-can-work.js @@ -0,0 +1,52 @@ +/** + * @param {number[]} milestones + * @return {number} + */ +const numberOfWeeks = function(milestones) { + let max = -Infinity + let res = 0, sum = 0 + for(const e of milestones) { + max = Math.max(e, max) + sum += e + } + + return Math.min(sum, (sum - max) * 2 + 1) +}; + + +// another + +/** + * @param {number[]} milestones + * @return {number} + */ +const numberOfWeeks = function(milestones) { + let sum = 0; + for (let i = 0; i < milestones.length; i++) { + sum += milestones[i]; + } + + let cantWork = 0; + for (let i = 0; i < milestones.length; i++) { + cantWork = Math.max(cantWork, milestones[i] - (sum - milestones[i]) - 1); + } + + return sum - cantWork; +}; + +// another + +/** + * @param {number[]} milestones + * @return {number} + */ +const numberOfWeeks = function(milestones) { + const max = Math.max(...milestones) + let sum = 0 + for(let i = 0; i < milestones.length; i++) { + sum += milestones[i] + } + const res = sum - max + + return Math.min(sum, res * 2 + 1) +}; diff --git a/1954-minimum-garden-perimeter-to-collect-enough-apples.js b/1954-minimum-garden-perimeter-to-collect-enough-apples.js new file mode 100644 index 00000000..13f18a9d --- /dev/null +++ b/1954-minimum-garden-perimeter-to-collect-enough-apples.js @@ -0,0 +1,18 @@ +/** + * @param {number} neededApples + * @return {number} + */ +var minimumPerimeter = function(neededApples) { + let l = 0, r = 100000; + while (l + 1 < r) { + let w = (l + r) >> 1; + let apples = 2 * w * (w + 1) * (2 * w + 1); + if (apples >= neededApples) { + r = w; + } else { + l = w; + } + } + + return r * 8; +}; diff --git a/1955-count-number-of-special-subsequences.js b/1955-count-number-of-special-subsequences.js new file mode 100644 index 00000000..8467f496 --- /dev/null +++ b/1955-count-number-of-special-subsequences.js @@ -0,0 +1,58 @@ +/* + * @lc app=leetcode id=1955 lang=javascript + * + * [1955] Count Number of Special Subsequences + */ + +// @lc code=start +/** + * @param {number[]} nums + * @return {number} + */ +const countSpecialSubsequences = function (nums) { + const dp = Array(3).fill(0), + mod = 10 ** 9 + 7 + for (let e of nums) { + dp[e] = (((dp[e] + dp[e]) % mod) + (e > 0 ? dp[e - 1] : 1)) % mod + } + return dp[2] +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const countSpecialSubsequences = function(nums) { + const mod = 10 ** 9 + 7 + const dp = Array.from({length: 10 **5 + 1}, () => Array(4).fill(-1)) + let n = nums.length, a = nums + return f(0, 0) + function f(index, firstMandatory) { + if (index == n && firstMandatory == 3) { + return 1; + } + if (index == n) { + return 0; + } + if (dp[index][firstMandatory] >= 0) { + return dp[index][firstMandatory]; + } + let result = 0; + if (a[index] == firstMandatory) { + result = (result + + f(index + 1, firstMandatory) + + f(index + 1, firstMandatory + 1) + ) % mod; + } + result = (result + f(index + 1, firstMandatory)) % mod; + + return dp[index][firstMandatory] = result; + } +}; + + + + + diff --git a/1959-minimum-total-space-wasted-with-k-resizing-operations.js b/1959-minimum-total-space-wasted-with-k-resizing-operations.js new file mode 100644 index 00000000..3529ed15 --- /dev/null +++ b/1959-minimum-total-space-wasted-with-k-resizing-operations.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minSpaceWastedKResizing = function(nums, k) { + const n = nums.length, INF = 200 * 1e6 + const memo = Array.from({length: n}, () => Array(k)) + return dp(0, k) + + function dp(i, k) { + if(i === n) return 0 + if(k < 0) return INF + if(memo[i][k] != null) return memo[i][k] + let res = INF, max = nums[i], sum = 0 + for(let j = i; j < n; j++) { + max = Math.max(max, nums[j]) + sum += nums[j] + const waste = max * (j - i + 1) - sum + res = Math.min(res, dp(j + 1, k - 1) + waste) + } + return memo[i][k] = res + } +}; diff --git a/1960-maximum-product-of-the-length-of-two-palindromic-substrings.js b/1960-maximum-product-of-the-length-of-two-palindromic-substrings.js new file mode 100644 index 00000000..7651f1eb --- /dev/null +++ b/1960-maximum-product-of-the-length-of-two-palindromic-substrings.js @@ -0,0 +1,59 @@ +/** + * @param {string} s + * @return {number} + */ +const maxProduct = function (s) { + const t1 = helper(s), + t2 = helper(reverse(s)) + let res = 0 + for (let n = s.length, i = 0, j = n - 2; i < n - 1; ++i, --j) + res = Math.max(res, t1[i] * t2[j]) + + return res +} +function reverse(s) { + return [...s].reverse().join('') +} +function helper(s) { + const man = manachers(s).filter( + (e, i, ar) => i >= 2 && i < ar.length - 2 && i % 2 === 0 + ) + const n = s.length, + { max } = Math + const ints = man.map((e, i) => [i - ~~(e / 2), i + ~~(e / 2)]) + const arr = Array(n).fill(0) + for (const [a, b] of ints) { + arr[b] = max(arr[b], b - a + 1) + } + for (let i = n - 2; i >= 0; i--) { + arr[i] = max(arr[i], arr[i + 1] - 2) + } + let tmp = 0 + for (let i = 0; i < n; i++) { + if (arr[i] > tmp) { + tmp = arr[i] + } else arr[i] = tmp + } + return arr +} +function manachers(s) { + const str = `@#${s.split('').join('#')}#$` + const arr = Array(str.length).fill(0) + + let center = 0, + right = 0 + for (let i = 1, n = str.length; i < n - 1; i++) { + if (i < right) { + arr[i] = Math.min(right - i, arr[2 * center - i]) + } + while (str[i + arr[i] + 1] === str[i - arr[i] - 1]) { + arr[i] += 1 + } + if (i + arr[i] > right) { + center = i + right = i + arr[i] + } + } + + return arr +} diff --git a/1961-check-if-string-is-a-prefix-of-array.js b/1961-check-if-string-is-a-prefix-of-array.js new file mode 100644 index 00000000..861c5bec --- /dev/null +++ b/1961-check-if-string-is-a-prefix-of-array.js @@ -0,0 +1,13 @@ +/** + * @param {string} s + * @param {string[]} words + * @return {boolean} + */ +const isPrefixString = function(s, words) { + let tmp = '' + for(let w of words) { + tmp += w + if(tmp === s) return true + } + return false +}; diff --git a/1962-remove-stones-to-minimize-the-total.js b/1962-remove-stones-to-minimize-the-total.js new file mode 100644 index 00000000..2821846c --- /dev/null +++ b/1962-remove-stones-to-minimize-the-total.js @@ -0,0 +1,87 @@ +/** + * @param {number[]} piles + * @param {number} k + * @return {number} + */ +const minStoneSum = function(piles, k) { + const pq = new PriorityQueue((a, b) => a > b) + for(let e of piles) pq.push(e) + while(k > 0) { + const tmp = pq.pop() + const e = tmp - (~~(tmp / 2)) + pq.push(e) + k-- + } + let res = 0 + while(!pq.isEmpty()) { + res += pq.pop() + } + return res +}; +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1963-minimum-number-of-swaps-to-make-the-string-balanced.js b/1963-minimum-number-of-swaps-to-make-the-string-balanced.js new file mode 100644 index 00000000..90a3793d --- /dev/null +++ b/1963-minimum-number-of-swaps-to-make-the-string-balanced.js @@ -0,0 +1,62 @@ +/** + * @param {string} s + * @return {number} + */ +const minSwaps = function(s) { + const stk = [] + for (let e of s) { + if(e === '[') stk.push(e) + else { + if(stk.length) { + stk.pop() + } else stk.push(e) + } + } + return Math.ceil(stk.length / 2) +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const minSwaps = function(s) { + const stack = [] + let num = 0 + for(let e of s) { + if(e === '[') { + stack.push(e) + num++ + } + if(e === ']') { + if(stack[stack.length - 1] === '[') { + stack.pop() + num-- + } + } + } + // console.log(num) + return Math.ceil(num / 2) +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const minSwaps = function(s) { + let num = 0 + for(let e of s) { + if(e === '[') { + num++ + } + if(e === ']') { + if(num > 0) { + num-- + } + } + } + return Math.ceil(num / 2) +}; diff --git a/1964-find-the-longest-valid-obstacle-course-at-each-position.js b/1964-find-the-longest-valid-obstacle-course-at-each-position.js new file mode 100644 index 00000000..878844f2 --- /dev/null +++ b/1964-find-the-longest-valid-obstacle-course-at-each-position.js @@ -0,0 +1,111 @@ +/** + * @param {number[]} obstacles + * @return {number[]} + */ +const longestObstacleCourseAtEachPosition = function(obstacles) { + const n = obstacles.length, res = [], stk = [] + for (let i = 0; i < n; i++) { + const cur = obstacles[i] + let idx = chk(cur) + if (idx === stk.length) { + stk.push(cur) + } else { + stk[idx] = cur + } + res.push(++idx) + } + + return res + + function chk(val) { + let l = 0, r = stk.length + while(l < r) { + const mid = ~~((l + r) / 2) + if(stk[mid] <= val) l = mid + 1 + else r = mid + } + return l + } +}; + +// another + +/** + * @param {number[]} obstacles + * @return {number[]} + */ +const longestObstacleCourseAtEachPosition = function(obstacles) { + const n = obstacles.length + const stack = [], res = [] + let len = 0 + + for(let i = 0; i < n; i++) { + const cur = obstacles[i] + const idx = chk(cur) + if(idx === len) { + stack.push(cur) + len++ + res.push(len) + }else { + stack[idx] = cur + res.push(idx + 1) + } + } + + return res + + function chk(x) { + if(len && stack[len - 1] <= x) return len + let l = 0, r = len - 1 + while(l < r) { + const mid = ~~((l + r) / 2) + if(stack[mid] <= x) { + l = mid + 1 + } else { + r = mid + } + } + return l + } +}; + + + + +// another + +/** + * @param {number[]} obstacles + * @return {number[]} + */ +const longestObstacleCourseAtEachPosition = function(obstacles) { + const n = obstacles.length + const stack = [], res = Array(n).fill(0) + let m = 0 + let j = 0; + for (let x of obstacles) { + let i = chk(x); + if (i == m) { + ++m; + stack.push(x); + } else { + stack[i] = x; + } + res[j++] = i + 1; + } + return res; + function chk(x) { + if (m && stack[m - 1] <= x) return m; + let l = 0, r = m - 1; + while (l < r) { + let m = (l + r) >> 1; + if (stack[m] > x) { + r = m; + } else { + l = m + 1; + } + } + return l; + } +}; + diff --git a/1969-minimum-non-zero-product-of-the-array-elements.js b/1969-minimum-non-zero-product-of-the-array-elements.js new file mode 100644 index 00000000..2b29dade --- /dev/null +++ b/1969-minimum-non-zero-product-of-the-array-elements.js @@ -0,0 +1,49 @@ +/** + * @param {number} p + * @return {number} + */ +const minNonZeroProduct = function (p) { + const MOD = BigInt(10 ** 9 + 7), bp = BigInt(p) + const bpm = BigInt(1n << bp) - 1n, base = BigInt(1n << bp) - 2n, pow = BigInt(1n << (bp - 1n)) - 1n + return Number((bpm % MOD) * fastPow(base, pow, MOD) % MOD) + +} + +function fastPow(base, power, mod) { + if(power === 0n) return 1n + base %= mod + let res = fastPow(base, power / 2n, mod) + res = (res * res) % mod + if(power & 1n) res = (res * base) % mod + return res +} + + +// another + + +/** + * @param {number} p + * @return {number} + */ +const minNonZeroProduct = function (p) { + const b = BigInt(p) + const mod = BigInt(10 ** 9 + 7) + + return ( + (((BigInt(1n << b) - 1n) % mod) * + pow(BigInt(1n << b) - 2n, BigInt(1n << (b - 1n)) - 1n)) % + mod + ) + + function pow(a, n) { + let r = 1n + a %= mod + while (n > 0n) { + r = (r * a) % mod + a = (a * a) % mod + n /= 2n + } + return r + } +} diff --git a/1970-last-day-where-you-can-still-cross.js b/1970-last-day-where-you-can-still-cross.js new file mode 100644 index 00000000..6ae51821 --- /dev/null +++ b/1970-last-day-where-you-can-still-cross.js @@ -0,0 +1,64 @@ +/** + * @param {number} row + * @param {number} col + * @param {number[][]} cells + * @return {number} + */ +const latestDayToCross = function (row, col, cells) { + let l = 0, + n = cells.length, + r = n + while (l < r) { + const mid = r - (~~((r - l) / 2)) + if (canWalk(mid)) { + l = mid + } else { + r = mid - 1 + } + } + + return l + 1 + + function canWalk(mid) { + const grid = Array.from({ length: row }, () => Array(col).fill(0)) + const dirs = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ] + for (let i = 0; i <= mid; i++) { + const [r, c] = cells[i] + grid[r - 1][c - 1] = 1 + } + + let q = [] + + for (let i = 0; i < col; i++) { + if (grid[0][i] === 0) { + q.push([0, i]) + grid[0][i] = 1 + } + } + + while (q.length) { + const size = q.length, + tmp = [] + for (let i = 0; i < size; i++) { + const [r, c] = q[i] + if (r === row - 1) return true + for (let [dr, dc] of dirs) { + const nr = r + dr, + nc = c + dc + if (nr < 0 || nr >= row || nc < 0 || nc >= col || grid[nr][nc] === 1) + continue + tmp.push([nr, nc]) + grid[nr][nc] = 1 + } + } + q = tmp + } + + return false + } +} diff --git a/1971-find-if-path-exists-in-graph.js b/1971-find-if-path-exists-in-graph.js new file mode 100644 index 00000000..154edce0 --- /dev/null +++ b/1971-find-if-path-exists-in-graph.js @@ -0,0 +1,29 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} start + * @param {number} end + * @return {boolean} + */ +const validPath = function(n, edges, start, end) { + const graph = {} + for(const [u, v] of edges) { + if(graph[u] == null) graph[u] = new Set() + if(graph[v] == null) graph[v] = new Set() + graph[u].add(v) + graph[v].add(u) + } + const q = [start], visited = new Set() + visited.add(start) + while(q.length) { + const cur = q.shift() + if(cur === end) return true + for(const next of graph[cur]) { + if(visited.has(next)) continue + q.push(next) + visited.add(next) + } + } + + return false +}; diff --git a/1976-number-of-ways-to-arrive-at-destination.js b/1976-number-of-ways-to-arrive-at-destination.js new file mode 100644 index 00000000..11572bdd --- /dev/null +++ b/1976-number-of-ways-to-arrive-at-destination.js @@ -0,0 +1,222 @@ +/** + * @param {number} n + * @param {number[][]} roads + * @return {number} + */ +const countPaths = function(n, roads) { + const graph = {} + for(let r of roads) { + const [u, v, t] = r + if(graph[u] == null) graph[u] = [] + if(graph[v] == null) graph[v] = [] + graph[u].push([v, t]) + graph[v].push([u, t]) + } + + return dijkstra(graph, n, 0) + + function dijkstra(graph, n, src) { + const dist = Array(n).fill(Infinity) + const ways = Array(n).fill(0), mod = 1e9 + 7 + ways[src] = 1 + dist[src] = 0 + const pq = new PriorityQueue((a, b) => a[0] === b[0] ? a[1] < b[1] : a[0] < b[0]) + pq.push([0, 0]) + while(!pq.isEmpty()) { + const [d, u] = pq.pop() + if(d > dist[u]) continue + if(graph[u] == null) graph[u] = [] + for(const [v, time] of graph[u]) { + if(dist[v] > d + time) { + ways[v] = ways[u] + dist[v] = d + time + pq.push([dist[v], v]) + } else if(dist[v] === d + time) { + ways[v] = (ways[v] + ways[u]) % mod + } + } + } + return ways[n - 1] + } + +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number} n + * @param {number[][]} roads + * @return {number} + */ +const countPaths = function(n, roads) { + const graph = {}, MOD = 1e9 + 7 + for(const [u, v, t] of roads) { + if(graph[u] == null) graph[u] = {} + if(graph[v] == null) graph[v] = {} + graph[u][v] = t + graph[v][u] = t + } + + return dijkstra(graph, n, 0) + + function dijkstra(graph, n, src) { + const dist = Array(n).fill(Infinity) + const ways = Array(n).fill(0) + ways[src] = 1 + dist[src] = 0 + const pq = new PriorityQueue((a, b) => a[0] < b[0]) + pq.push([0, 0]) + while(!pq.isEmpty()) { + const [d, u] = pq.pop() + if(d > dist[u]) continue + for(const next of Object.keys(graph[u] || {})) { + const val = graph[u][next] + if(dist[next] > d + val) { + dist[next] = d + val + ways[next] = ways[u] + pq.push([dist[next], next]) + } else if(dist[next] === d + val) { + ways[next] = (ways[next] + ways[u]) % MOD + } + } + } + + return ways[n - 1] + } +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/1977-number-of-ways-to-separate-numbers.js b/1977-number-of-ways-to-separate-numbers.js new file mode 100644 index 00000000..a9e2226b --- /dev/null +++ b/1977-number-of-ways-to-separate-numbers.js @@ -0,0 +1,32 @@ +/** + * @param {string} num + * @return {number} + */ +function numberOfCombinations(num) { + let dpArr = Array(3501).fill(0), + dp = Array(3501).fill(0), + prefix = Array(3501).fill(0), + n = num.length, + mod = 1e9 + 7 + for (let l = 1; l <= n; ++l) { + dp[0] = 1 + for (let i = n; i - l > 0; --i) + prefix[i - 1] = num[i - 1 - l] === num[i - 1] ? prefix[i] + 1 : 0 + for (let i = 0; i < n; ++i) { + dpArr[i + 1] = dp[i + 1] + if (l <= i + 1 && num[i + 1 - l] != '0') { + if ( + i + 1 - 2 * l >= 0 && + (prefix[i + 1 - l] >= l || + num[i + 1 - l + prefix[i + 1 - l]] > num[i + 1 - 2 * l + prefix[i + 1 - l]]) + ) + dpArr[i + 1] = (dpArr[i + 1] + dpArr[i + 1 - l]) % mod + else dpArr[i + 1] = (dpArr[i + 1] + dp[i + 1 - l]) % mod + } + } + const tmp = dp + dp = dpArr + dpArr = tmp + } + return dp[n] +} diff --git a/1979-find-greatest-common-divisor-of-array.js b/1979-find-greatest-common-divisor-of-array.js new file mode 100644 index 00000000..3028ce94 --- /dev/null +++ b/1979-find-greatest-common-divisor-of-array.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const findGCD = function(nums) { + let min = Math.min(...nums) + let max = Math.max(...nums) + return gcd(min, max) +}; + +function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) +} diff --git a/198-house-robber.js b/198-house-robber.js index 36203a07..17f82e5f 100644 --- a/198-house-robber.js +++ b/198-house-robber.js @@ -13,3 +13,36 @@ function rob(nums) { } return prev1; } + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const rob = function(nums) { + const n = nums.length + const dp = Array(n+1).fill(0) + dp[1] = nums[0] + + for(let i = 1; i < n; i++) { + dp[i + 1] = Math.max(dp[i], dp[i - 1] + nums[i]) + } + + return dp[n] +}; + +// another +/** + * @param {number[]} nums + * @return {number} + */ +const rob = function(nums) { + const n = nums.length + const dp = Array(n + 1).fill(0) + for(let i = 1; i <= n; i++) { + const e = nums[i - 1] + dp[i] = Math.max(dp[i - 1], (i === 1 ? 0 : dp[i - 2]) + e) + } + return dp[n] +}; diff --git a/1980-find-unique-binary-string.js b/1980-find-unique-binary-string.js new file mode 100644 index 00000000..1e24e6a6 --- /dev/null +++ b/1980-find-unique-binary-string.js @@ -0,0 +1,22 @@ +/** + * @param {string[]} nums + * @return {string} + */ +const findDifferentBinaryString = function(nums) { + const set = new Set(nums) + const len = nums[0].length + for(let i = 0, n = 1 << 17; i < n; i++) { + const tmp = pad(bin(i), len) + if(!set.has(tmp)) return tmp + } + return '' +}; + +function bin(num) { + return (num >>> 0).toString(2) +} + +function pad(str,n) { + while(str.length < n) str = '0' + str + return str +} diff --git a/1981-minimize-the-difference-between-target-and-chosen-elements.js b/1981-minimize-the-difference-between-target-and-chosen-elements.js new file mode 100644 index 00000000..f66a42de --- /dev/null +++ b/1981-minimize-the-difference-between-target-and-chosen-elements.js @@ -0,0 +1,47 @@ +/** + * @param {number[][]} mat + * @param {number} target + * @return {number} + */ +const minimizeTheDifference = function(mat, target) { + const m = mat.length, n = mat[0].length + const dp = Array.from({length: m}, () => Array(70*70).fill(-1)) + return fn(0, 0) + + function fn(row, sum) { + if(row === m) return Math.abs(target - sum) + if(dp[row][sum] !== -1) return dp[row][sum] + let res = Number.MAX_SAFE_INTEGER + for(let j = 0; j < n; j++) { + res = Math.min(res, fn(row + 1, sum + mat[row][j])) + } + return dp[row][sum] = res + } +}; + +// another + +/** + * @param {number[][]} mat + * @param {number} target + * @return {number} + */ +const minimizeTheDifference = function(mat, target) { + const m = mat.length, n = mat[0].length + const memo = Array.from({ length: m }, () => Array()) + return dfs(0, 0) + + function dfs(row, sum) { + if(row === m) return Math.abs(target - sum) + if(memo[row][sum] != null) return memo[row][sum] + let res = Number.MAX_SAFE_INTEGER + for(let i = 0; i < n; i++) { + res = Math.min(res, dfs(row + 1, sum + mat[row][i])) + } + + return memo[row][sum] = res + } +}; + + + diff --git a/1982-find-array-given-subset-sums.js b/1982-find-array-given-subset-sums.js new file mode 100644 index 00000000..ca16e18a --- /dev/null +++ b/1982-find-array-given-subset-sums.js @@ -0,0 +1,134 @@ +/** + * @param {number} n + * @param {number[]} sums + * @return {number[]} + */ +const recoverArray = function(n, sums) { + const res = [] + sums.sort((a, b) => a - b) + while(res.length < n) { + const used = Array(sums.length).fill(false) + const v0 = [], v1 = [] + let d = sums[1] - sums[0] + for(let i = 0, j = 1; ;i++, j++) { + while(i < sums.length && used[i]) i++ + if(i === sums.length) break + while(j <= i || sums[j] !== sums[i] + d) j++ + v0.push(sums[i]) + v1.push(sums[j]) + used[i] = used[j] = true + } + + if(bs(v0, 0)) { + res.push(d) + sums = v0 + }else { + res.push(-d) + sums = v1 + } + } + return res +}; + + +function bs(arr, e) { + let l = 0, r = arr.length - 1 + while(l < r) { + const mid = ~~((l + r) / 2) + if(arr[mid] < e) l = mid + 1 + else r = mid + } + + return arr[l] === e +} + +// another + +/** + * @param {number} n + * @param {number[]} sums + * @return {number[]} + */ +const recoverArray = function(n, sums) { + const res = [] + sums.sort((a, b) => a - b) + + while(res.length < n) { + const visited = Array(sums.length).fill(false) + const a1 = [], a2 = [] + const d = sums[1] - sums[0] + for(let i = 0, j = 1; i < sums.length; i++, j++) { + while(i < sums.length && visited[i]) i++ + if(i === sums.length) break + while(j <= i || sums[j] !== sums[i] + d) j++ + a1.push(sums[i]) + a2.push(sums[j]) + visited[i] = visited[j] = true + } + + if(bs(a1, 0)) { + sums = a1 + res.push(d) + } else { + sums = a2 + res.push(-d) + } + } + + return res +}; + +function bs(arr, val) { + let l = 0, r = arr.length - 1 + while(l < r) { + const mid = ~~((l + r) / 2) + if(arr[mid] < val) l = mid + 1 + else r = mid + } + + return arr[l] === val +} + +// another + +/** + * @param {number} n + * @param {number[]} sums + * @return {number[]} + */ +const recoverArray = function(n, sums) { + const res = [] + sums.sort((a, b) => a - b) + + while(res.length < n) { + const m = sums.length, visited = Array(m).fill(false) + let a1 = [], a2 = [], delta = sums[1] - sums[0] + for(let i = 0, j = 1; i < m && j < m; i++, j++) { + while(i < m && visited[i]) i++ + if(i === m) break + while(i >= j || sums[j] !== sums[i] + delta) j++ + if(j === m) break + a1.push(sums[i]) + a2.push(sums[j]) + visited[i] = visited[j] = true + } + if(binarySearch(a1, 0)) { + sums = a1 + res.push(delta) + } else { + sums = a2 + res.push(-delta) + } + } + return res + + function binarySearch(arr, val) { + let l = 0, r = arr.length - 1 + while(l < r) { + const mid = ~~((l + r) / 2) + if(arr[mid] < val) l = mid + 1 + else r = mid + } + return arr[l] === val + } +}; diff --git a/1983-widest-pair-of-indices-with-equal-range-sum.js b/1983-widest-pair-of-indices-with-equal-range-sum.js new file mode 100644 index 00000000..5b0d0233 --- /dev/null +++ b/1983-widest-pair-of-indices-with-equal-range-sum.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const widestPairOfIndices = function(nums1, nums2) { + const n = nums1.length + const diff = Array(n).fill(0) + let res = 0, sum1 = 0, sum2 = 0 + + for(let i = 0; i < n; i++) { + const cur1 = nums1[i], cur2 = nums2[i] + sum1 += cur1 + sum2 += cur2 + if(sum1 === sum2) res = i + 1 + diff[i] = sum1 - sum2 + } + const hash = {} + for(let i = 0; i < n; i++) { + const cur = diff[i] + if(hash[cur] == null) hash[cur] = i + else { + res = Math.max(res, i - hash[cur]) + } + } + + return res +}; diff --git a/1984-minimum-difference-between-highest-and-lowest-of-k-scores.js b/1984-minimum-difference-between-highest-and-lowest-of-k-scores.js new file mode 100644 index 00000000..fb38f96a --- /dev/null +++ b/1984-minimum-difference-between-highest-and-lowest-of-k-scores.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minimumDifference = function(nums, k) { + nums.sort((a, b) => a - b) + let res = Infinity + for(let i = 0, n = nums.length; i < n - k + 1; i++) { + res = Math.min(res, nums[i + k - 1] - nums[i]) + } + + return res + +}; diff --git a/1985-find-the-kth-largest-integer-in-the-array.js b/1985-find-the-kth-largest-integer-in-the-array.js new file mode 100644 index 00000000..3b542d53 --- /dev/null +++ b/1985-find-the-kth-largest-integer-in-the-array.js @@ -0,0 +1,9 @@ +/** + * @param {string[]} nums + * @param {number} k + * @return {string} + */ +const kthLargestNumber = function(nums, k) { + nums.sort((a, b) => BigInt(b) - BigInt(a) === 0n ? 0 : (BigInt(b) - BigInt(a) > 0n ? 1 : -1) ) + return nums[k - 1] +}; diff --git a/1986-minimum-number-of-work-sessions-to-finish-the-tasks.js b/1986-minimum-number-of-work-sessions-to-finish-the-tasks.js new file mode 100644 index 00000000..a3237bb6 --- /dev/null +++ b/1986-minimum-number-of-work-sessions-to-finish-the-tasks.js @@ -0,0 +1,95 @@ +/** + * @param {number[]} tasks + * @param {number} sessionTime + * @return {number} + */ +const minSessions = function(tasks, sessionTime) { + const n = tasks.length + const limit = 1 << n + + const dp = Array(limit).fill(Infinity) + dp[0] = 0 + for(let mask = 1; mask < limit; mask++) { + for(let sub = mask; sub; sub = (sub - 1) & mask) { + if(valid(sub)) { + dp[mask] = Math.min(dp[mask], dp[mask - sub] + 1) + } + } + } + + return dp[limit - 1] + + function valid(sub) { + let sum = 0 + for(let i = 0; i < 14; i++) { + if((sub >> i) & 1) sum += tasks[i] + } + + return sum <= sessionTime + } +}; + +// another + +/** + * @param {number[]} tasks + * @param {number} sessionTime + * @return {number} + */ +const minSessions = function(tasks, sessionTime) { + const n = tasks.length + const dp = Array.from({ length: 1 << 14 }, () => Array(16).fill(-1)) + return fn(0, 0) + + function fn(mask, consumed) { + if (mask === (1 << n) - 1) { + return consumed === 0 ? 0 : 1 + } + if (dp[mask][consumed] !== -1) { + return dp[mask][consumed]; + } + + let result = Number.MAX_VALUE; + if (consumed > 0) { + result = Math.min(result, 1 + fn(mask, 0)); + } + for (let i = 0; i < n; i++) { + if ((mask & (1 << i)) === 0 && consumed + tasks[i] <= sessionTime) { + result = Math.min(result, fn(mask | (1 << i), consumed + tasks[i])); + } + } + return dp[mask][consumed] = result; + } +}; + +// another + +/** + * @param {number[]} tasks + * @param {number} sessionTime + * @return {number} + */ +function minSessions(tasks, sessionTime) { + const n = tasks.length + const memo = Array.from({ length: 1 << n }, () => Array(15)) + return helper((1 << n) - 1, 0) + + function helper(mask, remain) { + if(mask === 0) return 0 + if(memo[mask][remain] != null) return memo[mask][remain] + let res = n + + for(let i = 0; i < n; i++) { + if((1 << i) & mask) { + const newMask = mask & (~(1 << i)) + if(tasks[i] <= remain) { + res = Math.min(res, helper(newMask, remain - tasks[i])) + } else { + res = Math.min(res, helper(newMask, sessionTime - tasks[i]) + 1) + } + } + } + + return memo[mask][remain] = res + } +} diff --git a/1987-number-of-unique-good-subsequences.js b/1987-number-of-unique-good-subsequences.js new file mode 100644 index 00000000..9cc21f0f --- /dev/null +++ b/1987-number-of-unique-good-subsequences.js @@ -0,0 +1,74 @@ +/** + * @param {string} binary + * @return {number} + */ +const numberOfUniqueGoodSubsequences = function (binary) { + const n = binary.length, + P = 1e9 + 7 + let first1Position = -1, + first0Position = -1 + for (let i = 0; i < binary.length; i++) { + if (binary[i] === '0' && first0Position == -1) { + first0Position = i + } + if (binary[i] === '1' && first1Position == -1) { + first1Position = i + } + if(first0Position !== -1 && first1Position !== -1) break + } + if (first1Position === -1) return 1 + if (first0Position === -1) return n + + const next0 = new Array(n).fill(0) + const next1 = new Array(n).fill(0) + let nextZero = -1, + nextOne = -1 + for (let i = binary.length - 1; i >= 0; i--) { + next0[i] = nextZero + next1[i] = nextOne + if (binary[i] === '0') { + nextZero = i + } else { + nextOne = i + } + } + const dp = new Array(n).fill(-1) + return (1 + fn(first1Position)) % P + + function fn(index) { + if (index == n) return 0 + if (dp[index] !== -1) return dp[index] + let result = 1 + if (next0[index] >= 0) { + result += fn(next0[index]) + result %= P + } + if (next1[index] >= 0) { + result += fn(next1[index]) + result %= P + } + return (dp[index] = result) + } +} + +// another + +/** + * @param {string} binary + * @return {number} + */ +const numberOfUniqueGoodSubsequences = function (binary) { + const n = binary.length, + mod = 1e9 + 7 + let hasZero = 0, ends1 = 0, ends0 = 0 + for(let ch of binary) { + if(ch === '1') { + ends1 = (ends1 + ends0 + 1) % mod + } else { + ends0 = (ends1 + ends0) % mod + hasZero = 1 + } + } + return (ends1 + ends0 + hasZero) % mod +} + diff --git a/199-binary-tree-right-side-view.js b/199-binary-tree-right-side-view.js new file mode 100644 index 00000000..7bbf5a42 --- /dev/null +++ b/199-binary-tree-right-side-view.js @@ -0,0 +1,44 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ +const rightSideView = function(root) { + if(root == null) return [] + const queue = [root] + const res = [] + while(queue.length) { + const len = queue.length + for(let i = 0; i < len; i++) { + const el = queue.shift() + if(i === len - 1) res.push(el.val) + if(el.left) queue.push(el.left) + if(el.right) queue.push(el.right) + } + } + return res +}; + +// another + +const rightSideView = function(root) { + const res = [] + const helper = function(node, level) { + if (!node) { + return + } + if (!res[level]) { + res.push(node.val) + } + helper(node.right, level + 1) + helper(node.left, level + 1) + } + helper(root, 0) + return res +} diff --git a/1991-find-the-middle-index-in-array.js b/1991-find-the-middle-index-in-array.js new file mode 100644 index 00000000..e2d5fcea --- /dev/null +++ b/1991-find-the-middle-index-in-array.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const findMiddleIndex = function(nums) { + const n = nums.length + const sum = nums.reduce((ac, e) => ac + e, 0) + + let res, leftSum = 0 + for(let i = 0; i < n; i++) { + if(leftSum === sum - leftSum - nums[i]) { + res = i + break + } + leftSum += nums[i] + } + + return res == null ? -1 : res +}; diff --git a/1994-the-number-of-good-subsets.js b/1994-the-number-of-good-subsets.js new file mode 100644 index 00000000..56f86517 --- /dev/null +++ b/1994-the-number-of-good-subsets.js @@ -0,0 +1,247 @@ +const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] +const M = 1e9 + 7 +/** + * @param {number[]} nums + * @return {number} + */ +var numberOfGoodSubsets = function (nums) { + const n = primes.length + const dp = new Array(1 << n).fill(0) + dp[0] = 1 + + const map = new Map() + for (const x of nums) { + map.set(x, (map.get(x) || 0) + 1) + } + + let count1 = 0 + for (const [x, count] of map) { + if (x === 1) continue + const encode = encoding(x) + if (encode === -1) continue + + for (let state = (1 << n) - 1; state >= 1; state--) { + if (state - encode === (state ^ encode)) { + dp[state] = (dp[state] + ((dp[state - encode] * count) % M)) % M + } + } + } + + let ret = 0 + for (let state = 1; state < 1 << n; state++) { + ret = (ret + dp[state]) % M + } + + let power2 = 1 + for (let i = 0; i < (map.get(1) || 0); i++) { + power2 = (power2 * 2) % M + } + + return mul(ret, power2) +} + +function mul(...arr) { + let res = 1n + for (const e of arr) { + res *= BigInt(e) + } + + return Number(res % BigInt(M)) +} + +function encoding(num) { + let encode = 0 + for (let i = 0; i < primes.length; i++) { + if (num % primes[i] === 0) { + encode += 1 << i + num /= primes[i] + } + if (num % primes[i] === 0) { + return -1 + } + } + return encode +} + +// another + +const M = 1e9 + 7 + +/** + * @param {number[]} nums + * @return {number} + */ +const numberOfGoodSubsets = function (nums) { + const set = new Set([ + 2, 3, 5, 6, 7, 10, 11, 13, 14, 15, 17, 19, 21, 22, 23, 26, 29, 30, + ]) + const map = new Map() + let count1 = 0 + + for (const x of nums) { + if (set.has(x)) { + map.set(x, (map.get(x) || 0) + 1) + } + if (x === 1) { + count1++ + } + } + + const n = map.size + const count = [] + const digit = [] + for (const [key, value] of map) { + digit.push(key) + count.push(value) + } + + let ret = 0 + for (let state = 1; state < 1 << n; state++) { + let flag = 1 + for (let i = 0; i < n; i++) { + if (((state >> i) & 1) === 0) continue + for (let j = i + 1; j < n; j++) { + if (((state >> j) & 1) === 0) continue + if (gcd(digit[i], digit[j]) !== 1) { + flag = 0 + break + } + } + if (flag === 0) break + } + + if (flag === 0) continue + + let ans = 1 + for (let i = 0; i < n; i++) { + if (((state >> i) & 1) === 0) continue + ans = mul(ans, count[i]) + } + ret = (ret + ans) % M + } + + ret = mul(ret, quickMul(2, count1)) + return ret +} + +function quickMul(x, N) { + if (N === 0) { + return 1 + } + const y = quickMul(x, Math.floor(N / 2)) + return N % 2 === 0 ? mul(y, y) : mul(y, y, x) +} + +function mul(...arr) { + let res = 1n + for (const e of arr) { + res *= BigInt(e) + } + + return Number(res % BigInt(M)) +} + +function gcd(a, b) { + while (b) { + ;[a, b] = [b, a % b] + } + return a +} + +// another + + +/** + * @param {number[]} nums + * @return {number} + */ +const numberOfGoodSubsets = function (nums) { + const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + const n = nums.length, + cnt = {}, + mod = BigInt(1e9 + 7) + const bm = [] + for (let num of nums) { + cnt[num] = (cnt[num] || 0n) + 1n + } + for (let i = 0; i < 31; i++) { + let tmp = 0 + for (let j = 0, m = primes.length; j < m; j++) { + const p = primes[j] + if (i % p === 0) tmp += 1 << j + } + bm[i] = tmp + } + const bad = new Set([4, 8, 9, 12, 16, 18, 20, 24, 25, 27, 28]) + const memo = {} + + function dp(mask, num) { + if (num === 1) return 1n + if (memo[mask] && memo[mask][num] != null) return memo[mask][num] + let res = dp(mask, num - 1) + if (!bad.has(num) && (mask | bm[num]) === mask) { + res += dp(mask ^ bm[num], num - 1) * (cnt[num] || 0n) + } + if (memo[mask] == null) memo[mask] = {} + return (memo[mask][num] = res % mod) + } + + return ((dp(1023, 30) - 1n) * pow(2n, cnt[1] || 0n, mod)) % mod +} + +function pow(base, exp, mod) { + if (exp === 0n) return 1n + // console.log(base, mod) + base %= mod + let res = pow(base, exp / 2n, mod) + res = (res * res) % mod + if (exp & 1n) res = (res * base) % mod + return res +} +/** + * @param {number[]} nums + * @return {number} + */ +const numberOfGoodSubsets = function (nums) { + const primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] + const n = nums.length, + cnt = {}, + mod = BigInt(1e9 + 7) + const bm = [] + for (let num of nums) { + cnt[num] = (cnt[num] || 0n) + 1n + } + for (let i = 0; i < 31; i++) { + let tmp = 0 + for (let j = 0, m = primes.length; j < m; j++) { + const p = primes[j] + if (i % p === 0) tmp += 1 << j + } + bm[i] = tmp + } + const bad = new Set([4, 8, 9, 12, 16, 18, 20, 24, 25, 27, 28]) + const memo = {} + + function dp(mask, num) { + if (num === 1) return 1n + if (memo[mask] && memo[mask][num] != null) return memo[mask][num] + let res = dp(mask, num - 1) + if (!bad.has(num) && (mask | bm[num]) === mask) { + res += dp(mask ^ bm[num], num - 1) * (cnt[num] || 0n) + } + if (memo[mask] == null) memo[mask] = {} + return (memo[mask][num] = res % mod) + } + + return ((dp(1023, 30) - 1n) * pow(2n, cnt[1] || 0n, mod)) % mod +} + +function pow(base, exp, mod) { + if (exp === 0n) return 1n + // console.log(base, mod) + base %= mod + let res = pow(base, exp / 2n, mod) + res = (res * res) % mod + if (exp & 1n) res = (res * base) % mod + return res +} diff --git a/1995-count-special-quadruplets.js b/1995-count-special-quadruplets.js new file mode 100644 index 00000000..419f45f2 --- /dev/null +++ b/1995-count-special-quadruplets.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const countQuadruplets = function(nums) { + let res = 0 + for(let a = 0, n = nums.length; a < n - 3; a++) { + for(let b = a + 1; b < n - 2; b++) { + for(let c = b + 1; c < n - 1; c++) { + for(let d = c + 1; d < n; d++) { + if(nums[a] + nums[b] + nums[c] === nums[d]) res++ + } + } + } + } + + + return res + +}; diff --git a/1996-the-number-of-weak-characters-in-the-game.js b/1996-the-number-of-weak-characters-in-the-game.js new file mode 100644 index 00000000..383d457e --- /dev/null +++ b/1996-the-number-of-weak-characters-in-the-game.js @@ -0,0 +1,96 @@ +/** + * @param {number[][]} properties + * @return {number} + */ +const numberOfWeakCharacters = function(properties) { + const props = properties, n = props.length, maxDefFromRight = Array(n) + props.sort((a, b) => a[0] - b[0]) + for(let max = 0, i = n - 1; i >= 0; i--) { + max = Math.max(max, props[i][1]) + maxDefFromRight[i] = max + } + let res = 0 + + for(let i = 0; i < n; i++) { + const cur = props[i] + let l = i, r = n + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if(props[mid][0] > props[i][0]) r = mid + else l = mid + 1 + } + + if(l < n && maxDefFromRight[l] > props[i][1]) { + res++ + } + } + + return res +}; + +// another + +/** + * @param {number[][]} properties + * @return {number} + */ +const numberOfWeakCharacters = function(properties) { + properties.sort((a, b) => a[0] - b[0] || b[1] - a[1]) + let stack = [], res = 0 + + for(let i = 0, n = properties.length; i < n; i++) { + while(stack.length && stack[stack.length - 1] < properties[i][1]) { + stack.pop() + res++ + } + stack.push(properties[i][1]) + } + + return res +}; + +// another + +/** + * @param {number[][]} properties + * @return {number} + */ +const numberOfWeakCharacters = function(properties) { + if (properties == null || properties.length == 0) { + return 0; + } + properties.sort((o1, o2) => { + if (o1[0] == o2[0]) { + return o1[1] - o2[1]; + } + return o1[0] - o2[0]; + }); + const { max } = Math + let mmax = Array(1e5 + 10).fill( 0); + let ans = 0; + let n = properties.length; + for (let i = n - 1; i >= 0; i--) mmax[properties[i][0]] = max(properties[i][1], mmax[properties[i][0]]); + for (let i = 1e5; i >= 1; i--) mmax[i] = max(mmax[i], mmax[i + 1]); + for (let i = 0; i < n; i++) { + if (mmax[properties[i][0] + 1] > properties[i][1]) ans++; + } + return ans; +}; + +// another + +/** + * @param {number[][]} properties + * @return {number} + */ +const numberOfWeakCharacters = function(properties) { + properties.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]) + let max = -Infinity, res = 0 + for(let n = properties.length, i = n - 1; i >= 0; i--) { + const [a, d] = properties[i] + if(d < max) res++ + max = Math.max(max, d) + } + + return res +}; diff --git a/1997-first-day-where-you-have-been-in-all-the-rooms.js b/1997-first-day-where-you-have-been-in-all-the-rooms.js new file mode 100644 index 00000000..8b503fdd --- /dev/null +++ b/1997-first-day-where-you-have-been-in-all-the-rooms.js @@ -0,0 +1,36 @@ +/** + * @param {number[]} nextVisit + * @return {number} + */ +const firstDayBeenInAllRooms = function(nextVisit) { + const P = 1e9+7; + const n = nextVisit.length; + const f = Array(n).fill(0) ; + f[0] = 0; + + for (let i = 1; i < n; i++) { + f[i] = (( + (2 * f[i - 1]) % P + + P - f[nextVisit[i - 1]]) % P + 2) % P; + } + + return f[n - 1]; +}; + +// another + +/** + * @param {number[]} nextVisit + * @return {number} + */ +const firstDayBeenInAllRooms = function(nextVisit) { + const mod = 1e9 + 7 + const n = nextVisit.length + const dp = Array(n).fill(0) + for(let i = 1; i < n; i++) { + // i - 1 ---> nextVisit[i - 1] ---> i - 1 ---> i + dp[i] = (dp[i - 1] + 1 + dp[i - 1] - dp[nextVisit[i - 1]] + 1 + mod) % mod + } + + return dp[n - 1] +}; diff --git a/1998-gcd-sort-of-an-array.js b/1998-gcd-sort-of-an-array.js new file mode 100644 index 00000000..68ecd546 --- /dev/null +++ b/1998-gcd-sort-of-an-array.js @@ -0,0 +1,133 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +const gcdSort = function(nums) { + const n = nums.length + const maxNum = Math.max(...nums); + const spf = sieve(maxNum); + + const uf = new UnionFind(maxNum + 1) + for(const e of nums) { + for(const f of getFactors(e)) uf.union(e, f) + } + const clone = nums.slice() + clone.sort((a, b) => a - b) + + for(let i = 0; i < n; i++) { + if(uf.find(nums[i]) !== uf.find(clone[i])) return false + } + + return true + + function sieve(n) { // O(Nlog(logN)) ~ O(N) + const res = [0, 0] + for (let i = 2; i <= n; ++i) res[i] = i; + for (let i = 2; i * i <= n; i++) { + if (res[i] != i) continue; // skip if `i` is not a prime number + for (let j = i * i; j <= n; j += i) { + if (res[j] == j) { // marking spf[j] if it is not previously marked + res[j] = i; + } + } + } + return res + } + + function getFactors(n) { // O(logN) + const factors = []; + while (n > 1) { + factors.push(spf[n]); + n = ~~(n /spf[n]); + } + return factors; + } +}; + +function gcd( x, y) { + return y == 0 ? x : gcd(y, x % y); +} + +class UnionFind { + constructor(n) { + this.parent = []; + for (let i = 0; i < n; i++) this.parent[i] = i; + } + find(x) { + if (x == this.parent[x]) return x; + return this.parent[x] = this.find(this.parent[x]); // Path compression + } + union(u, v) { + let pu = this.find(u), pv = this.find(v); + if (pu != pv) this.parent[pu] = pv; + } +}; + +// another + +/** + * @param {number[]} nums + * @return {boolean} + */ +const gcdSort = function(nums) { + const spf = Array(nums.length).fill(0) + let maxNum = Math.max(...nums); + sieve(maxNum); + + const uf = new UnionFind(maxNum+1); + for (let x of nums) { + for (let f of getFactors(x)) uf.union(f, x); + } + + + const sortedArr = nums.slice(); + sortedArr.sort((a, b) => a - b) + + for (let i = 0; i < nums.length; ++i) { + let pu = uf.find(sortedArr[i]); + let pv = uf.find(nums[i]); + if (pu != pv) return false; // can't swap nums[i] with sortedArr[i] + } + return true; + + function sieve( n) { // O(Nlog(logN)) ~ O(N) + for (let i = 2; i <= n; ++i) spf[i] = i; + for (let i = 2; i * i <= n; i++) { + if (spf[i] != i) continue; // skip if `i` is not a prime number + for (let j = i * i; j <= n; j += i) { + if (spf[j] == j) { // marking spf[j] if it is not previously marked + spf[j] = i; + } + } + } + } + + function getFactors(n) { // O(logN) + const factors = []; + while (n > 1) { + factors.push(spf[n]); + n = ~~(n /spf[n]); + } + return factors; + } +}; + +function gcd( x, y) { + return y == 0 ? x : gcd(y, x % y); +} + +class UnionFind { + constructor(n) { + this.parent = []; + for (let i = 0; i < n; i++) this.parent[i] = i; + } + find(x) { + if (x == this.parent[x]) return x; + return this.parent[x] = this.find(this.parent[x]); // Path compression + } + union( u, v) { + let pu = this.find(u), pv = this.find(v); + if (pu != pv) this.parent[pu] = pv; + } +}; + diff --git a/2-add-two-numbers.js b/2-add-two-numbers.js index eb448263..06f99a30 100755 --- a/2-add-two-numbers.js +++ b/2-add-two-numbers.js @@ -1,3 +1,34 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +const addTwoNumbers = function(l1, l2) { + let res = new ListNode(null) + let inc = false + let cur = res + while(l1 || l2 || inc) { + const tmp = ((l1 && l1.val) || 0) + ((l2 && l2.val) || 0) + (inc ? 1 : 0) + if(tmp >= 10) inc = true + else inc = false + cur.next = new ListNode(tmp % 10) + cur = cur.next + if(l1) l1 = l1.next + if(l2) l2 = l2.next + } + + return res.next +}; + +// another + /** * Definition for singly-linked list. * function ListNode(val) { @@ -45,3 +76,86 @@ function single(l1, l2, res) { } } } + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +const addTwoNumbers = function(l1, l2) { + let extra = false + const dummy = new ListNode() + let cur = dummy + while(l1 || l2) { + let val = 0 + if(l1) val += l1.val + if(l2) val += l2.val + if(extra) val += 1 + + if(val > 9) { + extra = true + val = val % 10 + } else { + extra = false + } + cur.next = new ListNode(val) + cur = cur.next + if(l1) l1 = l1.next + if(l2) l2 = l2.next + } + + if(extra) cur.next = new ListNode(1) + return dummy.next +}; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +const addTwoNumbers = function(l1, l2) { + const dummy = new ListNode(null) + let cur = dummy, carry = 0 + + while(l1 || l2) { + let v = 0 + if(l1 && l2) { + v = l1.val + l2.val + carry + l1 = l1.next + l2 = l2.next + } else { + const node = l1 || l2 + v = node.val + carry + if(l1) l1 = l1.next + if(l2) l2 = l2.next + } + + cur.next = new ListNode(v % 10) + cur = cur.next + if(v >= 10) carry = 1 + else carry = 0 + } + + if(carry) cur.next = new ListNode(1) + + return dummy.next +}; + diff --git a/20-valid-parentheses.js b/20-valid-parentheses.js index f05cb320..c9065a42 100755 --- a/20-valid-parentheses.js +++ b/20-valid-parentheses.js @@ -1,3 +1,48 @@ +/** + * @param {string} s + * @return {boolean} + */ + const isValid = function(s) { + const stack = [] + for(let c of s) { + if(c === '(') stack.push(')') + else if(c === '{') stack.push('}') + else if(c === '[') stack.push(']') + else if(stack.length === 0 || c !== stack.pop()) return false + } + return stack.length === 0 +}; + + +// another + +/** + * @param {string} s + * @return {boolean} + */ + const isValid = function(s) { + const stack = [] + const n = s.length + for(let c of s) { + if(c === '(' || c === '{' || c === '[') stack.push(c) + else if(c === ')') { + if(stack[stack.length - 1] === '(') stack.pop() + else return false + } + else if(c === '}') { + if(stack[stack.length - 1] === '{') stack.pop() + else return false + } + else if(c === ']') { + if(stack[stack.length - 1] === '[') stack.pop() + else return false + } + } + return stack.length === 0 +}; + +// another + /** * @param {string} s * @return {boolean} diff --git a/2000-reverse-prefix-of-word.js b/2000-reverse-prefix-of-word.js new file mode 100644 index 00000000..3553e662 --- /dev/null +++ b/2000-reverse-prefix-of-word.js @@ -0,0 +1,21 @@ +/** + * @param {string} word + * @param {character} ch + * @return {string} + */ +const reversePrefix = function(word, ch) { + const arr = word.split('') + let idx = -1 + for(let i = 0; i < arr.length; i++) { + if(arr[i] === ch) { + idx = i + break + } + } + if(idx !== -1) { + const pre = arr.slice(0, idx + 1) + const remain = arr.slice(idx + 1) + return pre.reverse().concat(remain).join('') + } + return word +}; diff --git a/2001-number-of-pairs-of-interchangeable-rectangles.js b/2001-number-of-pairs-of-interchangeable-rectangles.js new file mode 100644 index 00000000..bd69e8ad --- /dev/null +++ b/2001-number-of-pairs-of-interchangeable-rectangles.js @@ -0,0 +1,17 @@ +/** + * @param {number[][]} rectangles + * @return {number} + */ +const interchangeableRectangles = function(rectangles) { + const count = new Map() + + for (const [w, h] of rectangles) { + count.set( w / h, 1 + (count.get( w / h) || 0)) + } + + let res = 0 + for (let c of count.values()) { + if(c > 1) res += ((c * (c - 1)) / 2) + } + return res +}; diff --git a/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js b/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js new file mode 100644 index 00000000..49a6f516 --- /dev/null +++ b/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js @@ -0,0 +1,116 @@ +/** + * @param {string} s + * @return {number} + */ +const maxProduct = function(s) { + const n = s.length + const limit = (1 << n) - 1 + let res = 0 + for(let mask = 1; mask < limit; mask++) { + res = Math.max(res, lp(mask) * lp(limit - mask)) + } + return res + + function lp(state) { + if(state === 0) return 0 + const str = [] + let idx = 0 + // console.log((state)) + while(idx < s.length) { + // console.log((state >>> 0).toString(2)) + if((state >> idx) & 1) str.push(s[s.length - 1 - idx]) + idx++ + } + // console.log(str) + const len = str.length + const dp = Array.from({ length: len }, () => Array(len).fill(0)) + for(let i = 0; i < len; i++) dp[i][i] = 1 + + for(let length = 2; length <= len; length++) { + for(let i = 0; i + length - 1 < len; i++) { + const j = i + length - 1 + if(str[i] === str[j]) dp[i][j] = dp[i + 1][j - 1] + 2 + else dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]) + } + } + + // console.log(dp, len) + return dp[0][len - 1] + } +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +var maxProduct = function(s) { + const n = s.length; + let max = 0; + for (let i = 0; i < (1 << n); i++) { + let n0 = palindromic(i, s, true); + if (n0 === 0) continue; + for (let j = 0; j < (1 << n); j++) { + if ((i & j) > 0) continue; + max = Math.max(palindromic(j, s) * n0, max); + } + } + return max; +}; +function palindromic( i, s) { + const n = s.length; + let sub = ""; + for (let x = 0; x < n; x++) { + if (i & (1 << x)) sub += s[x] + } + let len = sub.length; + for (let i = 0; i < len; i++) { + if (sub[i] !== sub[len - i - 1]) return 0; + } + return len; +} + +// another + +/** + * @param {string} s + * @return {number} + */ +const maxProduct = function(s) { + const s1 = [], s2 = [], n = s.length + let res = 0 + dfs(0) + return res + + function dfs(idx) { + if(idx === n) { + if(isPalindromic(s1) && isPalindromic(s2)) { + res = Math.max(res, s1.length * s2.length) + } + return + } + const ch = s[idx] + s1.push(ch) + dfs(idx + 1) + s1.pop() + + s2.push(ch) + dfs(idx + 1) + s2.pop() + + dfs(idx + 1) + } + function isPalindromic(arr) { + let l = 0, r = arr.length - 1 + while(l < r) { + if(arr[l] === arr[r]) { + l++ + r-- + } else { + return false + } + } + return true + } +}; diff --git a/2003-smallest-missing-genetic-value-in-each-subtree.js b/2003-smallest-missing-genetic-value-in-each-subtree.js new file mode 100644 index 00000000..0089f20a --- /dev/null +++ b/2003-smallest-missing-genetic-value-in-each-subtree.js @@ -0,0 +1,94 @@ +/** + * @param {number[]} parents + * @param {number[]} nums + * @return {number[]} + */ +function smallestMissingValueSubtree(parent, nums) { + const graph = {}, + n = parent.length + const res = Array(n).fill(1) + const visited = new Set() + let miss = 1 + for (let i = 0; i < n; i++) { + if (graph[parent[i]] == null) graph[parent[i]] = [] + graph[parent[i]].push(i) + } + let idx = -1 + for (let i = 0; i < n; i++) { + if (nums[i] === 1) { + idx = i + break + } + } + + if (idx === -1) return res + let cur = idx, + pre = -1 + while (cur !== -1) { + const chidlren = graph[cur] + if (chidlren) { + for (const child of chidlren) { + if (child === pre) continue + dfs(child) + } + } + visited.add(nums[cur]) + while (visited.has(miss)) { + miss++ + } + // console.log(cur, miss, visited) + res[cur] = miss + pre = cur + cur = parent[cur] + } + + return res + + function dfs(node) { + visited.add(nums[node]) + const chidlren = graph[node] + if (chidlren) { + for (const child of chidlren) dfs(child) + } + } +} + +// another + + +/** + * @param {number[]} parents + * @param {number[]} nums + * @return {number[]} + */ +const smallestMissingValueSubtree = function(parents, nums) { + let n = parents.length; + const ans = new Array(n).fill(0); + const fn = new Array(100010).fill(0); + const tree = []; + const nums1 = nums; + for(let idx=0;idxrec && fn[pos]<=nodeIdx) { + pos++; + } + ans[root] = pos; + return pos; + } +}; + diff --git a/2006-count-number-of-pairs-with-absolute-difference-k.js b/2006-count-number-of-pairs-with-absolute-difference-k.js new file mode 100644 index 00000000..30302a8c --- /dev/null +++ b/2006-count-number-of-pairs-with-absolute-difference-k.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countKDifference = function(nums, k) { + const hash = {} + let res = 0 + for(let i = 0; i < nums.length; i++) { + const cur = nums[i] + if(hash[cur + k]) res += hash[cur + k] + if(hash[cur - k]) res += hash[cur - k] + + if(hash[cur] == null) hash[cur] = 0 + hash[cur]++ + } + return res +}; diff --git a/2007-find-original-array-from-doubled-array.js b/2007-find-original-array-from-doubled-array.js new file mode 100644 index 00000000..89e270d2 --- /dev/null +++ b/2007-find-original-array-from-doubled-array.js @@ -0,0 +1,53 @@ +/** + * @param {number[]} changed + * @return {number[]} + */ + const findOriginalArray = function(changed) { + const n = changed.length, res = [], { abs } = Math + if(n % 2 === 1 || n === 0) return res + const hash = {} + for(let e of changed) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + const keys = Object.keys(hash) + keys.sort((a, b) => abs(a) - abs(b)) + + for(let k of keys) { + if(hash[k] > (hash[k * 2] || 0)) return [] + for(let i = 0; i < hash[k]; i++) { + res.push(k) + hash[2 * k]-- + } + } + + return res +}; + +// another + +/** + * @param {number[]} changed + * @return {number[]} + */ + const findOriginalArray = function(changed) { + const n = changed.length, res = [] + if(n % 2 === 1 || n === 0) return res + const hash = {} + for(let e of changed) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + changed.sort((a, b) => a - b) + + for(let i = 0, len = n; i < len; i++) { + const cur = changed[i], dVal = cur * 2 + if (cur === 0 && hash[cur] % 2 === 1) continue + if(hash[dVal] && hash[cur]) { + res.push(cur) + hash[dVal]-- + hash[cur]-- + } + } + return res.length === n / 2 ? res : [] +}; diff --git a/2008-maximum-earnings-from-taxi.js b/2008-maximum-earnings-from-taxi.js new file mode 100644 index 00000000..eb4fb356 --- /dev/null +++ b/2008-maximum-earnings-from-taxi.js @@ -0,0 +1,52 @@ +/** + * @param {number} n + * @param {number[][]} rides + * @return {number} + */ +const maxTaxiEarnings = function(n, rides) { + const { max } = Math + const rideStartAt = Array.from({length: n}, () => []); + for (let ride of rides) { + let s = ride[0], e = ride[1], t = ride[2]; + rideStartAt[s].push([e, e - s + t]); // [end, dollar] + } + const dp = Array(n+1).fill(0); + for (let i = n-1; i >= 1; --i) { + for (let [e, d] of rideStartAt[i]) { + dp[i] = max(dp[i], dp[e] + d); + } + dp[i] = max(dp[i], dp[i + 1]); + } + return dp[1]; +}; + +// another + +/** + * @param {number} n + * @param {number[][]} rides + * @return {number} + */ +const maxTaxiEarnings = function(n, rides) { + const size = rides.length + rides.sort((a, b) => a[1] - b[1]) + const dp = [[0,0]] + for(const [s, e, t] of rides) { + const cur = bs(dp, s) + (e - s + t) + if(cur > dp[dp.length - 1][1]) { + dp.push([e, cur]) + } + } + return dp[dp.length - 1][1] + + function bs(arr, t) { + let l = 0, r = arr.length - 1 + while(l < r) { + const mid = r - ((r - l) >> 1) + if(arr[mid][0] > t) r = mid - 1 + else l = mid + } + // console.log(arr, t, l) + return arr[l][1] + } +}; diff --git a/2009-minimum-number-of-operations-to-make-array-continuous.js b/2009-minimum-number-of-operations-to-make-array-continuous.js new file mode 100644 index 00000000..4595f1b3 --- /dev/null +++ b/2009-minimum-number-of-operations-to-make-array-continuous.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minOperations = function(nums) { + const N = nums.length; + if(N === 1) return 0; + nums.sort((a, b) => a - b) + let M = 1; + for(let i = 1; i < N; i++) { + if(nums[i] != nums[i-1]) nums[M++] = nums[i]; + } + + let j = 0; + let res = N; + for(let i = 0; i < M; i++) { + // let `j` point to the first element that is out of range -- `> nums[i] + N - 1`. + while(j < M && nums[j] <= N + nums[i] - 1) j++; + // The length of this subarray is `j - i`. + // We need to replace `N - (j - i)` elements to make it continuous. + res = Math.min(res, N - (j - i)); + } + + return res; +}; diff --git a/201-bitwise-and-of-numbers-range.js b/201-bitwise-and-of-numbers-range.js index ab7ee841..7ab808b4 100644 --- a/201-bitwise-and-of-numbers-range.js +++ b/201-bitwise-and-of-numbers-range.js @@ -7,3 +7,20 @@ const rangeBitwiseAnd = function(m, n) { while(m>= 1 + n >>= 1 + s++ + } + return m << s +}; diff --git a/2011-final-value-of-variable-after-performing-operations.js b/2011-final-value-of-variable-after-performing-operations.js new file mode 100644 index 00000000..300d15a4 --- /dev/null +++ b/2011-final-value-of-variable-after-performing-operations.js @@ -0,0 +1,13 @@ +/** + * @param {string[]} operations + * @return {number} + */ +const finalValueAfterOperations = function(operations) { + let res = 0 + for(let op of operations) { + if(op.indexOf('++') !== -1) res++ + else res-- + } + + return res +}; diff --git a/2012-sum-of-beauty-in-the-array.js b/2012-sum-of-beauty-in-the-array.js new file mode 100644 index 00000000..62f7b28b --- /dev/null +++ b/2012-sum-of-beauty-in-the-array.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const sumOfBeauties = function(nums) { + const n = nums.length + const maxArr = Array(n).fill(0), minArr = Array(n).fill(0) + let max = -Infinity, min = Infinity + for(let i = 0; i < n; i++) { + const tmp = Math.max(max, nums[i]) + if(tmp > max) max = tmp + maxArr[i] = max + } + + for(let i = n - 1; i >= 0; i--) { + const tmp = Math.min(min, nums[i]) + if(tmp < min) min = tmp + minArr[i] = min + } + let res = 0 + + for(let i = 1; i < n - 1; i++) { + if(nums[i] > maxArr[i - 1] && nums[i] < minArr[i + 1]) res += 2 + else if(nums[i] > nums[i - 1] && nums[i] < nums[i + 1]) res += 1 + } + + return res +}; diff --git a/2013-detect-squares.js b/2013-detect-squares.js new file mode 100644 index 00000000..4efeefa0 --- /dev/null +++ b/2013-detect-squares.js @@ -0,0 +1,175 @@ + +var DetectSquares = function() { + this.mat = Array.from({length: 1001}, () => Array.from({length: 1001}, () => 0)); + this.ya = new Map() +}; + +/** + * @param {number[]} point + * @return {void} + */ +DetectSquares.prototype.add = function(point) { + const [x, y] = point; + this.mat[x][y]++; + if(this.ya.get(y) == null) this.ya.set(y, new Map()) + if(this.ya.get(y).get(x) == null) this.ya.get(y).set(x, 0) + this.ya.get(y).set(x, this.ya.get(y).get(x) + 1) +}; + +/** + * @param {number[]} point + * @return {number} + */ +DetectSquares.prototype.count = function(point) { + const [x, y] = point; + let res = 0 + if(!this.ya.has(y)) return res + for(const [key, cnt] of this.ya.get(y)) { + const i = +key + const d = Math.abs(x - i) + if(d === 0) continue + let j = y + d + if(j >= 0 && j < 1001) { + res += cnt * this.mat[x][j] * this.mat[i][j] + } + j = y - d + if(j >= 0 && j < 1001) { + res += cnt * this.mat[x][j] * this.mat[i][j] + } + } + + return res +}; + +/** + * Your DetectSquares object will be instantiated and called as such: + * var obj = new DetectSquares() + * obj.add(point) + * var param_2 = obj.count(point) + */ + +// another + + + +const DetectSquares = function() { + this.pts = [] + this.ptsCnt = {} +}; + +/** + * @param {number[]} point + * @return {void} + */ +DetectSquares.prototype.add = function(point) { + this.pts.push(point) + const key = `${point[0]},${point[1]}` + this.ptsCnt[key] = (this.ptsCnt[key] || 0) + 1 +}; + +/** + * @param {number[]} point + * @return {number} + */ +DetectSquares.prototype.count = function(point) { + let res = 0 + const [px, py] = point + for(const [x, y] of this.pts) { + if(px === x || py === y || Math.abs(px - x) !== Math.abs(py - y)) { + continue + } + res += (this.ptsCnt[`${px},${y}`] || 0) * (this.ptsCnt[`${x},${py}`] || 0) + } + + return res +}; + +/** + * Your DetectSquares object will be instantiated and called as such: + * var obj = new DetectSquares() + * obj.add(point) + * var param_2 = obj.count(point) + */ + + +// another + +var DetectSquares = function() { + this.xMap = new Map(); + this.yMap = new Map(); +}; + +/** + * @param {number[]} point + * @return {void} + */ +DetectSquares.prototype.add = function(point) { + const [ x, y ] = point; + + // X-map + if (this.xMap.has(x)) { + const xMap = this.xMap.get(x); + + if (xMap.has(y)) { + xMap.set(y, xMap.get(y) + 1); + } else { + xMap.set(y, 1); + } + } else { + const countMap = new Map(); + countMap.set(y, 1); + this.xMap.set(x, countMap); + } + + // Y-map + if (this.yMap.has(y)) { + const yMap = this.yMap.get(y); + + if (yMap.has(x)) { + yMap.set(x, yMap.get(x) + 1); + } else { + yMap.set(x, 1); + } + } else { + const countMap = new Map(); + countMap.set(x, 1); + this.yMap.set(y, countMap); + } +}; + +/** + * @param {number[]} point + * @return {number} + */ +DetectSquares.prototype.count = function(point) { + const [ x, y ] = point; + let ans = 0; + + if (this.xMap.has(x) && this.yMap.has(y)) { + for (const y2 of this.xMap.get(x).keys()) { + if (y === y2) { + continue; + } + + // Find parallel + const sideLen = Math.abs(y - y2); + const possibleX = [ x - sideLen, x + sideLen]; + + for (const px of possibleX) { + if (this.yMap.get(y).has(px) && this.xMap.has(px) && this.xMap.get(px).has(y2)) { + ans += this.xMap.get(x).get(y2) * this.yMap.get(y).get(px) + * this.xMap.get(px).get(y2); + } + } + } + } + + return ans; +}; + +/** + * Your DetectSquares object will be instantiated and called as such: + * var obj = new DetectSquares() + * obj.add(point) + * var param_2 = obj.count(point) + */ diff --git a/2014-longest-subsequence-repeated-k-times.js b/2014-longest-subsequence-repeated-k-times.js new file mode 100644 index 00000000..57941aba --- /dev/null +++ b/2014-longest-subsequence-repeated-k-times.js @@ -0,0 +1,133 @@ +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const longestSubsequenceRepeatedK = function(s, k) { + const n = s.length, a = 'a'.charCodeAt(0) + + let res = '' + const q = [''] + + while(q.length) { + const size = q.length + for(let i = 0; i < size; i++) { + const cur = q.shift() + for(let j = 0; j < 26; j++) { + const next = cur + String.fromCharCode(a + j) + if(isSub(s, next, k)) { + res = next + q.push(next) + } + } + + } + } + + return res + + + function isSub(s, p, k) { + let repeated = 0 + for(let i = 0, j = 0, n = s.length, m = p.length; i < n; i++) { + if(s[i] === p[j]) { + j++ + if(j === m) { + repeated++ + j = 0 + if(repeated === k) { + return true + } + } + } + } + + return false + } +}; + +// another + +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +var longestSubsequenceRepeatedK = function(s, k) { + // Max length of the subsequence can be determined by the length of the string and k + const maxLen = Math.floor(s.length / k); + + // Find all possible characters that can appear in the subsequence (characters must appear at + // least k times in s) + const charCount = new Map(); + const possibleChars = [] + + for (const char of s) { + if (charCount.has(char)) { + charCount.set(char, charCount.get(char) + 1); + } else { + charCount.set(char, 1); + } + } + + for (const char of charCount.keys()) { + if (charCount.get(char) >= k) { + possibleChars.push(char); + } + } + + // Test possibilities + let ans = ""; + dfs(""); + + return ans; + + // Recursive function, tests if the given subsequence repeats k times in s + function dfs(seq) { + // Does not have enough repeats, return + if (countRepeats(seq) < k) { + return; + } + + // Update our answer if the new subsequence is better + if (seq.length > ans.length || (seq.length === ans.length && seq > ans)) { + ans = seq; + } + + // Append possible characters to the subsequence and test again + if (seq.length < maxLen) { + for (const char of possibleChars) { + dfs(seq + char); + } + } + } + + // Counts the number of times the given subsequence repeats in s (up to k) + function countRepeats(seq) { + + // Empty string, return k + if (!seq) { + return k; + } + + let repeats = 0; + let seqIdx = 0; + + for (const char of s) { + if (char === seq[seqIdx]) { + seqIdx += 1; + + if (seqIdx >= seq.length) { + seqIdx = 0; + repeats += 1; + + if (repeats >= k) { + break; + } + } + } + } + + return repeats; + } +}; diff --git a/2015-average-height-of-buildings-in-each-segment.js b/2015-average-height-of-buildings-in-each-segment.js new file mode 100644 index 00000000..c58a3b4f --- /dev/null +++ b/2015-average-height-of-buildings-in-each-segment.js @@ -0,0 +1,36 @@ +/** + * @param {number[][]} buildings + * @return {number[][]} + */ +const averageHeightOfBuildings = function(buildings) { + const hash = {}, cnt = {} + for(const [s, e, h] of buildings) { + if(hash[s] == null) hash[s] = 0 + if(hash[e] == null) hash[e] = 0 + if(cnt[s] == null) cnt[s] = 0 + if(cnt[e] == null) cnt[e] = 0 + hash[s] += h + hash[e] -= h + cnt[s]++ + cnt[e]-- + } + + const res = [] + const keys = Object.keys(hash).map(e => +e) + keys.sort((a, b) => a - b) + let h = 0, c = 0 + for(const k of keys) { + if(h) res[res.length - 1][1] = k + h += hash[k] + c += cnt[k] + const avg = ~~(h / c) + if(h && ( + res.length === 0 || + res[res.length - 1][1] !== k || + res[res.length - 1][2] !== avg + )) { + res.push([k, k, avg]) + } + } + return res +}; diff --git a/2018-check-if-word-can-be-placed-in-crossword.js b/2018-check-if-word-can-be-placed-in-crossword.js new file mode 100644 index 00000000..059c6731 --- /dev/null +++ b/2018-check-if-word-can-be-placed-in-crossword.js @@ -0,0 +1,33 @@ +/** + * @param {character[][]} board + * @param {string} word + * @return {boolean} + */ +const placeWordInCrossword = function(board, word) { + for (let state of [board, getRotated(board)]) + for (let chars of state) + for (let token of chars.join('').split("#")) + for (let letters of [word, word.split('').reverse().join('')]) + if (letters.length == token.length) + if (canFit(letters, token)) + return true; + return false; +} + +function getRotated(board) { + const m = board.length; + const n = board[0].length; + + const rotated = Array.from({length: n}, () => Array(m)); + for (let i = 0; i < m; ++i) + for (let j = 0; j < n; ++j) + rotated[j][i] = board[i][j]; + return rotated; +} + +function canFit(letters, token) { + for (let i = 0; i < letters.length; ++i) + if (token.charAt(i) != ' ' && token.charAt(i) != letters.charAt(i)) + return false; + return true; +} diff --git a/2019-the-score-of-students-solving-math-expression.js b/2019-the-score-of-students-solving-math-expression.js new file mode 100644 index 00000000..9dee9e18 --- /dev/null +++ b/2019-the-score-of-students-solving-math-expression.js @@ -0,0 +1,43 @@ +/** + * @param {string} s + * @param {number[]} answers + * @return {number} + */ +const op = { + '+': ((a, b) => Number(a) + Number(b)), + '*':((a, b) => a * b), +} +let dp = {}; +const dfs = (s) => { + if(s.length == 0) return {}; + if(s.length == 1) return { [s[0]] : 1}; + const dps = dp[s]; + if(dps) return dps; + const res = {}; + for(let i = 0; i < s.length - 2; i += 2) { + const l = dfs(s.substr(0, i + 1)) + const r = dfs(s.substr(i + 2, s.length - i - 2)); + for(let x in l) { + for(let y in r) { + const z = op[s[i + 1]](x, y); + if(z > 1000) continue; + res[z] = 1; + } + } + + } + dp[s] = res; + return res; +} + +const scoreOfStudents = function(s, answers) { + const correct = eval(s); + dp = {}; + const allAns = dfs(s); + let ans = 0; + answers.forEach(x => { + if( x == correct) ans += 5; + else if(allAns[x]) ans += 2; + }) + return ans; +}; diff --git a/2023-number-of-pairs-of-strings-with-concatenation-equal-to-target.js b/2023-number-of-pairs-of-strings-with-concatenation-equal-to-target.js new file mode 100644 index 00000000..89b09319 --- /dev/null +++ b/2023-number-of-pairs-of-strings-with-concatenation-equal-to-target.js @@ -0,0 +1,17 @@ +/** + * @param {string[]} nums + * @param {string} target + * @return {number} + */ +const numOfPairs = function(nums, target) { + let res = 0 + + const n = nums.length + for(let i = 0; i < n; i++) { + for(let j = 0; j < n; j++) { + if(i !== j && nums[i] + nums[j] === target) res++ + } + } + + return res +}; diff --git a/2024-maximize-the-confusion-of-an-exam.js b/2024-maximize-the-confusion-of-an-exam.js new file mode 100644 index 00000000..a181942c --- /dev/null +++ b/2024-maximize-the-confusion-of-an-exam.js @@ -0,0 +1,50 @@ +/** + * @param {string} answerKey + * @param {number} k + * @return {number} + */ +const maxConsecutiveAnswers = function(answerKey, k) { + const helper = (str, transT) => { + let res = 0, l = 0, r = 0, num = 0 + const n = str.length + const target = transT === 1 ? 'T' : 'F' + while(r < n) { + if(str[r] === target) num++ + while(num > k) { + if(str[l] === target) num-- + l++ + } + res = Math.max(res, r - l + 1) + r++ + } + return res + } + + return Math.max(helper(answerKey, 0), helper(answerKey, 1)) +}; + +// another + +/** + * @param {string} answerKey + * @param {number} k + * @return {number} + */ +const maxConsecutiveAnswers = function(answerKey, k) { + let s = answerKey + const freq = Array(26).fill(0), n = s.length, A = 'A'.charCodeAt(0) + let res = 0, l = 0, r = 0, maxFreq = 0 + while(r < n) { + maxFreq = Math.max(maxFreq, ++freq[s.charCodeAt(r) - A]) + if(r - l + 1 - maxFreq > k) { + freq[s.charCodeAt(l) - A]-- + l++ + } + res = Math.max(res, r - l + 1) + r++ + } + + return res +}; + + diff --git a/2025-maximum-number-of-ways-to-partition-an-array.js b/2025-maximum-number-of-ways-to-partition-an-array.js new file mode 100644 index 00000000..ed96ae1e --- /dev/null +++ b/2025-maximum-number-of-ways-to-partition-an-array.js @@ -0,0 +1,90 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const waysToPartition = function (nums, k) { + const n = nums.length, pre = Array(n).fill(0), suf = Array(n).fill(0) + pre[0] = nums[0], suf[n - 1] = nums[n - 1] + for(let i = 1; i < n; i++) { + pre[i] = pre[i - 1] + nums[i] + suf[n - 1 - i] = suf[n - i] + nums[n - 1 - i] + } + const sum = nums.reduce((ac, e) => ac + e, 0) + let res = 0 + for(let i = 0; i < n - 1; i++) { + if(pre[i] === suf[i + 1]) res++ + } + const cnt = new Map() + const arr = Array(n).fill(0) + for(let i = 0; i < n; i++) { + const newSum = sum - nums[i] + k + if(newSum % 2 === 0) arr[i] += (cnt.get(newSum / 2) || 0) + cnt.set(pre[i], (cnt.get(pre[i]) || 0) + 1) + } + cnt.clear() + for(let i = n - 1; i >= 0; i--) { + const newSum = sum - nums[i] + k + if(newSum % 2 === 0) arr[i] += (cnt.get(newSum / 2) || 0) + cnt.set(suf[i], (cnt.get(suf[i]) || 0) + 1) + } + + for(let e of arr) { + if(e > res) res = e + } + + return res +} + + +// another + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const waysToPartition = function (nums, k) { + const n = nums.length + const pref = Array(n).fill(0), + suff = Array(n).fill(0) + pref[0] = nums[0] + suff[n - 1] = nums[n - 1] + for (let i = 1; i < n; ++i) { + pref[i] = pref[i - 1] + nums[i] + suff[n - 1 - i] = suff[n - i] + nums[n - 1 - i] + } + let ans = 0 + const left = {}, + right = {} + + for (let i = 0; i < n - 1; ++i) { + const delta = pref[i] - suff[i + 1] + if (right[delta] == null) right[delta] = 0 + right[delta]++ + } + + if (right[0]) ans = right[0] + for (let i = 0; i < n; ++i) { + //find the number of pivot indexes when nums[i] is changed to k + let curr = 0, + diff = k - nums[i] + if (left[diff]) curr += left[diff] + if (right[-diff]) curr += right[-diff] + + //update answer + ans = Math.max(ans, curr) + + //transfer the current element from right to left + if (i < n - 1) { + let dd = pref[i] - suff[i + 1] + if(left[dd] == null) left[dd] = 0 + if(right[dd] == null) right[dd] = 0 + left[dd]++ + right[dd]-- + if (right[dd] == 0) delete right[dd] + } + } + return ans +} diff --git a/2029-stone-game-ix.js b/2029-stone-game-ix.js new file mode 100644 index 00000000..eea5b685 --- /dev/null +++ b/2029-stone-game-ix.js @@ -0,0 +1,10 @@ +/** + * @param {number[]} stones + * @return {boolean} + */ +const stoneGameIX = function(stones) { + const cnt = Array(3).fill(0), { abs } = Math + for (let a of stones) cnt[a % 3]++; + if (cnt[0] % 2 == 0) return cnt[1] && cnt[2] + return abs(cnt[1] - cnt[2]) >= 3 +}; diff --git a/203-remove-linked-list-elements.js b/203-remove-linked-list-elements.js new file mode 100644 index 00000000..42807a2f --- /dev/null +++ b/203-remove-linked-list-elements.js @@ -0,0 +1,49 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @param {number} val + * @return {ListNode} + */ +const removeElements = function(head, val) { + const dummy = new ListNode(Infinity) + if(head == null) return null + dummy.next = head + let cur = head + let prev = dummy + while(cur) { + if(cur.val === val) { + prev.next = cur.next + cur = cur.next + } else { + prev = cur + cur = cur.next + } + } + return dummy.next +}; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @param {number} val + * @return {ListNode} + */ +const removeElements = function(head, val) { + if (head === null) return null; + head.next = removeElements(head.next, val); + return head.val === val ? head.next : head; +}; diff --git a/2030-smallest-k-length-subsequence-with-occurrences-of-a-letter.js b/2030-smallest-k-length-subsequence-with-occurrences-of-a-letter.js new file mode 100644 index 00000000..881d96aa --- /dev/null +++ b/2030-smallest-k-length-subsequence-with-occurrences-of-a-letter.js @@ -0,0 +1,36 @@ +/** + * @param {string} s + * @param {number} k + * @param {character} letter + * @param {number} repetition + * @return {string} + */ +const smallestSubsequence = function (s, k, letter, repetition) { + let n_letters = 0 + for (let i = 0; i < s.length; i++) if (s.charAt(i) == letter) n_letters++ + const stack = [] + for (let i = 0; i < s.length; i++) { + let c = s.charAt(i) + while ( + stack.length && + stack[stack.length - 1] > c && + s.length - i + stack.length > k && + (stack[stack.length - 1] != letter || n_letters > repetition) + ) { + if (stack.pop() == letter) repetition++ + } + if (stack.length < k) { + if (c == letter) { + stack.push(c) + repetition-- + } else if (k - stack.length > repetition) { + stack.push(c) + } + } + if (c == letter) n_letters-- + } + + let sb = '' + for (let c of stack) sb += c + return sb +} diff --git a/2031-count-subarrays-with-more-ones-than-zeros.js b/2031-count-subarrays-with-more-ones-than-zeros.js new file mode 100644 index 00000000..324c77f6 --- /dev/null +++ b/2031-count-subarrays-with-more-ones-than-zeros.js @@ -0,0 +1,41 @@ +const lowBit = (x) => x & -x +class FenwickTree { + constructor(n) { + if (n < 1) return + this.sum = Array(n + 1).fill(0) + } + update(i, delta) { + if (i < 1) return + while (i < this.sum.length) { + this.sum[i] += delta + i += lowBit(i) + } + } + query(i) { + if (i < 1) return 0 + let sum = 0 + while (i > 0) { + sum += this.sum[i] + i -= lowBit(i) + } + return sum + } +} + +/** + * @param {number[]} nums + * @return {number} + */ +const subarraysWithMoreZerosThanOnes = function(nums) { + const n = nums.length, mod = 1e9 + 7 + const bit = new FenwickTree(2 * n + 1) + bit.update(n + 1, 1) + let balance = 0, res = 0 + for(const e of nums) { + balance += (e === 1 ? 1 : -1) + bit.update(balance + n + 1, 1) + res = (res + bit.query(balance + n)) % mod + } + + return res +}; diff --git a/2032-two-out-of-three.js b/2032-two-out-of-three.js new file mode 100644 index 00000000..e392cbbe --- /dev/null +++ b/2032-two-out-of-three.js @@ -0,0 +1,32 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number[]} nums3 + * @return {number[]} + */ +const twoOutOfThree = function(nums1, nums2, nums3) { + const res = [] + const hash = {} + for(let e of new Set(nums1)) { + if(hash[e] == null) hash[e] = 0 + hash[e] = 1 + } + + for(let e of new Set(nums2)) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + + + for(let e of new Set(nums3)) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + + Object.keys(hash).forEach(k => { + if(hash[k] > 1) res.push(k) + }) + + + return res +}; diff --git a/2033-minimum-operations-to-make-a-uni-value-grid.js b/2033-minimum-operations-to-make-a-uni-value-grid.js new file mode 100644 index 00000000..43f45805 --- /dev/null +++ b/2033-minimum-operations-to-make-a-uni-value-grid.js @@ -0,0 +1,160 @@ +/** + * @param {number[][]} grid + * @param {number} x + * @return {number} + */ +function minOperations(grid, x) { + const m = grid.length, n = grid[0].length + const len = m * n, arr = [] + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + arr.push(grid[i][j]) + } + } + arr.sort((a, b) => a - b) + const mid = arr[Math.floor(len / 2)] + let res = 0 + for(const e of arr) { + const d = Math.abs(e - mid) + if(d % x !== 0) return -1 + res += d / x + } + + return res +}; + +// another + +/** + * @param {number[][]} grid + * @param {number} x + * @return {number} + */ +const minOperations = function (grid, x) { + const arr = [], + m = grid.length, + n = grid[0].length + const len = m * n + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + arr.push(grid[i][j]) + } + } + arr.sort((a, b) => a - b) + const mid = arr[~~(len / 2)], { abs } = Math + let res = 0 + for(const e of arr) { + if(abs(mid - e) % x !== 0) return -1 + res += abs(mid - e) / x + } + + return res +} + +// another + +/** + * @param {number[][]} grid + * @param {number} x + * @return {number} + */ +const minOperations = function(grid, x) { + const arr = [] + const m = grid.length, n = grid[0].length + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + arr.push(grid[i][j]) + } + } + arr.sort((a, b) => a - b) + + for(let i = 1; i < m * n; i++) { + if((arr[i] - arr[i - 1]) % x !== 0) return -1 + } + const sum = arr.reduce((ac, e) => ac + e, 0) + const pre = [] + pre.push(arr[0]) + for(let i = 1; i < m * n; i++) { + pre[i] = pre[i - 1] + arr[i] + } + + let res = 0, num = 0, min = sum - arr[0] * m * n, idx = 0 + for(let i = 1; i < m * n; i++) { + const cur = (i + 1) * arr[i] - pre[i] + (sum - pre[i] - arr[i] * (m * n - i - 1)) + // console.log(cur, (i + 1) * arr[i] - pre[i], sum - pre[i] - arr[i] * (m * n - i - 1)) + // const cur = sum - arr[i] * (m * n - i) + if(cur < min) { + idx = i + min = cur + } + } + + // console.log(idx) + + for(let i = 0; i < m * n; i++) { + if(i === idx) continue + res += Math.abs(arr[i] - arr[idx]) / x + } + + return res +}; +// 20 - 6 - 4 * 2 +// 2 4 6 8 +// 1 2 3 5 + +// another + +/** + * @param {number[][]} grid + * @param {number} x + * @return {number} + */ +const minOperations = function(grid, x) { + const arr = [], m = grid.length, n = grid[0].length + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + arr.push(grid[i][j]) + } + } + arr.sort((a, b) => a - b) + const mid = arr[~~((m * n) / 2)] + let res = 0 + + for(let e of arr) { + if (e !== mid) { + const cur = Math.abs(e - mid) + if(cur % x !== 0) return -1 + res += cur / x + } + } + return res +}; + +// another + +/** + * @param {number[][]} grid + * @param {number} x + * @return {number} + */ +function minOperations(grid, x) { + const m = grid.length, n = grid[0].length, mn = m * n, arr = [] + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + arr.push(grid[i][j]) + } + } + arr.sort((a, b) => a - b) + const mid = arr[~~(mn / 2)] + let res = 0 + + for(let e of arr) { + if(e !== mid) { + const delta = Math.abs(e - mid) + if(delta % x !== 0) return -1 + res += delta / x + } + } + + return res +}; diff --git a/2034-stock-price-fluctuation.js b/2034-stock-price-fluctuation.js new file mode 100644 index 00000000..67eecd73 --- /dev/null +++ b/2034-stock-price-fluctuation.js @@ -0,0 +1,62 @@ +const StockPrice = function () { + this.timeToPrice = new Map() + this.lastTime = 0 + this.minPrices = new MinPriorityQueue({ priority: (stock) => stock.price }) + this.maxPrices = new MaxPriorityQueue({ priority: (stock) => stock.price }) +} + +/** + * @param {number} timestamp + * @param {number} price + * @return {void} + */ +StockPrice.prototype.update = function (timestamp, price) { + this.timeToPrice.set(timestamp, price) + this.lastTime = Math.max(this.lastTime, timestamp) + this.minPrices.enqueue({ timestamp, price }) + this.maxPrices.enqueue({ timestamp, price }) +} + +/** + * @return {number} + */ +StockPrice.prototype.current = function () { + return this.timeToPrice.get(this.lastTime) +} + +/** + * @return {number} + */ +StockPrice.prototype.maximum = function () { + while ( + this.maxPrices.front().element.price !== + this.timeToPrice.get(this.maxPrices.front().element.timestamp) + ) { + this.maxPrices.dequeue() + } + + return this.maxPrices.front().element.price +} + +/** + * @return {number} + */ +StockPrice.prototype.minimum = function () { + while ( + this.minPrices.front().element.price !== + this.timeToPrice.get(this.minPrices.front().element.timestamp) + ) { + this.minPrices.dequeue() + } + + return this.minPrices.front().element.price +} + +/** + * Your StockPrice object will be instantiated and called as such: + * var obj = new StockPrice() + * obj.update(timestamp,price) + * var param_2 = obj.current() + * var param_3 = obj.maximum() + * var param_4 = obj.minimum() + */ diff --git a/2035-partition-array-into-two-arrays-to-minimize-sum-difference.js b/2035-partition-array-into-two-arrays-to-minimize-sum-difference.js new file mode 100644 index 00000000..630caf18 --- /dev/null +++ b/2035-partition-array-into-two-arrays-to-minimize-sum-difference.js @@ -0,0 +1,97 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const mi = Math.min, + abs = Math.abs +const minimumDifference = (nums) => { + let m = nums.length, + n = m >> 1 + let a = initializeGraph(n + 1) + let b = initializeGraph(n + 1) + for (let i = 0; i < 1 << n; i++) { + // mask + let sum = 0, + cnt = 0 + for (let j = 0; j < n; j++) { + if (i & (1 << j)) { + // bit of 1's + sum += nums[j] + cnt++ // bit count + } else { + sum -= nums[j] + } + } + a[cnt].push(sum) + ;(sum = 0), (cnt = 0) + for (let j = 0; j < n; j++) { + if (i & (1 << j)) { + sum += nums[n + j] + cnt++ + } else { + sum -= nums[n + j] + } + } + b[cnt].push(sum) + } + for (let i = 0; i < n; i++) { + a[i].sort((x, y) => x - y) + b[i].sort((x, y) => x - y) + } + let res = Number.MAX_SAFE_INTEGER + let bi = new Bisect() + for (let i = 0; i <= n; i++) { + for (const x of a[i]) { + let idx = bi.bisect_left(b[n - i], -x) // binary search lower_bound + if (idx != b[n - i].length) res = mi(res, abs(x + b[n - i][idx])) + if (idx != 0) { + idx-- + res = mi(res, abs(x + b[n - i][idx])) + } + } + } + return res +} + +//////////////////////////////////////// Template //////////////////////////////////////////////////////// +function Bisect() { + return { insort_right, insort_left, bisect_left, bisect_right } + function insort_right(a, x, lo = 0, hi = null) { + lo = bisect_right(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_right(a, x, lo = 0, hi = null) { + // > upper_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = (lo + hi) >> 1 + x < a[mid] ? (hi = mid) : (lo = mid + 1) + } + return lo + } + function insort_left(a, x, lo = 0, hi = null) { + lo = bisect_left(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_left(a, x, lo = 0, hi = null) { + // >= lower_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = (lo + hi) >> 1 + a[mid] < x ? (lo = mid + 1) : (hi = mid) + } + return lo + } +} + +const initializeGraph = (n) => { + let G = [] + for (let i = 0; i < n; i++) { + G.push([]) + } + return G +} +///////////////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/2037-minimum-number-of-moves-to-seat-everyone.js b/2037-minimum-number-of-moves-to-seat-everyone.js new file mode 100644 index 00000000..92ff7134 --- /dev/null +++ b/2037-minimum-number-of-moves-to-seat-everyone.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} seats + * @param {number[]} students + * @return {number} + */ +const minMovesToSeat = function(seats, students) { + let res = 0 + seats.sort((a, b) => a - b) + students.sort((a, b) => a - b) + + for(let i = 0; i < students.length; i++) { + res += Math.abs(seats[i] - students[i]) + } + + return res +}; diff --git a/2038-remove-colored-pieces-if-both-neighbors-are-the-same-color.js b/2038-remove-colored-pieces-if-both-neighbors-are-the-same-color.js new file mode 100644 index 00000000..e1dc029f --- /dev/null +++ b/2038-remove-colored-pieces-if-both-neighbors-are-the-same-color.js @@ -0,0 +1,12 @@ +/** + * @param {string} colors + * @return {boolean} + */ +const winnerOfGame = function(colors) { + let ac = 0, bc = 0 + for(let i = 1, n = colors.length; i < n - 1; i++) { + if(colors[i] === 'A' && colors[i - 1] === 'A' && colors[i + 1] === 'A') ac++ + if(colors[i] === 'B' && colors[i - 1] === 'B' && colors[i + 1] === 'B') bc++ + } + return ac > bc +}; diff --git a/204-count-primes.js b/204-count-primes.js index f0ae3e2d..6882fda6 100755 --- a/204-count-primes.js +++ b/204-count-primes.js @@ -1,3 +1,51 @@ +/** + * @param {number} n + * @return {number} + */ +const countPrimes = function(n) { + const arr = Array(n).fill(0) + + for(let i = 2; i * i < n; i++) { + if(arr[i] !== 0) continue + let j = i * i + while(j < n) { + arr[j] = 1 + j += i + } + } + + let res = 0 + for(let i = 2; i < n; i++) { + if(arr[i] === 0) res++ + } + return res +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +const countPrimes = function (n) { + const memo = Array(n).fill(false) + let res = 0 + for (let i = 2; i < n; i++) { + if (memo[i] === false) { + res++ + for (let j = 2; i * j < n; j++) { + memo[i * j] = true + } + } + } + + return res +} + + +// another + + /** * @param {number} n * @return {number} diff --git a/2040-kth-smallest-product-of-two-sorted-arrays.js b/2040-kth-smallest-product-of-two-sorted-arrays.js new file mode 100644 index 00000000..b1f3dadb --- /dev/null +++ b/2040-kth-smallest-product-of-two-sorted-arrays.js @@ -0,0 +1,40 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ +const kthSmallestProduct = function(nums1, nums2, k) { + const neg = nums1.filter(e => e < 0) + const pos = nums1.filter(e => e >= 0) + const negRev = neg.slice(), posRev = pos.slice() + negRev.reverse() + posRev.reverse() + + let l = - (10 ** 10), r = 10 ** 10 + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if(fn(mid) < k) l = mid + 1 + else r = mid + } + + return l + + function fn(val) { + let res = 0, n = nums2.length + let l = 0, r = n - 1 + const list = val >= 0 ? negRev.concat(pos) : neg.concat(posRev) + for(let e of list) { + if(e < 0) { + while(l < n && e * nums2[l] > val) l++ + res += n - l + } else if (e === 0) { + if(val >= 0) res += n + } else { + while(r >= 0 && e * nums2[r] > val) r-- + res += r + 1 + } + } + return res + } +}; diff --git a/2042-check-if-numbers-are-ascending-in-a-sentence.js b/2042-check-if-numbers-are-ascending-in-a-sentence.js new file mode 100644 index 00000000..1f128e49 --- /dev/null +++ b/2042-check-if-numbers-are-ascending-in-a-sentence.js @@ -0,0 +1,14 @@ +/** + * @param {string} s + * @return {boolean} + */ +const areNumbersAscending = function(s) { + const arr =s.split(' ') + const f = arr.filter(e => !Number.isNaN(+e)).map(e => +e) + let res = true + for(let i = 1; i < f.length; i++) { + if(f[i] <= f[i - 1]) return false + } + + return res +}; diff --git a/2043-simple-bank-system.js b/2043-simple-bank-system.js new file mode 100644 index 00000000..95ac0446 --- /dev/null +++ b/2043-simple-bank-system.js @@ -0,0 +1,56 @@ +/** + * @param {number[]} balance + */ +const Bank = function(balance) { + this.n = balance.length + balance.unshift(0) + this.b = balance + +}; + +/** + * @param {number} account1 + * @param {number} account2 + * @param {number} money + * @return {boolean} + */ +Bank.prototype.transfer = function(account1, account2, money) { + let res = true + if(account1 > this.n || account1 < 1) return false + if(account2 > this.n || account2 < 1) return false + if(this.b[account1]< money) return false + this.b[account1] -= money + this.b[account2] += money + return true +}; + +/** + * @param {number} account + * @param {number} money + * @return {boolean} + */ +Bank.prototype.deposit = function(account, money) { + if(account > this.n || account < 1) return false + this.b[account] += money + return true +}; + +/** + * @param {number} account + * @param {number} money + * @return {boolean} + */ +Bank.prototype.withdraw = function(account, money) { + if(account > this.n || account < 1) return false + if(this.b[account] < money) return false + this.b[account] -= money + return true +}; + +/** + * Your Bank object will be instantiated and called as such: + * var obj = new Bank(balance) + * var param_1 = obj.transfer(account1,account2,money) + * var param_2 = obj.deposit(account,money) + * var param_3 = obj.withdraw(account,money) + */ diff --git a/2044-count-number-of-maximum-bitwise-or-subsets.js b/2044-count-number-of-maximum-bitwise-or-subsets.js new file mode 100644 index 00000000..496a388c --- /dev/null +++ b/2044-count-number-of-maximum-bitwise-or-subsets.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const countMaxOrSubsets = function(nums) { + let res = 0, max = 0, n = nums.length + for(let num of nums) max |= num + dfs(0, 0) + dfs(0, nums[0]) + return res + + function dfs(i, cur) { + if(i === n) return + if(cur === max) return res += Math.pow(2, n - 1 - i) + dfs(i + 1, cur) + dfs(i + 1, cur | nums[i + 1]) + } +}; diff --git a/2045-second-minimum-time-to-reach-destination.js b/2045-second-minimum-time-to-reach-destination.js new file mode 100644 index 00000000..8bb74c36 --- /dev/null +++ b/2045-second-minimum-time-to-reach-destination.js @@ -0,0 +1,161 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} time + * @param {number} change + * @return {number} + */ +var secondMinimum = function(n, edges, time, change) { + let adj = initializeGraph(n + 1) + addEdgeToG(adj, edges) + let cost = initializeGraph(n + 1) + let pq = new PQ((a, b) => a[0] < b[0]) + pq.push([0, 1]) + let green = 2 * change + while (pq.size()) { + let cur = pq.pop() + let [t, node] = cur + if (cost[node].length == 2) continue + let nextT = + t % green < change ? t : (((t + green - 1) / green) >> 0) * green + let cn = cost[node].length + if (node == n) { + if (cn == 0 || cost[node][cn - 1] != t) { + cost[node].push(t) + } else { + continue + } + } else { + if (cn == 0 || cost[node][cn - 1] != nextT) { + cost[node].push(nextT) + } else { + continue + } + } + for (const next_node of adj[node]) pq.push([nextT + time, next_node]) + } + return cost[n][1] +}; +function initializeGraph(n) { + let G = [] + for (let i = 0; i < n; i++) { + G.push([]) + } + return G +} +function addEdgeToG(G, Edges) { + for (const [u, v] of Edges) { + G[u].push(v) + G[v].push(u) + } +} +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} time + * @param {number} change + * @return {number} + */ + var secondMinimum = function (n, edges, time, change) { + const graph = new Map() + for (let i = 1; i <= n; i++) graph.set(i, []) + for (const [u, v] of edges) { + graph.get(u).push(v) + graph.get(v).push(u) + } + const first = Array(n + 1).fill(Infinity) + const second = Array(n + 1).fill(Infinity) + first[1] = 0 + + const q = new MinPriorityQueue() + q.enqueue(1, 0) + + while (q.size()) { + let {element: node, priority: cur} = q.dequeue() + cur += time // cur: arrival time + let leave = cur + if (~~(cur / change) & 1) leave += change - (cur % change) + for (let nei of graph.get(node)) { + if (second[nei] <= cur) continue + if (first[nei] === cur) continue + if (first[nei] > cur) { + second[nei] = first[nei] + first[nei] = cur + } else { + second[nei] = cur + } + q.enqueue(nei, leave) + } + } + return second[n] +} diff --git a/2046-sort-linked-list-already-sorted-using-absolute-values.js b/2046-sort-linked-list-already-sorted-using-absolute-values.js new file mode 100644 index 00000000..c80d553a --- /dev/null +++ b/2046-sort-linked-list-already-sorted-using-absolute-values.js @@ -0,0 +1,30 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const sortLinkedList = function(head) { + if(head == null) return head + const dummy = new ListNode(null, head) + let pre = dummy, cur = head + while(cur) { + if(cur.val < 0 && cur !== head) { + const tmp = cur.next, tmpHead = dummy.next + dummy.next = cur + cur.next = tmpHead + pre.next = tmp + cur = tmp + } else { + pre = cur + cur = cur.next + } + } + + return dummy.next +}; diff --git a/2047-number-of-valid-words-in-a-sentence.js b/2047-number-of-valid-words-in-a-sentence.js new file mode 100644 index 00000000..689fb933 --- /dev/null +++ b/2047-number-of-valid-words-in-a-sentence.js @@ -0,0 +1,42 @@ +/** + * @param {string} sentence + * @return {number} + */ +const countValidWords = function(s) { + const arr = s.split(' ') + let res = 0 + for(const e of arr) { + if(e.trim() && valid(e.trim())) res ++ + } + return res +}; + +function valid(e) { + const zi = '0'.charCodeAt(0), ni = '9'.charCodeAt(0) + const len = e.length + for(const el of e) { + if(el.charCodeAt(0) >= zi && el.charCodeAt(0) <= ni) return false + } + const num = (p, n) => (p >= 'a' && p <= 'z') && (n >= 'a' && n <= 'z') + const hi = e.indexOf('-') + if(hi !== -1) { + if(hi === 0 || hi === e.length - 1 || e.indexOf('-', hi + 1) !== -1 || !num(e[hi - 1], e[hi + 1])) return false + } + + const p1 = e.indexOf('!') + if(p1 !== -1) { + if((len > 1 && p1 !== e.length - 1) || e.indexOf('-', p1 + 1) !== -1) return false + } + + const p2 = e.indexOf('.') + if(p2 !== -1) { + if((len > 1 && p2 !== e.length - 1) || e.indexOf('-', p2 + 1) !== -1) return false + } + + const p3 = e.indexOf(',') + if(p3 !== -1) { + if((len > 1 && p3 !== e.length - 1) || e.indexOf('-', p3 + 1) !== -1) return false + } + + return true +} diff --git a/2048-next-greater-numerically-balanced-number.js b/2048-next-greater-numerically-balanced-number.js new file mode 100644 index 00000000..b19e9e7a --- /dev/null +++ b/2048-next-greater-numerically-balanced-number.js @@ -0,0 +1,23 @@ +/** + * @param {number} n + * @return {number} + */ +const nextBeautifulNumber = function(n) { + while (true) { + ++n; + if (balance(n)) return n; + } + function balance(n) { + let cnt = Array(10).fill(0); + while (n) { + if (n % 10 == 0) return false; // no 0 allowed + cnt[n % 10]++; + n = ~~(n / 10); + } + for (let i = 1; i < 10; ++i) { + if (cnt[i] && cnt[i] !== i) return false; + } + return true; + } +}; + diff --git a/2049-count-nodes-with-the-highest-score.js b/2049-count-nodes-with-the-highest-score.js new file mode 100644 index 00000000..5be74015 --- /dev/null +++ b/2049-count-nodes-with-the-highest-score.js @@ -0,0 +1,58 @@ +/** + * @param {number[]} parents + * @return {number} + */ +const countHighestScoreNodes = function(parents) { + const n = parents.length, graph = {}, hash = {} + for(let i = 1; i < n; i++) { + if(graph[parents[i]] == null) graph[parents[i]] = [] + graph[parents[i]].push(i) + } + dfs(0) + + function dfs(node) { + let product = 1, num = 0 + for(let child of (graph[node] || [])) { + const tmp = dfs(child) + product *= tmp + num += tmp + } + if(n - 1 - num > 0) product *= (n - 1 - num) + hash[product] = (hash[product] || 0) + 1 + return num + 1 + } + const maxKey = Math.max(...Object.keys(hash)) + return hash[maxKey] +}; + +// another + +/** + * @param {number[]} parents + * @return {number} + */ +const countHighestScoreNodes = function(parents) { + const n = parents.length, hash = {}, graph = {} + for(let i = 1; i < n; i++) { + if(graph[parents[i]] == null) graph[parents[i]] = [] + graph[parents[i]].push(i) + } + + dfs(0) + const mk = Math.max(...Object.keys(hash)) + return hash[mk] + + function dfs(i) { + let num = 0, prod = 1 + for(const e of (graph[i] || []) ) { + const tmp = dfs(e) + num += tmp + prod *= tmp + } + + if(n - 1 - num > 0) prod *= (n - 1 - num) + hash[prod] = (hash[prod] || 0) + 1 + + return num + 1 + } +}; diff --git a/2050-parallel-courses-iii.js b/2050-parallel-courses-iii.js new file mode 100644 index 00000000..521a0eb0 --- /dev/null +++ b/2050-parallel-courses-iii.js @@ -0,0 +1,165 @@ +/** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ +const minimumTime = function(n, relations, time) { + const adj = Array(n + 1).fill(0).map(() => []); + const inDegree = Array(n + 1).fill(0); + for (const [u, v] of relations) { + adj[u].push(v); + inDegree[v]++; + } + let q = [] + const finishTime = Array(n + 1).fill(0); + for(let i = 1; i <= n; i++) { + if(inDegree[i] === 0) { + q.push(i); + finishTime[i] = time[i - 1]; + } + } + + + while(q.length) { + const size = q.length; + const tmp = [] + for(let i = 0; i < size; i++) { + const e = q[i]; + for(const v of adj[e]) { + inDegree[v]--; + finishTime[v] = Math.max(finishTime[v], finishTime[e] + time[v - 1]); + if(inDegree[v] === 0) { + tmp.push(v); + } + } + } + + q = tmp + } + + return Math.max(...finishTime.slice(1)) +}; + +// another + +/** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ +const minimumTime = function (n, relations, time) { + const inDegree = Array(n + 1).fill(0) + const graph = {}, dist = Array(n + 1).fill(0) + + for(const [pre, nxt] of relations) { + if(graph[pre] == null) graph[pre] = [] + graph[pre].push(nxt) + inDegree[nxt]++ + } + + let q = [] + for(let i = 1;i <=n;i++) { + if(inDegree[i]===0) { + q.push(i) + dist[i] = time[i - 1] + } + } + while(q.length) { + const size = q.length, nxt = [] + + for(let i = 0; i < size; i++) { + const cur = q[i] + for(const e of (graph[cur] || [])) { + dist[e] = Math.max(dist[e], dist[cur] + time[e - 1]) + inDegree[e]-- + if(inDegree[e] === 0) { + nxt.push(e) + } + } + } + + q = nxt + } + + return Math.max(...dist) +} + +// another + +/** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ +const minimumTime = function(n, relations, time) { + const graph = {}, dist = Array(n).fill(0), inDegree = Array(n).fill(0) + + for(let [pre, next] of relations) { + pre--, next-- + if(graph[pre] == null) graph[pre] = [] + graph[pre].push(next) + inDegree[next]++ + } + + const q = [] + for(let i = 0; i < n; i++) { + if(inDegree[i] === 0) { + q.push(i) + dist[i] = time[i] + } + } + + let res = 0 + while(q.length) { + const cur = q.shift() + for(const next of (graph[cur] || [])) { + dist[next] = Math.max(dist[next], dist[cur] + time[next]) + inDegree[next]-- + if(inDegree[next] === 0) q.push(next) + } + } + + return Math.max(...dist) +} + +// another + +/** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ +const minimumTime = function(n, relations, time) { + const graph = {}, dist = Array(n).fill(0), inDegree = Array(n).fill(0) + for(let [from, to] of relations) { + from--, to-- + if (graph[from] == null) graph[from] = [] + graph[from].push(to) + inDegree[to]++ + } + const q = [] + for(let i = 0; i < n; i++) { + if(inDegree[i] === 0) { + q.push(i) + dist[i] = time[i] + } + } + + while(q.length) { + const u = q.shift() + for(const v of (graph[u] || [])) { + dist[v] = Math.max(dist[v], dist[u] + time[v]) + if(--inDegree[v] === 0) q.push(v) + } + } + + let res = 0 + for(let e of dist) { + if(e > res) res = e + } + return res +}; diff --git a/2053-kth-distinct-string-in-an-array.js b/2053-kth-distinct-string-in-an-array.js new file mode 100644 index 00000000..152a135c --- /dev/null +++ b/2053-kth-distinct-string-in-an-array.js @@ -0,0 +1,19 @@ +/** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ +const kthDistinct = function(arr, k) { + let num = 0, hash = {} + + for(let str of arr) { + if(hash[str] == null) hash[str] = 0 + hash[str]++ + } + for(let str of arr) { + if(hash[str] > 1) continue + num++ + if(num === k) return str + } + return '' +}; diff --git a/2054-two-best-non-overlapping-events.js b/2054-two-best-non-overlapping-events.js new file mode 100644 index 00000000..07adffa0 --- /dev/null +++ b/2054-two-best-non-overlapping-events.js @@ -0,0 +1,118 @@ + +/** + * @param {number[][]} events + * @return {number} + */ +const maxTwoEvents = function(events) { + const n = events.length + events.sort((a, b) => a[0] - b[0]) + const dp = Array.from({ length: n }, () => Array(3).fill(-1)) + + return dfs(0, 0) + + function dfs(idx, cnt) { + if(cnt === 2 || idx >= n) return 0 + if(dp[idx][cnt] === -1) { + let end = events[idx][1] + let lo = idx + 1, hi = n - 1; + while (lo < hi) { + const mid = lo + ((hi - lo) >> 1); + if (events[mid][0] <= end) lo = mid + 1 + else hi = mid; + } + const include = events[idx][2] + (lo < n && events[lo][0] > end ? dfs(lo, cnt + 1) : 0); + const exclude = dfs(idx + 1, cnt); + dp[idx][cnt] = Math.max(include, exclude); + } + + return dp[idx][cnt] + } +}; + +// another + +/** + * @param {number[][]} events + * @return {number} + */ +const maxTwoEvents = function(events) { + const n = events.length, { max } = Math + let res = 0, maxVal = 0; + const pq = new PriorityQueue((a, b) => a[0] < b[0]); + events.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) + for (let e of events) { + for(; !pq.isEmpty() && pq.peek()[0] < e[0]; pq.pop()) + maxVal = max(maxVal, pq.peek()[1]); + res = max(res, maxVal + e[2]); + pq.push([e[1], e[2]]); + } + return res; +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2055-plates-between-candles.js b/2055-plates-between-candles.js new file mode 100644 index 00000000..bca0a066 --- /dev/null +++ b/2055-plates-between-candles.js @@ -0,0 +1,130 @@ +/** + * @param {string} s + * @param {number[][]} queries + * @return {number[]} + */ +const platesBetweenCandles = function (s, queries) { + const candleIdxArr = [] + const n = s.length + for(let i = 0; i < n; i++) { + if(s[i] === '|') candleIdxArr.push(i) + } + // console.log(candleIdxArr) + const res = [] + for(const [s, e] of queries) { + const l = lower(candleIdxArr, s, e) + const r = upper(candleIdxArr, s ,e) + const tmp = (candleIdxArr[r] - candleIdxArr[l] + 1) - (r - l + 1) + res.push(tmp >= 0 ? tmp : 0) + } + + return res + + + function lower(arr,s,e) { + let l = 0, r = arr.length - 1 + while(l < r) { + // console.log('lower',l, r) + const mid = ~~(l + (r - l)/2) + if(arr[mid] < s) l = mid + 1 + else r = mid + } + return l + } + + function upper(arr,s, e) { + let l = 0, r = arr.length - 1 + while(l < r) { + + const mid = r - ~~((r - l)/2) + // console.log('upper', l, r, mid, e) + if(arr[mid] > e) r = mid - 1 + else l = mid + } + return l + } +} + +// another + +/** + * @param {string} s + * @param {number[][]} queries + * @return {number[]} + */ +const platesBetweenCandles = function(s, queries) { + const n = s.length, + leftCandlePos = Array(n).fill(-1) + rightCandlePos = Array(n).fill(-1) + candleCnt = Array(n).fill(0) + let pos = -1 + for(let i = 0; i < n; i++) { + if(s[i] === '|') pos = i + leftCandlePos[i] = pos + } + pos = -1 + for(let i = n - 1; i >= 0; i--) { + if(s[i] === '|') pos = i + rightCandlePos[i] = pos + } + for(let i = 0, cnt = 0; i < n; i++) { + if(s[i] === '|') cnt++ + candleCnt[i] = cnt + } + + const len = queries.length, res = Array(len).fill(0) + + for(let i = 0; i < len; i++) { + const [left, right] = queries[i] + const leftCandle = rightCandlePos[left], rightCandle = leftCandlePos[right] + const delta = rightCandle - leftCandle + if(leftCandle !== -1 && rightCandle !== -1 && delta > 1) { + res[i] = delta + 1 - (candleCnt[rightCandle] - candleCnt[leftCandle] + 1) + } + } + + return res +} + +// another + +/** + * @param {string} s + * @param {number[][]} queries + * @return {number[]} + */ +const platesBetweenCandles = function (s, queries) { + const n = s.length + const leftArr = Array(n).fill(-1), + rightArr = Array(n).fill(n), + candleCnt = Array(n).fill(0) + let candle = -1 + for (let i = 0; i < n; i++) { + if (s[i] === '|') candle = i + leftArr[i] = candle + } + candle = n + for (let i = n - 1; i >= 0; i--) { + if (s[i] === '|') candle = i + rightArr[i] = candle + } + let cnt = 0 + for (let i = 0; i < n; i++) { + if (s[i] === '|') cnt++ + candleCnt[i] = cnt + } + // console.log(leftArr, rightArr) + const res = [] + for (const [s, e] of queries) { + const l = rightArr[s] + const r = leftArr[e] + const diff = r - l + if (diff > 1) { + const e = r - l + 1 - (candleCnt[r] - candleCnt[l] + 1) + res.push(e) + } else res.push(0) + } + + return res +} + diff --git a/2057-smallest-index-with-equal-value.js b/2057-smallest-index-with-equal-value.js new file mode 100644 index 00000000..c928e0da --- /dev/null +++ b/2057-smallest-index-with-equal-value.js @@ -0,0 +1,11 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var smallestEqual = function(nums) { + const n = nums.length + for(let i = 0; i < n; i++) { + if(i % 10 === nums[i]) return i + } + return -1 +}; diff --git a/2058-find-the-minimum-and-maximum-number-of-nodes-between-critical-points.js b/2058-find-the-minimum-and-maximum-number-of-nodes-between-critical-points.js new file mode 100644 index 00000000..efd5d273 --- /dev/null +++ b/2058-find-the-minimum-and-maximum-number-of-nodes-between-critical-points.js @@ -0,0 +1,33 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {number[]} + */ +const nodesBetweenCriticalPoints = function(head) { + const arr = [] + let cur = head + while(cur) { + arr.push(cur.val) + cur = cur.next + } + const idxArr = [] + const n = arr.length + for(let i = 1; i < n - 1; i++) { + if((arr[i] > arr[i - 1] && arr[i] > arr[i + 1]) || (arr[i] < arr[i - 1] && arr[i] < arr[i + 1])) { + idxArr.push(i) + } + } + + let min = Infinity, max = -1 + for(let i = 1; i < idxArr.length; i++) { + if(idxArr[i] - idxArr[i - 1] < min) min = idxArr[i] - idxArr[i - 1] + } + if(idxArr.length > 1) max = idxArr[idxArr.length - 1] - idxArr[0] + return [min === Infinity ? -1 : min, max] +}; diff --git a/2059-minimum-operations-to-convert-number.js b/2059-minimum-operations-to-convert-number.js new file mode 100644 index 00000000..05e7efd5 --- /dev/null +++ b/2059-minimum-operations-to-convert-number.js @@ -0,0 +1,36 @@ +/** + * @param {number[]} nums + * @param {number} start + * @param {number} goal + * @return {number} + */ +var minimumOperations = function (nums, start, goal) { + const visited = Array(1001).fill(0) + const q = [] + q.push([start, 0]) + visited[start] = 1 + while (q.length) { + const [val, idx] = q.shift() + if (val === goal) return idx + for (let e of nums) { + if (val + e === goal) return idx + 1 + if (val + e <= 1000 && val + e >= 0 && !visited[val + e]) { + visited[val + e] = 1 + q.push([val + e, idx + 1]) + } + if (val - e === goal) return idx + 1 + if (val - e <= 1000 && val - e >= 0 && !visited[val - e]) { + visited[val - e] = 1 + q.push([val - e, idx + 1]) + } + + if ((val ^ e) === goal) return idx + 1 + if ((val ^ e) <= 1000 && (val ^ e) >= 0 && !visited[val ^ e]) { + visited[val ^ e] = 1 + q.push([val ^ e, idx + 1]) + } + } + } + + return -1 +} diff --git a/206-reverse-linked-list.js b/206-reverse-linked-list.js index d804118a..82ccda9a 100755 --- a/206-reverse-linked-list.js +++ b/206-reverse-linked-list.js @@ -1,3 +1,30 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const reverseList = function(head) { + if(head == null) return head + const pre = new ListNode(null, head) + let cur = head + while(cur.next) { + const tmp = pre.next + pre.next = cur.next + cur.next = cur.next.next + pre.next.next = tmp + } + + return pre.next +}; + +// another + /** * Definition for singly-linked list. * function ListNode(val) { diff --git a/2060-check-if-an-original-string-exists-given-two-encoded-strings.js b/2060-check-if-an-original-string-exists-given-two-encoded-strings.js new file mode 100644 index 00000000..12be2ab2 --- /dev/null +++ b/2060-check-if-an-original-string-exists-given-two-encoded-strings.js @@ -0,0 +1,183 @@ +function possiblyEquals(s1, s2) { + const n = s1.length, m = s2.length; + const dp = Array.from({ length: n + 1 }, v => Array.from({ length: m + 1}, w => new Set())); + dp[0][0].add(0); + + for (let i = 0; i <= n; i++) { + for (let j = 0; j <= m; j++) { + for (let delta of dp[i][j]) { + // s1 is number + let num = 0; + if (delta <= 0) { + for (let p = i; i < Math.min(i + 3, n); p++) { + if (isDigit(s1[p])) { + num = num * 10 + Number(s1[p]); + dp[p + 1][j].add(delta + num); + } else { + break; + } + } + } + + // s2 is number + num = 0; + if (delta >= 0) { + for (let q = j; q < Math.min(j + 3, m); q++) { + if (isDigit(s2[q])) { + num = num * 10 + Number(s2[q]); + dp[i][q + 1].add(delta - num); + } else { + break; + } + } + } + + // match s1 non-digit character + if (i < n && delta < 0 && !isDigit(s1[i])) { + dp[i + 1][j].add(delta + 1); + } + + // match s2 non-digit character + if (j < m && delta > 0 && !isDigit(s2[j])) { + dp[i][j + 1].add(delta - 1); + } + + // two non-digit character match + if (i < n && j < m && delta == 0 && s1[i] == s2[j]) { + dp[i + 1][j + 1].add(0); + } + + } + } + } + return dp[n][m].has(0); +}; + +function isDigit(char) { + return (/^\d{1}$/g).test(char); +} + +// another + +/** + * @param {string} s1 + * @param {string} s2 + * @return {boolean} + */ +const possiblyEquals = function(s1, s2) { + const n = s1.length + const m = s2.length + const memo = Array.from({ length: n + 1 }, () => + Array.from({ length: m + 1 }, () => Array(1001).fill(null)) + ) + memo[0][0][1000] = true + + return dfs(0, 0, 0) + + function dfs(i, j, diff) { + if(memo[i][j][diff] != null) return memo[i][j][diff] + let res = false + if (i == n && j == m) res = diff === 0 + else if (i < n && isDigit(s1[i])) { + let ii = i + while (ii < n && isDigit( s1[ii] )) ii += 1 + for (let x of helper(s1.slice(i, ii))) { + if (dfs(ii, j, diff-x)) res = true + } + } else if (j < m && isDigit( s2[j] )) { + let jj = j + while (jj < m && isDigit( s2[jj] )) jj += 1 + for (let y of helper(s2.slice(j, jj))) { + if (dfs(i, jj, diff+y)) res = true + } + } else if (diff == 0) { + if (i < n && j < m && s1[i] == s2[j]) res = dfs(i+1, j+1, 0) + } else if (diff > 0) { + if (i < n) res = dfs(i+1, j, diff-1) + } else { + if (j < m) res = dfs(i, j+1, diff+1) + } + + memo[i][j][diff] = res + return res + } + + function isDigit(ch) { + return ch >= '0' && ch <= '9' + } + + function helper(str) { + const ans = new Set() + ans.add(+str) + for(let i = 1, len = str.length; i < len; i++) { + const pre = helper(str.slice(0, i)) + const post = helper(str.slice(i)) + for(let p of pre) { + for(let n of post) { + ans.add(p + n) + } + } + } + return Array.from(ans) + } +}; + +// another + +/** + * @param {string} s1 + * @param {string} s2 + * @return {boolean} + */ +var possiblyEquals = function (s1, s2) { + let n = s1.length + let m = s2.length + const f = Array.from({ length: n + 1 }, () => + Array.from({ length: m + 1 }, () => Array(1001).fill(false)) + ) + f[0][0][1000] = true + + for (let i = 0; i <= n; i++) + for (let j = 0; j <= m; j++) + for (let k = 0; k < 2000; k++) { + if (!f[i][j][k]) continue + // if k==1000 means length diff is 0, so check both next charactors. + if (i + 1 <= n && j + 1 <= m && k == 1000 && s1[i] == s2[j]) { + f[i + 1][j + 1][k] = true + } + // if first string is longer or same length, extend second string. + if (k >= 1000 && j + 1 <= m) { + if (s2[j] >= 'a' && s2[j] <= 'z') { + // do not extend to be a longer string using a-z. + if (k > 1000) { + f[i][j + 1][k - 1] = true + } + } else if (s2[j] > '0') { + let cur = 0 + for (let r = j; r < m; r++) { + if (s2[r] >= '0' && s2[r] <= '9') { + cur = cur * 10 + (s2[r] - '0') + f[i][r + 1][k - cur] = true + } else break + } + } + } + // if second string is longer or same length, extend first string. + if (k <= 1000 && i + 1 <= n) { + if (s1[i] >= 'a' && s1[i] <= 'z') { + if (k < 1000) { + f[i + 1][j][k + 1] = true + } + } else if (s1[i] > '0') { + let cur = 0 + for (let r = i; r < n; r++) { + if (s1[r] >= '0' && s1[r] <= '9') { + cur = cur * 10 + (s1[r] - '0') + f[r + 1][j][k + cur] = true + } else break + } + } + } + } + return f[n][m][1000] +} diff --git a/2062-count-vowel-substrings-of-a-string.js b/2062-count-vowel-substrings-of-a-string.js new file mode 100644 index 00000000..6645120c --- /dev/null +++ b/2062-count-vowel-substrings-of-a-string.js @@ -0,0 +1,27 @@ +/** + * @param {string} word + * @return {number} + */ +const countVowelSubstrings = function(word) { + let res = 0, n= word.length + for(let i = 0; i < n - 1;i++) { + for(let j = i + 1;j < n; j++) { + if(valid(word, i, j)) res++ + } + } + + return res + + function valid(s, i, j) { + const set = new Set(['a', 'e', 'i', 'o','u']) + const vis = new Set() + for(let idx = i; idx <= j; idx++) { + if(!set.has(s[idx])) return false + else { + vis.add(s[idx]) + } + } + // console.log(vis) + return vis.size === 5 + } +}; diff --git a/2063-vowels-of-all-substrings.js b/2063-vowels-of-all-substrings.js new file mode 100644 index 00000000..f05e18ed --- /dev/null +++ b/2063-vowels-of-all-substrings.js @@ -0,0 +1,20 @@ +/** + * @param {string} word + * @return {number} + */ +const countVowels = function(word) { + let res = 0n + const n = BigInt(word.length) + const set = new Set(['a', 'e', 'i', 'o', 'u']) + const dp = Array(n + 1n).fill(0n) + for(let i = 0n; i < n; i++) { + const ch = word[i] + if(set.has(ch)) dp[i + 1n] = dp[i] + (i + 1n) + else dp[i + 1n] = dp[i] + } + + for(const e of dp) res += e + return res +}; + + diff --git a/2064-minimized-maximum-of-products-distributed-to-any-store.js b/2064-minimized-maximum-of-products-distributed-to-any-store.js new file mode 100644 index 00000000..577fe013 --- /dev/null +++ b/2064-minimized-maximum-of-products-distributed-to-any-store.js @@ -0,0 +1,78 @@ +/** + * @param {number} n + * @param {number[]} quantities + * @return {number} + */ +const minimizedMaximum = function(n, quantities) { + const m = quantities.length + let l = 0, r = Math.max(...quantities) + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if(valid(mid)) r = mid + else l = mid + 1 + } + + return l + + function valid(mid) { + if(m > n) return false + let res = 0 + for (let i = 0; i < m; i++) { + res += Math.ceil(quantities[i] / mid) + } + return res <= n + } +}; + +// another + + +/** + * @param {number} n + * @param {number[]} quantities + * @return {number} + */ +var minimizedMaximum = function(n, quantities) { + let MAX = 0; + for (let x of quantities) MAX = Math.max(x, MAX); + let l = 1, r = MAX; + while (l < r) { + let mid = Math.floor((l + r) / 2); + if (valid(quantities, mid) <= n) r = mid; + else l = mid + 1; + } + return l; +}; + + + + function valid(quantities, max) { + let cnt = 0; + for (let x of quantities) cnt += Math.floor(x / max) + ((x % max) ? 1 : 0); + return cnt; + } + +// another + +/** + * @param {number} n + * @param {number[]} quantities + * @return {number} + */ +const minimizedMaximum = function(n, quantities) { + let MAX = 0; + for (let x of quantities) MAX = Math.max(x, MAX); + let l = 1, r = MAX; + while (l < r) { + let mid = Math.floor((l + r) / 2); + if (valid(quantities, mid, n)) l = mid + 1; + else r = mid; + } + return l; +}; + +function valid(quantities, max, n) { + let cnt = 0; + for (let x of quantities) cnt += Math.floor(x / max) + ((x % max) ? 1 : 0); + return cnt > n; +} diff --git a/2065-maximum-path-quality-of-a-graph.js b/2065-maximum-path-quality-of-a-graph.js new file mode 100644 index 00000000..ced6bb56 --- /dev/null +++ b/2065-maximum-path-quality-of-a-graph.js @@ -0,0 +1,113 @@ +/** + * @param {number[]} values + * @param {number[][]} edges + * @param {number} maxTime + * @return {number} + */ +const maximalPathQuality = function(values, edges, maxTime) { + const graph = {}, n = values.length + for(const [u, v, t] of edges) { + if(graph[u] == null) graph[u] = [] + if(graph[v] == null) graph[v] = [] + graph[u].push([v, t]) + graph[v].push([u, t]) + } + let res = 0, visited = new Array(n).fill(0) + visited[0] = 1 + bt(0, values[0], 0) + return res + + function bt(i, val, time) { + if(time > maxTime) return + if(i === 0) res = Math.max(res, val) + + for(const [next, nextTime] of (graph[i] || [])) { + const nextVal = visited[next] > 0 ? val : val + values[next] + visited[next]++ + bt(next, nextVal, time + nextTime) + visited[next]-- + } + } +}; + +// another + + +/** + * @param {number[]} values + * @param {number[][]} edges + * @param {number} maxTime + * @return {number} + */ +const maximalPathQuality = function(values, edges, maxTime) { + const graph = {}, n = values.length + for(const [u, v, t] of edges) { + if(graph[u] == null) graph[u] = [] + if(graph[v] == null) graph[v] = [] + graph[u].push([v, t]) + graph[v].push([u, t]) + } + let res = 0, visited = Array(n).fill(false) + bt(0, 0, 0) + return res + + function bt(i, cur, time) { + if(time > maxTime) return + const backup = visited[i] + if(!visited[i]) { + visited[i] = true + cur += values[i] + } + + if(i === 0) { + res = Math.max(res, cur) + } + + for(const [next, nextTime] of (graph[i] || [])) { + bt(next, cur, time + nextTime) + } + visited[i] = backup + } +}; + +// another + +/** + * @param {number[]} values + * @param {number[][]} edges + * @param {number} maxTime + * @return {number} + */ +const maximalPathQuality = function(values, edges, maxTime) { + let zeroMax = 0; + let n = values.length; + let ll = Array.from({length: n + 1}, () => []) + for (let edge of edges) { + let u = edge[0]; + let v = edge[1]; + let t = edge[2]; + ll[u].push([v, t]); + ll[v].push([u, t]); + } + const visited = Array(n + 1).fill(false); + dfs(0, 0, 0, maxTime, visited); + return zeroMax; + + function dfs(val, curNode, curTime, maxTime, visited) { + if (curTime > maxTime) { + return; + } + let before = visited[curNode]; + if (!visited[curNode]) { + val += values[curNode]; + visited[curNode] = true; + } + if (curNode == 0) { + zeroMax = Math.max(zeroMax, val); + } + for (let next of (ll[curNode] || [])) { + dfs(val, next[0], curTime + next[1], maxTime, visited); + } + visited[curNode] = before; + } +}; diff --git a/2068-check-whether-two-strings-are-almost-equivalent.js b/2068-check-whether-two-strings-are-almost-equivalent.js new file mode 100644 index 00000000..7c242d12 --- /dev/null +++ b/2068-check-whether-two-strings-are-almost-equivalent.js @@ -0,0 +1,21 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {boolean} + */ +const checkAlmostEquivalent = function(word1, word2) { + const a = 'a'.charCodeAt(0), n = word1.length + const arr1 = Array(26).fill(0), arr2 = Array(26).fill(0) + + for(const ch of word1) { + arr1[ch.charCodeAt(0) - a]++ + } + for(const ch of word2) { + arr2[ch.charCodeAt(0) - a]++ + } + for(let i = 0; i < 26; i++) { + if(Math.abs(arr1[i] - arr2[i]) > 3) return false + } + + return true +}; diff --git a/2069-walking-robot-simulation-ii.js b/2069-walking-robot-simulation-ii.js new file mode 100644 index 00000000..50be2e38 --- /dev/null +++ b/2069-walking-robot-simulation-ii.js @@ -0,0 +1,49 @@ +/** + * @param {number} width + * @param {number} height + */ +const Robot = function(width, height) { + this.i = 0 + const pos = Array() + this.len = width + height - 1 + width - 1 + height - 2 + pos.push( [0,0,3] ) + for(let i = 1; i < width; i++) { + pos.push([i, 0, 0]) + } + for(let i = 1; i < height; i++) { + pos.push([width - 1, i, 1]) + } + for(let i = 1; i < width; i++) { + pos.push([width - 1 - i, height - 1, 2]) + } + for(let i = 1; i < height - 1; i++) { + pos.push([0, height - 1 - i, 3]) + } + this.pos = pos +}; + +/** + * @param {number} num + * @return {void} + */ +Robot.prototype.step = function(num) { + this.i += num +}; + +/** + * @return {number[]} + */ +Robot.prototype.getPos = function() { + return this.pos[this.i % this.len].slice(0, 2) +}; + +/** + * @return {string} + */ +Robot.prototype.getDir = function() { + const hash = ['East', 'North', 'West', 'South'] + if(this.i === 0) return hash[0] + else { + return hash[this.pos[this.i % this.len][2]] + } +}; diff --git a/207-course-schedule.js b/207-course-schedule.js new file mode 100644 index 00000000..09233baa --- /dev/null +++ b/207-course-schedule.js @@ -0,0 +1,192 @@ +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {boolean} + */ +const canFinish = function (numCourses, prerequisites) { + const set = new Set() + const indegree = Array(numCourses).fill(0) + const graph = {} + + for (const [s, e] of prerequisites) { + indegree[e]++ + if (graph[s] == null) graph[s] = [] + graph[s].push(e) + } + + let q = [] + for (let i = 0; i < numCourses; i++) { + if (indegree[i] === 0) q.push(i) + } + + while (q.length) { + const nxt = [] + for (let i = 0, size = q.length; i < size; i++) { + const cur = q[i] + set.add(cur) + for (const e of graph[cur] || []) { + indegree[e]-- + if (indegree[e] === 0 && !set.has(e)) { + nxt.push(e) + } + } + } + + q = nxt + } + + return set.size === numCourses +} + +// another + + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {boolean} + */ +const canFinish = function(numCourses, prerequisites) { + const [graph, inDegree] = buildGraph(numCourses, prerequisites) + + const q = [] + for(let i = 0; i < numCourses; i++) { + if(inDegree.get(i) == null) q.push(i) + } + let num = 0 + while(q.length) { + const pre = q.pop() + num++ + for(const next of (graph.get(pre) || [])) { + inDegree.set(next, inDegree.get(next) - 1) + if(inDegree.get(next) === 0) q.push(next) + } + } + return num === numCourses + + + function buildGraph(n, arr) { + const res = new Map(), inDegree = new Map() + for(const [cur, pre] of arr) { + if(res.get(pre) == null) res.set(pre, new Set()) + res.get(pre).add(cur) + if(inDegree.get(cur) == null) inDegree.set(cur, 0) + inDegree.set(cur, inDegree.get(cur) + 1) + } + return [res, inDegree] + } +}; + +// another + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {boolean} + */ +const canFinish = function(numCourses, prerequisites) { + const seen = new Set() + const seeing = new Set() + const adj = [...Array(numCourses)].map(r => []) + for (let [u, v] of prerequisites) { + adj[v].push(u) + } + for (let c = 0; c < numCourses; c++) { + if (!dfs(c)) { + return false + } + } + return true + function dfs(v) { + if (seen.has(v)) return true + if (seeing.has(v)) return false + seeing.add(v) + for (let nv of adj[v]) { + if (!dfs(nv)) { + return false + } + } + seeing.delete(v) + seen.add(v) + return true + } +} + +// another + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {boolean} + */ +const canFinish = function(vertices, edges) { + const sortedOrder = [] + if (vertices <= 0) { + return sortedOrder + } + const inDegree = Array(vertices).fill(0) + const graph = Array(vertices) + .fill(0) + .map(() => Array()) + edges.forEach(edge => { + let parent = edge[0] + let child = edge[1] + graph[parent].push(child) + inDegree[child]++ + }) + const sources = [] + for (let i = 0; i < inDegree.length; i++) { + if (inDegree[i] === 0) { + sources.push(i) + } + } + while (sources.length > 0) { + const vertex = sources.shift() + sortedOrder.push(vertex) + + graph[vertex].forEach(child => { + inDegree[child] -= 1 + if (inDegree[child] === 0) { + sources.push(child) + } + }) + } + return sortedOrder.length === vertices ? true : false +} + +// another + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {boolean} + */ +const canFinish = function(numCourses, prerequisites) { + const set = new Set(), hash = {} + for(let i = 0; i < prerequisites.length; i++) { + const [cur, pre] = prerequisites[i] + if(hash[cur] == null) hash[cur] = new Set() + hash[cur].add(pre) + } + const q = [] + + for(let i = 0; i < numCourses; i++) { + if(hash[i] == null) q.push(i) + } + let visited = 0 + + while(q.length) { + const cur = q.shift() + visited++ + Object.keys(hash).forEach(k => { + if(hash[k].has(cur)) { + hash[k].delete(cur) + } + if(hash[k].size === 0) { + delete hash[k] + q.push(+k) + } + }) + } + return visited === numCourses +}; diff --git a/2071-maximum-number-of-tasks-you-can-assign.js b/2071-maximum-number-of-tasks-you-can-assign.js new file mode 100644 index 00000000..dabb440a --- /dev/null +++ b/2071-maximum-number-of-tasks-you-can-assign.js @@ -0,0 +1,75 @@ +//////////////////////////////////////////////Template///////////////////////////////////////////////////////////// +function Bisect() { + return { insort_right, insort_left, bisect_left, bisect_right } + function insort_right(a, x, lo = 0, hi = null) { + lo = bisect_right(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_right(a, x, lo = 0, hi = null) { + // > upper_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + x < a[mid] ? (hi = mid) : (lo = mid + 1) + } + return lo + } + function insort_left(a, x, lo = 0, hi = null) { + lo = bisect_left(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_left(a, x, lo = 0, hi = null) { + // >= lower_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + a[mid] < x ? (lo = mid + 1) : (hi = mid) + } + return lo + } +} +/** + * @param {number[]} tasks + * @param {number[]} workers + * @param {number} pills + * @param {number} strength + * @return {number} + */ +const maxTaskAssign = function(tasks, workers, pills, strength) { + tasks.sort((a, b) => a - b) + workers.sort((a, b) => b - a) + const m = tasks.length, n = workers.length + const { min, floor } = Math + let l = 0, r = min(n, m) + while (l < r) { + const mid = r - floor((r - l) / 2) + if (check(mid)) l = mid + else r = mid - 1 + } + + return l + + function check(k){ + const wArr = workers.slice(0, k), tArr = tasks.slice(0, k) + let tries = pills, bs = new Bisect() + wArr.reverse() + tArr.reverse() + + for (let elem of tArr) { + const place = bs.bisect_left(wArr, elem) + if (place < wArr.length) { + wArr.pop() + } else if (tries > 0) { + const place2 = bs.bisect_left(wArr, elem - strength) + if (place2 < wArr.length) { + wArr.splice(place2, 1) + tries -= 1 + } + } else return false + } + + return wArr.length === 0 + } +}; diff --git a/2073-time-needed-to-buy-tickets.js b/2073-time-needed-to-buy-tickets.js new file mode 100644 index 00000000..f468ef72 --- /dev/null +++ b/2073-time-needed-to-buy-tickets.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} tickets + * @param {number} k + * @return {number} + */ +const timeRequiredToBuy = function(tickets, k) { + let res = 0 + + while(tickets[k] !== 0) { + res += helper(tickets, k) + } + + return res + + function helper(arr, k) { + let tmp = 0 + for(let i = 0; i < arr.length; i++) { + if(arr[i] > 0) { + arr[i]-- + tmp++ + } + if(arr[k] === 0) break + } + return tmp + } + +}; diff --git a/2074-reverse-nodes-in-even-length-groups.js b/2074-reverse-nodes-in-even-length-groups.js new file mode 100644 index 00000000..357cdfb3 --- /dev/null +++ b/2074-reverse-nodes-in-even-length-groups.js @@ -0,0 +1,41 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const reverseEvenLengthGroups = function(head) { + const arr = [] + let cur = head + while(cur) { + arr.push(cur) + cur = cur.next + } + let len = 1, res = [] + for(let i = 0, n = arr.length; i < n; ) { + let backup = len, tmp = [], rev = len % 2 === 0 + while(len && i < n) { + tmp.push(arr[i]) + i++ + len-- + } + if((tmp.length % 2 === 0) ) { + tmp.reverse() + } + res.push(...tmp) + len = backup + 1 + } + for(let i = 0; i < res.length; i++) { + if(i === res.length - 1) res[i].next = null + else { + res[i].next = res[i + 1] + } + } + + return res[0] +}; diff --git a/2075-decode-the-slanted-ciphertext.js b/2075-decode-the-slanted-ciphertext.js new file mode 100644 index 00000000..d0b88b7d --- /dev/null +++ b/2075-decode-the-slanted-ciphertext.js @@ -0,0 +1,29 @@ +/** + * @param {string} encodedText + * @param {number} rows + * @return {string} + */ +var decodeCiphertext = function(encodedText, rows) { + let n = encodedText.length; + let cols = ~~(n / rows); + const matrix = Array.from({ length: rows }, () => Array(cols).fill('')) + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + matrix[i][j] = encodedText[i * cols + j]; + } + } + let ans = ""; + for (let i = 0; i < cols; i++) { + let t = Math.min(rows, cols - i); + for (let j = 0; j < t; j++) { + ans += matrix[j][i + j]; + } + } + let idx = ans.length - 1 + for(; idx >= 0; idx--) { + if(ans[idx] === ' ') continue + else break + } + return ans.slice(0, idx + 1); +}; + diff --git a/2076-process-restricted-friend-requests.js b/2076-process-restricted-friend-requests.js new file mode 100644 index 00000000..a757b1c9 --- /dev/null +++ b/2076-process-restricted-friend-requests.js @@ -0,0 +1,40 @@ +/** + * @param {number} n + * @param {number[][]} restrictions + * @param {number[][]} requests + * @return {boolean[]} + */ +var friendRequests = function(n, restrictions, requests) { + function validation(arr) { + for (const [x, y] of restrictions) { + if (arr[x] == arr[y]) return false + } + + return true + } + + + + let groupId = [] + for(let i = 0; i < n; i++) groupId.push(i) + + + const ans = [] + for(let [u, v] of requests) { + if (v < u) [u, v] = [v, u] + const tmp = groupId.slice() + + for(let i = 0; i < n; i++) { + if (tmp[i] == groupId[v]) tmp[i] = groupId[u] + } + + if (validation(tmp)) { + ans.push(true) + groupId = tmp + } else ans.push(false) + } + + + return ans +}; + diff --git a/2078-two-furthest-houses-with-different-colors.js b/2078-two-furthest-houses-with-different-colors.js new file mode 100644 index 00000000..0e3c6406 --- /dev/null +++ b/2078-two-furthest-houses-with-different-colors.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} colors + * @return {number} + */ +const maxDistance = function(colors) { + const n = colors.length + let res = 0 + for(let i = 1; i < n; i++) { + const cur = colors[i] + for(let j = 0; j < i; j++) { + if(colors[i] !== colors[j]) { + res = Math.max(res, i - j) + break + } + } + } + + return res +}; diff --git a/2079-watering-plants.js b/2079-watering-plants.js new file mode 100644 index 00000000..b2c784d9 --- /dev/null +++ b/2079-watering-plants.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} plants + * @param {number} capacity + * @return {number} + */ +const wateringPlants = function(plants, capacity) { + let res = 0, cap = capacity, full = capacity + for(let i = 0, n = plants.length; i < n; i++) { + const cur = plants[i] + cap -= cur + if(cap >= 0) res++ + else { + res = res + (i + i + 1) + cap = full - cur + } + } + + return res +}; diff --git a/208-implement-trie-prefix-tree.js b/208-implement-trie-prefix-tree.js new file mode 100644 index 00000000..30c460ea --- /dev/null +++ b/208-implement-trie-prefix-tree.js @@ -0,0 +1,152 @@ +/** + * Initialize your data structure here. + */ +const Trie = function() { + this.root = {} +}; + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function(word) { + let curr = this.root + word.split('').forEach(ch => (curr = curr[ch] = curr[ch] || {})) + curr.isWord = true +}; + +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function(word) { + let node = this.traverse(word) + return !!node && !!node.isWord +}; + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function(prefix) { + return !!this.traverse(prefix) +}; + +/** + * Your Trie object will be instantiated and called as such: + * var obj = new Trie() + * obj.insert(word) + * var param_2 = obj.search(word) + * var param_3 = obj.startsWith(prefix) + */ + +Trie.prototype.traverse = function(word) { + let curr = this.root + for (let i = 0; i < word.length; i++) { + if (!curr) return null + curr = curr[word[i]] + } + return curr +} + +// another + +class Trie { + constructor() { + this.links = new Map(); + this.isWord = false; + } + insert(word) { + let node = this; + for (const c of word) { + if (!node.links.has(c)) node.links.set(c, new Trie()); + node = node.links.get(c); + } + node.isWord = true; + } + search(word) { + const node = this.traverse(word); + return node ? node.isWord : false; + } + startsWith(prefix) { + const node = this.traverse(prefix); + return node !== null; + } + traverse(word) { + let node = this; + for (const c of word) { + if (node.links.has(c)) node = node.links.get(c); + else return null; + } + return node; + } +} + +// another +/** + * Initialize your data structure here. + */ +const Trie = function () { + this.root = new Node(null) +} + +/** + * Inserts a word into the trie. + * @param {string} word + * @return {void} + */ +Trie.prototype.insert = function (word) { + let cur = this.root + for (let i = 0, len = word.length; i < len; i++) { + if (!cur.children.has(word[i])) cur.children.set(word[i], new Node(null)) + cur = cur.children.get(word[i]) + if (i === len - 1) cur.word = true + } +} + +/** + * Returns if the word is in the trie. + * @param {string} word + * @return {boolean} + */ +Trie.prototype.search = function (word) { + let cur = this.root + for (let i = 0, len = word.length; i < len; i++) { + if (cur.children.has(word[i])) cur = cur.children.get(word[i]) + else return false + if (i === len - 1) return cur.word === true + } +} + +/** + * Returns if there is any word in the trie that starts with the given prefix. + * @param {string} prefix + * @return {boolean} + */ +Trie.prototype.startsWith = function (prefix) { + let cur = this.root + for (let i = 0, len = prefix.length; i < len; i++) { + if (cur.children.has(prefix[i])) cur = cur.children.get(prefix[i]) + else return false + if (i === len - 1) return true + } +} + +class Node { + constructor(v) { + this.val = v + this.word = false + this.children = new Map() + } +} + +/** + * Your Trie object will be instantiated and called as such: + * var obj = new Trie() + * obj.insert(word) + * var param_2 = obj.search(word) + * var param_3 = obj.startsWith(prefix) + */ diff --git a/2080-range-frequency-queries.js b/2080-range-frequency-queries.js new file mode 100644 index 00000000..c474380b --- /dev/null +++ b/2080-range-frequency-queries.js @@ -0,0 +1,69 @@ +//////////////////////////////////////////////Template///////////////////////////////////////////////////////////// +function Bisect() { + return { insort_right, insort_left, bisect_left, bisect_right } + function insort_right(a, x, lo = 0, hi = null) { + lo = bisect_right(a, x, lo, hi); + a.splice(lo, 0, x); + } + function bisect_right(a, x, lo = 0, hi = null) { // > upper_bound + if (lo < 0) throw new Error('lo must be non-negative'); + if (hi == null) hi = a.length; + while (lo < hi) { + let mid = parseInt((lo + hi) / 2); + x < a[mid] ? hi = mid : lo = mid + 1; + } + return lo; + } + function insort_left(a, x, lo = 0, hi = null) { + lo = bisect_left(a, x, lo, hi); + a.splice(lo, 0, x); + } + function bisect_left(a, x, lo = 0, hi = null) { // >= lower_bound + if (lo < 0) throw new Error('lo must be non-negative'); + if (hi == null) hi = a.length; + while (lo < hi) { + let mid = parseInt((lo + hi) / 2); + a[mid] < x ? lo = mid + 1 : hi = mid; + } + return lo; + } +} + +// counter with {value: array indices (increasing order)} +const counter_value_in_indexA_in = (a_or_s) => { let m = new Map(); let n = a_or_s.length; for (let i = 0; i < n; i++) { if (!m.has(a_or_s[i])) m.set(a_or_s[i], []); m.get(a_or_s[i]).push(i); } return m; }; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * @param {number[]} arr + */ +var RangeFreqQuery = function(arr) { + let a = arr + this.m = counter_value_in_indexA_in(a) + this.bi = new Bisect(); +}; + +/** + * @param {number} left + * @param {number} right + * @param {number} value + * @return {number} + */ +RangeFreqQuery.prototype.query = function(left, right, value) { + let l = left, r =right, x = value, m = this.m, bi = this.bi + if (!m.has(x)) return 0; + let a = m.get(x), len = a.length; + let min = a[0], max = a[len - 1]; + if (l <= min && r >= max) return len; // cover all + if (r < min || l > max) return 0; // out of bound + let lbs = bi.bisect_left(a, l); // needs lbs >= l (lower bound will find first >= l) + let ubs = bi.bisect_right(a, r); // needs ubs <= r (upper bound will find first ubs > r, -1 will guarantee <= r) + ubs--; + return ubs - lbs + 1; +}; + +/** + * Your RangeFreqQuery object will be instantiated and called as such: + * var obj = new RangeFreqQuery(arr) + * var param_1 = obj.query(left,right,value) + */ + diff --git a/2081-sum-of-k-mirror-numbers.js b/2081-sum-of-k-mirror-numbers.js new file mode 100644 index 00000000..118be589 --- /dev/null +++ b/2081-sum-of-k-mirror-numbers.js @@ -0,0 +1,26 @@ +const isPalindrome = (s) => { let n = s.length; let i = 0; let j = n - 1; while (i < j) { if (s[i++] != s[j--]) return false; } return true; }; + +const int = parseInt; +/** + * @param {number} k + * @param {number} n + * @return {number} + */ +var kMirror = function(k, n) { + let res = 0; + for (let len = 1; ; len++) { + let min = 10 ** ((len - 1) >> 1), max = 10 ** ((len + 1) >> 1); + for (let base = min; base < max; base++) { + let x = base; + for (let i = len & 1 ? int(base / 10) : base; i > 0; i = int(i / 10)) { + x = x * 10 + i % 10; + } + let s = x.toString(k); + if (isPalindrome(s)) { + res += x; + n--; + if (!n) return res; + } + } + } +}; diff --git a/2082-the-number-of-rich-customers.sql b/2082-the-number-of-rich-customers.sql new file mode 100644 index 00000000..fa154f5e --- /dev/null +++ b/2082-the-number-of-rich-customers.sql @@ -0,0 +1,2 @@ +# Write your MySQL query statement below +SELECT COUNT(DISTINCT customer_id) AS rich_count FROM Store WHERE amount > 500; diff --git a/2083-substrings-that-begin-and-end-with-the-same-letter.js b/2083-substrings-that-begin-and-end-with-the-same-letter.js new file mode 100644 index 00000000..3e1522a9 --- /dev/null +++ b/2083-substrings-that-begin-and-end-with-the-same-letter.js @@ -0,0 +1,28 @@ +/** + * @param {string} s + * @return {number} + */ +const numberOfSubstrings = function(s) { + const hash = {} + const n = s.length + for(let i = 0; i < n; i++) { + const ch = s[i] + if(hash[ch] == null) hash[ch] = [] + hash[ch].push(i) + } + + let res = 0 + const keys = Object.keys(hash) + keys.forEach(k => { + res += helper(k) + }) + + return res + + + function helper(k) { + const arr = hash[k] + const len = arr.length + return len * (len + 1) / 2 + } +}; diff --git a/2084-drop-type-1-orders-for-customers-with-type-0-orders.sql b/2084-drop-type-1-orders-for-customers-with-type-0-orders.sql new file mode 100644 index 00000000..113dc39f --- /dev/null +++ b/2084-drop-type-1-orders-for-customers-with-type-0-orders.sql @@ -0,0 +1,6 @@ +# Write your MySQL query statement below +SELECT * FROM Orders +WHERE (customer_id, order_type) +IN (SELECT customer_id, MIN(order_type) + FROM Orders + GROUP BY customer_id); diff --git a/2086-minimum-number-of-buckets-required-to-collect-rainwater-from-houses.js b/2086-minimum-number-of-buckets-required-to-collect-rainwater-from-houses.js new file mode 100644 index 00000000..e7193788 --- /dev/null +++ b/2086-minimum-number-of-buckets-required-to-collect-rainwater-from-houses.js @@ -0,0 +1,17 @@ +/** + * @param {string} street + * @return {number} + */ +var minimumBuckets = function(street) { + const arr = street.split(''), n = arr.length + let res = 0 + for(let i = 0; i < arr.length; i++) { + if(arr[i] === 'H') { + if(i > 0 && arr[i - 1] === 'B') continue + if(i < n - 1 && arr[i + 1] === '.') arr[i + 1] = 'B', res++ + else if(i > 0 && arr[i - 1] === '.') arr[i - 1] = 'B', res++ + else return -1 + } + } + return res +}; diff --git a/2088-count-fertile-pyramids-in-a-land.js b/2088-count-fertile-pyramids-in-a-land.js new file mode 100644 index 00000000..f1677e0d --- /dev/null +++ b/2088-count-fertile-pyramids-in-a-land.js @@ -0,0 +1,31 @@ +/** + * @param {number[][]} grid + * @return {number} + */ + const countPyramids = function(grid) { + const rev = clone(grid).reverse() + let res = count(grid) + res += count(rev) + return res + + function clone(grid) { + return grid.map(e => e.slice()) + } + + function count(grid) { + const m = grid.length, n = grid[0].length + let res = 0 + for (let i = 1; i < m; i++) { + for (let j = 1; j < n - 1; j++) { + if (grid[i][j] && grid[i - 1][j]) { + grid[i][j] = Math.min( + grid[i - 1][j - 1], + grid[i - 1][j + 1] + ) + 1 + res += grid[i][j] - 1 + } + } + } + return res + } +}; diff --git a/2089-find-target-indices-after-sorting-array.js b/2089-find-target-indices-after-sorting-array.js new file mode 100644 index 00000000..ddc093b9 --- /dev/null +++ b/2089-find-target-indices-after-sorting-array.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ +const targetIndices = function(nums, target) { + let res = [] + nums.sort((a, b) => a - b) + for(let i = 0; i < nums.length; i++) { + if(nums[i] === target) res.push(i) + } + return res +}; diff --git a/2090-k-radius-subarray-averages.js b/2090-k-radius-subarray-averages.js new file mode 100644 index 00000000..c99d400c --- /dev/null +++ b/2090-k-radius-subarray-averages.js @@ -0,0 +1,43 @@ +const lowBit = (x) => x & -x +class FenwickTree { + constructor(n) { + if (n < 1) return + this.sum = Array(n + 1).fill(0) + } + update(i, delta) { + if (i < 1) return + while (i < this.sum.length) { + this.sum[i] += delta + i += lowBit(i) + } + } + query(i) { + if (i < 1) return 0 + let sum = 0 + while (i > 0) { + sum += this.sum[i] + i -= lowBit(i) + } + return sum + } +} +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +const getAverages = function(nums, k) { + const n = nums.length + const bit = new FenwickTree(n) + for(let i = 0; i < n; i++) { + bit.update(i + 1, nums[i]) + } + const res = Array(n).fill(-1) + // console.log(bit) + for(let i = k; i < n - k; i++) { + const pre = bit.query(i + 1 - k - 1), cur = bit.query(i + 1 + k) + res[i] = ~~((cur - pre) / (k * 2 + 1)) + } + + return res +}; diff --git a/2091-removing-minimum-and-maximum-from-array.js b/2091-removing-minimum-and-maximum-from-array.js new file mode 100644 index 00000000..81d73144 --- /dev/null +++ b/2091-removing-minimum-and-maximum-from-array.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumDeletions = function(nums) { + let mi = Infinity, ma = -Infinity + let mii = -1, mai = -1 + const { max, min, abs } = Math, n = nums.length + for(let i = 0; i < n; i++) { + const e = nums[i] + if(e < mi) { + mi = e + mii = i + } + if(e > ma) { + ma = e + mai = i + } + } + + const disMi = abs(mii + 1, n - mii) + const disMa = abs(mai + 1, n - mai) + let res = 0 + let lmi = min(mii, mai), lma = max(mii, mai) + + res += min(lmi + 1 + n - lma, lma + 1, n - lmi) + + + return res +}; diff --git a/2092-find-all-people-with-secret.js b/2092-find-all-people-with-secret.js new file mode 100644 index 00000000..fc592271 --- /dev/null +++ b/2092-find-all-people-with-secret.js @@ -0,0 +1,95 @@ +/** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ +const findAllPeople = function(n, meetings, firstPerson) { + meetings.sort((a, b) => a[2] - b[2]) + const uf = new UnionFind(n); + uf.connect(0, firstPerson); + let ppl = []; + for (let i = 0, len = meetings.length; i < len; ) { + ppl = []; + let time = meetings[i][2]; + while (i < len && meetings[i][2] === time) { + uf.connect(meetings[i][0], meetings[i][1]); + ppl.push(meetings[i][0]); + ppl.push(meetings[i][1]); + i++ + } + for (let n of ppl) { + if (!uf.connected(0, n)) uf.reset(n); + } + } + let ans = []; + for (let i = 0; i < n; ++i) { + if (uf.connected(0, i)) ans.push(i); + } + return ans; +}; + +class UnionFind { + constructor(n) { + this.arr = Array(n).fill(null) + this.arr.forEach((e, i, arr) => arr[i] = i) + } + connect(a, b) { + this.arr[this.find(a)] = this.find(this.arr[b]) + } + find(a) { + return this.arr[a] === a ? a : (this.arr[a] = this.find(this.arr[a])) + } + connected(a, b) { + return this.find(a) === this.find(b) + } + reset(a) { + this.arr[a] = a + } +} + +// another + +/** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ +const findAllPeople = function(n, meetings, firstPerson) { + meetings.sort((a, b) => a[2] - b[2]) + const shared = new Set([0, firstPerson]) + + let start = new Set(), links = {} + for(let i = 0, len = meetings.length; i < len; i++) { + const [x,y,t] = meetings[i] + if(i > 0 && t !== meetings[i - 1][2]) { + bfs(start, links) + start = new Set() + links = {} + } + if(shared.has(x)) start.add(x) + if(shared.has(y)) start.add(y) + if(links[x] == null) links[x] = [] + if(links[y] == null) links[y] = [] + links[x].push(y) + links[y].push(x) + } + + bfs(start, links) + return Array.from(shared) + + function bfs(start, links) { + const visited = new Set() + while(start.size) { + const it = start[Symbol.iterator]() + const cur = it.next().value + start.delete(cur) + visited.add(cur) + shared.add(cur) + for(let e of (links[cur] || [])) { + if(!visited.has(e)) start.add(e) + } + } + } +}; diff --git a/2094-finding-3-digit-even-numbers.js b/2094-finding-3-digit-even-numbers.js new file mode 100644 index 00000000..a3f166fe --- /dev/null +++ b/2094-finding-3-digit-even-numbers.js @@ -0,0 +1,49 @@ +/** + * @param {number[]} digits + * @return {number[]} + */ +const findEvenNumbers = function(digits) { + const set = new Set(), visited = new Set() + helper(0, []) + const res = Array.from(set) + res.sort((a, b) => a - b) + return res + + function helper(idx, cur) { + if(cur.length === 3) { + set.add(+cur.join('')) + return + } + for(let i = 0; i < digits.length; i++) { + if(visited.has(i)) continue + const d = digits[i] + if(d === 0) { + if(cur.length === 0) continue + else { + cur.push(d) + visited.add(i) + helper(i + 1, cur) + visited.delete(i) + cur.pop() + } + } else { + const isEven = d % 2 === 0 + if(cur.length === 3 - 1) { + if(isEven) { + cur.push(d) + visited.add(i) + helper(i + 1, cur) + visited.delete(i) + cur.pop() + } else continue + } else { + cur.push(d) + visited.add(i) + helper(i + 1, cur) + visited.delete(i) + cur.pop() + } + } + } + } +}; diff --git a/2095-delete-the-middle-node-of-a-linked-list.js b/2095-delete-the-middle-node-of-a-linked-list.js new file mode 100644 index 00000000..7ee0aef7 --- /dev/null +++ b/2095-delete-the-middle-node-of-a-linked-list.js @@ -0,0 +1,36 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const deleteMiddle = function(head) { + if(head == null) return head + const dummy = new ListNode(null, head) + let n = 0, cur = head + while(cur) { + n++ + cur = cur.next + } + if(n === 1) return null + const mid = Math.floor(n / 2) + cur = dummy.next + let pre = dummy + for(let i = 0; i < n; i++) { + if(i === mid - 1) { + pre = cur + // pre.next = cur.next.next + } + if(i === mid) { + pre.next = cur.next + } + if(i > mid) break + cur = cur.next + } + return dummy.next +}; diff --git a/2096-step-by-step-directions-from-a-binary-tree-node-to-another.js b/2096-step-by-step-directions-from-a-binary-tree-node-to-another.js new file mode 100644 index 00000000..af3be49d --- /dev/null +++ b/2096-step-by-step-directions-from-a-binary-tree-node-to-another.js @@ -0,0 +1,30 @@ +/** + * 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 + * @param {number} startValue + * @param {number} destValue + * @return {string} + */ +const getDirections = function (root, startValue, destValue) { + let start = '' + let end = '' + const traverse = (node, path) => { + if (node === null) return + if (node.val === startValue) start = path + if (node.val === destValue) end = path + if (start !== '' && end !== '') return + if (node.left !== null) traverse(node.left, path + 'L') + if (node.right !== null) traverse(node.right, path + 'R') + } + traverse(root, '') + let skip = 0 + while (start[skip] && start[skip] === end[skip]) skip++ + return 'U'.repeat(start.length - skip) + end.slice(skip) +} diff --git a/2097-valid-arrangement-of-pairs.js b/2097-valid-arrangement-of-pairs.js new file mode 100644 index 00000000..35ae9f41 --- /dev/null +++ b/2097-valid-arrangement-of-pairs.js @@ -0,0 +1,36 @@ +const packDGInOutDegreeMap = (gm, edges, dm) => { for (const [u, v] of edges) { if (!gm.has(u)) gm.set(u, []); gm.get(u).push(v); dm.set(u, (dm.get(u) || 0) + 1); dm.set(v, (dm.get(v) || 0) - 1); } }; + +/** + * @param {number[][]} pairs + * @return {number[][]} + */ +const validArrangement = (pairs) => { + let g = new Map(), deg = new Map(), res = []; + packDGInOutDegreeMap(g, pairs, deg); + let start = -1; + for (const [node, ] of deg) { // looking for starting node + if (start == -1 || deg.get(node) == 1) start = node; + } + let path = eulerianPath(g, start); + path.reverse(); + for (let i = 1; i < path.length; i++) { + res.push([path[i-1], path[i]]); + } + return res; +}; + +const eulerianPath = (g, start) => { // eulerian Path with Hierholzer’s Algorithm + let st = [start], path = []; + while (st.length) { + let u = st[st.length - 1], ua = g.get(u) || []; + if (ua.length) { + let v = ua.pop(); + g.set(u, ua); + st.push(v); + } else { + path.push(u); + st.pop(); + } + } + return path; +}; diff --git a/2098-subsequence-of-size-k-with-the-largest-even-sum.js b/2098-subsequence-of-size-k-with-the-largest-even-sum.js new file mode 100644 index 00000000..e78fd154 --- /dev/null +++ b/2098-subsequence-of-size-k-with-the-largest-even-sum.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const largestEvenSum = function(nums, k) { + nums.sort((a, b) => b - a) + let sum = 0 + for(let i = 0; i < k; i++) sum += nums[i] + if(sum % 2 === 0) return sum + + const INF = 10 ** 6 + let minOdd = INF, minEven = INF + for(let i = 0; i < k; i++) { + if(nums[i] % 2 === 0) minEven = Math.min(minEven, nums[i]) + else minOdd = Math.min(minOdd, nums[i]) + } + + const n = nums.length + let res = -1 + for(let i = k; i < n; i++) { + if(nums[i] % 2 === 0 && minOdd !== INF) { + res = Math.max(res, sum - minOdd + nums[i]) + } + if(nums[i] % 2 === 1 && minEven !== INF) { + res = Math.max(res, sum - minEven + nums[i]) + } + } + + return res +}; diff --git a/21-merge-two-sorted-lists.js b/21-merge-two-sorted-lists.js index 83091e5c..3d094664 100755 --- a/21-merge-two-sorted-lists.js +++ b/21-merge-two-sorted-lists.js @@ -22,3 +22,37 @@ const mergeTwoLists = function(l1, l2) { return l2; } }; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +const mergeTwoLists = function(l1, l2) { + const dummy = new ListNode() + let cur = dummy + while(l1 && l2) { + if(l1.val < l2.val) { + cur.next = new ListNode(l1.val) + l1 = l1.next + } else { + cur.next = new ListNode(l2.val) + l2 = l2.next + } + + cur = cur.next + } + if(l1) cur.next = l1 + if(l2) cur.next = l2 + + return dummy.next +}; diff --git a/210-course-schedule-ii.js b/210-course-schedule-ii.js new file mode 100644 index 00000000..acfd8832 --- /dev/null +++ b/210-course-schedule-ii.js @@ -0,0 +1,156 @@ +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {number[]} + */ +const findOrder = function(numCourses, prerequisites) { + const graph = {}, inDegree = Array(numCourses).fill(0) + for(const [s, e] of prerequisites) { + inDegree[s]++ + if(graph[e] == null) graph[e] = [] + graph[e].push(s) + } + + const res = [] + let q = [] + for(let i = 0; i < numCourses; i++) { + if(inDegree[i] === 0) q.push(i) + } + + while(q.length) { + const nxt = [] + for(let i = 0; i < q.length; i++) { + const cur = q[i] + res.push(cur) + for(const e of (graph[cur] || [])) { + inDegree[e]-- + if(inDegree[e] === 0) nxt.push(e) + } + } + q = nxt + } + + return res.length === numCourses ? res : [] +} + +// another + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {number[]} + */ +const findOrder = function(numCourses, prerequisites) { + const indegree = new Array(numCourses).fill(0) + const graph = {} + for (let [course, prereq] of prerequisites) { + indegree[course]++ + graph[prereq] === undefined + ? (graph[prereq] = [course]) + : graph[prereq].push(course) + } + const queue = [], + ans = [] + for (let i = 0; i < indegree.length; i++) if (!indegree[i]) queue.push(i) + while (queue.length) { + let cur = queue.shift() + ans.push(cur) + for (let neigbhors of graph[cur] || []) { + if (!--indegree[neigbhors]) queue.push(neigbhors) + } + } + return ans.length === numCourses ? ans : [] +} + +// another + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {number[]} + */ +const findOrder = function(numCourses, prerequisites) { + const seen = new Set() + const seeing = new Set() + const res = [] + + const adj = [...Array(numCourses)].map(r => []) + for (let [u, v] of prerequisites) { + adj[v].push(u) + } + for (let c = 0; c < numCourses; c++) { + if (!dfs(c)) { + return [] + } + } + return res.reverse() + + function dfs(v) { + if (seen.has(v)) { + return true + } + if (seeing.has(v)) { + return false + } + seeing.add(v) + for (let nv of adj[v]) { + if (!dfs(nv)) { + return false + } + } + seeing.delete(v) + seen.add(v) + res.push(v) + return true + } +} + +// another + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {number[]} + */ +var findOrder = function(numCourses, prerequisites) { + const inDegree = new Array(numCourses).fill(0); + const graph = {}; + for (let i = 0;i < prerequisites.length;i++) { + const e = prerequisites[i]; + inDegree[e[0]]++; + if (graph[e[1]]) { + graph[e[1]].push(e[0]); + } else { + graph[e[1]] = [e[0]]; + } + } + let q = [] + for (let i = 0;i < inDegree.length;i++) { + if (inDegree[i] === 0) { + q.push(i); + } + } + const res = [] + let count = 0; + while(q.length) { + const tmp = [] + const size = q.length + for(let i = 0;i < size;i++) { + const node = q[i] + res.push(node) + count++ + if (graph[node]) { + for (let j = 0;j < graph[node].length;j++) { + inDegree[graph[node][j]]-- + if (inDegree[graph[node][j]] === 0) { + tmp.push(graph[node][j]) + } + } + } + } + + q = tmp + } + + return count === numCourses ? res : []; +}; diff --git a/2100-find-good-days-to-rob-the-bank.js b/2100-find-good-days-to-rob-the-bank.js new file mode 100644 index 00000000..c90bacd8 --- /dev/null +++ b/2100-find-good-days-to-rob-the-bank.js @@ -0,0 +1,39 @@ +/** + * @param {number[]} security + * @param {number} time + * @return {number[]} + */ +const goodDaysToRobBank = function(security, time) { + const n = security.length, sec = security + const pre = Array(n).fill(0), post = Array(n).fill(0) + + const res = [] + let num = 0 + for(let i = 1; i < n; i++) { + if(sec[i] <= sec[i - 1]) { + num++ + } else { + num = 0 + } + pre[i] = num + } + + num = 0 + for(let i = n - 2; i >= 0; i--) { + if(sec[i] <= sec[i + 1]) { + num++ + } else { + num = 0 + } + post[i] = num + } + + // console.log(pre, post) + for(let i = 0; i < n; i++) { + if(pre[i] >= time && post[i] >= time) { + res.push(i) + } + } + + return res +}; diff --git a/2101-detonate-the-maximum-bombs.js b/2101-detonate-the-maximum-bombs.js new file mode 100644 index 00000000..7abf5737 --- /dev/null +++ b/2101-detonate-the-maximum-bombs.js @@ -0,0 +1,82 @@ +/** + * @param {number[][]} bombs + * @return {number} + */ + const maximumDetonation = function(bombs) { + let n = bombs.length, res = 1, graph = {} + for(let i = 0; i < n; i++) { + for(let j = 0; j < n; j++) { + if (i === j) continue + if (bombAdj(bombs[i], bombs[j])) { + if (graph[i] == null) graph[i] = [] + graph[i].push(j) + } + } + } + function dfs(node, visited) { + for(const next of (graph[node] || [])) { + if(!visited.has(next)) { + visited.add(next) + dfs(next, visited) + } + } + } + for (let i = 0; i < n; i++) { + const set = new Set([i]) + dfs(i, set) + res = Math.max(res, set.size) + } + + return res +}; + +function bombAdj(source, target) { + const [x1, y1, r1] = source + const [x2, y2] = target + const { abs } = Math + return abs(x1 - x2) ** 2 + abs(y1 - y2) ** 2 <= r1 ** 2 +} + +// another + +/** + * @param {number[][]} bombs + * @return {number} + */ +const maximumDetonation = function(bombs) { + const n = bombs.length, graph = {} + for(let i = 0; i < n; i++) { + for(let j = 0; j < n; j++) { + if(i === j) continue + if(adjValid(bombs[i], bombs[j])) { + if(graph[i] == null) graph[i] = [] + graph[i].push(j) + } + } + } + + let res = 0 + for(let i = 0; i < n; i++) { + const set = new Set([i]) + dfs(i, set) + res = Math.max(res, set.size) + } + return res + + function dfs(node, visited){ + for (const e of (graph[node] || [])) { + if(!visited.has(e)) { + visited.add(e) + dfs(e, visited) + } + } + } + + function adjValid(start, target) { + const [sx, sy, r] = start + const [ex, ey] = target + return Math.abs(sx - ex) ** 2 + Math.abs(sy - ey) ** 2 <= r ** 2 + } +}; + + diff --git a/2102-sequentially-ordinal-rank-tracker.js b/2102-sequentially-ordinal-rank-tracker.js new file mode 100644 index 00000000..3e2f8c83 --- /dev/null +++ b/2102-sequentially-ordinal-rank-tracker.js @@ -0,0 +1,334 @@ +const maxFn = (a, b) => a.score === b.score ? a.name < b.name : a.score > b.score +const minFn = (a, b) => a.score === b.score ? a.name > b.name : a.score < b.score +const SORTracker = function() { + this.maxPQ = new PQ(maxFn) + this.minPQ = new PQ(minFn) + this.idx = 0 +}; + +/** + * @param {string} name + * @param {number} score + * @return {void} + */ +SORTracker.prototype.add = function(name, score) { + this.maxPQ.push({name, score}) +}; + +/** + * @return {string} + */ +SORTracker.prototype.get = function() { + if(this.idx) { + this.minPQ.push(this.maxPQ.pop()) + while(maxFn(this.maxPQ.peek(), this.minPQ.peek())) { + const tmp = this.minPQ.pop() + this.minPQ.push(this.maxPQ.pop()) + this.maxPQ.push(tmp) + } + } + this.idx++ + return this.maxPQ.peek().name +}; + +/** + * Your SORTracker object will be instantiated and called as such: + * var obj = new SORTracker() + * obj.add(name,score) + * var param_2 = obj.get() + */ + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +const maxComp = (a, b) => { + return a[1] === b[1] ? b[0].localeCompare(a[0]) > 0 : a[1] > b[1] +} + +const minComp = (a, b) => { + return a[1] === b[1] ? a[0].localeCompare(b[0]) > 0: a[1] < b[1] +} + +const SORTracker = function() { + // max + this.pq = new PriorityQueue(maxComp) + // min + this.best = new PriorityQueue(minComp) +}; + +/** + * @param {string} name + * @param {number} score + * @return {void} + */ +SORTracker.prototype.add = function(name, score) { + this.pq.push([name, score]) + while(!this.best.isEmpty() && maxComp(this.pq.peek(), this.best.peek())) { + const a = this.best.pop(), b = this.pq.pop() + this.best.push(b) + this.pq.push(a) + } +}; + +/** + * @return {string} + */ +SORTracker.prototype.get = function() { + const tmp = this.pq.pop() + this.best.push(tmp) + return tmp[0] +}; + +/** + * Your SORTracker object will be instantiated and called as such: + * var obj = new SORTracker() + * obj.add(name,score) + * var param_2 = obj.get() + */ + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + + +// another + +const SORTracker = function() { + this.maxCmp = (a, b) => a[1] === b[1] ? a[0] < b[0] : a[1] > b[1] + this.minCmp = (a, b) => a[1] === b[1] ? a[0] > b[0] : a[1] < b[1] + this.maxQ = new PriorityQueue(this.maxCmp) + this.minQ = new PriorityQueue(this.minCmp) + this.cnt = 0 +}; + +/** + * @param {string} name + * @param {number} score + * @return {void} + */ +SORTracker.prototype.add = function(name, score) { + this.maxQ.push([name, score]) +}; + +/** + * @return {string} + */ +SORTracker.prototype.get = function() { + if(this.cnt) { + this.minQ.push(this.maxQ.pop()) + while(this.maxCmp(this.maxQ.peek(), this.minQ.peek())) { + const tmp = this.minQ.pop() + this.minQ.push(this.maxQ.pop()) + this.maxQ.push(tmp) + } + } + this.cnt++ + + return this.maxQ.peek()[0] +}; + +/** + * Your SORTracker object will be instantiated and called as such: + * var obj = new SORTracker() + * obj.add(name,score) + * var param_2 = obj.get() + */ + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2103-rings-and-rods.js b/2103-rings-and-rods.js new file mode 100644 index 00000000..eb8abfab --- /dev/null +++ b/2103-rings-and-rods.js @@ -0,0 +1,22 @@ +/** + * @param {string} rings + * @return {number} + */ +const countPoints = function(rings) { + const hash = {} + + for(let i = 0, n = rings.length; i < n; i+=2) { + const ch = rings[i], num = +rings[i + 1] + if(hash[num] == null) hash[num] = new Set() + hash[num].add(ch) + } + + + + let res = 0 + Object.keys(hash).forEach(k => { + if(hash[k].size === 3) res++ + }) + + return res +}; diff --git a/2104-sum-of-subarray-ranges.js b/2104-sum-of-subarray-ranges.js new file mode 100644 index 00000000..2feb3f2e --- /dev/null +++ b/2104-sum-of-subarray-ranges.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const subArrayRanges = function(nums) { + const n = nums.length, { max, min } = Math + let res = 0 + + for(let i = 0; i < n; i++) { + let [most, least] = [-Infinity, Infinity] + for(let j = i; j < n; j++) { + most = max(most, nums[j]) + least = min(least, nums[j]) + res += most - least + } + } + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const subArrayRanges = function(nums) { + let res = 0, n = nums.length + for(let i = 0; i < n; i++) { + let max = nums[i], min = nums[i] + for(let j = i; j < n; j++) { + max = Math.max(max, nums[j]) + min = Math.min(min, nums[j]) + res += max - min + } + } + return res +}; diff --git a/2105-watering-plants-ii.js b/2105-watering-plants-ii.js new file mode 100644 index 00000000..3d4f62e6 --- /dev/null +++ b/2105-watering-plants-ii.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} plants + * @param {number} capacityA + * @param {number} capacityB + * @return {number} + */ +const minimumRefill = function(plants, capacityA, capacityB) { + const n = plants.length + let [left, right] = [0, n - 1] + let [A, B] = [capacityA, capacityB] + let ans = 0 + while (left < right) { + if (A < plants[left]) { + A = capacityA + ans += 1 + } + + A -= plants[left] + left += 1 + if (B < plants[right]) { + B = capacityB + ans += 1 + } + + B -= plants[right] + right -= 1 + } + + + if (left != right || A >= plants[left] || B >= plants[left]) return ans + return ans + 1 +}; + diff --git a/2106-maximum-fruits-harvested-after-at-most-k-steps.js b/2106-maximum-fruits-harvested-after-at-most-k-steps.js new file mode 100644 index 00000000..95c808c0 --- /dev/null +++ b/2106-maximum-fruits-harvested-after-at-most-k-steps.js @@ -0,0 +1,66 @@ +/** + * @param {number[][]} fruits + * @param {number} startPos + * @param {number} k + * @return {number} + */ +const maxTotalFruits = function(fruits, startPos, k) { + let n = fruits.length, { max, min } = Math + let pos = fruits.map(([p,a]) => p) + const prefix = Array(n).fill(0) + + let curr = 0 + for (let i = 0; i < n; i++) { + curr += fruits[i][1] + prefix[i] = curr + } + + function bisect_left(a, x, lo = 0, hi = null) { + // >= lower_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + a[mid] < x ? (lo = mid + 1) : (hi = mid) + } + return lo + } + function bisect_right(a, x, lo = 0, hi = null) { + // > upper_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + x < a[mid] ? (hi = mid) : (lo = mid + 1) + } + return lo + } + function query(left, right) { + left = max(left, 0) + right = min(right, 200000) + let l = bisect_left(pos, left) + let r = bisect_right(pos, right) - 1 + if (l > r) return 0 + if (!l) return prefix[r] + return prefix[r] - prefix[l - 1] + } + + + let best = 0 + let idx = 0 + for(let right = startPos + k; right > startPos - 1; right -= 2) { + let cand = query(startPos - idx, right) + best = max(best, cand) + idx += 1 + } + + idx = 0 + for(let left = startPos - k; left < startPos + 1; left += 2) { + let cand = query(left, startPos + idx) + best = max(best, cand) + idx += 1 + } + + return best +}; + diff --git a/2111-minimum-operations-to-make-the-array-k-increasing.js b/2111-minimum-operations-to-make-the-array-k-increasing.js new file mode 100644 index 00000000..821bceef --- /dev/null +++ b/2111-minimum-operations-to-make-the-array-k-increasing.js @@ -0,0 +1,87 @@ +/** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ +const kIncreasing = function(arr, k) { + let res = 0, matrix = Array.from({ length: k }, () => []), n = arr.length + for(let i = 0; i < k; i++) { + for(let j = i; j < n; j += k) { + matrix[i].push(arr[j]) + } + } + + for (let i = 0; i < k; i++) { + res += matrix[i].length - nonDecreasing(matrix[i]) + } + + return res + + function bisect_right(ar, x, l = 0, r) { + if(r == null) r = ar.length + while(l < r) { + const mid = ~~((l + r) / 2) + if(ar[mid] <= x) l = mid + 1 + else r = mid + } + return l + } + + function nonDecreasing(ar) { + let stk = [] + for(let e of ar) { + const idx = bisect_right(stk, e) + if(idx === stk.length) stk.push(e) + else stk[idx] = e + } + + return stk.length + } +}; + +// another +/** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ +const kIncreasing = function(arr, k) { + const n = arr.length + const a = Array.from({ length: k }, () => Array()) + + for(let i = 0; i < k; i++) { + for(let j = i; j < n; j += k) { + a[i].push(arr[j]) + } + } + + let res = 0 + for(let i = 0; i < a.length; i++) { + const r = a[i] + res += r.length - lis(r) + } + + return res + + function bisect_right(a, x, lo = 0, hi = null) { // > upper_bound + if (lo < 0) throw new Error('lo must be non-negative'); + if (hi == null) hi = a.length; + while (lo < hi) { + let mid = parseInt((lo + hi) / 2); + x < a[mid] ? hi = mid : lo = mid + 1; + } + return lo; + } + + function lis(ar) { + let q = [] + for (let x of ar) { + let i = bisect_right(q, x) + if (i == q.length) q.push(x) + else q[i] = x + } + + return q.length + } +}; + diff --git a/2115-find-all-possible-recipes-from-given-supplies.js b/2115-find-all-possible-recipes-from-given-supplies.js new file mode 100644 index 00000000..856512dd --- /dev/null +++ b/2115-find-all-possible-recipes-from-given-supplies.js @@ -0,0 +1,95 @@ +/** + * @param {string[]} recipes + * @param {string[][]} ingredients + * @param {string[]} supplies + * @return {string[]} + */ +const findAllRecipes = function(recipes, ingredients, supplies) { + const set = new Set(supplies), res = [], graph = {}, n = recipes.length + const inDegree = {} + for(let x of recipes) inDegree[x] = 0 + for(let i = 0; i < n; i++) { + for(let j = 0; j < ingredients[i].length; j++) { + const ing = ingredients[i][j] + if(!set.has(ing)) { + if (graph[ing] == null) graph[ing] = [] + graph[ing].push(recipes[i]) + inDegree[recipes[i]]++ + } + } + } + // Kahn's Algorithm + const q = [] + for(let x in inDegree) { + if (inDegree[x] === 0) q.push(x) + } + while(q.length) { + const len = q.length + for(let i = 0; i < len; i++) { + const cur = q.pop() + res.push(cur) + for(let next of (graph[cur] || [])) { + inDegree[next]-- + if(inDegree[next] === 0) { + q.push(next) + } + } + } + } + return res +}; + +// another + +/** + * @param {string[]} recipes + * @param {string[][]} ingredients + * @param {string[]} supplies + * @return {string[]} + */ +const findAllRecipes = function(recipes, ingredients, supplies) { + const graph = {} + const n = recipes.length + + const inDegree = {} + supplies = new Set(supplies) + for(const e of recipes) inDegree[e] = 0 + + let q = [] + for(let i = 0; i < n; i++) { + const rec = recipes[i] + for(let e of ingredients[i]) { + if(!supplies.has(e)) { + if(graph[e] == null) graph[e] = [] + graph[e].push(rec) + inDegree[rec]++ + } + } + } + // console.log(inDegree) + for(let i = 0; i < n; i++) { + if(inDegree[recipes[i]] === 0) { + q.push(recipes[i]) + } + } + + // console.log(q) + const res = [] + while(q.length) { + const size = q.length + const nxt = [] + + for(let i = 0; i < size; i++) { + const cur = q[i] + res.push(cur) + for(const e of (graph[cur] || [])) { + inDegree[e]-- + if(inDegree[e] === 0) nxt.push(e) + } + } + + q = nxt + } + + return res +}; diff --git a/2116-check-if-a-parentheses-string-can-be-validcheck-if-a-parentheses-string-can-be-valid.js b/2116-check-if-a-parentheses-string-can-be-validcheck-if-a-parentheses-string-can-be-valid.js new file mode 100644 index 00000000..9c654fd1 --- /dev/null +++ b/2116-check-if-a-parentheses-string-can-be-validcheck-if-a-parentheses-string-can-be-valid.js @@ -0,0 +1,46 @@ +/** + * @param {string} s + * @param {string} locked + * @return {boolean} + */ +const canBeValid = function(s, locked) { + const n = s.length + if(n % 2 === 1) return false + let x = 0 + for(let i = 0; i < n; i++) { + if(s[i] === '(' || locked[i] === '0') x++ + else if(x > 0) x-- + else return false + } + x = 0 + for(let i = n - 1; i >= 0; i--) { + if(s[i] === ')' || locked[i] === '0') x++ + else if(x > 0) x-- + else return false + } + return true +}; + +// another + +/** + * @param {string} s + * @param {string} locked + * @return {boolean} + */ +const canBeValid = function (s, locked) { + return s.length % 2 === 0 && chk(s, locked, '(') && chk(s, locked, ')') + + function chk(s, locked, op) { + let bal = 0, + wild = 0, + sz = s.length + let start = op === '(' ? 0 : sz - 1, + dir = op === '(' ? 1 : -1 + for (let i = start; i >= 0 && i < sz && wild + bal >= 0; i += dir) { + if (locked[i] === '1') bal += s[i] === op ? 1 : -1 + else wild++ + } + return Math.abs(bal) <= wild + } +} diff --git a/2119-a-number-after-a-double-reversal.js b/2119-a-number-after-a-double-reversal.js new file mode 100644 index 00000000..6d82d7f3 --- /dev/null +++ b/2119-a-number-after-a-double-reversal.js @@ -0,0 +1,9 @@ +/** + * @param {number} num + * @return {boolean} + */ +var isSameAfterReversals = function(num) { + if(('' +num).length === 1) return true + const tmp = (''+num).endsWith('0') + return !tmp +}; diff --git a/2121-intervals-between-identical-elements.js b/2121-intervals-between-identical-elements.js new file mode 100644 index 00000000..3507ba0e --- /dev/null +++ b/2121-intervals-between-identical-elements.js @@ -0,0 +1,69 @@ +/** + * @param {number[]} arr + * @return {number[]} + */ +const getDistances = function(arr) { + const hash = {} + const n = arr.length + for(let i = 0; i < n; i++) { + const e = arr[i] + if(hash[e] == null) hash[e] = [] + hash[e].push(i) + } + const res = [] + for(const [k, v] of Object.entries(hash)) { + helper(v) + } + return res + + function helper(idxArr) { + let sum = 0 + const len = idxArr.length + for(let i = 1; i < len; i++) { + sum += idxArr[i] - idxArr[0] + } + const first = idxArr[0] + res[first] = sum + for(let i = 1; i < len; i++) { + const pre = res[idxArr[i - 1]] + const delta = idxArr[i] - idxArr[i - 1] + const tmp = pre + i * delta - (len - i) * delta + res[idxArr[i]] = tmp + } + } +}; + +// another + + +/** + * @param {number[]} arr + * @return {number[]} + */ +const getDistances = function(arr) { + let n = arr.length + const pre = Array(n).fill(0), suf = Array(n).fill(0), res = Array(n).fill(0), mp = {} + + for(let i = 0; i < n; i++) { + if(mp[arr[i]] == null) mp[arr[i]] = [] + mp[arr[i]].push(i) + } + + Object.keys(mp).forEach(k => { + const idxArr = mp[k] + for(let i = 1; i < idxArr.length; i++) { + pre[idxArr[i]] = pre[idxArr[i - 1]] + i * (idxArr[i] - idxArr[i - 1]) + } + }) + + Object.keys(mp).forEach(k => { + const idxArr = mp[k] + for(let i = idxArr.length - 2; i >= 0; i--) { + suf[idxArr[i]] = suf[idxArr[i + 1]] + (idxArr.length - 1 - i) * (idxArr[i + 1] - idxArr[i]) + } + }) + + for(let i = 0; i < n; i++) res[i] = pre[i] + suf[i] + + return res +}; diff --git a/2122-recover-the-original-array.js b/2122-recover-the-original-array.js new file mode 100644 index 00000000..daa3a91e --- /dev/null +++ b/2122-recover-the-original-array.js @@ -0,0 +1,35 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const recoverArray = function(nums) { + const n = nums.length, cnt = calcHash(nums) + nums.sort((a, b) => a - b) + for(let i = 1; i < n; i++) { + const tk = nums[i] - nums[0] + if(tk === 0 || tk % 2 === 1) continue + const [valid, res] = helper(tk) + if(valid) return res + } + + function helper(tk) { + const res = [], hash = Object.assign({}, cnt) + for(let i = 0; i < n; i++) { + const cur = nums[i] + if(hash[cur] === 0) continue + if(hash[cur + tk] === 0 || hash[cur + tk] == null) return [false] + hash[cur]-- + hash[cur + tk]-- + res.push(cur + tk / 2) + } + return [true, res] + } + function calcHash(arr) { + const hash = {} + for(let e of arr) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + return hash + } +}; diff --git a/2124-check-if-all-as-appears-before-all-bs.js b/2124-check-if-all-as-appears-before-all-bs.js new file mode 100644 index 00000000..071f480a --- /dev/null +++ b/2124-check-if-all-as-appears-before-all-bs.js @@ -0,0 +1,9 @@ +/** + * @param {string} s + * @return {boolean} + */ +const checkString = function(s) { + const la = s.lastIndexOf('a') + const fb = s.indexOf('b') + return fb === -1 ? true : la < fb +}; diff --git a/2125-number-of-laser-beams-in-a-bank.js b/2125-number-of-laser-beams-in-a-bank.js new file mode 100644 index 00000000..cd5bb046 --- /dev/null +++ b/2125-number-of-laser-beams-in-a-bank.js @@ -0,0 +1,24 @@ +/** + * @param {string[]} bank + * @return {number} + */ +var numberOfBeams = function(bank) { + const comb = (num1, num2) => num1 * num2 + const m = bank.length, n = bank[0].length + if(m === 0 || n === 0) return 0 + let pre = 0, res = 0 + for(let j = 0; j < n; j++) { + if(bank[0][j] === '1') pre++ + } + for(let i = 1; i < m; i++) { + let chk = 0, cur = bank[i] + for(let j = 0; j < n; j++) { + if(cur[j] === '1') chk++ + } + if(chk) { + res += comb(pre, chk) + pre = chk + } + } + return res +}; diff --git a/2126-destroying-asteroids.js b/2126-destroying-asteroids.js new file mode 100644 index 00000000..add34396 --- /dev/null +++ b/2126-destroying-asteroids.js @@ -0,0 +1,20 @@ +/** + * @param {number} mass + * @param {number[]} asteroids + * @return {boolean} + */ +const asteroidsDestroyed = function(mass, asteroids) { + asteroids.sort((a, b) => a - b) + let res = true + for(let i = 0, n = asteroids.length; i < n; i++) { + const cur = asteroids[i] + if(mass >= cur) { + mass += cur + } else { + res = false + break + } + } + + return res +}; diff --git a/2127-maximum-employees-to-be-invited-to-a-meeting.js b/2127-maximum-employees-to-be-invited-to-a-meeting.js new file mode 100644 index 00000000..8a8efe69 --- /dev/null +++ b/2127-maximum-employees-to-be-invited-to-a-meeting.js @@ -0,0 +1,162 @@ +/** + * @param {number[]} favorite + * @return {number} + */ +const maximumInvitations = function(favorite) { + const n = favorite.length + const inDegree = Array(n).fill(0) + const { max } = Math + for(let i = 0; i < n; i++) { + inDegree[favorite[i]]++ + } + + let q = [] + const visited = Array(n).fill(0) + const depth = Array(n).fill(1) + for(let i = 0; i < n; i++) { + if(inDegree[i] === 0) { + q.push(i) + visited[i] = 1 + depth[i] = 1 + } + } + + while(q.length) { + const cur = q.pop() + const nxt = favorite[cur] + inDegree[nxt]-- + if(inDegree[nxt] === 0) { + q.push(nxt) + visited[nxt] = 1 + } + depth[nxt] = max(depth[nxt], depth[cur] + 1) + } + + let maxLoopSize = 0 + let twoNodesSize = 0 + + for(let i = 0; i < n; i++) { + if(visited[i] === 1) continue + let j = i + let cnt = 0 + while(visited[j] === 0) { + cnt++ + visited[j] = 1 + j = favorite[j] + } + + if(cnt > 2) { + maxLoopSize = max(maxLoopSize, cnt) + } else if(cnt === 2) { + twoNodesSize += depth[i] + depth[favorite[i]] + } + } + + return max(maxLoopSize, twoNodesSize) +}; + +// another + +/** + * @param {number[]} favorite + * @return {number} + */ +const maximumInvitations = function (favorite) { + const n = favorite.length + const indegree = Array(n).fill(0) + for (let i = 0; i < n; i++) indegree[favorite[i]]++ + const { max } = Math + let q = [] + const visited = Array(n).fill(0) + const depth = Array(n).fill(1) + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + depth[i] = 1 + visited[i] = 1 + q.push(i) + } + } + + while (q.length) { + const cur = q.shift() + const nxt = favorite[cur] + indegree[nxt]-- + if (indegree[nxt] == 0) { + q.push(nxt) + visited[nxt] = 1 + } + depth[nxt] = depth[cur] + 1 + } + + let max_circle_size = 0 + let max_link_size = 0 + for (let i = 0; i < n; i++) { + if (visited[i] === 1) continue + let j = i + let count = 0 + while (visited[j] == 0) { + count++ + visited[j] = 1 + j = favorite[j] + } + if (count > 2) max_circle_size = max(max_circle_size, count) + else if (count == 2) max_link_size += depth[i] + depth[favorite[i]] + } + + return max(max_circle_size, max_link_size) +} + +// another + +/** + * @param {number[]} favorite + * @return {number} + */ +var maximumInvitations = function(favorite) { + const n = favorite.length, m = Array(n).fill(-1), r = Array.from({ length: n }, () => []) + for(let i = 0; i < n; i++) r[favorite[i]].push(i) + + function dfs(u) { + if(m[u] !== -1) return m[u] + let res = 0 + for(let v of r[u]) res = Math.max(res, dfs(v)) + return m[u] = 1 + res + } + let res = 0, free = 0 + for(let i = 0; i < n; ++i) { + if (m[i] != -1) continue; // skip visited nodes + if (favorite[favorite[i]] == i) { + m[i] = m[favorite[i]] = 0; + let a = 0, b = 0; // find the length of the longest arms starting from `i` and `A[i]` + for (let v of r[i]) { + if (v == favorite[i]) continue; + a = Math.max(a, dfs(v)); + } + for (let v of r[favorite[i]]) { + if (v == i) continue; + b = Math.max(b, dfs(v)); + } + free += a + b + 2; // this free component is of length `a+b+2` + } + } + function dfs2(u) { + if (m[u] != -1) return[u, m[u], false]; // this is the merge point + m[u] = 0; + let [mergePoint, depth, mergePointMet] = dfs2(favorite[u]); + if (mergePointMet) { // If we've met the merge point again already, this node is outside of the cycle and should be ignored. + m[u] = 0; + return [mergePoint, depth, true]; + } + m[u] = 1 + depth; // If we haven't met the merge point, we increment the depth. + return [mergePoint, m[u], u == mergePoint]; + } + + for(let i = 0; i < n; i++) { + if(m[i] !== -1) continue + let [mergePoint, depth, mergePointMet] = dfs2(i) + if(mergePointMet) res = Math.max(res, depth) + } + + return Math.max(res, free) +}; + diff --git a/2128-remove-all-ones-with-row-and-column-flips.js b/2128-remove-all-ones-with-row-and-column-flips.js new file mode 100644 index 00000000..55b28358 --- /dev/null +++ b/2128-remove-all-ones-with-row-and-column-flips.js @@ -0,0 +1,31 @@ +/** + * @param {number[][]} grid + * @return {boolean} + */ +const removeOnes = function(grid) { + const m = grid.length + const n = grid[0].length + const first = grid[0], firstFliped = flip(first) + for(let i = 1; i < m; i++) { + if(!equal(first, grid[i]) && !equal(firstFliped, grid[i])) return false + } + + return true + + function flip(arr) { + const res = [] + for(const e of arr) { + res.push(e === 1 ? 0 : 1) + } + return res + } + + function equal(a, b) { + const n = a.length + for(let i = 0; i < n; i++) { + if(a[i] !== b[i]) return false + } + + return true + } +}; diff --git a/213-house-robber-ii.js b/213-house-robber-ii.js index f7195425..c4e1037f 100644 --- a/213-house-robber-ii.js +++ b/213-house-robber-ii.js @@ -17,3 +17,48 @@ const rob = function(nums) { return Math.max(startFromFirst[nums.length - 1], startFromSecond[nums.length]) }; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const rob = function(nums) { + if(nums.length === 1) return nums[0] + return Math.max(helper(0, nums.length - 2), helper(1, nums.length - 1)) + + function helper(l, r) { + let inc = 0, exc = 0 + for(let i = l; i <= r; i++) { + const pi = inc, pe = exc + inc = exc + nums[i] + exc = Math.max(pi, pe) + } + return Math.max(inc, exc) + } +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const rob = function(nums) { + const n = nums.length + nums = nums.concat(nums) + let res = 0 + for(let i = 0; i < n; i++) { + let tmp = nums[i] + let pp = 0 + let p = 0 + for(let j = i; j < n + i - 1; j++) { + tmp = Math.max(tmp, pp + nums[j], p); + [pp, p] = [p, tmp] + } + res = Math.max(res, tmp) + } + + return res +}; diff --git a/2130-maximum-twin-sum-of-a-linked-list.js b/2130-maximum-twin-sum-of-a-linked-list.js new file mode 100644 index 00000000..b1e45990 --- /dev/null +++ b/2130-maximum-twin-sum-of-a-linked-list.js @@ -0,0 +1,65 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {number} + */ +const pairSum = function(head) { + let slow = head, fast = head + while(fast && fast.next) { + slow = slow.next + fast = fast.next.next + } + // reverse + let next = null, pre = null + while(slow) { + next = slow.next + slow.next = pre + pre = slow + slow = next + } + + let res = 0 + while(pre) { + res = Math.max(res, pre.val + head.val) + pre = pre.next + head = head.next + } + + return res +}; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {number} + */ +const pairSum = function(head) { + const arr = [] + let cur = head + + while(cur) { + arr.push(cur.val) + cur = cur.next + } + + let res = 0 + for(let i = 0, n = arr.length; i < n / 2; i++) { + res = Math.max(res, arr[i] + arr[n - 1 - i]) + } + + return res +}; diff --git a/2132-stamping-the-grid.js b/2132-stamping-the-grid.js new file mode 100644 index 00000000..e3e936e4 --- /dev/null +++ b/2132-stamping-the-grid.js @@ -0,0 +1,59 @@ +/** + * @param {number[][]} grid + * @param {number} stampHeight + * @param {number} stampWidth + * @return {boolean} + */ +var possibleToStamp = function(grid, stampHeight, stampWidth) { + let d = []; + let a = grid; + let h = grid.length; + let w = grid[0].length; + for (let i = 0; i <= h; i++) { + d[i] = new Array(w + 1).fill(0); + } + //d - height of empty cells below + for (let i = h - 1; i >= 0; i--) { + for (let j = 0; j < w; j++) { + if (a[i][j] === 0) d[i][j] = d[i + 1][j] + 1; + } + } + //find stamps, and start to fill matrix + for (let i = 0; i < h; i++) { + let columns = 0; //width of consecutive empty columns with height>=stampHeight + for (let j = 0; j <= w; j++) { + if (d[i][j] >= stampHeight) { //column can be part of stamp + columns++; + if (columns >= stampWidth) { + //fill first row + if (columns === stampWidth) { + //fill previous columns + for (let l = j - stampWidth + 1; l <= j; l++) { + a[i][l] = stampHeight + } + } else { + a[i][j] = stampHeight; + } + } + } else { + columns = 0; + } + } + //fill cells below + for (let l = 0; l < w; l++) { + if (a[i][l] > 1) { + a[i + 1][l] = a[i][l] - 1; + } + } + } + + //check if all cells covered + let ans = true; + for (let i = 0; i < h; i++) { + for (let j = 0; j < w; j++) { + if (a[i][j] === 0) ans = false; + } + } + + return ans; +}; diff --git a/2136-earliest-possible-day-of-full-bloom.js b/2136-earliest-possible-day-of-full-bloom.js new file mode 100644 index 00000000..6a736966 --- /dev/null +++ b/2136-earliest-possible-day-of-full-bloom.js @@ -0,0 +1,61 @@ +/** + * @param {number[]} plantTime + * @param {number[]} growTime + * @return {number} + */ +const earliestFullBloom = function(plantTime, growTime) { + const n = plantTime.length, arr = Array(n) + for(let i = 0; i < n; i++) { + arr.push([growTime[i], plantTime[i]]) + } + arr.sort((a, b) => b[0] - a[0]) + + let res = 0, cur = 0 + for(let i = 0; i < n; i++) { + const e = arr[i] + res = Math.max(res, cur + e[0] + e[1]) + cur += e[1] + } + + return res +}; + +// another + + +/** + * @param {number[]} plantTime + * @param {number[]} growTime + * @return {number} + */ +const earliestFullBloom = function(plantTime, growTime) { + const sum = arr => arr.reduce((ac, e) => ac +e, 0) + let l = 0, r = sum(plantTime) + sum(growTime) + const n = plantTime.length + + const a = [] + for(let i = 0; i < n; i++) { + a.push([growTime[i], plantTime[i] ]) + } + + a.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) + a.reverse() + function chk(d) { + let total = -1 + let max_num = 0 + for(let i = 0; i < n; i++) { + total += a[i][1] + max_num = Math.max(max_num, total + a[i][0] + 1) + } + return max_num <= d + } + + while (l < r) { + let m = ~~((l + r) / 2) + if (chk(m)) r = m + else l = m + 1 + } + + return l +}; + diff --git a/2138-divide-a-string-into-groups-of-size-k.js b/2138-divide-a-string-into-groups-of-size-k.js new file mode 100644 index 00000000..1e532b80 --- /dev/null +++ b/2138-divide-a-string-into-groups-of-size-k.js @@ -0,0 +1,23 @@ +/** + * @param {string} s + * @param {number} k + * @param {character} fill + * @return {string[]} + */ +var divideString = function(s, k, fill) { + let res = [], tmp = '' + for(let i = 0, n = s.length; i < n; i++) { + tmp += s[i] + if(tmp.length === k) { + res.push(tmp) + tmp = '' + } + } + if(tmp.length) { + for(let i = 0, limit = k - tmp.length; i < limit; i++) { + tmp += fill + } + res.push(tmp) + } + return res +}; diff --git a/2139-minimum-moves-to-reach-target-score.js b/2139-minimum-moves-to-reach-target-score.js new file mode 100644 index 00000000..abbd61f9 --- /dev/null +++ b/2139-minimum-moves-to-reach-target-score.js @@ -0,0 +1,28 @@ +/** + * @param {number} target + * @param {number} maxDoubles + * @return {number} + */ +const minMoves = function(target, maxDoubles) { + let count = 0; + + while(target != 1){ + + if(target % 2 != 0){ + target--; + count++; + } + else{ + if(maxDoubles != 0){ + target /= 2; + count++; + maxDoubles--; + } + else{ + count += target - 1; + break; + } + } + } + return count; +}; diff --git a/214-shortest-palindrome.js b/214-shortest-palindrome.js index a0b99e14..a278095f 100644 --- a/214-shortest-palindrome.js +++ b/214-shortest-palindrome.js @@ -11,3 +11,76 @@ const shortestPalindrome = function(s) { let suffix = s.substring(j); return suffix.split('').reverse().join('') + shortestPalindrome(s.substring(0, j)) + suffix; }; + +// another + +/** + * @param {string} s + * @return {string} + */ +const shortestPalindrome = function (s) { + const tmp = s + '#' + s.split('').reverse().join('') + const fail = getFail(tmp) + return ( + s + .split('') + .slice(fail[fail.length - 1]) + .reverse() + .join('') + s + ) +} + +function getFail(s) { + const n = s.length + const table = new Array(n).fill(0) + let index = 0 + for (let i = 1; i < n; ) { + if (s.charAt(index) === s.charAt(i)) { + table[i] = ++index + i++ + } else { + if (index > 0) { + index = table[index - 1] + } else { + index = 0 + i++ + } + } + } + return table +} + +// another + +/** + * @param {string} s + * @return {string} + */ +const shortestPalindrome = function(s) { + const tmp = `${s}#${reverse(s)}` + const table = kmp(tmp) + return `${reverse(s.slice(table[table.length - 1]))}${s}` +}; +function reverse(str) { + return [...str].reverse().join('') +} + +function kmp(s) { + const n = s.length, table = Array(n).fill(0) + let idx = 0 + for(let i = 1; i < n; ) { + if(s[i] === s[idx]) { + idx++ + table[i] = idx + i++ + } else { + if(idx > 0) { + idx = table[idx - 1] + } else { + idx = 0 + i++ + } + } + } + return table +} diff --git a/2140-solving-questions-with-brainpower.js b/2140-solving-questions-with-brainpower.js new file mode 100644 index 00000000..646ba1d2 --- /dev/null +++ b/2140-solving-questions-with-brainpower.js @@ -0,0 +1,35 @@ +/** + * @param {number[][]} questions + * @return {number} + */ +const mostPoints = function(questions) { + const n = questions.length, dp = Array(n + 1).fill(0) + for (let i = n - 1; i >= 0; i--) { + const [gain, p] = questions[i] + dp[i] = Math.max(dp[i + 1], (dp[p + i + 1] || 0) + gain) + } + return dp[0] +}; + +// another + +/** + * @param {number[][]} questions + * @return {number} + */ +const mostPoints = function (questions) { + let n = questions.length + const temp = Array(n).fill(0) + + temp[n - 1] = questions[n - 1][0] + + for (let i = n - 2; i >= 0; i--) { + if (i + questions[i][1] + 1 <= n - 1) + temp[i] = Math.max( + temp[i + 1], + questions[i][0] + temp[i + questions[i][1] + 1] + ) + else temp[i] = Math.max(temp[i + 1], questions[i][0]) + } + return temp[0] +} diff --git a/2141-maximum-running-time-of-n-computers.js b/2141-maximum-running-time-of-n-computers.js new file mode 100644 index 00000000..d71ebb67 --- /dev/null +++ b/2141-maximum-running-time-of-n-computers.js @@ -0,0 +1,69 @@ +/** + * @param {number} n + * @param {number[]} batteries + * @return {number} + */ +const maxRunTime = function(n, batteries) { + n = BigInt(n) + batteries = batteries.map(e => BigInt(e)) + const sum = batteries.reduce((ac, e) => ac + e, 0n) + let l = 0n, r = sum / n + while(l < r) { + const mid = r - (r - l) / 2n + if(valid(mid)) l = mid + else r = mid - 1n + } + + return l + + function valid(mid) { + let curSum = 0n, target = mid * n + for(const e of batteries) { + curSum += e > mid ? mid : e + if(curSum >= target) return true + } + return false + } +}; + + +// another + + +/** + * @param {number} n + * @param {number[]} batteries + * @return {number} + */ +var maxRunTime = function (n, batteries) { + batteries.sort((a, b) => a - b) + const sum = batteries.reduce((ac, e) => ac + BigInt(e), 0n) + let hi = ~~(sum / BigInt(n)) + 1n, + lo = 0n + while (lo < hi) { + let mid = ~~((lo + hi) / 2n) + if (chk(mid)) { + lo = mid + 1n + } else { + hi = mid + } + } + + return lo - 1n + function chk(x) { + let current = 0n + let i = 0n + for (let b of batteries) { + if (i == BigInt(n)) break + if (b > x) b = x + if (b >= x - current) { + i += 1n + current = BigInt(b) - (x - current) + } else { + current += BigInt(b) + } + } + + return i == n + } +} diff --git a/2148-count-elements-with-strictly-smaller-and-greater-elements.js b/2148-count-elements-with-strictly-smaller-and-greater-elements.js new file mode 100644 index 00000000..739a4604 --- /dev/null +++ b/2148-count-elements-with-strictly-smaller-and-greater-elements.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var countElements = function(nums) { + let min = Infinity, max = -Infinity + for(let e of nums) { + if(e > max) max = e + if(e < min) min = e + } + let res = 0 + for(let e of nums) { + if(e > min && e < max) res++ + } + return res +}; diff --git a/2149-rearrange-array-elements-by-sign.js b/2149-rearrange-array-elements-by-sign.js new file mode 100644 index 00000000..9f4f1d71 --- /dev/null +++ b/2149-rearrange-array-elements-by-sign.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const rearrangeArray = function(nums) { + const pos = [], neg = [] + for(let e of nums) { + if(e >= 0) pos.push(e) + else neg.push(e) + } + const res = [] + for(let i = 0; i < nums.length; i++) { + if(i % 2 === 0) res.push(pos[~~(i / 2)]) + else res.push(neg[~~(i / 2)]) + } + return res +}; diff --git a/215-kth-largest-element-in-an-array.js b/215-kth-largest-element-in-an-array.js index c0514eb2..cbf5ce05 100755 --- a/215-kth-largest-element-in-an-array.js +++ b/215-kth-largest-element-in-an-array.js @@ -66,42 +66,74 @@ function quickselect(arr, lo, hi, k) { * @param {number} k * @return {number} */ -const findKthLargest = function(list, k) { - const len = list.length - let lo = 0 - let hi = len - 1 - let pivot = 0 - let t = len - k - while(lo < hi) { - pivot = partition(list, lo, hi) - if(pivot === t) { - break - } else if(pivot < t) { - lo = pivot + 1 - } else if(pivot > t) { - hi = pivot - 1 +const findKthLargest = function(nums, k) { + const n = nums.length + let l = 0, r = n - 1, t = n - k + while(l < r) { + const mid = partition(nums, l, r) + if(mid < t) { + l = mid + 1 + } else { + if(mid === t) break + else r = mid - 1 } } - - return list[t] -} + return nums[t] +}; -function partition(arr, s, e) { - let t = arr[e] - let i = s - for(let j = s; j <= e - 1; j++) { - if(arr[j] <= t) { +function partition(arr, left, right) { + let pivot = arr[right] + let l = left, r = right - 1, j = left + for(let i = left; i < right; i++) { + if(arr[i] <= pivot) { swap(arr, i, j) - i++ + j++ } } - swap(arr, i, e) - return i + swap(arr, j, right) + return j } function swap(arr, i, j) { - let tmp = arr[i] + const tmp = arr[i] arr[i] = arr[j] arr[j] = tmp } +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const findKthLargest = function(nums, k) { + const n = nums.length + let l = 0, r = n - 1, t = n - k + while(l < r) { + const idx = partition(nums, l, r) + if (idx === t) return nums[t] + if (idx < t) l = idx + 1 + else r = idx - 1 + } + return nums[l] +}; + +function partition(arr, l, r) { + let tmp = l, pivot = arr[l] + while(l < r) { + while(l < r && arr[r] >= pivot) r-- + while(l < r && arr[l] <= pivot) l++ + swap(arr, l, r) + } + swap(arr, l, tmp) + return l +} + +function swap(arr, i, j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp +} + + diff --git a/2150-find-all-lonely-numbers-in-the-array.js b/2150-find-all-lonely-numbers-in-the-array.js new file mode 100644 index 00000000..ee604c44 --- /dev/null +++ b/2150-find-all-lonely-numbers-in-the-array.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var findLonely = function(nums) { + nums.sort((a, b) => a - b) + const cnt = {} + for(let e of nums) { + if(cnt[e] == null) cnt[e] = 0 + cnt[e]++ + } + // console.log(cnt) + const res = [] + for(let i = 0, n = nums.length; i < n; i++) { + if(i === 0){ + if(nums[i + 1] !== nums[i] + 1 && cnt[nums[i]] === 1) { + res.push(nums[i]) + } + } + else if(i === n - 1 ) { + if(nums[i] !== nums[i - 1] + 1 && cnt[nums[i]] === 1) { + res.push(nums[i]) + } + } + else if(cnt[nums[i]] === 1 && nums[i] !== nums[i - 1] + 1 && nums[i] !== nums[i + 1] - 1) { + res.push(nums[i]) + } + } + + return res +}; diff --git a/2151-maximum-good-people-based-on-statements.js b/2151-maximum-good-people-based-on-statements.js new file mode 100644 index 00000000..37bc7de5 --- /dev/null +++ b/2151-maximum-good-people-based-on-statements.js @@ -0,0 +1,40 @@ +/** + * @param {number[][]} statements + * @return {number} + */ +const maximumGood = function (statements) { + const n = statements.length + let res = 0, + c = (1 << n) - 1 + for (let i = 0; i < c + 1; i++) { + let s = dec2bin(i) + s = '0'.repeat(n - s.length) + s + let arr = [], + f = 1 + for (let i = 0; i < n; i++) { + if (s[i] === '1') arr.push(i) + } + for (let i of arr) { + for (let j = 0; j < n; j++) { + if (statements[i][j] !== 2 && statements[i][j] !== +s[j]) { + f = 0 + break + } + } + if (!f) break + } + if (f) res = Math.max(res, cnt(s, '1')) + } + + return res +} +function cnt(s, ch) { + let res = 0 + for (let e of s) { + if (e === ch) res++ + } + return res +} +function dec2bin(dec) { + return (dec >>> 0).toString(2) +} diff --git a/2152-minimum-number-of-lines-to-cover-points.js b/2152-minimum-number-of-lines-to-cover-points.js new file mode 100644 index 00000000..78453f54 --- /dev/null +++ b/2152-minimum-number-of-lines-to-cover-points.js @@ -0,0 +1,50 @@ +/** + * @param {number[][]} points + * @return {number} + */ +const minimumLines = function(points) { + const n = points.length + const limit = 1 << n + const dp = Array(limit).fill(n) + dp[0] = 0 + for(let mask = 1; mask < limit; mask++) { + for(let sub = mask; sub; sub = (sub - 1) & mask) { + if(valid(sub)) { + dp[mask] = Math.min(dp[mask], dp[mask - sub] + 1) + } + } + } + return dp[limit - 1] + + function valid(sub) { + let res = true + const arr = [] + let idx = 0 + while(sub) { + if(sub & 1) arr.push(idx) + sub = sub >> 1 + idx++ + } + if(arr.length <= 2) return res + for(let i = 2; i < arr.length; i++) { + if(!isSameLine(points[arr[0]], points[arr[1]], points[arr[i]])) { + return false + } + } + return res + } +}; + + +function bitCnt(num) { + let res = 0 + while(num) { + if(num & 1) res++ + num = num >> 1 + } + return res +} +function isSameLine(p1, p2, p3) { + const delta = (p3[1] - p2[1]) * (p2[0] - p1[0]) - (p2[1] - p1[1]) * (p3[0] - p2[0]) + return delta === 0 +} diff --git a/2154-keep-multiplying-found-values-by-two.js b/2154-keep-multiplying-found-values-by-two.js new file mode 100644 index 00000000..398ea7f1 --- /dev/null +++ b/2154-keep-multiplying-found-values-by-two.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @param {number} original + * @return {number} + */ +var findFinalValue = function(nums, original) { + let res = original + while(nums.indexOf(res) !== -1) { + // const idx = nums.indexOf(res) + res *= 2 + } + return res +}; diff --git a/2155-all-divisions-with-the-highest-score-of-a-binary-array.js b/2155-all-divisions-with-the-highest-score-of-a-binary-array.js new file mode 100644 index 00000000..adf57c4a --- /dev/null +++ b/2155-all-divisions-with-the-highest-score-of-a-binary-array.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var maxScoreIndices = function(nums) { + const n = nums.length + // if(n === 1) return [0] + const leftZero = Array(n).fill(0), rightOne = Array(n).fill(0) + for (let i = 0, sum = 0; i < n; i++) { + if(nums[i] === 0) sum++ + leftZero[i] = sum + } + for (let i = n - 1, sum = 0; i >= 0; i--) { + if(nums[i] === 1) sum++ + rightOne[i] = sum + } + let hash = {} + for (let i = 0, sum = 0; i <= n; i++) { + + hash[i] = (i === 0 ? 0 : leftZero[i - 1]) + (i === n ? 0 : rightOne[i]) + } + const max = Math.max(...Object.values(hash)) + const res = [] + Object.keys(hash).forEach(k => { + if(hash[k] === max) res.push(+k) + }) + return res +}; diff --git a/2156-find-substring-with-given-hash-value.js b/2156-find-substring-with-given-hash-value.js new file mode 100644 index 00000000..0549a3b3 --- /dev/null +++ b/2156-find-substring-with-given-hash-value.js @@ -0,0 +1,30 @@ +/** + * @param {string} s + * @param {number} power + * @param {number} modulo + * @param {number} k + * @param {number} hashValue + * @return {string} + */ +var subStrHash = function (s, power, modulo, k, hashValue) { + let n = s.length; + const p_pow = Array(n + 1); + p_pow[0] = 1n; + power = BigInt(power); + let m = BigInt(modulo); + for (let i = 1; i < p_pow.length; i++) p_pow[i] = (p_pow[i - 1] * power) % m; + + const val = (ch) => BigInt(ch.charCodeAt(0) - "a".charCodeAt(0)); + const h = Array(n + 1).fill(0n); + for (let i = n - 1; i >= 0; i--) + h[i] = (h[i + 1] * power + val(s[i]) + 1n) % m; + + for (let i = 0; i + k - 1 < n; i++) { + let cur_h = (h[i] - h[i + k] * p_pow[k]) % m; + let temp = (cur_h + m) % m; + if (temp == hashValue) { + return s.substr(i, k); + } + } + return ""; +}; diff --git a/2161-partition-array-according-to-given-pivot.js b/2161-partition-array-according-to-given-pivot.js new file mode 100644 index 00000000..e3bf6995 --- /dev/null +++ b/2161-partition-array-according-to-given-pivot.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @param {number} pivot + * @return {number[]} + */ +var pivotArray = function(nums, pivot) { + const less = [], greater = [], mid = [] + for(const e of nums) { + if(e < pivot) less.push(e) + else if(e === pivot) mid.push(e) + else greater.push(e) + } + + return less.concat(mid, greater) +}; diff --git a/2163-minimum-difference-in-sums-after-removal-of-elements.js b/2163-minimum-difference-in-sums-after-removal-of-elements.js new file mode 100644 index 00000000..862bbe53 --- /dev/null +++ b/2163-minimum-difference-in-sums-after-removal-of-elements.js @@ -0,0 +1,158 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumDifference = function(nums) { + const n = nums.length, len = n / 3 + const maxCompare = (p, c) => { return p === c ? 0 : (p > c ? -1 : 1)} + const minCompare = (p, c) => { return p === c ? 0 : (p < c ? -1 : 1)} + const maxHeap = new PriorityQueue({compare: maxCompare}) + const minHeap = new PriorityQueue({compare: minCompare}) + const pre = Array(n).fill(Infinity), suffix = Array(n).fill(-Infinity) + for(let i = 0, sum = 0; i < 2 * len; i++) { + const cur = nums[i] + maxHeap.enqueue(cur) + sum += cur + if(maxHeap.size() > len) { + const tmp = maxHeap.dequeue() + sum -= tmp + } + if(maxHeap.size() === len) { + pre[i] = sum + } + } + + for(let i = n - 1, sum = 0; i >= len; i--) { + const cur = nums[i] + minHeap.enqueue(cur) + sum += cur + if(minHeap.size() > len) { + const tmp = minHeap.dequeue() + sum -= tmp + } + if(minHeap.size() === len) { + suffix[i] = sum + } + } + + // console.log(pre, suffix) + let res = Infinity + for(let i = len - 1; i < n - len; i++) { + res = Math.min(res, pre[i] - suffix[i + 1]) + } + return res +}; + +// another + + +/** + * @param {number[]} nums + * @return {number} + */ +const minimumDifference = function(nums) { + const n = nums.length, len = n / 3 + const maxHeap = new PriorityQueue((a, b) => a > b) + const minHeap = new PriorityQueue((a, b) => a < b) + const pre = Array(n).fill(Infinity), suffix = Array(n).fill(-Infinity) + for(let i = 0, sum = 0; i < 2 * len; i++) { + const cur = nums[i] + maxHeap.push(cur) + sum += cur + if(maxHeap.size() > len) { + const tmp = maxHeap.pop() + sum -= tmp + } + if(maxHeap.size() === len) { + pre[i] = sum + } + } + + for(let i = n - 1, sum = 0; i >= len; i--) { + const cur = nums[i] + minHeap.push(cur) + sum += cur + if(minHeap.size() > len) { + const tmp = minHeap.pop() + sum -= tmp + } + if(minHeap.size() === len) { + suffix[i] = sum + } + } + + // console.log(pre, suffix) + let res = Infinity + for(let i = len - 1; i < n - len; i++) { + res = Math.min(res, pre[i] - suffix[i + 1]) + } + return res +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2164-sort-even-and-odd-indices-independently.js b/2164-sort-even-and-odd-indices-independently.js new file mode 100644 index 00000000..b57971c9 --- /dev/null +++ b/2164-sort-even-and-odd-indices-independently.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var sortEvenOdd = function(nums) { + let nums_size = nums.length; + for (let i = 0; i < nums_size - 2; i++) { + for (let j = i + 2; j < nums_size; j += 2) { + if (i % 2 == 1) { + if (nums[i] < nums[j]) { + let temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + } else { + if (nums[i] > nums[j]) { + let temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } + } + } + } + return nums; +}; diff --git a/2165-smallest-value-of-the-rearranged-number.js b/2165-smallest-value-of-the-rearranged-number.js new file mode 100644 index 00000000..7be3004b --- /dev/null +++ b/2165-smallest-value-of-the-rearranged-number.js @@ -0,0 +1,20 @@ +/** + * @param {number} num + * @return {number} + */ +var smallestNumber = function(num) { + const minus = num < 0 + const nums = Math.abs(num) + .toString() + .split('') + .map(_ => parseInt(_)) + .sort((a, b) => minus ? b-a : a-b); + if(!minus && nums[0] === 0) { + let i = 0 + while(nums[i] === 0 && i < nums.length-1) i++ + nums[0] = nums[i] + nums[i] = 0 + } + const answer = parseInt(nums.map(_ => _.toString()).join('')) + return minus ? -answer : answer +}; diff --git a/2166-design-bitset.js b/2166-design-bitset.js new file mode 100644 index 00000000..4c177ba6 --- /dev/null +++ b/2166-design-bitset.js @@ -0,0 +1,171 @@ +/** + * @param {number} size + */ +const Bitset = function (size) { + this.arr = Array.from({ length: 2 }, (el, idx) => + Array(size).fill(idx === 0 ? 0 : 1) + ) + this.cur = 0 + this.cnt = 0 +} + +/** + * @param {number} idx + * @return {void} + */ +Bitset.prototype.fix = function (idx) { + if(this.arr[this.cur][idx] === 1) return + this.arr[this.cur][idx] = 1 + this.arr[this.cur ^ 1][idx] = 0 + this.cnt++ +} + +/** + * @param {number} idx + * @return {void} + */ +Bitset.prototype.unfix = function (idx) { + if(this.arr[this.cur][idx] === 0) return + this.arr[this.cur][idx] = 0 + this.arr[this.cur ^ 1][idx] = 1 + this.cnt-- +} + +/** + * @return {void} + */ +Bitset.prototype.flip = function () { + this.cur ^= 1 + this.cnt = this.arr[this.cur].length - this.cnt +} + +/** + * @return {boolean} + */ +Bitset.prototype.all = function () { + return this.cnt === this.arr[this.cur].length +} + +/** + * @return {boolean} + */ +Bitset.prototype.one = function () { + return this.cnt > 0 +} + +/** + * @return {number} + */ +Bitset.prototype.count = function () { + return this.cnt +} + +/** + * @return {string} + */ +Bitset.prototype.toString = function () { + return this.arr[this.cur].join('') +} + +/** + * Your Bitset object will be instantiated and called as such: + * var obj = new Bitset(size) + * obj.fix(idx) + * obj.unfix(idx) + * obj.flip() + * var param_4 = obj.all() + * var param_5 = obj.one() + * var param_6 = obj.count() + * var param_7 = obj.toString() + */ + +// another + +/** + * @param {number} size + */ +var Bitset = function(size) { + this.s = Array.from({ length:2 }, () => Array()) + this.cnt = 0 + this.now = 0 + for (let i = 0; i < size; i++) { + this.s[this.now].push( '0'); + this.s[this.now ^ 1].push( '1'); + } +}; + +/** + * @param {number} idx + * @return {void} + */ +Bitset.prototype.fix = function(idx) { + if (this.s[this.now][idx] == '1') return; + // swap(this.s[this.now][idx], this.s[this.now ^ 1][idx]); + const tmp = this.s[this.now][idx] + this.s[this.now][idx] = this.s[this.now ^ 1][idx] + this.s[this.now ^ 1][idx] = tmp + this.cnt++; +}; + +/** + * @param {number} idx + * @return {void} + */ +Bitset.prototype.unfix = function(idx) { + if (this.s[this.now][idx] == '0') return; + // swap(this.s[this.now][idx], this.s[this.now ^ 1][idx]); + const tmp = this.s[this.now][idx] + this.s[this.now][idx] = this.s[this.now ^ 1][idx] + this.s[this.now ^ 1][idx] = tmp + this.cnt--; +}; + +/** + * @return {void} + */ +Bitset.prototype.flip = function() { + this.now = this.now ^ 1; + this.cnt = this.s[0].length - this.cnt; +}; + +/** + * @return {boolean} + */ +Bitset.prototype.all = function() { + return this.cnt == this.s[0].length; +}; + +/** + * @return {boolean} + */ +Bitset.prototype.one = function() { + return this.cnt !== 0 +}; + +/** + * @return {number} + */ +Bitset.prototype.count = function() { + return this.cnt; +}; + +/** + * @return {string} + */ +Bitset.prototype.toString = function() { + return this.s[this.now].join(''); +}; + + +/** + * Your Bitset object will be instantiated and called as such: + * var obj = new Bitset(size) + * obj.fix(idx) + * obj.unfix(idx) + * obj.flip() + * var param_4 = obj.all() + * var param_5 = obj.one() + * var param_6 = obj.count() + * var param_7 = obj.toString() + */ + diff --git a/2167-minimum-time-to-remove-all-cars-containing-illegal-goods.js b/2167-minimum-time-to-remove-all-cars-containing-illegal-goods.js new file mode 100644 index 00000000..6f4ca66e --- /dev/null +++ b/2167-minimum-time-to-remove-all-cars-containing-illegal-goods.js @@ -0,0 +1,128 @@ +/** + * @param {string} s + * @return {number} + */ +const minimumTime = function(s) { + const n = s.length + const arr = [] + for(let ch of s) { + arr.push(ch === '1' ? 1 : -1) + } + const score = minSum(arr) + return n + score + + function minSum(ar) { + const dp = Array(n).fill(Infinity) + dp[0] = ar[0] + let ans = dp[0] + for(let i = 1; i < n; i++) { + dp[i] = Math.min(ar[i], ar[i] + dp[i - 1]) + ans = Math.min(ans, dp[i]) + } + return ans > 0 ? 0 : ans + } +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const minimumTime = function(s) { + const n = s.length + const arr = [] + for(let ch of s) { + arr.push(ch === '1' ? 1 : -1) + } + const score = minSum(arr) + return n + score + + function minSum(ar) { + const dp = Array(n).fill(0) + dp[0] = ar[0] + for(let i = 1; i < n; i++) { + dp[i] = Math.min(ar[i], ar[i] + dp[i - 1]) + } + return Math.min(0, Math.min(...dp)) + } +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const minimumTime = function(s) { + if(s.length === 1) return s === '1' ? 1 : 0 + const n = s.length + const arr = [] + for(let ch of s) { + arr.push(ch === '1' ? 1 : -1) + } + const score = minSum(arr) + return n + score + + function minSum(ar) { + const dp = Array(n).fill(0) + dp[0] = ar[0] + let ans = dp[0] + for(let i = 1; i < n; i++) { + dp[i] = Math.min(ar[i], ar[i] + dp[i - 1]) + ans = Math.min(0, ans, dp[i]) + } + return ans + } +}; + +// another + + +/** + * @param {string} s + * @return {number} + */ +var minimumTime = function(s) { + + const { max, min } = Math + + let n = s.length; + const l = Array.from({ length: n + 1 }, () => Array(2).fill(0)) + const r = Array.from({ length: n + 1 }, () => Array(2).fill(0)) + for (let i = 0; i < n; i++) l[i][0] = l[i][1] = r[i][0] = r[i][1] = 0; + if (s[0] == '1') { + l[0][0] = 1; + l[0][1] = 2; + } + for (let i = 1; i < n; i++) { + if (s[i] == '0') { + l[i][0] = l[i - 1][0]; + l[i][1] = l[i - 1][1]; + } else { + l[i][0] = i + 1; + l[i][1] = min(l[i - 1][0], l[i - 1][1]) + 2; + } + } + if (s[n - 1] == '1') { + r[n - 1][0] = 1; + r[n - 1][1] = 2; + } + for (let i = n - 2; i >= 0; i--) { + if (s[i] == '0') { + r[i][0] = r[i + 1][0]; + r[i][1] = r[i + 1][1]; + } else { + r[i][0] = n - i; + r[i][1] = min(r[i + 1][0], r[i + 1][1]) + 2; + } + } + let ans = n; + for (let i = -1; i < n; i++) { + let cost = 0; + if (i != -1) cost += min(l[i][0], l[i][1]); + if (i != n - 1) cost += min(r[i + 1][0], r[i + 1][1]); + ans = min(ans, cost); + } + return ans; +}; diff --git a/2169-count-operations-to-obtain-zero.js b/2169-count-operations-to-obtain-zero.js new file mode 100644 index 00000000..5d4a260d --- /dev/null +++ b/2169-count-operations-to-obtain-zero.js @@ -0,0 +1,14 @@ +/** + * @param {number} num1 + * @param {number} num2 + * @return {number} + */ +var countOperations = function(num1, num2) { + let res = 0 + while(num1 !== 0 && num2 !== 0) { + if(num1 >= num2) num1 -= num2 + else num2 -= num1 + res++ + } + return res +}; diff --git a/2172-maximum-and-sum-of-array.js b/2172-maximum-and-sum-of-array.js new file mode 100644 index 00000000..02ca3260 --- /dev/null +++ b/2172-maximum-and-sum-of-array.js @@ -0,0 +1,42 @@ +/** + * @param {number[]} nums + * @param {number} numSlots + * @return {number} + */ +const maximumANDSum = function (nums, numSlots) { + const n = nums.length + nums.unshift(0) + const m = Math.pow(3, numSlots) + + const dp = Array.from({ length: n + 1 }, () => Array(m).fill(-Infinity)) + dp[0][0] = 0 + + let ret = 0 + + for (let state = 1; state < m; state++) { + let i = 0 + let temp = state + while (temp > 0) { + i += temp % 3 + temp = Math.floor(temp / 3) + } + if (i > n) continue + + for (let j = 0; j < numSlots; j++) { + if (filled(state, j) >= 1) { + dp[i][state] = Math.max( + dp[i][state], + dp[i - 1][state - Math.pow(3, j)] + (nums[i] & (j + 1)) + ) + } + } + if (i === n) ret = Math.max(ret, dp[i][state]) + } + + return ret +} + +function filled(state, k) { + for (let i = 0; i < k; i++) state = Math.floor(state / 3) + return state % 3 +} diff --git a/2178-maximum-split-of-positive-even-integers.js b/2178-maximum-split-of-positive-even-integers.js new file mode 100644 index 00000000..8efc231c --- /dev/null +++ b/2178-maximum-split-of-positive-even-integers.js @@ -0,0 +1,18 @@ +/** + * @param {number} finalSum + * @return {number[]} + */ +const maximumEvenSplit = function(finalSum) { + if(finalSum % 2 === 1) return [] + const res = [] + let i = 2 + while(i <= finalSum) { + res.push(i) + finalSum -= i + i += 2 + } + + const last = res.pop() + res.push(finalSum + last) + return res +}; diff --git a/2179-count-good-triplets-in-an-array.js b/2179-count-good-triplets-in-an-array.js new file mode 100644 index 00000000..56aca32c --- /dev/null +++ b/2179-count-good-triplets-in-an-array.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} a + * @param {number[]} b + * @return {number} + */ +const goodTriplets = function(a, b) { + let n = a.length, m = new Map(), res = 0; + for (let i = 0; i < n; i++) m.set(b[i], i); + let fen = new Fenwick(n + 3); + for (let i = 0; i < n; i++) { + let pos = m.get(a[i]); + let l = fen.query(pos), r = (n - 1 - pos) - (fen.query(n - 1) - fen.query(pos)); + res += l * r; + fen.update(pos, 1); + } + return res; +}; +function Fenwick(n) { + let tree = Array(n).fill(0); + return { query, update } + function query(i) { + let sum = 0; + i++; + while (i > 0) { + sum += tree[i]; + i -= i & -i; + } + return sum; + } + function update(i, v) { + i++; + while (i < n) { + tree[i] += v; + i += i & -i; + } + } +} diff --git a/218-the-skyline-problem.js b/218-the-skyline-problem.js index 515675d3..81f1f00c 100644 --- a/218-the-skyline-problem.js +++ b/218-the-skyline-problem.js @@ -1,3 +1,131 @@ +/** + * @param {number[][]} buildings + * @return {number[][]} + */ +const getSkyline = function(buildings) { + const hash = {} + for(const b of buildings) { + const [s, e, h] = b + if(hash[s] == null) hash[s] = [] + if(hash[e] == null) hash[e] = [] + hash[s].push(h) + hash[e].push(-h) + } + const ms = new MultiSet() + const res = [] + + for(const [pos, hs] of Object.entries(hash)) { + for(const h of hs) { + if(h > 0) { + ms.add(h) + } else { + ms.remove(-h) + } + } + const h = ms.max || 0 + if(res.length === 0 || res[res.length - 1][1] !== h) { + res.push([+pos, h]) + } + } + + + return res +}; + +class MultiSet { + constructor() { + this.countMap = new Map() + this.valueList = [] + } + remove(value) { + if(!this.countMap.has(value)) return false + let index = binarySearch(this.valueList, value) + if (this.countMap.get(value) === 1) { + this.valueList.splice(index, 1) + this.countMap.delete(value) + } else { + this.countMap.set(value, (this.countMap.get(value) || 0) - 1) + } + return true + } + add(value) { + let index = binarySearch(this.valueList, value) + if (index < 0) { + this.valueList.splice(-index - 1, 0, value) + this.countMap.set(value, 1) + } else { + this.countMap.set(value, this.countMap.get(value) + 1) + } + } + get max() { + return this.valueList[this.valueList.length - 1] + } + get min() { + return this.valueList[0] + } +} + +function binarySearch(arr, val) { + let l = 0, r = arr.length + while( l < r ) { + const mid = Math.floor((l + r) / 2) + if(arr[mid] < val) { + l = mid + 1 + } else { + r = mid + } + } + if(arr[l] !== val) return -(l + 1) + + return l +} + +// another + + +/** + * @param {number[][]} buildings + * @return {number[][]} + */ +var getSkyline = function(buildings) { + const edgeSet = new Set(); + for (let i = 0; i < buildings.length; i++) { + const [from, to] = buildings[i]; + edgeSet.add(from); + edgeSet.add(to); + } + const positions = [...edgeSet]; + positions.sort((a, b) => a - b); + + const pq = new PriorityQueue({compare: (a, b) => b[2] - a[2]}); + + const result = []; + + let j = 0; + for (let i = 0; i < positions.length; i++) { + const position = positions[i]; + + for (j; j < buildings.length && buildings[j][0] <= position; j++) { + pq.enqueue(buildings[j]); + } + + while (!pq.isEmpty() && pq.front()[1] <= position) { + pq.dequeue(); + } + + let maxHeight = pq.front()?.[2] ?? 0; + + if (!result.length || result.at(-1)[1] !== maxHeight) { + result.push([position, maxHeight]); + } + } + + return result; +}; + +// another + + /** * @param {number[][]} buildings * @return {number[][]} @@ -53,3 +181,150 @@ function combineOutputs(a, b) { } return combined } + + +// another + +/** + * @param {number[][]} buildings + * @return {number[][]} + */ +const getSkyline = function (buildings) { + const n = buildings.length + const arr = [] + const res = [] + for(const [s, e, h] of buildings) { + arr.push([s, -h]) + arr.push([e, h]) + } + arr.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) + const ms = new MultiSet() + ms.insert(0) + let pre = 0 + for(const [p, h] of arr) { + h < 0 ? ms.insert(-h) : ms.eraseOne(h) + const cur = ms.last() + if(cur !== pre) { + res.push([p, cur]) + pre = cur + } + } + + + return res +} + +//////////////////////// Template ////////////////////////////////// +function Bisect() { + return { insort_right, insort_left, bisect_left, bisect_right } + function insort_right(a, x, lo = 0, hi = null) { + lo = bisect_right(a, x, lo, hi); + a.splice(lo, 0, x); + } + function bisect_right(a, x, lo = 0, hi = null) { // > upper_bound + if (lo < 0) throw new Error('lo must be non-negative'); + if (hi == null) hi = a.length; + while (lo < hi) { + let mid = parseInt((lo + hi) / 2); + a[mid] > x ? hi = mid : lo = mid + 1; + } + return lo; + } + function insort_left(a, x, lo = 0, hi = null) { + lo = bisect_left(a, x, lo, hi); + a.splice(lo, 0, x); + } + function bisect_left(a, x, lo = 0, hi = null) { // >= lower_bound + if (lo < 0) throw new Error('lo must be non-negative'); + if (hi == null) hi = a.length; + while (lo < hi) { + let mid = parseInt((lo + hi) / 2); + a[mid] < x ? lo = mid + 1 : hi = mid; + } + return lo; + } +} + +function MultiSet(elements) { + let a = [], m = new Map(), bi = new Bisect(); + initialize(); + return { insert, first, last, get, search, poll, pollLast, lower_bound, upper_bound, findKth, eraseByIndex, eraseOne, eraseAll, contains, size, clear, show }; + function initialize() { + if (elements) { + for (const x of elements) { + bi.insort_right(a, x); + m.set(x, m.get(x) + 1 || 1); + } + } + } + function insert(x) { + bi.insort_right(a, x); + m.set(x, m.get(x) + 1 || 1); + } + function first() { + return a[0]; + } + function last() { + return a[a.length - 1]; + } + function get(i) { + return a[i]; + } + function poll() { + let res = a[0]; + a.splice(0, 1); + removeOneOrManyMap(m, res); + return res; + } + function pollLast() { + let res = a.pop(); + removeOneOrManyMap(m, res); + return res; + } + function lower_bound(x) { + return bi.bisect_left(a, x); + } + function upper_bound(x) { + return bi.bisect_right(a, x); + } + function findKth(k) { + return a[k - 1]; + } + function search(x) { + return lower_bound(x); + } + function eraseByIndex(idx) { + removeOneOrManyMap(m, a[idx]); + a.splice(idx, 1); + } + function eraseOne(x) { + let idx = lower_bound(x); + if (a[idx] == x) a.splice(idx, 1); + removeOneOrManyMap(m, x); + } + function eraseAll(x) { + if (contains(x)) { + let idx = search(x), occ = m.get(x); + while (occ--) a.splice(idx, 1); + m.delete(x); + } + } + function removeOneOrManyMap(m, x, cnt = 1) { + let occ = m.get(x); + occ > cnt ? m.set(x, occ - cnt) : m.delete(x); + } + function contains(x) { + return m.has(x); + } + function size() { + return a.length; + } + function clear() { + a = []; + m.clear(); + } + function show() { + return a; + } +} +/////////////////////////////////////////////////////////////////// diff --git a/2180-count-integers-with-even-digit-sum.js b/2180-count-integers-with-even-digit-sum.js new file mode 100644 index 00000000..c15c2dc9 --- /dev/null +++ b/2180-count-integers-with-even-digit-sum.js @@ -0,0 +1,22 @@ +/** + * @param {number} num + * @return {number} + */ +var countEven = function(num) { + let res = 0 + for(let i = 1; i <= num; i++) { + const tmp = sum(i) + if(tmp % 2 === 0) res++ + } + + return res +}; + +function sum(e) { + let res = 0 + while(e) { + res += e % 10 + e = Math.floor(e/10) + } + return res +} diff --git a/2181-merge-nodes-in-between-zeros.js b/2181-merge-nodes-in-between-zeros.js new file mode 100644 index 00000000..12bcb723 --- /dev/null +++ b/2181-merge-nodes-in-between-zeros.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) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +var mergeNodes = function(head) { + const dummy = new ListNode() + const arr = [] + let cur = head + while(cur) { + arr.push(cur) + cur = cur.next + } + let tail = dummy + let lastIdx = 0, sum = 0 + if(arr.length) { + for(let i = 1; i < arr.length; i++) { + const tmp = arr[i] + if(tmp.val === 0 && sum !== 0) { + lastIdx = i + tail.next = new ListNode(sum) + tail = tail.next + sum = 0 + } else { + sum += tmp.val + } + } + } + + return dummy.next +}; diff --git a/2182-construct-string-with-repeat-limit.js b/2182-construct-string-with-repeat-limit.js new file mode 100644 index 00000000..3672040b --- /dev/null +++ b/2182-construct-string-with-repeat-limit.js @@ -0,0 +1,46 @@ +/** + * @param {string} s + * @param {number} repeatLimit + * @return {string} + */ +var repeatLimitedString = function(s, repeatLimit) { + const a = 'a'.charCodeAt(0) + const ch = Array(26).fill(0) + for(let e of s) { + const idx = e.charCodeAt(0) + ch[idx - a]++ + } + let res = '', last = '' + while(true) { + let len = res.length + let h = false + for(let i = 25; i >= 0; i--) { + if(ch[i] >= repeatLimit && res[res.length - 1] !== String.fromCharCode(a + i)) { + + res += String.fromCharCode(a + i).repeat(repeatLimit) + ch[i] -= repeatLimit + + if(ch[i]) { + for(let j = i - 1; j >= 0; j--) { + if(ch[j]) { + res += String.fromCharCode(a + j) + ch[j]-- + break + } + } + break + } + + }else if(ch[i] > 0 && res[res.length - 1] !== String.fromCharCode(a + i)) { + + res += String.fromCharCode(a + i).repeat(ch[i]) + ch[i] = 0 + break + } + } + if(len === res.length) break + } + + + return res +}; diff --git a/2183-count-array-pairs-divisible-by-k.js b/2183-count-array-pairs-divisible-by-k.js new file mode 100644 index 00000000..268ad344 --- /dev/null +++ b/2183-count-array-pairs-divisible-by-k.js @@ -0,0 +1,58 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countPairs = function (nums, k) { + const map = new Map() + + let res = 0 + for(const e of nums) { + const tmp = gcd(e, k) + + for(const [key, v] of map) { + if(tmp * key % k === 0) { + res += v + } + } + if(map.get(tmp) == null) map.set(tmp, 0) + map.set(tmp, map.get(tmp) + 1) + } + + return res + + function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) + } +} + +// another + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const coutPairs = function(nums, k) { + let res = 0; + let cnt = Array(1e5 + 1).fill(0); + const n = nums.length + for (let i = 0; i < n; ++i) { + if (nums[i] % k == 0) { + res += i; + ++cnt[0]; + } + else { + let div = gcd(k, nums[i]); + for (let d = 0; d <= div; ++d) res += cnt[k / div * d]; + ++cnt[div]; + } + } + return res; +}; + +function gcd(a, b) { + if(b === 0) return a + return gcd(b, a % b) +} diff --git a/2184-number-of-ways-to-build-sturdy-brick-wall.js b/2184-number-of-ways-to-build-sturdy-brick-wall.js new file mode 100644 index 00000000..99624b12 --- /dev/null +++ b/2184-number-of-ways-to-build-sturdy-brick-wall.js @@ -0,0 +1,103 @@ +/** + * @param {number} height + * @param {number} width + * @param {number[]} bricks + * @return {number} + */ +const buildWall = function (height, width, bricks) { + const mod = 1e9 + 7 + const avail = [] + const bset = new Set(bricks) + const m = width - 1, limit = 1 << m + for(let mask = 0; mask < limit; mask++) { + const idxArr = [-1] + for(let j = 0; j < m; j++) { + if((mask >> j) & 1) idxArr.push(j) + } + idxArr.push(m) + let flag = true + for(let j = 1, len = idxArr.length; j < len; j++) { + if(!bset.has(idxArr[j] - idxArr[j - 1])) { + flag = false + break + } + } + if(flag) avail.push(mask) + } + + let res = 0 + if(height === 1) return avail.length + const dp = Array.from({ length: height }, () => Array(limit).fill(0)) + for(const mask of avail) { + dp[0][mask] = 1 + } + + for(let i = 1; i < height; i++) { + for(let j = 0, len = avail.length; j < len; j++) { + const cur = avail[j] + for(let k = 0; k < len; k++) { + const pre = avail[k] + if((cur & pre) === 0) { + dp[i][cur] = (dp[i][cur] + dp[i - 1][pre]) % mod + } + } + if(i === height - 1) { + res = (res + dp[i][cur]) % mod + } + } + } + + return res +} + +// another + +/** + * @param {number} height + * @param {number} width + * @param {number[]} bricks + * @return {number} + */ +const buildWall = function (height, width, bricks) { + const MOD = 1e9 + 7 + const rowPerms = new Set() // save all possible permutations of a row as a bitmask + const memo = [] + for (let i = 0; i <= height; ++i) { + memo[i] = new Array(2 ** 10).fill(0) + } + findAllPossRowPerms(rowPerms, 0, 0 | 0) + return countWaysToBuildSturdyWall(height, 0) + + function countWaysToBuildSturdyWall(currHeight, prevRowPerm) { + if (currHeight === 0) return 1 + if (memo[currHeight][prevRowPerm] != 0) { + return memo[currHeight][prevRowPerm] + } + let totCount = 0 + for (const rowPerm of rowPerms) { + if ((rowPerm & prevRowPerm) === 0) { + totCount = + (totCount + countWaysToBuildSturdyWall(currHeight - 1, rowPerm)) % MOD + } + } + memo[currHeight][prevRowPerm] = totCount + return totCount + } + + function findAllPossRowPerms(rowPerms, currWidth, mask) { + if (currWidth === width) { + rowPerms.add(mask) + return + } + // The reason why we don't want to mark the 0 index is that we are going from right to left + // when creating the wall and unlike other points of a row, the all rows will be flushed + // against the 0 index. + if (currWidth > 0) mask |= 1 << currWidth + for (const brick of bricks) { + if (currWidth + brick <= width) { + findAllPossRowPerms(rowPerms, currWidth + brick, mask) + } + } + return + } +} diff --git a/2188-minimum-time-to-finish-the-race.js b/2188-minimum-time-to-finish-the-race.js new file mode 100644 index 00000000..2e995cff --- /dev/null +++ b/2188-minimum-time-to-finish-the-race.js @@ -0,0 +1,103 @@ +/** + * @param {number[][]} tires + * @param {number} changeTime + * @param {number} numLaps + * @return {number} + */ + const minimumFinishTime = function (tires, changeTime, numLaps) { + tires = preprocess(tires) + let n = tires.length + const { max, min } = Math + // to handle the cases where numLaps is small + // pre[i][j]: the total time to run j laps consecutively with tire i + const pre = Array.from({ length: n }, () => + Array(20).fill(Infinity) + ) + for (let i = 0; i < n; i++) { + pre[i][1] = tires[i][0] + for (let j = 2; j < 20; j++) { + if (pre[i][j - 1] * tires[i][1] >= 2e9) break + pre[i][j] = pre[i][j - 1] * tires[i][1] + } + // since we define it as the total time, rather than just the time for the j-th lap + // we have to make it prefix sum + for (let j = 2; j < 20; j++) { + if (pre[i][j - 1] + pre[i][j] >= 2e9) break + pre[i][j] += pre[i][j - 1] + } + } + + // dp[x]: the minimum time to finish x laps + const dp = Array(numLaps + 1).fill(Infinity) + for (let i = 0; i < n; i++) { + dp[1] = min(dp[1], tires[i][0]) + } + for (let x = 1; x <= numLaps; x++) { + if (x < 20) { + // x is small enough, so an optimal solution might never changes tires! + for (let i = 0; i < n; i++) { + dp[x] = min(dp[x], pre[i][x]) + } + } + for (let j = x - 1; j > 0 && j >= x - 18; j--) { + dp[x] = min(dp[x], dp[j] + changeTime + dp[x - j]) + } + } + + return dp[numLaps] +} + +function preprocess(tires) { + tires.sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0])) + const res = [] + for (let t of tires) { + if (res.length === 0 || res[res.length - 1][1] > t[1]) { + res.push(t) + } + } + return res +} + +// another + +/** + * @param {number[][]} tires + * @param {number} changeTime + * @param {number} numLaps + * @return {number} + */ +var minimumFinishTime = function (tires, changeTime, numLaps) { + let N = tires.length, + len = 0 + const { max, min } = Math + const best = Array(numLaps).fill(Infinity), + dp = Array(numLaps + 1).fill(Infinity) + for (let i = 0; i < N; ++i) { + // We assume we also need `changeTime` time to use the first tire + // so that we don't need to treat the first tire as a special case + let f = tires[i][0], + r = tires[i][1], + sum = changeTime, + p = 1 + for (let j = 0; j < numLaps; ++j) { + sum += f * p + // If using the same tire takes no less time than changing the tire, + // stop further using the current tire + if (f * p >= f + changeTime) break + best[j] = min(best[j], sum) + len = max(len, j + 1) + p *= r + } + } + // dp[i + 1] is the minimum time to finish `numLaps` laps + dp[0] = 0 + for (let i = 0; i < numLaps; ++i) { + for (let j = 0; j < len && i - j >= 0; ++j) { + // try using the same tire in the last `j+1` laps + dp[i + 1] = min(dp[i + 1], dp[i - j] + best[j]) + } + } + // minus the `changeTime` we added to the first tire + return dp[numLaps] - changeTime +} + diff --git a/2189-number-of-ways-to-build-house-of-cards.js b/2189-number-of-ways-to-build-house-of-cards.js new file mode 100644 index 00000000..986c2152 --- /dev/null +++ b/2189-number-of-ways-to-build-house-of-cards.js @@ -0,0 +1,18 @@ +/** + * @param {number} n + * @return {number} + */ +const houseOfCards = function(n) { + const memo = Array.from({ length: n + 1 }, () => Array(n + 2).fill(null)) + return helper(n, n + 1) + + function helper(remain, preRow) { + if(remain === 0 || remain === 2) return 1 + if(memo[remain][preRow] != null) return memo[remain][preRow] + let res = 0 + for(let i = 5; i <= remain && i < preRow; i += 3) { + res += helper(remain - i, i) + } + return memo[remain][preRow] = res + } +}; diff --git a/2192-all-ancestors-of-a-node-in-a-directed-acyclic-graph.js b/2192-all-ancestors-of-a-node-in-a-directed-acyclic-graph.js new file mode 100644 index 00000000..4ae95f82 --- /dev/null +++ b/2192-all-ancestors-of-a-node-in-a-directed-acyclic-graph.js @@ -0,0 +1,64 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[][]} + */ +const getAncestors = function(n, edges) { + const res = Array.from({ length: n }, () => []) + const graph = {} + + for(const [u, v] of edges) { + if(graph[u] == null) graph[u] = [] + graph[u].push(v) + } + + for(let i = 0; i < n; i++) { + dfs(i, i) + } + + return res + + function dfs(p, cur) { + for(const nxt of (graph[cur] || [])) { + if(res[nxt].length === 0 || res[nxt][res[nxt].length - 1] !== p) { + res[nxt].push(p) + dfs(p, nxt) + } + } + } +}; + +// another + +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[][]} + */ +const getAncestors = function(n, edges) { + const res = Array.from({ length: n }, () => new Set()) + const inDegree = Array(n).fill(0) + const graph = {} + + for(const [u, v] of edges) { + if(graph[v] == null) graph[v] = [] + graph[v].push(u) + inDegree[v]++ + } + + const visited = Array(n).fill(false) + for (let i = 0; i < n; i++) { + if (!visited[i]) dfs(i); + } + + return res.map(set => Array.from(set).sort((a, b) => a - b)) + + function dfs(i) { + visited[i] = true + for(const p of (graph[i] || [])) { + if(visited[p] === false) dfs(p) + res[i].add(p) + for(const e of res[p]) res[i].add(e) + } + } +}; diff --git a/2193-minimum-number-of-moves-to-make-palindrome.js b/2193-minimum-number-of-moves-to-make-palindrome.js new file mode 100644 index 00000000..266ef822 --- /dev/null +++ b/2193-minimum-number-of-moves-to-make-palindrome.js @@ -0,0 +1,21 @@ +/** + * @param {string} s + * @return {number} + */ +const minMovesToMakePalindrome = function(s) { + let res = 0 + const arr = s.split('') + + while(arr.length) { + const idx = arr.indexOf(arr[arr.length - 1]) + if(idx === arr.length - 1) { + res += ~~(idx / 2) + } else { + res += idx + arr.splice(idx, 1) + } + arr.pop() + } + + return res +}; diff --git a/2197-replace-non-coprime-numbers-in-array.js b/2197-replace-non-coprime-numbers-in-array.js new file mode 100644 index 00000000..a2551d90 --- /dev/null +++ b/2197-replace-non-coprime-numbers-in-array.js @@ -0,0 +1,22 @@ +const gcd = (a, b) => (b == 0 ? a : gcd(b, a % b)); +/** + * @param {number[]} nums + * @return {number[]} + */ +const replaceNonCoprimes = function (nums) { + const stk = []; + for (let x of nums) { + if (stk.length === 0) { + stk.push(x); + } else { + while (stk.length && gcd(stk[stk.length - 1], x) !== 1) { + // check if it can be merged with the value to its left + const last = stk.pop(), + g = gcd(x, last); + x = (x / g) * last; // merge value, update lcm to x + } + stk.push(x); + } + } + return stk; +}; diff --git a/220-contains-duplicate-iii.js b/220-contains-duplicate-iii.js new file mode 100644 index 00000000..e0247c1c --- /dev/null +++ b/220-contains-duplicate-iii.js @@ -0,0 +1,54 @@ +/** + * @param {number[]} nums + * @param {number} k + * @param {number} t + * @return {boolean} + */ +const containsNearbyAlmostDuplicate = function(nums, k, t) { + if (k < 1 || t < 0) { + return false + } + const array = new Map() + const num = 10 ** 10 + for (let i = 0, iL = nums.length; i < iL; ++i) { + const noNegative = nums[i] + num + const factor = Math.floor(noNegative / (t + 1)) + if ( + array.has(factor) || + (array.has(factor - 1) && noNegative - array.get(factor - 1) <= t) || + (array.has(factor + 1) && array.get(factor + 1) - noNegative <= t) + ) { + return true + } + if (array.size >= k) { + array.delete(Math.floor((nums[i - k] + num) / (t + 1))) + } + array.set(factor, noNegative) + } + return false +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @param {number} t + * @return {boolean} + */ +const containsNearbyAlmostDuplicate = function(nums, k, t) { + const map = nums + .map((val, idx) => ({ val, idx })) + .sort((a, b) => a.val - b.val) + let l = 0 + let r = 1 + while (r < map.length) { + const diff = Math.abs(map[r].val - map[l].val) + const range = Math.abs(map[r].idx - map[l].idx) + if (diff <= t && range <= k) return true + else if (diff > t) l++ + else if (range > k) r++ + if (l === r) r++ + } + return false +} diff --git a/2202-maximize-the-topmost-element-after-k-moves.js b/2202-maximize-the-topmost-element-after-k-moves.js new file mode 100644 index 00000000..244e6835 --- /dev/null +++ b/2202-maximize-the-topmost-element-after-k-moves.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var maximumTop = function(nums, k) { + const n = nums.length + if(k === 0) return n >= 1 ? nums[0] : -1 + if(k === 1) return n === 1 ? -1 : nums[1] + if(n === 1) return k % 2 === 0 ? nums[0] : -1 + const tmp = nums.slice(0, Math.min(k - 1, n)) + let res = Math.max(...tmp) + if(k < n) res = Math.max(res, nums[k]) + return res +}; diff --git a/2203-minimum-weighted-subgraph-with-the-required-paths.js b/2203-minimum-weighted-subgraph-with-the-required-paths.js new file mode 100644 index 00000000..fe35f1de --- /dev/null +++ b/2203-minimum-weighted-subgraph-with-the-required-paths.js @@ -0,0 +1,64 @@ +const initializeGraph = (n) => { + let g = [] + for (let i = 0; i < n; i++) { + g.push([]) + } + return g +} +const packDGCost = (g, ig, edges) => { + for (const [u, v, cost] of edges) { + g[u].push([v, cost]) + ig[v].push([u, cost]) + } +} +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} src1 + * @param {number} src2 + * @param {number} dest + * @return {number} + */ +var minimumWeight = function(n, edges, src1, src2, dest) { + let g = initializeGraph(n), + ig = initializeGraph(n) + packDGCost(g, ig, edges) + /* + src1 -> x + src2 -> x + x -> dest find smallest distance from all nodes to the destination, run Dijkstra in reverse from the destination + */ + let d1 = dijkstra(g, src1), + d2 = dijkstra(g, src2), + d3 = dijkstra(ig, dest), + res = Number.MAX_SAFE_INTEGER + for (let i = 0; i < n; i++) res = Math.min(res, d1[i] + d2[i] + d3[i]) + return res == Number.MAX_SAFE_INTEGER ? -1 : res +} + +const dijkstra = (g, start) => { + // store the shortest distance from startNode to all other nodes + let n = g.length, + dis = Array(n).fill(Number.MAX_SAFE_INTEGER) + let pq = new MinPriorityQueue({ + compare: (x, y) => { + if (x[0] != y[0]) return x[0] - y[0] + return x[1] - y[1] + }, + }) + dis[start] = 0 + pq.enqueue([start, 0]) + while (pq.size()) { + let [cur, d] = pq.dequeue() + if (d > dis[cur]) continue // larger distance, no need to find the route to next node + for (const [child, cost] of g[cur]) { + let toChildCost = d + cost + if (toChildCost < dis[child]) { + // each time total wight/cost to current child is smaller, updated it + dis[child] = toChildCost + pq.enqueue([child, toChildCost]) + } + } + } + return dis +}; diff --git a/2204-distance-to-a-cycle-in-undirected-graph.js b/2204-distance-to-a-cycle-in-undirected-graph.js new file mode 100644 index 00000000..a9ba46cc --- /dev/null +++ b/2204-distance-to-a-cycle-in-undirected-graph.js @@ -0,0 +1,75 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ +const distanceToCycle = function(n, edges) { + const hash = {} + let graph = new Map() + for(const [u, v] of edges) { + if(graph.get(u) == null) graph.set(u, new Set()) + if(graph.get(v) == null) graph.set(v, new Set()) + graph.get(u).add(v) + graph.get(v).add(u) + } + + const clonedGraph = new Map() + for(const [k, v] of graph) { + clonedGraph.set(k, new Set(v)) + } + + let level = 0 + let q = [] + const visited = new Set() + for(const [k, v] of graph) { + if(graph.get(k).size === 1) { + q.push(k) + } + } + + while(q.length) { + const size = q.length + const nxt = [] + for(let i = 0; i < size; i++) { + const cur = q[i] + for(const e of (graph.get(cur) || [])) { + graph.get(e).delete(cur) + if(graph.get(e).size === 1) { + nxt.push(e) + } + } + } + q = nxt + } + + q = [] + + visited.clear() + for(const [k, v] of graph) { + if(v.size === 2) { + q.push(k) + visited.add(k) + } + } + const res = Array(n).fill(0) + graph = clonedGraph + while(q.length) { + level++ + const size = q.length + const nxt = [] + for(let i = 0; i < size; i++) { + const cur = q[i] + for(const e of (graph.get(cur) || [])) { + if(!visited.has(e)) { + nxt.push(e) + res[e] = level + visited.add(e) + } + } + } + + q = nxt + } + + return res +}; diff --git a/2209-minimum-white-tiles-after-covering-with-carpets.js b/2209-minimum-white-tiles-after-covering-with-carpets.js new file mode 100644 index 00000000..a964a6c8 --- /dev/null +++ b/2209-minimum-white-tiles-after-covering-with-carpets.js @@ -0,0 +1,28 @@ +/** + * @param {string} floor + * @param {number} numCarpets + * @param {number} carpetLen + * @return {number} + */ +const minimumWhiteTiles = function(floor, numCarpets, carpetLen) { + // 0: black, 1: white + const n = floor.length + // dp[i][j]: the minimum number of white tiles still visible + // when using j tiles to cover the first i tiles + const dp = Array.from({ length: n + 1 }, () => Array(numCarpets + 1).fill(0)) + + const ones = Array(n + 1).fill(0) + for(let i = 1; i <= n; i++) { + ones[i] = ones[i - 1] + (floor[i - 1] === '1' ? 1 : 0) + } + for(let i = 1; i <= n; i++) { + dp[i][0] = ones[i] + for(let j = 1; j <= numCarpets; j++) { + const skip = dp[i - 1][j] + (floor[i - 1] === '1' ? 1 : 0) + const cover = dp[Math.max(i - carpetLen, 0)][j - 1] + dp[i][j] = Math.min(skip, cover) + } + } + + return dp[n][numCarpets] +}; diff --git a/2210-count-hills-and-valleys-in-an-array.js b/2210-count-hills-and-valleys-in-an-array.js new file mode 100644 index 00000000..7ffb12a9 --- /dev/null +++ b/2210-count-hills-and-valleys-in-an-array.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const countHillValley = function(nums) { + const arr = [nums[0]], n = nums.length + for(let i = 1; i < n; i++) { + if(nums[i] !== nums[i - 1]) arr.push(nums[i]) + } + let res = 0 + for(let i = 1; i < arr.length - 1; i++) { + if( + arr[i] > arr[i - 1] && arr[i] > arr[i + 1] || + arr[i] < arr[i - 1] && arr[i] < arr[i + 1] + ) res++ + } + + return res +}; diff --git a/2211-count-collisions-on-a-road.js b/2211-count-collisions-on-a-road.js new file mode 100644 index 00000000..03ab8347 --- /dev/null +++ b/2211-count-collisions-on-a-road.js @@ -0,0 +1,43 @@ +/** + * @param {string} directions + * @return {number} + */ +const countCollisions = function(directions) { + let res = 0, n = directions.length + + let flag = false + // left -> right + for(let i = 0; i < n; i++) { + if(directions[i] !== 'L') { + flag = true + } else { + res += flag ? 1 : 0 + } + } + flag = false + // right -> left + for(let i = n - 1; i >= 0; i--) { + if(directions[i] !== 'R') { + flag = true + } else { + res += flag ? 1 : 0 + } + } + + return res +}; + +// another + +/** + * @param {string} directions + * @return {number} + */ + const countCollisions = function(directions) { + let res = 0, n = directions.length + let left = 0, right = n - 1 + while(left < n && directions[left] === 'L') left++ + while(right >= 0 && directions[right] === 'R') right-- + for(let i = left; i <= right; i++) res += directions[i] === 'S' ? 0 : 1 + return res +}; diff --git a/2212-maximum-points-in-an-archery-competition.js b/2212-maximum-points-in-an-archery-competition.js new file mode 100644 index 00000000..fd5ede74 --- /dev/null +++ b/2212-maximum-points-in-an-archery-competition.js @@ -0,0 +1,30 @@ +/** + * @param {number} numArrows + * @param {number[]} aliceArrows + * @return {number[]} + */ +const maximumBobPoints = function(numArrows, aliceArrows) { + let bestScore = 0, res = null + const sum = arr => arr.reduce((ac, e) => ac + e, 0) + bt(0, numArrows, 0, Array(12).fill(0)) + res[0] += numArrows - sum(res) + return res + + function bt(k, remain, score, bobArrows) { + if(k == 12) { + if(score > bestScore) { + bestScore = score + res = bobArrows.slice(0) + } + return + } + bt(k + 1, remain, score, bobArrows) + let arrowsNeeded = aliceArrows[k] + 1 + if(remain >= arrowsNeeded) { + let bak = bobArrows[k] + bobArrows[k] = arrowsNeeded + bt(k + 1, remain - arrowsNeeded, score + k, bobArrows) + bobArrows[k] = bak + } + } +}; diff --git a/2213-longest-substring-of-one-repeating-character.js b/2213-longest-substring-of-one-repeating-character.js new file mode 100644 index 00000000..cb527cb1 --- /dev/null +++ b/2213-longest-substring-of-one-repeating-character.js @@ -0,0 +1,105 @@ +/** + * @param {string} s + * @param {string} queryCharacters + * @param {number[]} queryIndices + * @return {number[]} + */ +const longestRepeating = function(s, queryCharacters, queryIndices) { + let n = queryCharacters.length + const ans = [] + + const segmentTree = new SegmentTree(s) + for (let i = 0; i < n; i++) { + segmentTree.update(1, 0, s.length - 1, queryIndices[i], queryCharacters[i]) + ans.push(segmentTree.getMax()) + } + + return ans +}; + +class TreeNode { + constructor(max, preStart, preEnd, sufStart, sufEnd) { + this.max = max + this.preStart = preStart + this.preEnd = preEnd + this.sufStart = sufStart + this.sufEnd = sufEnd + } +} + +class SegmentTree { + constructor(s) { + this.n = s.length + this.s = s.split('') + this.tree = new Array(4 * s.length) + this.build(s, 1, 0, s.length - 1) + } + + build(s, treeIndex, left, right) { + if (left === right) { + this.tree[treeIndex] = new TreeNode(1, left, left, right, right) + return + } + + let mid = left + Math.floor((right - left) / 2) + this.build(s, treeIndex * 2, left, mid) + this.build(s, treeIndex * 2 + 1, mid + 1, right) + + this.tree[treeIndex] = this.merge( + this.tree[treeIndex * 2], + this.tree[treeIndex * 2 + 1], + left, + mid, + right + ) + } + + update(treeIndex, left, right, index, val) { + if (left === right) { + this.tree[treeIndex] = new TreeNode(1, left, left, right, right) + this.s[index] = val + return + } + + let mid = left + Math.floor((right - left) / 2) + if (mid < index) { + this.update(treeIndex * 2 + 1, mid + 1, right, index, val) + } else { + this.update(treeIndex * 2, left, mid, index, val) + } + + this.tree[treeIndex] = this.merge( + this.tree[treeIndex * 2], + this.tree[treeIndex * 2 + 1], + left, + mid, + right + ) + } + + merge(l, r, left, mid, right) { + let max = Math.max(l.max, r.max) + let preStart = l.preStart + let preEnd = l.preEnd + let sufStart = r.sufStart + let sufEnd = r.sufEnd + + if (this.s[mid] === this.s[mid + 1]) { + max = Math.max(max, r.preEnd - l.sufStart + 1) + if (l.preEnd - l.preStart + 1 === mid - left + 1) { + preEnd = r.preEnd + } + if (r.sufEnd - r.sufStart + 1 === right - mid) { + sufStart = l.sufStart + } + } + + return new TreeNode(max, preStart, preEnd, sufStart, sufEnd) + } + + getMax() { + return this.tree[1].max + } +} + + diff --git a/2214-minimum-health-to-beat-game.js b/2214-minimum-health-to-beat-game.js new file mode 100644 index 00000000..21c1d29e --- /dev/null +++ b/2214-minimum-health-to-beat-game.js @@ -0,0 +1,10 @@ +/** + * @param {number[]} damage + * @param {number} armor + * @return {number} + */ +const minimumHealth = function(damage, armor) { + const l = Math.max(...damage) + const sum = damage.reduce((ac, e) => ac + e, 0) + return sum - (armor >= l ? l : armor) + 1 +}; diff --git a/2215-find-the-difference-of-two-arrays.js b/2215-find-the-difference-of-two-arrays.js new file mode 100644 index 00000000..07a46f8d --- /dev/null +++ b/2215-find-the-difference-of-two-arrays.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number[][]} + */ +var findDifference = function(nums1, nums2) { + const set1 = new Set(nums1), set2 = new Set(nums2) + const res = [new Set(), new Set()] + for(let e of nums1) { + if(set2.has(e)) continue + else res[0].add(e) + } + for(let e of nums2) { + if(set1.has(e)) continue + else res[1].add(e) + } + res[0] = Array.from(res[0]) + res[1] = Array.from(res[1]) + return res +}; diff --git a/2216-minimum-deletions-to-make-array-beautiful.js b/2216-minimum-deletions-to-make-array-beautiful.js new file mode 100644 index 00000000..4c7f09dd --- /dev/null +++ b/2216-minimum-deletions-to-make-array-beautiful.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minDeletion = function(nums) { + let res = 0, n = nums.length + + for(let i = 0; i < n; i += 2) { + while(i < n - 1 && nums[i] === nums[i + 1]) { + i++ + res++ + } + } + if((n - res) % 2 === 1) res++ + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const minDeletion = function(nums) { + let res = 0, i = 0 + for(i = 0, n = nums.length; i < n - 1;) { + if(nums[i] === nums[i + 1]) { + res++ + i++ + }else{ + i += 2 + } + } + if((nums.length - res) % 2 === 1) res++ + + return res +}; diff --git a/2217-find-palindrome-with-fixed-length.js b/2217-find-palindrome-with-fixed-length.js new file mode 100644 index 00000000..400bc1a3 --- /dev/null +++ b/2217-find-palindrome-with-fixed-length.js @@ -0,0 +1,45 @@ +/** + * @param {number[]} queries + * @param {number} intLength + * @return {number[]} + */ +var kthPalindrome = function(queries, intLength) { + if (intLength == 1) { + let res = [] + for (let item of queries) { + if (item <= 9) res.push(item) + else res.push(-1) + } + return res + } + + let n = Math.floor(intLength / 2) + let ref = +("1"+"0".repeat(n-1)) + + if (intLength % 2 == 0) { + let res = [] + for (let item of queries) res.push(gen_even(item)) + return res + } else { + let res = [] + for (let item of queries) res.push(gen_odd(item)) + return res + } + + function gen_even(val) { + let part = ref + val - 1 + part = '' + part + if (part.length != n) return -1 + return +(part + part.split('').reverse().join('')) + } + + + function gen_odd(val) { + let mod = (val - 1) % 10 + let div = Math.floor((val - 1) / 10) + let part = ref + div + mod = '' + mod, part = '' + part + if (part.length != n) return -1 + return +(part + mod + part.split('').reverse().join('')) + } +}; diff --git a/2218-maximum-value-of-k-coins-from-piles.js b/2218-maximum-value-of-k-coins-from-piles.js new file mode 100644 index 00000000..10f29d22 --- /dev/null +++ b/2218-maximum-value-of-k-coins-from-piles.js @@ -0,0 +1,51 @@ +/** + * @param {number[][]} piles + * @param {number} k + * @return {number} + */ +var maxValueOfCoins = function(piles, k) { + let dp = Array(k + 1).fill(0); + for (let i = 0; i < piles.length; i++) { + const next = Array(k + 1).fill(0); + for (let l = 1; l <= k; l++) { + let sum = 0; + next[l] = dp[l]; + for (let j = 0; j < Math.min(piles[i].length, l); j++) { + sum += piles[i][j]; + next[l] = Math.max(next[l], dp[l - j - 1] + sum); + } + } + dp = next; + } + return dp[k]; +}; + +// another + +/** + * @param {number[][]} piles + * @param {number} k + * @return {number} + */ +const maxValueOfCoins = function(piles, k) { + const n = piles.length + const memo = Array.from({ length: n + 1 }, () => Array(k + 1).fill(null)) + return helper(0, k) + + // TC: O(k * m) + // k: k + // n: length of piles + // m: sum(piles[i]), total elements of all piles + function helper(i, k) { + if(k == 0 || i === n) return 0 + if(memo[i][k] != null) return memo[i][k] + let res = helper(i + 1, k) + let cur = 0 + + for(let j = 0; j < Math.min(piles[i].length, k); j++) { + cur += piles[i][j] + res = Math.max(res, cur + helper(i + 1, k - j - 1)) + } + return memo[i][k] = res + } +}; diff --git a/2221-find-triangular-sum-of-an-array.js b/2221-find-triangular-sum-of-an-array.js new file mode 100644 index 00000000..561102a5 --- /dev/null +++ b/2221-find-triangular-sum-of-an-array.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const triangularSum = function(nums) { + while(nums.length > 1) { + const arr = [] + for(let i = 0, n = nums.length; i < n - 1; i++) { + arr.push((nums[i] + nums[i + 1]) % 10) + } + nums = arr + } + return nums[0] +}; diff --git a/2222-number-of-ways-to-select-buildings.js b/2222-number-of-ways-to-select-buildings.js new file mode 100644 index 00000000..02572411 --- /dev/null +++ b/2222-number-of-ways-to-select-buildings.js @@ -0,0 +1,27 @@ +/** + * @param {string} s + * @return {number} + */ +const numberOfWays = function(s) { + let one = 0, zero = 0 + for(const ch of s) { + if(ch === '1') one++ + else zero++ + } + let preOne = 0, preZero = 0 + let res = 0 + + for(const ch of s) { + if(ch === '1') { + res += preZero * zero + preOne++ + one-- + } else { + res += preOne * one + preZero++ + zero-- + } + } + + return res +}; diff --git a/2223-sum-of-scores-of-built-strings.js b/2223-sum-of-scores-of-built-strings.js new file mode 100644 index 00000000..2f8c3d48 --- /dev/null +++ b/2223-sum-of-scores-of-built-strings.js @@ -0,0 +1,61 @@ +/** + * @param {string} s + * @return {number} + */ +var sumScores = function(s) { + let res = 0 + const pre = lps(s) + const cnt = [] + for(let i = 0; i < s.length; i++) { + const j = pre[i] + cnt.push(j === 0 ? 0 : cnt[j - 1] + 1) + } + res = cnt.reduce((ac, e) => ac + e, 0) + s.length + return res + + function lps(s) { + const n = s.length + const res = Array(n).fill(0) + + for(let i = 1, j = 0; i < n; i++) { + while(j && s[j] !== s[i]) { + j = Math.max(0, res[j - 1]) + } + j += (s[i] === s[j] ? 1 : 0) + res[i] = j + } + + return res + } +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +var sumScores = function(s) { + function z_function(s) { + let n = s.length + let z = Array(n).fill(0) + let l = 0, r = 0 + for (let i = 1; i < n; i++) { + if (i <= r) z[i] = Math.min(r - i + 1, z[i - l]) + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) { + z[i] += 1 + } + + if (i + z[i] - 1 > r) { + l = i + r = i + z[i] - 1 + } + + } + return z + } + + const sum = z_function(s).reduce((ac, e) => ac + e, 0) + return sum + s.length +}; + diff --git a/2224-minimum-number-of-operations-to-convert-time.js b/2224-minimum-number-of-operations-to-convert-time.js new file mode 100644 index 00000000..6b25bb4b --- /dev/null +++ b/2224-minimum-number-of-operations-to-convert-time.js @@ -0,0 +1,41 @@ +/** + * @param {string} current + * @param {string} correct + * @return {number} + */ +var convertTime = function(current, correct) { + const s = current.split(':').map(e => +e) + const t = correct.split(':').map(e => +e) + let res = 0 + // hour + if(s[0] < t[0]) res += t[0] - s[0] + else if(s[0] > t[0]) res += (24 - (s[0] - t[0])) + + // min + let delta = t[1] - s[1] + if(delta > 0) { + if(delta >= 15) { + res += ~~(delta / 15) + delta %= 15 + } + if(delta >= 5) { + res += ~~(delta / 5) + delta %= 5 + } + res += delta + } else if(delta < 0) { + res-- + delta += 60 + if(delta >= 15) { + res += ~~(delta / 15) + delta %= 15 + } + if(delta >= 5) { + res += ~~(delta / 5) + delta %= 5 + } + res += delta + } + + return res +}; diff --git a/2225-find-players-with-zero-or-one-losses.js b/2225-find-players-with-zero-or-one-losses.js new file mode 100644 index 00000000..7023be33 --- /dev/null +++ b/2225-find-players-with-zero-or-one-losses.js @@ -0,0 +1,29 @@ +/** + * @param {number[][]} matches + * @return {number[][]} + */ +var findWinners = function(matches) { + const win = {}, lose = {}, total = new Set(), ls = new Set() + for(const [w, l] of matches) { + if(win[w] == null) win[w] = 0 + win[w]++ + if(lose[l] == null) lose[l] = 0 + lose[l]++ + total.add(l) + total.add(w) + ls.add(l) + } + + const loseKeys = Object.keys(lose) + const a0 = [] + for(const e of total) { + if(!ls.has(e)) a0.push(e) + } + const a1 = [] + for(const e of loseKeys) { + if(lose[e] === 1) a1.push(e) + } + a0.sort((a, b) => a - b) + a1.sort((a, b) => a - b) + return [a0, a1] +}; diff --git a/2226-maximum-candies-allocated-to-k-children.js b/2226-maximum-candies-allocated-to-k-children.js new file mode 100644 index 00000000..38ed2088 --- /dev/null +++ b/2226-maximum-candies-allocated-to-k-children.js @@ -0,0 +1,42 @@ +/** + * @param {number[]} candies + * @param {number} k + * @return {number} + */ +const maximumCandies = function(candies, k) { + let max = candies.reduce((ac, e) => ac + e, 0); + let min = 0; + while (min < max) { + let mid = max - Math.floor((max - min) / 2); + let cnt = 0; + for (let cand of candies) { + cnt += ~~(cand / mid); + } + if (cnt < k) { + max = mid - 1; + } else { + min = mid; + } + } + return min; +}; + +// another + +/** + * @param {number[]} candies + * @param {number} k + * @return {number} + */ +const maximumCandies = function(candies, k) { + let max = candies.reduce((ac, e) => ac + e, 0) + let min = 0 + while(min < max) { + const mid = max - Math.floor((max - min) /2) + let num = 0 + for(let e of candies) num += ~~(e / mid) + if(num < k) max = mid - 1 + else min = mid + } + return min +}; diff --git a/2227-encrypt-and-decrypt-strings.js b/2227-encrypt-and-decrypt-strings.js new file mode 100644 index 00000000..8178208e --- /dev/null +++ b/2227-encrypt-and-decrypt-strings.js @@ -0,0 +1,30 @@ +class Encrypter { + constructor(keys, values, dictionary) { + this.mapKeyToValue = {}; + this.mapCount = {}; + const n = keys.length; + + for (let i = 0; i < n; i++) { + const key = keys[i]; + const value = values[i]; + this.mapKeyToValue[key] = value; + } + + for (const dict of dictionary) { + const encrypted = this.encrypt(dict); + this.mapCount[encrypted] = (this.mapCount[encrypted] || 0) + 1; + } + } + + encrypt(word1) { + let res = ''; + for (const char of word1) { + res += this.mapKeyToValue[char]; + } + return res; + } + + decrypt(word2) { + return this.mapCount[word2] || 0; + } +} diff --git a/223-rectangle-area.js b/223-rectangle-area.js new file mode 100644 index 00000000..6c30c9d2 --- /dev/null +++ b/223-rectangle-area.js @@ -0,0 +1,69 @@ +/** + * @param {number} A + * @param {number} B + * @param {number} C + * @param {number} D + * @param {number} E + * @param {number} F + * @param {number} G + * @param {number} H + * @return {number} + */ +const computeArea = function(A, B, C, D, E, F, G, H) { + const areaA = (C - A) * (D - B) + const areaB = (G - E) * (H - F) + const intersectionArea = + Math.max(0, Math.min(C, G) - Math.max(A, E)) * + Math.max(0, Math.min(D, H) - Math.max(B, F)) + return areaA + areaB - intersectionArea +} + + +// another + + +/** + * @param {number} A + * @param {number} B + * @param {number} C + * @param {number} D + * @param {number} E + * @param {number} F + * @param {number} G + * @param {number} H + * @return {number} + */ +const computeArea = function(A, B, C, D, E, F, G, H) { + const x1 = A, + x2 = C, + x3 = E, + x4 = G + const y1 = B, + y2 = D, + y3 = F, + y4 = H + return ( + area(x1, y1, x2, y2) + + area(x3, y3, x4, y4) - + delta(x1, x2, x3, x4) * delta(y1, y2, y3, y4) + ) +} + +function area(x1, y1, x2, y2) { + return Math.abs(x1 - x2) * Math.abs(y1 - y2) +} + +function delta(v1, v2, v3, v4) { + if (v1 > v2) { + let tmp = v1 + v1 = v2 + v2 = tmp + } + if (v3 > v4) { + let tmp = v3 + v3 = v4 + v4 = tmp + } + if (v3 >= v2 || v4 <= v1) return 0 + return Math.min(v2, v4) - Math.max(v1, v3) +} diff --git a/2233-maximum-product-after-k-increments.js b/2233-maximum-product-after-k-increments.js new file mode 100644 index 00000000..d65aa854 --- /dev/null +++ b/2233-maximum-product-after-k-increments.js @@ -0,0 +1,90 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumProduct = function (nums, k) { + const pq = new PriorityQueue((a, b) => a < b) + let res = 1 + for(const e of nums) pq.push(e) + const mod = 1e9 + 7 + while(k) { + const e = pq.pop() + pq.push(e + 1) + k-- + } + while(!pq.isEmpty()) { + const e = pq.pop() + res = (res * e) % mod + } + + return res +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2234-maximum-total-beauty-of-the-gardens.js b/2234-maximum-total-beauty-of-the-gardens.js new file mode 100644 index 00000000..01af8481 --- /dev/null +++ b/2234-maximum-total-beauty-of-the-gardens.js @@ -0,0 +1,93 @@ +/** + * @param {number[]} flowers + * @param {number} newFlowers + * @param {number} target + * @param {number} full + * @param {number} partial + * @return {number} + */ +const maximumBeauty = function (flowers, newFlowers, target, full, partial) { + flowers.sort((x, y) => x - y) + flowers = flowers.map((x) => Math.min(x, target)) + let a = flowers, + n = a.length, + k = newFlowers, + pre = preSum(a), + bi = new Bisect() + let res = 0 + for (let i = 0; i <= n; i++) { + if (i < n && a[n - 1 - i] == target) continue + let step = i * target - (pre[n] - pre[n - i]) + if (step <= k) { + let beauty + if (i == n) { + beauty = i * full + } else { + let minPartial = BinarySearch(a[0], target, step, i) + beauty = i * full + minPartial * partial + } + if (beauty > res) res = beauty + } + } + return res + + function BinarySearch (low, high, step, i) { + while (low < high - 1) { + let mid = low + parseInt((high - low) / 2) + if (possible(mid, step, i)) { + low = mid + } else { + high = mid + } + } + return low + } + + function possible (m, step, i) { + let idx = bi.bisect_left(a, m, 0, n - i) + let need = m * idx - pre[idx] + return need <= k - step + } +} + +/////////////////// Template ///////////////////////////////// +function Bisect() { + return { insort_right, insort_left, bisect_left, bisect_right } + function insort_right(a, x, lo = 0, hi = null) { + lo = bisect_right(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_right(a, x, lo = 0, hi = null) { + // > upper_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + a[mid] > x ? (hi = mid) : (lo = mid + 1) + } + return lo + } + function insort_left(a, x, lo = 0, hi = null) { + lo = bisect_left(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_left(a, x, lo = 0, hi = null) { + // >= lower_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + a[mid] < x ? (lo = mid + 1) : (hi = mid) + } + return lo + } +} + +const preSum = (a) => { + let pre = [0] + for (let i = 0; i < a.length; i++) { + pre.push(pre[i] + a[i]) + } + return pre +} +////////////////////////////////////////////////////////////////// diff --git a/2235-add-two-integers.js b/2235-add-two-integers.js new file mode 100644 index 00000000..f90c2657 --- /dev/null +++ b/2235-add-two-integers.js @@ -0,0 +1,8 @@ +/** + * @param {number} num1 + * @param {number} num2 + * @return {number} + */ +var sum = function(num1, num2) { + return num1 + num2 +}; diff --git a/2237-count-positions-on-street-with-required-brightness.js b/2237-count-positions-on-street-with-required-brightness.js new file mode 100644 index 00000000..8ee6b11e --- /dev/null +++ b/2237-count-positions-on-street-with-required-brightness.js @@ -0,0 +1,25 @@ +/** + * @param {number} n + * @param {number[][]} lights + * @param {number[]} requirement + * @return {number} + */ +var meetRequirement = function(n, lights, requirement) { + const arr = Array(n + 1).fill(0) + for(const [pos, ra] of lights) { + const start = Math.max(0, pos - ra) + const end = Math.min(n - 1, pos + ra) + arr[start]++ + arr[end + 1]-- + } + for(let i = 1; i <= n; i++) { + arr[i] += arr[i - 1] + } + + let res = 0 + for(let i = 0; i < n; i++) { + if(arr[i] >= requirement[i]) res++ + } + + return res +}; diff --git a/224-basic-calculator.js b/224-basic-calculator.js new file mode 100644 index 00000000..cf886088 --- /dev/null +++ b/224-basic-calculator.js @@ -0,0 +1,125 @@ +/** + * @param {string} s + * @return {number} + */ +const calculate = function(s) { + let stack = [] + let num = 0 + let sign = 1 + let res = 0 + for (let i = 0; i < s.length; i++) { + let char = s.charAt(i) + if (char >= '0' && char <= '9') { + num = num * 10 + parseInt(char, 10) + } else if (char === '+') { + res += sign * num + sign = 1 + num = 0 + } else if (char === '-') { + res += sign * num + sign = -1 + num = 0 + } else if (char === '(') { + stack.push(res) + stack.push(sign) + sign = 1 + res = 0 + num = 0 + } else if (char === ')') { + res += sign * num + res *= stack.pop() + res += stack.pop() + num = 0 + } + } + return res + sign * num +} + +// another + +/** + * @param {string} s + * @return {number} + */ +const calculate = function(s) { + s = s.split(' ').join('') + const n = s.length, stack = [] + const isNum = ch => ch >= '0' && ch <= '9' + let num = 0, op = 1, res = 0 + for(let i = 0; i < n; i++) { + const ch = s[i] + if(isNum(ch)) { + num = num * 10 + (+ch) + } else { + if(ch === '(') { + stack.push(res) + stack.push(op) + num = 0 + op = 1 + res = 0 + } else if(ch === ')') { + res += num * op + res *= stack.pop() + res += stack.pop() + num = 0 + op = 1 + } else if(ch === '+') { + res += op * num + op = 1 + num = 0 + } else if(ch === '-') { + res += op * num + op = -1 + num = 0 + } + } + } + + return res + op * num +}; + +// another +/** + * @param {string} s + * @return {number} + */ +const calculate = function(s) { + s = s.trim() + + let res = 0, num = 0, op = 1 + const isDigit = ch => ch >= '0' && ch <= '9' + const stk = [] + for(let i = 0, n = s.length; i < n; i++) { + + const e = s[i] + if(e === ' ') continue + if(isDigit(e)) num = num * 10 + (+e) + else { + + if(e === '(') { + stk.push(res) + stk.push(op) + + res = 0 + num = 0 + op = 1 + } else if(e === ')') { + res += num * op + res *= stk.pop() + res += stk.pop() + op = 1 + num = 0 + } else if(e === '-') { + res += num * op + op = -1 + num = 0 + } else if(e === '+') { + res += num * op + op = 1 + num = 0 + } + } + } + + return res + num * op +}; diff --git a/2242-maximum-score-of-a-node-sequence.js b/2242-maximum-score-of-a-node-sequence.js new file mode 100644 index 00000000..983fb9f8 --- /dev/null +++ b/2242-maximum-score-of-a-node-sequence.js @@ -0,0 +1,139 @@ +class Heap { + constructor(data = []) { + this.data = data + this.comparator = (a, b) => a[1] - b[1] + this.heapify() + } + + // O(nlog(n)). In fact, O(n) + heapify() { + if (this.size() < 2) return + for (let i = 1; i < this.size(); i++) { + this.bubbleUp(i) + } + } + + // O(1) + peek() { + if (this.size() === 0) return null + return this.data[0] + } + + // O(log(n)) + offer(value) { + this.data.push(value) + this.bubbleUp(this.size() - 1) + } + + // O(log(n)) + poll() { + if (this.size() === 0) return null + const result = this.data[0] + const last = this.data.pop() + if (this.size() !== 0) { + this.data[0] = last + this.bubbleDown(0) + } + return result + } + + // O(log(n)) + bubbleUp(index) { + while (index > 0) { + const parentIndex = (index - 1) >> 1 + if (this.comparator(this.data[index], this.data[parentIndex]) < 0) { + this.swap(index, parentIndex) + index = parentIndex + } else { + break + } + } + } + + // O(log(n)) + bubbleDown(index) { + const lastIndex = this.size() - 1 + while (true) { + const leftIndex = index * 2 + 1 + const rightIndex = index * 2 + 2 + let findIndex = index + if ( + leftIndex <= lastIndex && + this.comparator(this.data[leftIndex], this.data[findIndex]) < 0 + ) { + findIndex = leftIndex + } + if ( + rightIndex <= lastIndex && + this.comparator(this.data[rightIndex], this.data[findIndex]) < 0 + ) { + findIndex = rightIndex + } + if (index !== findIndex) { + this.swap(index, findIndex) + index = findIndex + } else { + break + } + } + } + + // O(1) + swap(index1, index2) { + ;[this.data[index1], this.data[index2]] = [ + this.data[index2], + this.data[index1], + ] + } + + // O(1) + size() { + return this.data.length + } + + toArray() { + return this.data.reverse().map((dt) => dt.index) + } +} + +/** + * @param {number[]} scores + * @param {number[][]} edges + * @return {number} + */ +const maximumScore = (scores, edges) => { + const n = scores.length + const top3 = new Array(n).fill().map(() => new Heap()) + + for (const [u, v] of edges) { + top3[u].offer([v, scores[v]]) + if (top3[u].size() > 3) top3[u].poll() + top3[v].offer([u, scores[u]]) + if (top3[v].size() > 3) top3[v].poll() + } + + const top3Array = new Array(n) + + for (let i = 0; i < n; i++) { + top3Array[i] = [...top3[i].data] + } + + let ans = -1 + for (let [b, c] of edges) { + if (top3[b].size() < 2 || top3[c].size() < 2) { + continue + } + + const score = scores[b] + scores[c] + + for (let [a, scoreA] of top3Array[b]) { + for (let [d, scoreD] of top3Array[c]) { + if (a !== b && a !== c && d !== b && d !== c && a !== d) { + ans = Math.max(ans, scoreA + score + scoreD) + } + } + } + } + + return ans +} diff --git a/2243-calculate-digit-sum-of-a-string.js b/2243-calculate-digit-sum-of-a-string.js new file mode 100644 index 00000000..f322e42c --- /dev/null +++ b/2243-calculate-digit-sum-of-a-string.js @@ -0,0 +1,26 @@ +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const digitSum = function(s, k) { + let cur = s + while(cur.length > k) { + const arr = [] + for(let i = 0; i < cur.length; i += k) { + let tmp = '' + for(let j = 0; j < k && i + j < cur.length; j++) { + tmp += cur[i + j] + } + arr.push(tmp) + } + arr.forEach((e, i) => { + let res = 0 + for(let ch of e) res += +ch + arr[i] = '' +res + }) + cur = arr.join('') + + } + return cur +}; diff --git a/2244-minimum-rounds-to-complete-all-tasks.js b/2244-minimum-rounds-to-complete-all-tasks.js new file mode 100644 index 00000000..102e1e54 --- /dev/null +++ b/2244-minimum-rounds-to-complete-all-tasks.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} tasks + * @return {number} + */ +const minimumRounds = function(tasks) { + let res = 0 + const hash = {} + for(let e of tasks) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + const keys = Object.keys(hash).map(e => +e) + for(const k of keys) { + if(hash[k] / 3 >= 1) res += ~~(hash[k] / 3) + if(hash[k] % 3 === 2) res++ + if(hash[k] % 3 === 1) { + if(hash[k] >= 4) res++ + else return -1 + } + } + + return res +}; diff --git a/2245-maximum-trailing-zeros-in-a-cornered-path.js b/2245-maximum-trailing-zeros-in-a-cornered-path.js new file mode 100644 index 00000000..b4914d6d --- /dev/null +++ b/2245-maximum-trailing-zeros-in-a-cornered-path.js @@ -0,0 +1,143 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const maxTrailingZeros = function maxTrailingZeros(grid) { + const m = grid.length + const n = grid[0].length + + const factors = (num, k) => { + let sum = 0 + while (!(num % k)) { + num /= k + sum += 1 + } + + return sum + } + + const getRowPrefixSum = (k) => { + const rowPrefixSum = [] + for (let i = 0; i < m; i++) { + rowPrefixSum.push([factors(grid[i][0], k)]) + for (let j = 1; j < n; j++) { + rowPrefixSum[i][j] = factors(grid[i][j], k) + rowPrefixSum[i][j - 1] + } + } + + return rowPrefixSum + } + + const getColPrefixSum = (k) => { + const colPrefixSum = [[factors(grid[0][0], k)]] + for (let i = 1; i < m; i++) { + colPrefixSum.push([factors(grid[i][0], k) + colPrefixSum[i - 1][0]]) + } + + for (let j = 1; j < n; j++) { + colPrefixSum[0][j] = factors(grid[0][j], k) + for (let i = 1; i < m; i++) { + colPrefixSum[i][j] = factors(grid[i][j], k) + colPrefixSum[i - 1][j] + } + } + + return colPrefixSum + } + + const twoRow = getRowPrefixSum(2) + const fiveRow = getRowPrefixSum(5) + const twoCol = getColPrefixSum(2) + const fiveCol = getColPrefixSum(5) + + let max = 0 + + // now check every cell in the whole grid + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + const twoLeft = twoRow[i][j] + const twoRight = twoRow[i][n - 1] - (j && twoRow[i][j - 1]) + const twoUp = i && twoCol[i - 1][j] + const twoDown = twoCol[m - 1][j] - twoCol[i][j] + + const fiveLeft = fiveRow[i][j] + const fiveRight = fiveRow[i][n - 1] - (j && fiveRow[i][j - 1]) + const fiveUp = i && fiveCol[i - 1][j] + const fiveDown = fiveCol[m - 1][j] - fiveCol[i][j] + + const corneredPaths = [ + Math.min(twoLeft + twoUp, fiveLeft + fiveUp), + Math.min(twoLeft + twoDown, fiveLeft + fiveDown), + Math.min(twoRight + twoUp, fiveRight + fiveUp), + Math.min(twoRight + twoDown, fiveRight + fiveDown), + ] + + const trailingZeros = Math.max(...corneredPaths) + + if (trailingZeros > max) { + max = trailingZeros + } + } + } + + return max +} + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const maxTrailingZeros = function(grid) { + const g = grid + const m = g.length; + const n = g[0].length; + const ta = [...Array(m)].map(i => Array(n).fill(1)); + const tb = [...Array(m)].map(i => Array(n).fill(1)); + const tc = [...Array(m)].map(i => Array(n).fill(1)); + const td = [...Array(m)].map(i => Array(n).fill(1)); + + const c52 = (s) => { + let c5 = 0; + let c2 = 0; + while (s % 2 === 0) { + s = s / 2; + c2++; + } + while (s % 5 === 0) { + s = s / 5; + c5++; + } + return [c5, c2]; + } + + const c10 = ([c5, c2]) => { + return Math.min(c5, c2); + } + + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + ta[i][j] = (j === 0) ? c52(g[i][j]) : [c52(g[i][j])[0] + ta[i][j-1][0], c52(g[i][j])[1] + ta[i][j-1][1]]; + tb[i][j] = (i === 0) ? c52(g[i][j]) : [c52(g[i][j])[0] + tb[i-1][j][0], c52(g[i][j])[1] + tb[i-1][j][1]]; + } + } + + for (let i = m-1; i >= 0; i--) { + for (let j = n-1; j >= 0; j--) { + tc[i][j] = (j === n-1) ? c52(g[i][j]) : [c52(g[i][j])[0] + tc[i][j+1][0], c52(g[i][j])[1] + tc[i][j+1][1]]; // : ctz(hg(g[i][j]) * tc[i][j+1][0], tc[i][j+1][1]); // hg(g[i][j]) * tc[i][j+1]; + td[i][j] = (i === m-1) ? c52(g[i][j]) : [c52(g[i][j])[0] + td[i+1][j][0], c52(g[i][j])[1] + td[i+1][j][1]]; // : ctz(hg(g[i][j]) * td[i+1][j][0], td[i+1][j][1]); // hg(g[i][j]) * td[i+1][j]; + } + } + + let ret = 0; + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + let s1 = i === 0 ? c10(ta[i][j]) : c10([ta[i][j][0] + tb[i-1][j][0], ta[i][j][1] + tb[i-1][j][1]]); + let s2 = i === m - 1 ? c10(ta[i][j]) : c10([ta[i][j][0] + td[i+1][j][0], ta[i][j][1] + td[i+1][j][1]]); + let s3 = i === 0 ? c10(tc[i][j]) : c10([tc[i][j][0] + tb[i-1][j][0], tc[i][j][1] + tb[i-1][j][1]]); + let s4 = i === m - 1 ? c10(tc[i][j]) : c10([tc[i][j][0] + td[i+1][j][0], tc[i][j][1] + td[i+1][j][1]]); + ret = Math.max(ret, s1, s2, s3, s4); + } + } + return ret; +}; diff --git a/2246-determine-if-two-events-have-conflict.js b/2246-determine-if-two-events-have-conflict.js new file mode 100644 index 00000000..d139a672 --- /dev/null +++ b/2246-determine-if-two-events-have-conflict.js @@ -0,0 +1,38 @@ +/** + * @param {string[]} event1 + * @param {string[]} event2 + * @return {boolean} + */ +var haveConflict = function(event1, event2) { + const fn = arr => arr.map(e => e.split(':').map(e => +e).reduce((ac,e,i) => i === 0 ? ac + 60 * e : ac + e, 0)) + const arr1 = fn(event1) + const arr2 = fn(event2) + const hash = {} + + if(hash[arr1[0]] == null) hash[arr1[0]] = 0 + hash[arr1[0]]++ + + if(hash[arr1[1] + 1] == null) hash[arr1[1] + 1] = 0 + hash[arr1[1] + 1]-- + + if(hash[arr2[0]] == null) hash[arr2[0]] = 0 + hash[arr2[0]]++ + + if(hash[arr2[1] + 1] == null) hash[arr2[1] + 1] = 0 + hash[arr2[1] + 1]-- + + const keys = Object.keys(hash).map(e => +e) + keys.sort((a, b) => a - b) + + let num = 0 + for(let i = 0; i < keys.length; i++) { + num += hash[keys[i]] + if(num > 1) return true + } + + // const arr = [].concat(arr1, arr2) + // arr.sort((a, b) => a - b) + // if(arr2[1] >= arr1[0] && arr2[0] <= arr1[1]) return true + // if(arr2[1] >= arr1[1] && arr2[0] <= arr1[1]) return true + return false +}; diff --git a/2246-longest-path-with-different-adjacent-characters.js b/2246-longest-path-with-different-adjacent-characters.js new file mode 100644 index 00000000..0b9e53e7 --- /dev/null +++ b/2246-longest-path-with-different-adjacent-characters.js @@ -0,0 +1,69 @@ +/** + * @param {number[]} parent + * @param {string} s + * @return {number} + */ +var longestPath = function(parent, s) { + const n = parent.length + const hash = {} + for(let i = 1; i < n; i++) { + if(hash[parent[i]] == null) hash[parent[i]] = [] + hash[parent[i]].push(i) + } + + let res = 0 + dfs(0) + return res + + function dfs(i) { + let max1 = 0, max2 = 0 + for(const j of (hash[i] || [])) { + const len = dfs(j) + if(s[i] === s[j]) continue + if(len > max1) { + const tmp = max1 + max1 = len + max2 = tmp + } else if(len > max2) { + max2 = len + } + } + res = Math.max(res, max1 + max2 + 1) + return max1 + 1 + } +}; + + +// another + +/** + * @param {number[]} parent + * @param {string} s + * @return {number} + */ +var longestPath = function(parent, s) { + let n = s.length, res = 0; + const {max} = Math + let children = Array.from({ length: n}, () => Array()); + for (let i = 1; i < n; ++i) children[parent[i]].push(i); + dfs(children, s, 0); + return res; + + function dfs(children, s, i) { + let big1 = 0, big2 = 0; + for (let j of (children[i] || [])) { + let cur = dfs(children, s, j); + if (s[i] == s[j]) continue; + if (cur > big2) big2 = cur; + if (big2 > big1) { + let tmp = big1 + big1 = big2 + big2 = tmp + }; + } + res = max(res, big1 + big2 + 1); + return big1 + 1; + } +}; + + diff --git a/2248-intersection-of-multiple-arrays.js b/2248-intersection-of-multiple-arrays.js new file mode 100644 index 00000000..14f26787 --- /dev/null +++ b/2248-intersection-of-multiple-arrays.js @@ -0,0 +1,16 @@ +/** + * @param {number[][]} nums + * @return {number[]} + */ +var intersection = function(nums) { + let set = new Set(nums[0]) + for (let i = 1; i < nums.length; i++) { + const r = nums[i] + const tmp = new Set() + for(let e of r) { + if(set.has(e)) tmp.add(e) + } + set = tmp + } + return Array.from(set).sort((a, b) => a - b) +}; diff --git a/2249-count-lattice-points-inside-a-circle.js b/2249-count-lattice-points-inside-a-circle.js new file mode 100644 index 00000000..273add11 --- /dev/null +++ b/2249-count-lattice-points-inside-a-circle.js @@ -0,0 +1,22 @@ +/** + * @param {number[][]} circles + * @return {number} + */ +var countLatticePoints = function(circles) { + const set = new Set() + for(let arr of circles) helper(arr) + return set.size + + function helper(arr) { + const [cx, cy, r] = arr + let bottomLeftX = cx - r, bottomLeftY = cy - r + let topRightX = cx + r, topRightY = cy + r + for(let i = bottomLeftX; i <= topRightX; i++) { + for(let j = bottomLeftY; j <= topRightY; j++) { + if (Math.sqrt((i - cx) ** 2 + (j - cy) ** 2) <= r) { + set.add(`${i},${j}`) + } + } + } + } +}; diff --git a/2250-count-number-of-rectangles-containing-each-point.js b/2250-count-number-of-rectangles-containing-each-point.js new file mode 100644 index 00000000..b76d92e0 --- /dev/null +++ b/2250-count-number-of-rectangles-containing-each-point.js @@ -0,0 +1,83 @@ +/** + * @param {number[][]} rectangles + * @param {number[][]} points + * @return {number[]} + */ +const countRectangles = function(rectangles, points) { + const rect = rectangles + const matrix = Array.from({ length: 101 }, () => []) + for(const [x, y] of rect) { + matrix[y].push(x) + } + for(const row of matrix) row.sort((a, b) => a - b) + const res = [] + + for(const [x, y] of points) { + + let cnt = 0 + for(let i = y; i <= 100; i++) { + const arr = matrix[i], n = arr.length + let l = 0, r = n + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if(mid === n || arr[mid] >= x) r = mid + else l = mid + 1 + } + cnt += n - l + } + + res.push(cnt) + } + + return res +}; + +// another + +/** + * @param {number[][]} rectangles + * @param {number[][]} points + * @return {number[]} + */ +function countRectangles(rect, points) { + const hash = {} + for(let [y, x] of rect) { + if(hash[x] == null) hash[x] = [] + hash[x].push(y) + } + const keys = Object.keys(hash).map(e => +e) + for(const k of keys) { + hash[k].sort((a, b) => a - b) + } + keys.sort((a, b) => a - b) + const res = [] + const n = keys.length + // console.log(keys, hash) + for(const [y, x] of points) { + let v = 0 + const idx = helper(keys, x) + for(let i = idx; i < n; i++) { + const k = keys[i] + const p = helper(hash[k], y) + v += p === hash[k].length ? 0 : hash[k].length - p + } + res.push(v) + } + + return res + + function helper(arr, val) { + let l = 0, r = arr.length + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if(valid(mid)) r = mid + else l = mid + 1 + } + // console.log(arr, val, l) + return l + + function valid(mid) { + return arr[mid] >= val + } + } +} diff --git a/2251-number-of-flowers-in-full-bloom.js b/2251-number-of-flowers-in-full-bloom.js new file mode 100644 index 00000000..13158e59 --- /dev/null +++ b/2251-number-of-flowers-in-full-bloom.js @@ -0,0 +1,27 @@ +/** + * @param {number[][]} flowers + * @param {number[]} persons + * @return {number[]} + */ +const fullBloomFlowers = function(flowers, persons) { + const arr = [] + for(const [s, e] of flowers) { + arr.push([s, 1]) + arr.push([e, 3]) + } + for(let i = 0; i < persons.length; i++) { + arr.push([persons[i], 2, i]) + } + arr.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) + const res = [] + let cnt = 0 + for(let e of arr) { + if(e[1] === 1) cnt++ + else if(e[1] === 3) cnt-- + else { + res[e[2]] = cnt + } + } + + return res +}; diff --git a/2258-escape-the-spreading-fire.js b/2258-escape-the-spreading-fire.js new file mode 100644 index 00000000..b5520376 --- /dev/null +++ b/2258-escape-the-spreading-fire.js @@ -0,0 +1,103 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const maximumMinutes = function (grid) { + const [m, n] = [grid.length, grid[0].length] + const dir = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ] + + function isValidCell(x, y) { + return x >= 0 && x < m && y >= 0 && y < n + } + + const fireDist = new Array(m) + for (let i = 0; i < m; i++) { + fireDist[i] = new Array(n).fill(Infinity) + } + + const firePoints = [] + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] === 1) { + firePoints.push([i, j]) + fireDist[i][j] = 0 + } + } + } + + while (firePoints.length) { + const [x0, y0] = firePoints.shift() + + for (const [dx, dy] of dir) { + const [x1, y1] = [x0 + dx, y0 + dy] + + if ( + isValidCell(x1, y1) && + grid[x1][y1] === 0 && + fireDist[x0][y0] + 1 < fireDist[x1][y1] + ) { + fireDist[x1][y1] = fireDist[x0][y0] + 1 + firePoints.push([x1, y1]) + } + } + } + + function canEscape(delay) { + const visited = new Array(m) + for (let i = 0; i < m; i++) { + visited[i] = new Array(n).fill(false) + } + + const queue = [[0, 0]] + let currMinutes = delay + + while (queue.length) { + currMinutes++ + + for (let i = queue.length; i > 0; i--) { + const [i0, j0] = queue.shift() + visited[i0][j0] = true + + for (const [di, dj] of dir) { + const [i1, j1] = [i0 + di, j0 + dj] + + if ( + isValidCell(i1, j1) && + grid[i1][j1] === 0 && + !visited[i1][j1] && + (currMinutes < fireDist[i1][j1] || + (currMinutes === fireDist[i1][j1] && + i1 === m - 1 && + j1 === n - 1)) + ) { + if (i1 === m - 1 && j1 === n - 1) { + return true + } + queue.push([i1, j1]) + } + } + } + } + + return false + } + + let [left, right] = [-1, 1_000_000_000] + + while (left < right) { + const middle = Math.floor((left + right + 1) / 2) + + if (canEscape(middle)) { + left = middle + } else { + right = middle - 1 + } + } + + return left +} diff --git a/2259-remove-digit-from-number-to-maximize-result.js b/2259-remove-digit-from-number-to-maximize-result.js new file mode 100644 index 00000000..d7bc3daa --- /dev/null +++ b/2259-remove-digit-from-number-to-maximize-result.js @@ -0,0 +1,19 @@ +/** + * @param {string} number + * @param {character} digit + * @return {string} + */ +const removeDigit = function(number, digit) { + const arr = number.split('') + const idxArr = [] + arr.forEach((e,i) => { + if(e === digit) idxArr.push(i) + }) + const res = [] + for(const i of idxArr) { + const clone = arr.slice() + clone.splice(i, 1) + res.push(clone.join('')) + } + return res.reduce((ac, e) => e > ac ? e : ac, res[0]) +}; diff --git a/226-invert-binary-tree.js b/226-invert-binary-tree.js new file mode 100644 index 00000000..60a57563 --- /dev/null +++ b/226-invert-binary-tree.js @@ -0,0 +1,72 @@ +/** + * 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 {TreeNode} + */ +const invertTree = function (root) { + if (root) { + ;[root.left, root.right] = [invertTree(root.right), invertTree(root.left)] + } + return root +} + +// another + +/** + * 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 {TreeNode} + */ +const invertTree = function (root) { + if (!root) return root + let queue = [root] + while (queue.length) { + let node = queue.shift() + if (node.left) { + queue.push(node.left) + } + if (node.right) { + queue.push(node.right) + } + let left = node.left + node.left = node.right + node.right = left + } + return root +} + +// anoother + +/** + * 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 {TreeNode} + */ +const invertTree = function(root) { + if(root == null) return root + let tmp = root.left + root.left = invertTree(root.right) + root.right = invertTree(tmp) + return root +}; diff --git a/2260-minimum-consecutive-cards-to-pick-up.js b/2260-minimum-consecutive-cards-to-pick-up.js new file mode 100644 index 00000000..bb2bc53e --- /dev/null +++ b/2260-minimum-consecutive-cards-to-pick-up.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} cards + * @return {number} + */ +var minimumCardPickup = function(cards) { + const hash = {}, n = cards.length + for(let i = 0; i < n; i++) { + const cur = cards[i] + if(hash[cur] == null) hash[cur] = [] + hash[cur].push(i) + } + let res = Infinity + + Object.keys(hash).forEach(k => { + const arr = hash[k] + const len = arr.length + for(let i = 1; i < len; i++) { + res = Math.min(res, arr[i] - arr[i - 1] + 1) + } + + }) + + + return res === Infinity ? -1 : res +}; diff --git a/2261-k-divisible-elements-subarrays.js b/2261-k-divisible-elements-subarrays.js new file mode 100644 index 00000000..691bcf2b --- /dev/null +++ b/2261-k-divisible-elements-subarrays.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @param {number} k + * @param {number} p + * @return {number} + */ +const countDistinct = function(nums, k, p) { + const se = new Set() + let n = nums.length + for (let i = 0; i < n; i++) { + let tmp = "" + let cnt = 0 + for (let j = i; j < n; j++) { + if (nums[j] % p == 0) + cnt++ + if (cnt <= k) { + tmp = tmp + (nums[j]) + "-" + se.add(tmp) + } else break + } + } + return se.size +}; diff --git a/2262-total-appeal-of-a-string.js b/2262-total-appeal-of-a-string.js new file mode 100644 index 00000000..96fdec98 --- /dev/null +++ b/2262-total-appeal-of-a-string.js @@ -0,0 +1,41 @@ +/** + * @param {string} s + * @return {number} + */ +const appealSum = function (s) { + const n = s.length, pos = Array(26).fill(-1) + let res = 0 + const a = 'a'.charCodeAt(0) + for(let i = 0; i < n; i++) { + let tmp = n - i, idx = s.charCodeAt(i) - a + if(pos[idx] !== -1) { + tmp += (i - pos[idx] - 1) * (n - i) + } else tmp += i * (n - i) + res += tmp + pos[idx] = i + } + + return res +} + + +// another + +/** + * @param {string} s + * @return {number} + */ +var appealSum = function(s) { + const cnt = Array(26).fill(-1); + let ans = 0; + let n = s.length; + const a = 'a'.charCodeAt(0) + for (let i = 0; i < n; i++) { + let tmp = n - i; + if (cnt[s[i].charCodeAt(0) - a] !== -1) tmp += (i - cnt[s[i].charCodeAt(0) - a] - 1) * (n - i); + else tmp += i * (n - i); + ans += tmp; + cnt[s[i].charCodeAt(0) - a] = i; + } + return ans; +}; diff --git a/2263-make-array-non-decreasing-or-non-increasing.js b/2263-make-array-non-decreasing-or-non-increasing.js new file mode 100644 index 00000000..63b4d19b --- /dev/null +++ b/2263-make-array-non-decreasing-or-non-increasing.js @@ -0,0 +1,93 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var convertArray = function (nums) { + function helper(nums) { + let que = new PriorityQueue((a, b)=>a > b) + let res = 0 + for (let num of nums) { + if (!que.isEmpty() && num < que.peek()) { + res += que.pop() - num + que.push(num) + } + que.push(num) + } + return res + } + + + let nums2 = Array(nums.length).fill(0) + for (let i = 0; i < nums.length; i++) { + nums2[nums.length - 1 - i] = nums[i] + } + return Math.min(helper(nums), helper(nums2)) +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2264-largest-3-same-digit-number-in-string.js b/2264-largest-3-same-digit-number-in-string.js new file mode 100644 index 00000000..62acf554 --- /dev/null +++ b/2264-largest-3-same-digit-number-in-string.js @@ -0,0 +1,20 @@ +/** + * @param {string} num + * @return {string} + */ +var largestGoodInteger = function(num) { + let res = '' + const n = num.length + const isDigit = ch => ch >= '0' && ch <= '9' + for(let i = 1; i < n - 1; i++) { + const ch = num[i] + if(!isDigit(ch)) continue + if(!isDigit(num[i - 1])) continue + if(!isDigit(num[i + 1])) continue + if(num[i - 1] == num[i] && num[i] === num[i + 1]) { + if(ch.repeat(3) > res) res = ch.repeat(3) + } + } + + return res +}; diff --git a/2265-count-nodes-equal-to-average-of-subtree.js b/2265-count-nodes-equal-to-average-of-subtree.js new file mode 100644 index 00000000..6e8ba21f --- /dev/null +++ b/2265-count-nodes-equal-to-average-of-subtree.js @@ -0,0 +1,27 @@ +/** + * 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 {number} + */ +var averageOfSubtree = function(root) { + let res = 0 + dfs(root) + return res + + function dfs(node) { + if(node == null) return [0, 0] + let [lSum, lNum] = dfs(node.left) + let [rSum, rNum] = dfs(node.right) + if(node.val === Math.floor((node.val + lSum + rSum) / (lNum + rNum + 1))) { + res++ + } + return [node.val + lSum + rSum, lNum + rNum + 1] + } +}; diff --git a/2266-count-number-of-texts.js b/2266-count-number-of-texts.js new file mode 100644 index 00000000..09320bf4 --- /dev/null +++ b/2266-count-number-of-texts.js @@ -0,0 +1,33 @@ +/** + * @param {string} pressedKeys + * @return {number} + */ +var countTexts = function(pressedKeys) { + const s = pressedKeys + const mod = 1e9 + 7 + + let n = s.length + let dp = Array(n + 1).fill(0) + dp[0] = 1 + dp[1] = 1 + let counter = Array(10).fill(3) + counter[0] = 0 + counter[1] = 0 + counter[7] = 4 + counter[9] = 4 + for(let i = 2; i <= n; i++) { + let x = +(s[i - 1]) + let j = 0 + while (j < counter[x] && i - 1 >= j && s[i - 1 - j] == s[i - 1]) { + dp[i] += dp[i - 1 - j] + j += 1 + } + + dp[i] %= mod + } + + return dp[n] + +}; + + diff --git a/2267-check-if-there-is-a-valid-parentheses-string-path.js b/2267-check-if-there-is-a-valid-parentheses-string-path.js new file mode 100644 index 00000000..bafe3949 --- /dev/null +++ b/2267-check-if-there-is-a-valid-parentheses-string-path.js @@ -0,0 +1,80 @@ +/** + * @param {character[][]} grid + * @return {boolean} + */ +const hasValidPath = function (grid) { + const m = grid.length + const n = grid[0].length + if (grid[0][0] != '(' || grid[m - 1][n - 1] != ')') return false + const dp = kdArr(-1, [m, n, ~~((m + n) / 2) + 1]) + + + function dfs(i, j, left) { + if (i >= m || j >= n) return false + if (grid[i][j] === '(') left++ + else left-- + if (left < 0 || left > Math.floor((m + n) / 2)) return false + if (dp[i][j][left] != -1) return dp[i][j][left] + if (i == m - 1 && j == n - 1 && left == 0) return (dp[i][j][left] = true) + return (dp[i][j][left] = dfs(i, j + 1, left) || dfs(i + 1, j, left)) + } + return dfs(0, 0, 0) + + function kdArr(defaultVal, arr) { + if(arr.length === 1) return Array(arr[0]).fill(defaultVal) + + const res = [] + for(let i = 0, len = arr[0]; i < len; i++) { + res.push(kdArr(defaultVal, arr.slice(1))) + } + + return res + } +} + + +// another + +/** + * @param {character[][]} grid + * @return {boolean} + */ +var hasValidPath = function(grid) { + if (grid[0][0] == ")") return false + let m = grid.length, n = grid[0].length + const dirs = [[0, 1], [1, 0]] + + if ((m + n - 1) % 2 == 1) return false + const a = Array.from({ length: m }, () => Array(n).fill(null)) + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] === '(') a[i][j] = 1 + else a[i][j] = -1 + } + } + + + const visited = new Set([`0,0,1`]) + let q = [[0, 0, 1]] + + while (q.length){ + const tmp = [] + for (const [x, y, v] of q) { + if (`${x},${y},${v}` == `${m - 1},${n - 1},0`) return true + for (const [dx, dy] of dirs) { + let i= x + dx, j = y + dy + if (0 <= i && i < m && 0 <= j && j < n) { + let v2 = v + a[i][j] + if (v2 >= 0 && !visited.has(`${i},${j},${v2}`) ) { + tmp.push([i, j, v2]) + visited.add(`${i},${j},${v2}`) + } + + } + } + } + q = tmp + } + return false +}; + diff --git a/2268-minimum-number-of-keypresses.js b/2268-minimum-number-of-keypresses.js new file mode 100644 index 00000000..c2db66f7 --- /dev/null +++ b/2268-minimum-number-of-keypresses.js @@ -0,0 +1,23 @@ +/** + * @param {string} s + * @return {number} + */ +var minimumKeypresses = function (s) { + const freq = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for (const e of s) { + freq[e.charCodeAt(0) - a]++ + } + let res = 0 + freq.sort((a, b) => b - a) + + // console.log(freq) + for (let i = 0; i < 26; i++) { + if (freq[i] === 0) break + const step = 1 + Math.floor(i / 9) + const val = step * freq[i] + res += val + } + + return res +} diff --git a/227-basic-calculator-ii.js b/227-basic-calculator-ii.js new file mode 100644 index 00000000..e0f174ae --- /dev/null +++ b/227-basic-calculator-ii.js @@ -0,0 +1,95 @@ +/** + * @param {string} s + * @return {number} + */ +const calculate = function(s) { + const stk = [] + let op = '+', num = 0 + s = s.trim() + const isDigit = ch => ch >= '0' && ch <= '9' + for(let i = 0, n = s.length; i < n; i++) { + const ch = s[i] + if(ch === ' ') continue + if(isDigit(ch)) { + num = (+num) * 10 + (+ch) + } + if(!isDigit(ch) || i === n - 1) { + if(op === '-') stk.push(-num) + else if(op === '+') stk.push(num) + else if(op === '*') stk.push(stk.pop() * num) + else if(op === '/') stk.push(~~(stk.pop() / num)) + + op = ch + num = 0 + } + } + let res = 0 + for(const e of stk) res += e + + return res +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const calculate = function(s) { + const stack = [], n = s.length + let op = '+', num = 0 + for(let i = 0; i < n; i++) { + const isNumber = s[i] >= '0' && s[i] <= '9' + if(isNumber) num = num * 10 + (+s[i]) + if((!isNumber && s[i] !== ' ') || i === n - 1) { + if(op === '+') stack.push(num) + else if(op === '-') stack.push(-num) + else if(op === '*') stack.push(stack.pop() * num) + else if(op === '/') stack.push(~~(stack.pop() / num)) + op = s[i] + num = 0 + } + } + + return stack.reduce((ac, e) => ac + e, 0) +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const calculate = function(s) { + if(s == null || s.length === 0) return 0 + let sum = 0, num = 0, op = '+', tmp = 0 + const stack = [] + for(let i = 0; i < s.length; i++) { + const ch = s[i] + const isInt = ch => ch >= '0' && ch <= '9' + if(isInt(ch)) { + num = num * 10 + (+ch) + } + if((!isInt(ch) && ch !== ' ') || i === s.length - 1) { + if(op === '+') { + sum += tmp + tmp = num + } + else if(op === '-') { + sum += tmp + tmp = - num + } + else if(op === '*') { + tmp *= num + } + else if(op === '/') { + tmp = ~~(tmp / num) + } + op = ch + num = 0 + } + + } + + return sum + tmp +} diff --git a/2270-number-of-ways-to-split-array.js b/2270-number-of-ways-to-split-array.js new file mode 100644 index 00000000..ac92367e --- /dev/null +++ b/2270-number-of-ways-to-split-array.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var waysToSplitArray = function(nums) { + let res = 0, sum = 0 + const n = nums.length + if(n === 0) return res + const pre = Array(n).fill(0) + pre[0] = nums[0] + sum += nums[0] + for(let i = 1; i < n; i++) { + pre[i] = nums[i] + pre[i - 1] + sum += nums[i] + } + for(let i = 0; i < n - 1; i++) { + if(pre[i] >= sum - pre[i]) res++ + } + + return res +}; diff --git a/2271-maximum-white-tiles-covered-by-a-carpet.js b/2271-maximum-white-tiles-covered-by-a-carpet.js new file mode 100644 index 00000000..f19e23d8 --- /dev/null +++ b/2271-maximum-white-tiles-covered-by-a-carpet.js @@ -0,0 +1,60 @@ +/** + * @param {number[][]} tiles + * @param {number} carpetLen + * @return {number} + */ +const maximumWhiteTiles = function (tiles, carpetLen) { + const sorted = tiles.sort((a, b) => a[0] - b[0]) + let res = 0 + + let total = 0 + let right = 0 + + for (let tile of sorted) { + const start = tile[0] + const end = start + carpetLen - 1 + while (right < sorted.length && tiles[right][1] < end) { + total += tiles[right][1] - tiles[right][0] + 1 + right++ + } + if (right === sorted.length || sorted[right][0] > end) { + res = Math.max(res, total) + } else { + res = Math.max(res, total + (end - tiles[right][0] + 1)) + } + total -= tile[1] - tile[0] + 1 + } + + return res +} + +// another + +/** + * @param {number[][]} tiles + * @param {number} carpetLen + * @return {number} + */ +const maximumWhiteTiles = function (tiles, carpetLen) { + tiles.sort((a, b) => a[0] - b[0]) + let res = 0, total = 0, right = 0 + const n = tiles.length + for(let i = 0; i < n; i++) { + const [l, r] = tiles[i] + const end = l + carpetLen - 1 + while(right < n && tiles[right][1] <= end) { + total += tiles[right][1] - tiles[right][0] + 1 + right++ + } + + if(right === n || tiles[right][0] > end) { + res = Math.max(res, total) + } else { + res = Math.max(res, total + end - tiles[right][0] + 1) + } + + total -= r - l + 1 + } + + return res +} diff --git a/2272-substring-with-largest-variance.js b/2272-substring-with-largest-variance.js new file mode 100644 index 00000000..d31fb2bd --- /dev/null +++ b/2272-substring-with-largest-variance.js @@ -0,0 +1,36 @@ +/** + * @param {string} s + * @return {number} + */ +const largestVariance = (s) => { + let se = new Set(s), + n = s.length, + res = 0 + for (const x of se) { + // max + for (const y of se) { + // min + if (x != y) { + let pre = Array(n + 1).fill(0), + preX, + preY, + diff = 0 + for (let i = 0; i < n; i++) { + if (s[i] == x) { + preX = i + 1 + diff++ + } + if (s[i] == y) { + preY = i + 1 + diff-- + } + pre[i + 1] = Math.min(pre[i], diff) + if (preX == undefined || preY == undefined) continue + res = Math.max(res, diff - pre[Math.min(preX, preY) - 1]) + } + } + } + } + return res +} + diff --git a/2273-find-resultant-array-after-removing-anagrams.js b/2273-find-resultant-array-after-removing-anagrams.js new file mode 100644 index 00000000..c9775eff --- /dev/null +++ b/2273-find-resultant-array-after-removing-anagrams.js @@ -0,0 +1,32 @@ +/** + * @param {string[]} words + * @return {string[]} + */ +const removeAnagrams = function(words) { + const res = [] + const n = words.length + + for(let i = 0; i < n;) { + let j = i + 1 + while(j < n && isAna(words[i], words[j])) j++ + res.push(words[i]) + i = j + } + return res + + function isAna(s1, s2) { + const arr = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for(let i = 0; i < s1.length; i++) { + arr[s1.charCodeAt(i) - a]++ + } + for(let i = 0; i < s2.length; i++) { + arr[s2.charCodeAt(i) - a]-- + } + for(const e of arr) { + if(e !== 0) return false + } + return true + } +}; + diff --git a/2274-maximum-consecutive-floors-without-special-floors.js b/2274-maximum-consecutive-floors-without-special-floors.js new file mode 100644 index 00000000..aa9e7b72 --- /dev/null +++ b/2274-maximum-consecutive-floors-without-special-floors.js @@ -0,0 +1,22 @@ +/** + * @param {number} bottom + * @param {number} top + * @param {number[]} special + * @return {number} + */ +var maxConsecutive = function(bottom, top, special) { + special.sort((a, b) => a - b) + let res = 0 + + if(bottom < special[0]) { + res = special[0] - bottom + } + for(let i = 1; i < special.length; i++) { + res = Math.max(res, special[i] - special[i - 1] - 1) + } + if(top > special[special.length - 1]) { + res = Math.max(res, top - special[special.length - 1]) + } + + return res +}; diff --git a/2275-largest-combination-with-bitwise-and-greater-than-zero.js b/2275-largest-combination-with-bitwise-and-greater-than-zero.js new file mode 100644 index 00000000..e08649e4 --- /dev/null +++ b/2275-largest-combination-with-bitwise-and-greater-than-zero.js @@ -0,0 +1,41 @@ +/** + * @param {number[]} candidates + * @return {number} + */ +const largestCombination = function(candidates) { + let res = 0 + for(let i = 0; i < 25; i++) { + let tmp = 0, bit = 1 << i + for(const e of candidates) { + if((e & bit) !== 0) tmp++ + } + res = Math.max(res, tmp) + } + return res +}; + +// another + +/** + * @param {number[]} candidates + * @return {number} + */ +const largestCombination = function(candidates) { + const arr = Array(24).fill(0), len = 24 + for(const e of candidates) { + const str = toBin(e) + for(let n = str.length, i = n - 1; i >= 0; i--) { + const cur = str[i] + if(cur === '1') { + arr[len - 1 - (n - 1 - i)]++ + } + } + } + + return Math.max(...arr) + + function toBin(num) { + return (num >>> 0).toString(2) + } +}; + diff --git a/2276-count-integers-in-intervals.js b/2276-count-integers-in-intervals.js new file mode 100644 index 00000000..2647fd6b --- /dev/null +++ b/2276-count-integers-in-intervals.js @@ -0,0 +1,200 @@ +var CountIntervals = function() { + this.intervals = [] + this.ans = 0 +}; + +/** + * @param {number} left + * @param {number} right + * @return {void} + */ +CountIntervals.prototype.add = function(left, right) { + let l = 0, r = this.intervals.length + while (l < r) { + const m = Math.floor((l + r) / 2) + if (this.intervals[m][1] >= left) { + r = m + } else { + l = m + 1 + } + } + + let index = l + while (index < this.intervals.length && this.intervals[index][0] <= right) { + left = Math.min(left, this.intervals[index][0]) + right = Math.max(right, this.intervals[index][1]) + this.ans -= this.intervals[index][1] - this.intervals[index][0] + 1 + index += 1 + } + this.ans += right - left + 1 + this.intervals.splice(l, index - l, [left, right]) +}; + + +/** + * @return {number} + */ +CountIntervals.prototype.count = function() { + return this.ans +}; + +// another + +function binarySearch(l, r, fn) { + while (l <= r) { + const m = Math.floor((l + r) / 2) + if (fn(m)) { + l = m + 1 + } else { + r = m - 1 + } + } + return r +} + +var CountIntervals = function () { + this.intervals = [] + this.size = 0 +} + +/** + * @param {number} left + * @param {number} right + * @return {void} + */ +CountIntervals.prototype.add = function (left, right) { + const intervals = this.intervals + if (!intervals.length) { + intervals.push({ left, right }) + this.size += right - left + 1 + } else if (left > intervals[intervals.length - 1].right) { + intervals.push({ left, right }) + this.size += right - left + 1 + } else if (right < intervals[0].left) { + intervals.unshift({ left, right }) + this.size += right - left + 1 + } else { + const i = binarySearch(0, intervals.length - 1, (x) => { + return intervals[x].left < left + }) + let j, + start, + end, + sum = 0 + if (i < 0 || intervals[i].right < left) { + j = i + 1 + start = left + end = right + } else { + j = i + start = intervals[j].left + end = right + } + let first = -1 + while (j < intervals.length && right >= intervals[j].left) { + if (first < 0) first = j + end = Math.max(end, intervals[j].right) + sum += intervals[j].right - intervals[j].left + 1 + j++ + } + // delete [first, j) + // console.log('delete', j - first, '-', first, j) + this.size += end - start + 1 - sum + if (first < 0) { + this.intervals.splice(i + 1, 0, { left: start, right: end }) + } else { + this.intervals.splice(first, j - first, { left: start, right: end }) + } + } +} + +/** + * @return {number} + */ +CountIntervals.prototype.count = function () { + return this.size +} + + +// another + + + +var CountIntervals = function () { + this.root = new Node(1, 10 ** 9) +} + +/** + * @param {number} left + * @param {number} right + * @return {void} + */ +CountIntervals.prototype.add = function (left, right) { + this.root.addInterval(left, right) +} + +/** + * @return {number} + */ +CountIntervals.prototype.count = function () { + return this.root.total +} + +/** + * Your CountIntervals object will be instantiated and called as such: + * var obj = new CountIntervals() + * obj.add(left,right) + * var param_2 = obj.count() + */ + +class Node { + constructor(min, max) { + this.min = min + this.max = max + this.currentMin = -1 + this.currentMax = -1 + this.total = 0 + this.left = null + this.right = null + } + + addInterval(left, right) { + if (this.currentMin < 0) { + this.currentMin = left + this.currentMax = right + this.total = right - left + 1 + return this.total + } + + const mid = (this.min + this.max) >> 1 + + if (this.left) { + if (left <= mid) this.left.addInterval(left, Math.min(mid, right)) + if (right > mid) this.right.addInterval(Math.max(mid + 1, left), right) + + this.total = this.left.total + this.right.total + return + } + + if (left <= this.currentMax + 1 && right >= this.currentMin - 1) { + this.currentMin = Math.min(this.currentMin, left) + this.currentMax = Math.max(this.currentMax, right) + this.total = this.currentMax - this.currentMin + 1 + return + } + this.left = new Node(this.min, mid) + this.right = new Node(mid + 1, this.max) + + if (left <= mid) this.left.addInterval(left, Math.min(mid, right)) + if (right > mid) this.right.addInterval(Math.max(left, mid + 1), right) + if (this.currentMin <= mid) + this.left.addInterval(this.currentMin, Math.min(mid, this.currentMax)) + if (this.currentMax > mid) + this.right.addInterval( + Math.max(mid + 1, this.currentMin), + this.currentMax + ) + + this.total = this.left.total + this.right.total + } +} diff --git a/2277-closest-node-to-path-in-tree.js b/2277-closest-node-to-path-in-tree.js new file mode 100644 index 00000000..b8ef00ef --- /dev/null +++ b/2277-closest-node-to-path-in-tree.js @@ -0,0 +1,99 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[][]} query + * @return {number[]} + */ +const closestNode = function(n, edges, query) { + const g = new Map() + for(const [p, q] of edges) { + if(!g.has(p)) g.set(p, new Set()) + if(!g.has(q)) g.set(q, new Set()) + g.get(p).add(q) + g.get(q).add(p) + } + const dist = Array.from({ length: n }, () => Array(n).fill(null)) + for(let i = 0; i < n; i++) dfs(i, i, 0) + const res = [] + // console.log(dist) + for(const [s, e, t] of query) { + let tmp = Infinity, cur = s, el + while(true) { + if(dist[cur][t] < tmp) { + tmp = dist[cur][t] + el = cur + } + if(cur === e) break + for(const nxt of (g.get(cur) || [])) { + if(dist[cur][e] === dist[nxt][e] + 1) { + cur = nxt + break + } + } + } + res.push(el) + } + + return res + + function dfs(root, node, d) { + dist[root][node] = d + for(const nxt of (g.get(node) || [])) { + if(nxt !== root && dist[root][nxt] == null) { + dfs(root, nxt, d + 1) + } + } + } +}; + +// another + + +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[][]} query + * @return {number[]} + */ +const closestNode = function (n, edges, query) { + const graph = {} + for (const [a, b] of edges) { + if (graph[a] == null) graph[a] = [] + if (graph[b] == null) graph[b] = [] + graph[a].push(b) + graph[b].push(a) + } + + const dis = Array.from({ length: n }, () => Array(n).fill(Infinity)) + for (let i = 0; i < n; i++) { + let que = [i] + dis[i][i] = 0 + while (que.length) { + const tmp = [] + for (const q of que) { + for (const nxt of graph[q] || []) { + if (dis[i][nxt] === Infinity) { + dis[i][nxt] = dis[i][q] + 1 + tmp.push(nxt) + } + } + } + que = tmp + } + } + + const arr = [] + + for (const [a, b, q] of query) { + let tmp = Infinity, res = -1 + for (let idx = 0; idx < n; idx++) { + const d= dis[idx][a] + dis[idx][b] + dis[idx][q] + if(d < tmp) { + tmp = d + res = idx + } + } + arr.push(res) + } + return arr +} diff --git a/228-summary-ranges.js b/228-summary-ranges.js new file mode 100644 index 00000000..eb708bde --- /dev/null +++ b/228-summary-ranges.js @@ -0,0 +1,57 @@ +/** + * @param {number[]} nums + * @return {string[]} + */ +const summaryRanges = function(nums) { + if (nums == null || nums.length === 0) return [] + const res = [] + if (nums.length === 1) return [`${nums[0]}`] + let start = nums[0] + let end = nums[0] + let endVal = end + for (let i = 1, len = nums.length; i < len; i++) { + let cur = nums[i] + if (cur - end > 1) { + endVal = end + insert(res, start, end) + start = cur + end = cur + } else { + end = cur + } + } + if (endVal !== end) { + insert(res, start, end) + } + return res +} + +function insert(arr, start, end) { + if (start === end) { + arr.push(`${start}`) + } else { + arr.push(`${start}->${end}`) + } +} + +// another + +const summaryRanges = nums => { + if (!nums || nums.length === 0) { + return []; + } + const returnArray = []; + let tempIdx = 0; + for (let i = 0; i < nums.length; i++) { + if (nums[i] + 1 !== nums[i + 1]) { + if (tempIdx === i) { + returnArray.push(nums[tempIdx].toString()); + } else { + returnArray.push(nums[tempIdx].toString() + "->" + nums[i].toString()); + } + tempIdx = i + 1; + } + } + + return returnArray; +}; diff --git a/2280-minimum-lines-to-represent-a-line-chart.js b/2280-minimum-lines-to-represent-a-line-chart.js new file mode 100644 index 00000000..a8d50bf9 --- /dev/null +++ b/2280-minimum-lines-to-represent-a-line-chart.js @@ -0,0 +1,59 @@ +/** + * @param {number[][]} stockPrices + * @return {number} + */ +const minimumLines = function(stockPrices) { + let res = 1 + const n = stockPrices.length + if(n === 1) return 0 + stockPrices.sort((a, b) => a[0] - b[0]) + for(let i = 2; i < n; i++) { + const cur = stockPrices[i], p = stockPrices[i - 1], pp = stockPrices[i - 2] + if(chk(pp, p, cur)) continue + else res++ + } + + + return res +}; + +function chk(p1, p2, p3) { + const bi = BigInt + // (y3 - y1) / (x3 - x1) == (y2 - y1) / (x2 - x1) + const [x1, y1] = p1, [x2, y2] = p2, [x3, y3] = p3 + return (bi(y3) - bi(y1)) * (bi(x2) - bi(x1)) === (bi(y2) - bi(y1)) * (bi(x3) - bi(x1)) +} + + + +// another + +/** + * @param {number[][]} stockPrices + * @return {number} + */ +var minimumLines = function(stockPrices) { + let res = 1 + const ma = stockPrices + const n = ma.length + if(n === 0 || n === 1) return 0 + ma.sort((a, b) => a[0] - b[0]) + const eps = 1e-30 + let dx = ma[1][0] - ma[0][0], dy = ma[1][1] - ma[0][1] + for(let i = 2; i < n; i++) { + const cur = ma[i], pre = ma[i - 1] + const dxx = cur[0] - pre[0], dyy = cur[1] - pre[1] + if(BigInt(dxx) * BigInt(dy) !== BigInt(dx) * BigInt(dyy)) res++ + dx = dxx + dy = dyy + } + + return res +}; + +function product(p1, p2, p3) { + // 首先根据坐标计算p1p2和p1p3的向量,然后再计算叉乘 + // p1p2 向量表示为 (p2.x-p1.x,p2.y-p1.y) + // p1p3 向量表示为 (p3.x-p1.x,p3.y-p1.y) + return (p2.x-p1.x)*(p3.y-p1.y) - (p2.y-p1.y)*(p3.x-p1.x); +} diff --git a/2281-sum-of-total-strength-of-wizards.js b/2281-sum-of-total-strength-of-wizards.js new file mode 100644 index 00000000..5c6e9e1f --- /dev/null +++ b/2281-sum-of-total-strength-of-wizards.js @@ -0,0 +1,53 @@ +/** + * @param {number[]} strength + * @return {number} + */ +const totalStrength = function (strength) { + const mod = BigInt(1e9 + 7) + let res = 0n + const n = strength.length + strength = strength.map(e => BigInt(e)) + const leftsum = Array(n + 1).fill(0n), + rightsum = Array(n + 1).fill(0n), + leftmul = Array(n + 1).fill(0n), + rightmul = Array(n + 1).fill(0n) + const asc = [] + const big = BigInt + + for (let i = 0; i < n; i++) { + leftsum[i + 1] = (leftsum[i] + strength[i]) % mod + leftmul[i + 1] = (leftmul[i] + big(i + 1) * strength[i]) % mod + } + + for (let i = n - 1; i >= 0; i--) { + rightsum[i] = (rightsum[i + 1] + strength[i]) % mod + rightmul[i] = (rightmul[i + 1] + big(n - i) * strength[i]) % mod + } + + // j is the exclusive right index + for (let j = 0; j <= n; j++) { + while ( + asc.length && + (j === n || strength[asc[asc.length - 1]] >= strength[j]) + ) { + const k = asc.pop() + const i = asc.length === 0 ? 0 : asc[asc.length - 1] + 1 + const left = + (mod + + leftmul[k + 1] - + leftmul[i] - + ((big(i) * (leftsum[k + 1] - leftsum[i])) % mod)) % + mod + const right = + (mod + + rightmul[k + 1] - + rightmul[j] - + ((big(n - j) * (rightsum[k + 1] - rightsum[j])) % mod)) % + mod + const sum = (left * big(j - k) + right * big(k - i + 1)) % mod + res = (res + sum * strength[k]) % mod + } + asc.push(j) + } + return res +} diff --git a/2282-number-of-people-that-can-be-seen-in-a-grid.js b/2282-number-of-people-that-can-be-seen-in-a-grid.js new file mode 100644 index 00000000..90c1fb32 --- /dev/null +++ b/2282-number-of-people-that-can-be-seen-in-a-grid.js @@ -0,0 +1,40 @@ +/** + * @param {number[][]} heights + * @return {number[][]} + */ +const seePeople = function(heights) { + const m = heights.length, n = heights[0].length + const res = Array.from({ length: m }, () => Array(n).fill(0)) + + for(let i = 0; i < m; i++) { + const stk = [] + for(let j = n - 1; j >= 0; j--) { + let del = 0 + + while(stk.length && heights[i][j] > heights[i][stk[stk.length - 1]]) { + del++ + stk.pop() + } + res[i][j] = del + (stk.length ? 1 : 0) + if(stk.length && heights[i][j] === heights[i][stk[stk.length - 1]]) continue + stk.push(j) + } + } + + for(let j = 0; j < n; j++) { + const stk = [] + for(let i = m - 1; i >= 0; i--) { + let del = 0 + + while(stk.length && heights[i][j] > heights[stk[stk.length - 1]][j]) { + del++ + stk.pop() + } + res[i][j] += del + (stk.length ? 1 : 0) + if(stk.length && heights[i][j] === heights[stk[stk.length - 1]][j]) continue + stk.push(i) + } + } + + return res +}; diff --git a/2286-booking-concert-tickets-in-groups.js b/2286-booking-concert-tickets-in-groups.js new file mode 100644 index 00000000..231a0e73 --- /dev/null +++ b/2286-booking-concert-tickets-in-groups.js @@ -0,0 +1,123 @@ +/** + * @param {number} n + * @param {number} m + */ +function BookMyShow(n, m) { + let a = Array(n).fill(0), st = new SegmentTreeRMQ(a), fen = new Fenwick(n + 3); + for (let i = 0; i < n; i++) fen.update(i, m); + return { gather, scatter } + function gather(k, maxRow) { + let idx = st.indexOf(0, m - k); + if (idx == -1 || idx > maxRow) return []; + let min = st.minx(idx, idx + 1); + st.update(idx, min + k); + fen.update(idx, -k); + return [idx, min]; + } + function scatter(k, maxRow) { + let totToMaxRow = fen.query(maxRow); + if (totToMaxRow < k) return false; + while (k > 0) { + let idx = st.indexOf(0, m - 1); + if (idx == -1 || idx > maxRow) break; + let min = st.minx(idx, idx + 1); + let use = Math.min(k, m - min); + k -= use; + st.update(idx, min + use); + fen.update(idx, -use); + } + return true; + } +} + +/** + * Your BookMyShow object will be instantiated and called as such: + * var obj = new BookMyShow(n, m) + * var param_1 = obj.gather(k,maxRow) + * var param_2 = obj.scatter(k,maxRow) + */ +////////////////////////////////////////////////// Template //////////////////////////////////////////////////////////////////// +function Fenwick(n) { + let a = Array(n).fill(0); + return { query, update, rangeSum, tree } + function query(i) { // [0, i] prefix sum + let sum = 0; + for (i++; i > 0; i = parent(i)) sum += a[i]; + return sum; + } + function update(i, v) { + for (i++; i < n; i = next(i)) a[i] += v; + } + function rangeSum(l, r) { + return query(r) - query(l - 1); + } + function parent(x) { + return x - lowestOneBit(x); + } + function next(x) { + return x + lowestOneBit(x); + } + function lowestOneBit(x) { + return x & -x; + } + function tree() { + return a; + } +} + +function SegmentTreeRMQ(A) { + let n = A.length, h = Math.ceil(Math.log2(n)), len = 2 * 2 ** h, a = Array(len).fill(Number.MAX_SAFE_INTEGER); + h = 2 ** h; + initializeFromArray(); + return { update, minx, indexOf, tree } + function initializeFromArray() { + for (let i = 0; i < n; i++) a[h + i] = A[i]; + for (let i = h - 1; i >= 1; i--) propagate(i); + } + function update(pos, v) { + a[h + pos] = v; + for (let i = parent(h + pos); i >= 1; i = parent(i)) propagate(i); + } + function propagate(i) { + a[i] = Math.min(a[left(i)], a[right(i)]); + } + function minx(l, r) { + let min = Number.MAX_SAFE_INTEGER; + if (l >= r) return min; + l += h; + r += h; + for (; l < r; l = parent(l), r = parent(r)) { + if (l & 1) min = Math.min(min, a[l++]); + if (r & 1) min = Math.min(min, a[--r]); + } + return min; + } + function indexOf(l, v) { + if (l >= h) return -1; + let cur = h + l; + while (1) { + if (a[cur] <= v) { + if (cur >= h) return cur - h; + cur = left(cur); + } else { + cur++; + if ((cur & cur - 1) == 0) return -1; + if (cur % 2 == 0) cur = parent(cur); + } + } + } + function parent(i) { + return i >> 1; + } + function left(i) { + return 2 * i; + } + function right(i) { + return 2 * i + 1; + } + function tree() { + return a; + } +} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/2287-rearrange-characters-to-make-target-string.js b/2287-rearrange-characters-to-make-target-string.js new file mode 100644 index 00000000..d7eb46f9 --- /dev/null +++ b/2287-rearrange-characters-to-make-target-string.js @@ -0,0 +1,26 @@ +/** + * @param {string} s + * @param {string} target + * @return {number} + */ +var rearrangeCharacters = function(s, target) { + const a = 'a'.charCodeAt(0), arr = Array(26).fill(0) + for(let ch of target) { + arr[ch.charCodeAt(0) - a]++ + } + let min = Math.min(...arr.filter(e => e > 0)) + const sa = Array(26).fill(0) + for(const e of s) { + sa[e.charCodeAt(0) - a]++ + } + let res = -1 + for(let i = 0; i < 26; i++) { + const sv = sa[i], tv = arr[i] + if(tv === 0) continue + const v = ~~(sv / tv) + if(res === -1) res = v + else res = Math.min(res, v) + } + + return res +}; diff --git a/2288-apply-discount-to-prices.js b/2288-apply-discount-to-prices.js new file mode 100644 index 00000000..c353d5c3 --- /dev/null +++ b/2288-apply-discount-to-prices.js @@ -0,0 +1,16 @@ +/** + * @param {string} sentence + * @param {number} discount + * @return {string} + */ +var discountPrices = function(sentence, discount) { + const arr = sentence.split(' '), n = arr.length + for(let i = 0; i < n; i++) { + const cur = arr[i] + const rest = cur.slice(1) + if(cur.startsWith('$') && rest.length && !Number.isNaN(+rest)) { + arr[i] = '$' + ((+rest) * (100 - discount) / 100).toFixed(2) + } + } + return arr.join(' ') +}; diff --git a/2289-steps-to-make-array-non-decreasing.js b/2289-steps-to-make-array-non-decreasing.js new file mode 100644 index 00000000..1fdfc322 --- /dev/null +++ b/2289-steps-to-make-array-non-decreasing.js @@ -0,0 +1,68 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var totalSteps = function(nums) { + const n = nums.length + let res = 0, j = -1; + const dp = Array(n).fill(0), stack = Array(n).fill(0); + for (let i = n - 1; i >= 0; --i) { + while (j >= 0 && nums[i] > nums[stack[j]]) { + dp[i] = Math.max(++dp[i], dp[stack[j--]]) + res = Math.max(res, dp[i]) + } + stack[++j] = i + } + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const totalSteps = function(nums) { + let res = 0, stk = [] + stk.push([nums[0], 0]) + for(let i = 1, n = nums.length; i < n; i++) { + let steps = 0 + while(stk.length && stk[stk.length - 1][0] <= nums[i]) { + const peek = stk.pop() + steps = Math.max(steps, peek[1]) + } + if(stk.length === 0) steps = 0 + else steps++ + + res = Math.max(res, steps) + stk.push([nums[i], steps]) + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const totalSteps = function(nums) { + let res = 0 + const stk = [] + for(const e of nums) { + let steps = 1 + while(stk.length && e >= stk[stk.length - 1][0]) { + const tmp = stk.pop() + steps = Math.max(tmp[1] + 1, steps) + } + if(stk.length === 0) steps = 0 + else { + res = Math.max(res, steps) + } + stk.push([e, steps]) + } + return res +}; + + diff --git a/229-majority-element-ii.js b/229-majority-element-ii.js index 96d6c824..2f1b5be7 100644 --- a/229-majority-element-ii.js +++ b/229-majority-element-ii.js @@ -1,3 +1,42 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const majorityElement = function(nums) { + let candidate1 = 0, candidate2 = 0, cnt1 = 0, cnt2 = 0 + for(const e of nums) { + if(e === candidate1) { + cnt1++ + } else if(e === candidate2) { + cnt2++ + } else if(cnt1 === 0) { + candidate1 = e + cnt1++ + } else if(cnt2 === 0) { + candidate2 = e + cnt2++ + } else { + cnt1-- + cnt2-- + } + } + + const n = nums.length + let c1 = 0, c2 = 0 + for(const e of nums) { + if(e === candidate1) c1++ + if(e === candidate2) c2++ + } + const k = Math.floor(n / 3) + const res = [] + if(c1 > k) res.push(candidate1) + if(c2 > k) res.push(candidate2) + if(res[0] === res[1]) res.pop() + return res +}; + +// another + /** * @param {number[]} nums * @return {number[]} diff --git a/2290-minimum-obstacle-removal-to-reach-corner.js b/2290-minimum-obstacle-removal-to-reach-corner.js new file mode 100644 index 00000000..84e799ff --- /dev/null +++ b/2290-minimum-obstacle-removal-to-reach-corner.js @@ -0,0 +1,23 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var minimumObstacles = function(grid) { + const m = grid.length, n = grid[0].length + const dist = Array.from({ length: m }, () => Array(n).fill(Infinity)) + const pq = new MinPriorityQueue({ priority: (x) => x[0] }) + const dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]] + dist[0][0] = 0 + pq.enqueue([dist[0][0], 0, 0]) + while(pq.size()) { + const [v, i, j] = pq.dequeue().element + if(i === m - 1 && j === n - 1) return v + for(const [dx, dy] of dirs) { + const nx = i + dx, ny = j + dy + if(nx >= 0 && nx < m && ny >= 0 && ny < n && v + grid[nx][ny] < dist[nx][ny]) { + dist[nx][ny] = v + grid[nx][ny] + pq.enqueue([dist[nx][ny], nx, ny]) + } + } + } +}; diff --git a/2291-maximum-profit-from-trading-stocks.js b/2291-maximum-profit-from-trading-stocks.js new file mode 100644 index 00000000..27aba95e --- /dev/null +++ b/2291-maximum-profit-from-trading-stocks.js @@ -0,0 +1,43 @@ +/** + * @param {number[]} present + * @param {number[]} future + * @param {number} budget + * @return {number} + */ +const maximumProfit = function(present, future, budget) { + const dp = new Array(budget + 1).fill(0); + for (let i = 0; i < present.length; i++){ + for (let j = budget; j >= 0; j--){ + if (j >= present[i] && present[i] < future[i]){ + dp[j] = Math.max(dp[j], dp[j - present[i]] + future[i] - present[i]); + } + } + } + return dp[budget]; +}; + +// another + +/** + * @param {number[]} present + * @param {number[]} future + * @param {number} budget + * @return {number} + */ +const maximumProfit = function(present, future, budget) { + const n = present.length + const dp = Array.from({ length: n + 1 }, () => Array(budget + 1).fill(0)) + + for(let b = 0; b <= budget; b++) { + for(let i = 1; i <= n; i++) { + const cost = present[i - 1] + const diff = future[i - 1] - cost + dp[i][b] = dp[i - 1][b] + if(b >= cost) { + dp[i][b] = Math.max(dp[i][b], dp[i - 1][b - cost] + diff) + } + } + } + + return dp[n][budget] + }; diff --git a/2293-min-max-game.js b/2293-min-max-game.js new file mode 100644 index 00000000..ba574743 --- /dev/null +++ b/2293-min-max-game.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minMaxGame = function(nums) { + let cur = nums + while(cur.length > 1) { + const n = cur.length + const tmp = Array(n / 2) + for(let i = 0; i < n / 2; i++) { + const odd = i % 2 === 1 + if(odd) { + tmp[i] = Math.max(cur[2 * i], cur[2 * i + 1]) + } else { + tmp[i] = Math.min(cur[2 * i], cur[2 * i + 1]) + } + } + cur = tmp + } + + return cur[0] +}; diff --git a/2294-partition-array-such-that-maximum-difference-is-k.js b/2294-partition-array-such-that-maximum-difference-is-k.js new file mode 100644 index 00000000..86db6794 --- /dev/null +++ b/2294-partition-array-such-that-maximum-difference-is-k.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var partitionArray = function(nums, k) { + nums.sort((a, b) => a - b) + let res = 1, pre = nums[0], n = nums.length + for(let i = 1; i < n; i++) { + const cur = nums[i] + if(cur - pre > k) { + res++ + pre = cur + } + } + + return res +}; diff --git a/2295-replace-elements-in-an-array.js b/2295-replace-elements-in-an-array.js new file mode 100644 index 00000000..97a9fd71 --- /dev/null +++ b/2295-replace-elements-in-an-array.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @param {number[][]} operations + * @return {number[]} + */ +var arrayChange = function(nums, operations) { + const map = new Map(), n = nums.length + const res = Array(n) + for(let i = 0; i < n; i++) { + const cur = nums[i] + map.set(cur, i) + res[i] = cur + } + + for(const [v, vv] of operations) { + const idx = map.get(v) + res[idx] = vv + map.set(vv, idx) + } + + return res +}; diff --git a/2296-design-a-text-editor.js b/2296-design-a-text-editor.js new file mode 100644 index 00000000..1e953e41 --- /dev/null +++ b/2296-design-a-text-editor.js @@ -0,0 +1,146 @@ +const TextEditor = function () { + this.stk1 = [] + this.stk2 = [] +} + +/** + * @param {string} text + * @return {void} + */ +TextEditor.prototype.addText = function (text) { + for (const ch of text) this.stk1.push(ch) +} + +/** + * @param {number} k + * @return {number} + */ +TextEditor.prototype.deleteText = function (k) { + let res = 0 + while (this.stk1.length && k) { + k-- + res++ + this.stk1.pop() + } + return res +} + +/** + * @param {number} k + * @return {string} + */ +TextEditor.prototype.cursorLeft = function (k) { + let res = '' + while (this.stk1.length && k) { + const tmp = this.stk1.pop() + this.stk2.push(tmp) + k-- + } + + return this.slice() +} + +/** + * @param {number} k + * @return {string} + */ +TextEditor.prototype.cursorRight = function (k) { + let res = '' + + while (this.stk2.length && k) { + const tmp = this.stk2.pop() + this.stk1.push(tmp) + k-- + } + + return this.slice() +} + +TextEditor.prototype.slice = function() { + let res = '' + for ( + let len = this.stk1.length, size = Math.min(10, this.stk1.length), i = 0; + i < size; + i++ + ) { + res = this.stk1[len - i - 1] + res + } + return res +} + +// another + + +class Node { + constructor(val) { + this.val = val + this.prev = null + this.next = null + } +} + +var TextEditor = function() { + this.left = [] + this.right = [] + this.idx = 0 +}; + +/** + * @param {string} text + * @return {void} + */ +TextEditor.prototype.addText = function(text) { + for(const ch of text) this.left.push(ch) +}; + +/** + * @param {number} k + * @return {number} + */ +TextEditor.prototype.deleteText = function(k) { + let res = 0 + while(this.left.length && k) { + res++ + this.left.pop() + k-- + } + return res +}; + +/** + * @param {number} k + * @return {string} + */ +TextEditor.prototype.cursorLeft = function(k) { + while(k && this.left.length) { + const tmp = this.left.pop() + this.right.push(tmp) + k-- + } + + return this.left.slice(Math.max(0, this.left.length - 10), this.left.length).join('') +}; + +/** + * @param {number} k + * @return {string} + */ +TextEditor.prototype.cursorRight = function(k) { + while(k && this.right.length) { + const tmp = this.right.pop() + this.left.push(tmp) + k-- + } + + return this.left.slice(Math.max(0, this.left.length - 10), this.left.length).join('') +}; + + +/** + * Your TextEditor object will be instantiated and called as such: + * var obj = new TextEditor() + * obj.addText(text) + * var param_2 = obj.deleteText(k) + * var param_3 = obj.cursorLeft(k) + * var param_4 = obj.cursorRight(k) + */ diff --git a/2298-tasks-count-in-the-weekend.sql b/2298-tasks-count-in-the-weekend.sql new file mode 100644 index 00000000..9ad50b93 --- /dev/null +++ b/2298-tasks-count-in-the-weekend.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +# Write your MySQL query statement below +SELECT SUM(WEEKDAY(submit_date)>=5) AS weekend_cnt, +SUM(WEEKDAY(submit_date)<5) AS working_cnt +FROM Tasks; diff --git a/23-merge-k-sorted-lists.js b/23-merge-k-sorted-lists.js index 982922fa..1804d044 100644 --- a/23-merge-k-sorted-lists.js +++ b/23-merge-k-sorted-lists.js @@ -33,3 +33,147 @@ function merge(lists, l, r) { head.next = left ? left : right return dummy.next } + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode[]} lists + * @return {ListNode} + */ +const mergeKLists = function(lists) { + if(lists == null || lists.length === 0) return null + if(lists.length === 1) return lists[0] + if(lists.length === 2) return mergeTwo(lists[0], lists[1]) + const left = mergeKLists(lists.slice(0, ~~(lists.length / 2))) + const right = mergeKLists(lists.slice(~~(lists.length / 2))) + + return mergeTwo(left, right) +}; + +function mergeTwo(l1, l2) { + const dummy = new ListNode() + let cur = dummy + while(l1 && l2) { + if(l1.val < l2.val) { + cur.next = l1 + l1 = l1.next + } else { + cur.next = l2 + l2 = l2.next + } + cur = cur.next + } + if(l1) cur.next = l1 + if(l2) cur.next = l2 + + + return dummy.next +} + + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode[]} lists + * @return {ListNode} + */ +const mergeKLists = function(lists) { + if(lists == null || lists.length === 0) return null + const dummy = new ListNode() + let head = dummy + const pq = new PriorityQueue((a, b) => a.val < b.val) + for(let list of lists) { + while(list) { + pq.push(list) + list = list.next + } + } + while(!pq.isEmpty()) { + const pop = pq.pop() + head.next = new ListNode(pop.val) + head = head.next + } + return dummy.next +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/230-kth-smallest-element-in-a-bst.js b/230-kth-smallest-element-in-a-bst.js new file mode 100644 index 00000000..2876bc07 --- /dev/null +++ b/230-kth-smallest-element-in-a-bst.js @@ -0,0 +1,31 @@ +/** + * 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 + * @param {number} k + * @return {number} + */ +const kthSmallest = function (root, k) { + const st = [] + while (root !== null) { + st.push(root) + root = root.left + } + while (k !== 0) { + const n = st.pop() + k-- + if (k === 0) return n.val + let right = n.right + while (right !== null) { + st.push(right) + right = right.left + } + } + return -1 +} diff --git a/2301-match-substring-after-replacement.js b/2301-match-substring-after-replacement.js new file mode 100644 index 00000000..1e507b5e --- /dev/null +++ b/2301-match-substring-after-replacement.js @@ -0,0 +1,80 @@ +/** + * @param {string} ch + */ +function encode(ch) { + let c = ch.charCodeAt(0) + const a = 'a'.charCodeAt(0) + const A = 'A'.charCodeAt(0) + const zero = '0'.charCodeAt(0) + if (c >= a) return c - a; + if (c >= A) return c - A + 26; + return c - zero + 52; +} + +/** + * @param {string} s + * @param {string} sub + * @param {character[][]} mappings + * @return {boolean} + */ +const matchReplacement = function (s, sub, mappings) { + const adj = Array(62 * 62).fill(0) + const m = s.length, n = sub.length + for(const ch of sub) adj[encode(ch) * 62 + encode(ch)] = 1 + for(const [f, t] of mappings) { + adj[encode(f) * 62 + encode(t)] = 1 + } + + for(let i = m - n; i >= 0; i--) { + for(let si = i, j = 0;; si++, j++) { + if(j === n) return true + if(adj[encode(sub[j]) * 62 + encode(s[si])] === 0) break + } + } + + return false +}; + + +// another + + +let adj = new Uint8Array(3844); + +/** + * @param {string} ch + */ +function encode(ch) { + let c = ch.charCodeAt(); + if (c >= 97) return c - 97; + if (c >= 65) return c - 39; + return c + 4; +} + +/** + * @param {string} s + * @param {string} sub + * @param {character[][]} mappings + * @return {boolean} + */ +var matchReplacement = function (s, sub, mappings) { + let n = s.length; + let m = sub.length; + + adj.fill(0); + for (let [cf, ct] of mappings) { + adj[encode(cf) * 62 + encode(ct)] = 1; + }; + for (let i = 0; i < 62; ++i) { + adj[i * 62 + i] = 1; + } + + for (let l = n - m; l >= 0; --l) { + for (let d = 0, r = l; ; ++d, ++r) { + if (d == m) return true; + if (!adj[encode(sub[d]) * 62 + encode(s[r])]) break; + } + } + + return false; +}; diff --git a/2302-count-subarrays-with-score-less-than-k.js b/2302-count-subarrays-with-score-less-than-k.js new file mode 100644 index 00000000..4125da43 --- /dev/null +++ b/2302-count-subarrays-with-score-less-than-k.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countSubarrays = function(nums, k) { + let sum = 0 + let res = 0 + for(let i = 0, j = 0, n = nums.length; i < n; i++) { + sum += nums[i] + while(sum * (i - j + 1) >= k) sum -= nums[j++] + res += i - j + 1 + } + + return res +}; diff --git a/2303-calculate-amount-paid-in-taxes.js b/2303-calculate-amount-paid-in-taxes.js new file mode 100644 index 00000000..fd731f22 --- /dev/null +++ b/2303-calculate-amount-paid-in-taxes.js @@ -0,0 +1,22 @@ +/** + * @param {number[][]} brackets + * @param {number} income + * @return {number} + */ +var calculateTax = function(brackets, income) { + let res = 0 + const arr = brackets + let first = Math.min(income, arr[0][0]) + res = first * arr[0][1] / 100 + let remain = income - first + for(let i = 1; i < arr.length; i++) { + if(remain === 0) break + const [cur, r] = arr[i] + const gap = cur - arr[i - 1][0] + const real = Math.min(gap, remain) + res += real * r / 100 + remain -= real + } + + return res +}; diff --git a/2304-minimum-path-cost-in-a-grid.js b/2304-minimum-path-cost-in-a-grid.js new file mode 100644 index 00000000..65d117c1 --- /dev/null +++ b/2304-minimum-path-cost-in-a-grid.js @@ -0,0 +1,29 @@ +/** + * @param {number[][]} grid + * @param {number[][]} moveCost + * @return {number} + */ +var minPathCost = function(grid, moveCost) { + const m = grid.length, n = grid[0].length + const memo = Array.from({ length: 2 }, () => Array(n)) + for(let i = 0; i < n; i++) { + memo[0][i] = grid[0][i] + } + let cur = 0 + for(let i = 0; i < m - 1; i++) { + const nxt = cur ^ 1 + for(let t = 0; t < n; t++) { + memo[nxt][t] = Infinity + } + for(let j = 0; j < n; j++) { + const v = grid[i][j] + for(let k = 0; k < n; k++) { + const cost = moveCost[v][k] + memo[nxt][k] = Math.min(memo[nxt][k], memo[cur][j] + grid[i + 1][k] + cost) + } + } + cur ^= 1 + } + + return Math.min(...memo[cur]) +}; diff --git a/2305-fair-distribution-of-cookies.js b/2305-fair-distribution-of-cookies.js new file mode 100644 index 00000000..38eae083 --- /dev/null +++ b/2305-fair-distribution-of-cookies.js @@ -0,0 +1,32 @@ +/** + * @param {number[]} cookies + * @param {number} k + * @return {number} + */ +const distributeCookies = function(cookies, k) { + const n = cookies.length + let res = Infinity + const arr = Array(n).fill(0) + + bt(0) + return res + + function bt(idx) { + if(idx === n) { + res = Math.min(res, Math.max(...arr)) + return + } + const cur = cookies[idx] + const visited = new Set() + for(let i = 0; i < k; i++) { + const e = arr[i] + if(visited.has(arr[i])) continue + if(cur + e >= res) continue + visited.add(arr[i]) + arr[i] += cur + bt(idx + 1) + arr[i] -= cur + if(arr[i] === 0) break + } + } +}; diff --git a/2306-naming-a-company.js b/2306-naming-a-company.js new file mode 100644 index 00000000..626417ca --- /dev/null +++ b/2306-naming-a-company.js @@ -0,0 +1,22 @@ +/** + * @param {string[]} ideas + * @return {number} + */ +const distinctNames = function (ideas) { + let smap = Array.from({ length: 26 }, (_) => new Set()), + ans = 0 + for (let i = 0; i < ideas.length; i++) { + let word = ideas[i] + smap[word.charCodeAt(0) - 97].add(word.slice(1)) + } + for (let i = 0; i < 25; i++) { + let a = smap[i] + for (let j = i + 1; j < 26; j++) { + let b = smap[j], + count = 0 + for (let w of a) if (b.has(w)) count++ + ans += (a.size - count) * (b.size - count) * 2 + } + } + return ans +} diff --git a/231-power-of-two.js b/231-power-of-two.js index 9b53cca2..397c73ba 100644 --- a/231-power-of-two.js +++ b/231-power-of-two.js @@ -14,3 +14,30 @@ const isPowerOfTwo = function(n) { } return false }; + +// another + +/** + * @param {number} n + * @return {boolean} + */ +const isPowerOfTwo = function(n) { + return Math.log2(n)%1 === 0 +}; + +// another + +/** + * @param {number} n + * @return {boolean} + */ +const isPowerOfTwo = n => n < 1 ? false : Number.MAX_VALUE % n === 0 + +// another + +/** + * @param {number} n + * @return {boolean} + */ +const isPowerOfTwo = x => x > 0 ? !(x & (x - 1)) : false; + diff --git a/2311-longest-binary-subsequence-less-than-or-equal-to-k.js b/2311-longest-binary-subsequence-less-than-or-equal-to-k.js new file mode 100644 index 00000000..8ff9dddd --- /dev/null +++ b/2311-longest-binary-subsequence-less-than-or-equal-to-k.js @@ -0,0 +1,23 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const longestSubsequence = function(s, k) { + let val = 0, pow = 1, oneNum = 0 + for(let i = s.length - 1; i >= 0 && val + pow <= k; i--) { + if(s[i] === '1') { + oneNum++ + val += pow + } + pow <<= 1 + } + return cnt(s, '0') + oneNum + function cnt(s, t) { + let res = 0 + for(const e of s) { + if(e === '0') res++ + } + return res + } +}; diff --git a/2312-selling-pieces-of-wood.js b/2312-selling-pieces-of-wood.js new file mode 100644 index 00000000..8cf6f8b5 --- /dev/null +++ b/2312-selling-pieces-of-wood.js @@ -0,0 +1,51 @@ +/** + * @param {number} m + * @param {number} n + * @param {number[][]} prices + * @return {number} + */ +const sellingWood = function(m, n, prices) { + const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)) + for(const [h, w, p] of prices) { + dp[h][w] = p + } + + for (let i = 1; i <= m; ++i) { + for (let j = 1; j <= n; ++j) { + for (let k = 1; k <= i / 2; ++k) { + dp[i][j] = Math.max(dp[i][j], dp[k][j] + dp[i - k][j]); + } + for (let k = 1; k <= j / 2; ++k) { + dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[i][j - k]); + } + } + } + return dp[m][n]; +}; + +// another + +/** + * @param {number} m + * @param {number} n + * @param {number[][]} prices + * @return {number} + */ +const sellingWood = function(m, n, prices) { + const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)) + + for(const [h, w, p] of prices) dp[h][w] = p + for(let i = 1; i <= m; i++) { + for(let j = 1; j <= n; j++) { + for(let k = 1; k <= i / 2; k++) { + dp[i][j] = Math.max(dp[i][j], dp[k][j] + dp[i - k][j]) + } + + for(let k = 1; k <= j / 2; k++) { + dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[i][j - k]) + } + } + } + + return dp[m][n] +}; diff --git a/2313-minimum-flips-in-binary-tree-to-get-result.js b/2313-minimum-flips-in-binary-tree-to-get-result.js new file mode 100644 index 00000000..f11fa541 --- /dev/null +++ b/2313-minimum-flips-in-binary-tree-to-get-result.js @@ -0,0 +1,125 @@ +/** + * 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 + * @param {boolean} result + * @return {number} + */ +const minimumFlips = function(root, result) { + const dp = new Map() + return dfs(root, result) + + function dfs(node, expected) { + if(node.val === 0 || node.val === 1) { + return (!!node.val) === !!expected ? 0 : 1 + } + if(dp.has(node) && dp.get(node).has(expected)) { + return dp.get(node).get(expected) + } + let res = Infinity + + if(node.val === 2) { + if(expected) { + res = Math.min(dfs(node.left, 1), dfs(node.right, 1)) + } else { + res = dfs(node.left, 0) + dfs(node.right, 0) + } + } else if(node.val === 3) { + if(expected) { + res = dfs(node.left, 1) + dfs(node.right, 1) + } else { + res = Math.min(dfs(node.left, 0), dfs(node.right, 0)) + } + } else if(node.val === 4) { + if(expected) { + res = Math.min(dfs(node.left, 0) + dfs(node.right, 1), dfs(node.left, 1) + dfs(node.right, 0)) + } else { + res = Math.min(dfs(node.left, 1) + dfs(node.right, 1), dfs(node.left, 0) + dfs(node.right, 0)) + } + + } else if(node.val === 5) { + const child = node.left || node.right + if(expected) { + res = dfs(child, 0) + } else { + res = dfs(child, 1) + } + } + + if(!dp.has(node)) dp.set(node, new Map()) + dp.get(node).set(expected, res) + return res + } +}; + +// another + +/** + * 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 + * @param {boolean} result + * @return {number} + */ +const minimumFlips = function (root, result) { + const [FALSE, TRUE, OR, AND, XOR, NOT] = [0, 1, 2, 3, 4, 5] + const costs = new Map() + + const getMin = (node, target) => { + if (node.val === FALSE || node.val === TRUE) + return Math.abs(target - node.val) + + const nodeCosts = costs.get(node) || [-1, -1] + if (nodeCosts[target] >= 0) return nodeCosts[target] + + if (node.val === NOT) { + nodeCosts[target] = getMin(node.left || node.right, 1 - target) + } else if (node.val === OR) { + nodeCosts[target] = + target === FALSE + ? getMin(node.left, 0) + getMin(node.right, 0) + : Math.min( + getMin(node.left, 0) + getMin(node.right, 1), + getMin(node.left, 1) + getMin(node.right, 0), + getMin(node.left, 1) + getMin(node.right, 1) + ) + } else if (node.val === AND) { + nodeCosts[target] = + target === TRUE + ? getMin(node.left, 1) + getMin(node.right, 1) + : Math.min( + getMin(node.left, 0) + getMin(node.right, 1), + getMin(node.left, 1) + getMin(node.right, 0), + getMin(node.left, 0) + getMin(node.right, 0) + ) + } else { + nodeCosts[target] = + target === FALSE + ? Math.min( + getMin(node.left, 0) + getMin(node.right, 0), + getMin(node.left, 1) + getMin(node.right, 1) + ) + : Math.min( + getMin(node.left, 0) + getMin(node.right, 1), + getMin(node.left, 1) + getMin(node.right, 0) + ) + } + + costs.set(node, nodeCosts) + return nodeCosts[target] + } + + return getMin(root, result ? 1 : 0) +} diff --git a/2317-maximum-xor-after-operations.js b/2317-maximum-xor-after-operations.js new file mode 100644 index 00000000..44a60632 --- /dev/null +++ b/2317-maximum-xor-after-operations.js @@ -0,0 +1,10 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maximumXOR = function(nums) { + let res = 0 + for(const e of nums) res |= e + + return res +}; diff --git a/2318-number-of-distinct-roll-sequences.js b/2318-number-of-distinct-roll-sequences.js new file mode 100644 index 00000000..14e19cee --- /dev/null +++ b/2318-number-of-distinct-roll-sequences.js @@ -0,0 +1,87 @@ +/** + * @param {number} n + * @return {number} + */ +const distinctSequences = function(n) { + const hash = { + 1: [2,3,4,5,6], + 2: [1,3,5], + 3: [1,2,4,5], + 4: [1,3,5], + 5: [1,2,3,4,6], + 6: [1,5], + } + + const memo = kdArr(0, [7,7,n+1]) + const mod = 1e9 + 7 + let res = 0 + for(let i = 1; i <= 6; i++) { + res = (res + dfs(i, 0, n - 1)) % mod + } + + + return res + + function dfs(s,i,j) { + if(j === 0) return 1 + if(memo[s][i][j] !== 0) return memo[s][i][j] + let res = 0 + for(let e of hash[s]) { + if(e !== i) { + res = (res + dfs(e, s, j - 1)) % mod + } + } + memo[s][i][j] = res + return res + } + + function kdArr(defaultVal, arr) { + if(arr.length === 1) return Array(arr[0]).fill(defaultVal) + + const res = [] + for(let i = 0, len = arr[0]; i < len; i++) { + res.push(kdArr(defaultVal, arr.slice(1))) + } + + return res + } +}; + +// another + + +/** + * @param {number} n + * @return {number} + */ +const dp = MultidimensionalArray(0, 1e4 + 1, 7, 7) +const distinctSequences = function (n, p = 0, pp = 0) { + const mod = 1e9 + 7 + if (n === 0) return 1 + if (dp[n][p][pp] === 0) { + for (let d = 1; d < 7; d++) { + if (d !== p && d !== pp && (p === 0 || gcd(d, p) === 1)) { + dp[n][p][pp] = (dp[n][p][pp] + distinctSequences(n - 1, d, p)) % mod + } + } + } + + return dp[n][p][pp] +} + +function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) +} + +function MultidimensionalArray(defaultValue, ...args) { + if (args.length === 1) { + return Array(args[0]).fill(defaultValue) + } + const res = [] + + for (let i = 0, n = args[0]; i < n; i++) { + res.push(MultidimensionalArray(defaultValue, ...args.slice(1))) + } + + return res +} diff --git a/2319-check-if-matrix-is-x-matrix.js b/2319-check-if-matrix-is-x-matrix.js new file mode 100644 index 00000000..65bbdc79 --- /dev/null +++ b/2319-check-if-matrix-is-x-matrix.js @@ -0,0 +1,22 @@ +/** + * @param {number[][]} grid + * @return {boolean} + */ +var checkXMatrix = function(grid) { + const n = grid.length + const onDiag = (i, j) => { + return i === j || j === n - 1 - i + } + for(let i = 0; i < n; i++) { + for(let j = 0;j < n; j++) { + const valid = onDiag(i, j) + if(valid) { + if(grid[i][j] === 0) return false + }else { + if(grid[i][j] !== 0) return false + } + } + } + + return true +}; diff --git a/232-implement-queue-using-stacks.js b/232-implement-queue-using-stacks.js index cd50590d..5477a853 100644 --- a/232-implement-queue-using-stacks.js +++ b/232-implement-queue-using-stacks.js @@ -1,46 +1,46 @@ -/** - * Initialize your data structure here. - */ -const MyQueue = function() { - this.queue = [] + +var MyQueue = function() { + this.input = [] + this.output = [] }; -/** - * Push element x to the back of queue. +/** * @param {number} x * @return {void} */ MyQueue.prototype.push = function(x) { - this.queue.push(x) + this.input.push(x) }; /** - * Removes the element from in front of queue and returns that element. * @return {number} */ MyQueue.prototype.pop = function() { - return this.queue.shift() + if(this.output.length === 0) { + while(this.input.length) { + this.output.push(this.input.pop()) + } + } + return this.output.pop() }; /** - * Get the front element. * @return {number} */ MyQueue.prototype.peek = function() { - return this.queue[0] + return this.output[this.output.length - 1] || this.input[0] }; /** - * Returns whether the queue is empty. * @return {boolean} */ MyQueue.prototype.empty = function() { - return this.queue.length === 0 + return this.input.length === 0 && this.output.length === 0 }; /** * Your MyQueue object will be instantiated and called as such: - * var obj = Object.create(MyQueue).createNew() + * var obj = new MyQueue() * obj.push(x) * var param_2 = obj.pop() * var param_3 = obj.peek() diff --git a/2320-count-number-of-ways-to-place-houses.js b/2320-count-number-of-ways-to-place-houses.js new file mode 100644 index 00000000..b1d6f302 --- /dev/null +++ b/2320-count-number-of-ways-to-place-houses.js @@ -0,0 +1,35 @@ +/** + * @param {number} n + * @return {number} + */ +const countHousePlacements = function(n) { + const mod = BigInt(1e9 + 7) + let house = 1n, space = 1n, total = 2n + for(let i = 2; i <= n; i++) { + house = space + space = total + total = (house + space) % mod + } + + return total * total % mod +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +var countHousePlacements = function(n) { + const mod = 1e9 + 7 + let f0 = 1; + let f1 = 1; + for (let i = 1; i < n; i++) { + let nf0 = (f0 + f1) % mod; + let nf1 = f0; + f0 = nf0; + f1 = nf1; + } + let m = (f0 + f1) % mod; + return BigInt(m) * BigInt(m) % BigInt(mod) +}; diff --git a/2321-maximum-score-of-spliced-array.js b/2321-maximum-score-of-spliced-array.js new file mode 100644 index 00000000..84fbf277 --- /dev/null +++ b/2321-maximum-score-of-spliced-array.js @@ -0,0 +1,65 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +var maximumsSplicedArray = function(nums1, nums2) { + let n = nums1.length; + let arr = new Array(n).fill(0); + let s1 = 0, s2 = 0; + for (let i = 0; i < n; i++) { + s1 += nums1[i]; + s2 += nums2[i]; + } + for (let i = 0; i < n; i++) { + arr[i] = nums1[i] - nums2[i]; + } + let sum = 0; + let min1 = 0; + let max1 = 0; + for (let i = 0; i < n; i++) { + sum += arr[i]; + max1 = Math.max(sum - min1, max1); + min1 = Math.min(min1, sum); + } + sum = 0; + let min2 = 0; + let max2 = 0; + for (let i = 0; i < n; i++) { + sum += arr[i]; + min2 = Math.min(sum - max2, min2); + max2 = Math.max(max2, sum); + } + return Math.max(s2 + max1, s1 - min2); +}; + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const maximumsSplicedArray = function (nums1, nums2) { + let sum1 = 0, + sum2 = 0, + max1 = 0, + max2 = 0, + ac1 = 0, + ac2 = 0 + sum1 = nums1.reduce((ac, e) => ac + e, 0) + sum2 = nums2.reduce((ac, e) => ac + e, 0) + const { max } = Math + let res = max(sum1, sum2) + for (let i = 0, n = nums1.length; i < n; i++) { + ac1 += nums1[i] - nums2[i] + ac2 += nums2[i] - nums1[i] + max1 = max(max1, ac1) + max2 = max(max2, ac2) + if(ac1 < 0) ac1 = 0 + if(ac2 < 0) ac2 = 0 + } + res = max(res, sum1 + max2, sum2 + max1) + + return res +} diff --git a/2322-minimum-score-after-removals-on-a-tree.js b/2322-minimum-score-after-removals-on-a-tree.js new file mode 100644 index 00000000..5adcde91 --- /dev/null +++ b/2322-minimum-score-after-removals-on-a-tree.js @@ -0,0 +1,234 @@ +/** + * @param {number[]} nums + * @param {number[][]} edges + * @return {number} + */ +const minimumScore = function (nums, edges) { + const n = nums.length, m = edges.length + const graph = {} + const children = {} + const xor = nums.slice(0) + const degree = Array(n).fill(0) + + for(const [p, q] of edges) { + if(graph[p] == null) graph[p] = [] + if(graph[q] == null) graph[q] = [] + graph[p].push(q) + graph[q].push(p) + degree[p]++ + degree[q]++ + } + + let val = 0 + const seen = new Set() + const queue = [] + for(let i = 0; i < n; i++) { + val ^= nums[i] + if(degree[i] === 1) { + queue.push(i) + seen.add(i) + } + } + + while(queue.length) { + const cur = queue.shift() + for(const nxt of (graph[cur] || [])) { + if(!seen.has(nxt)) { + if(children[nxt] == null) children[nxt] = new Set() + children[nxt].add(cur) + for(const e of (children[cur] || [])) { + children[nxt].add(e) + } + xor[nxt] ^= xor[cur] + } + degree[nxt]-- + if(degree[nxt] === 1) { + seen.add(nxt) + queue.push(nxt) + } + } + } + + let res = Infinity + + for(let i = 0; i < m - 1; i++) { + for(let j = i + 1; j < m; j++) { + let [a, b] = edges[i] + // Let a, c be the lower break points + if(children[a]?.has(b)) { + ;[a, b] = [b, a] + } + let [c, d] = edges[j] + if(children[c]?.has(d)) { + ;[c, d] = [d, c] + } + let cur + if(children[a]?.has(c)) { + cur = [xor[c], xor[a] ^ xor[c], val ^ xor[a]] + } else if(children[c]?.has(a)) { + cur = [xor[a], xor[c] ^ xor[a], val ^ xor[c]] + } else { + cur = [xor[a], xor[c], val ^ xor[a] ^ xor[c]] + } + res = Math.min(res, Math.max(...cur) - Math.min(...cur)) + } + } + + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number[][]} edges + * @return {number} + */ +var minimumScore = function (nums, edges) { + let n = nums.length, + ans = Infinity + let visited = Array(n).fill(0) + let pc = [] + let adj = Array.from({ length: n }, () => []) + let child_xor = Array(n).fill(0) + let childs = Array.from({ length: n }, () => Array(n).fill(false)) + const { min, max } = Math + let par = Array(n).fill(0) + + // Creating an adjacency matrix + for (const edge of edges) + adj[edge[0]].push(edge[1]), adj[edge[1]].push(edge[0]) + + dfs(0) + + // console.log(childs) + // console.log(pc) + for (let i = 0; i < pc.length; i++) + for (let j = i + 1; j < pc.length; j++) { + // removing an edge i and j + let a = pc[i][1], + b = pc[j][1] // node that will come below when you delete an edge i and j + let xa = child_xor[a], + xb = child_xor[b], + xc = child_xor[0] + // console.log(a,b) + if (childs[a][b]) (xc ^= xa), (xa ^= xb) + else (xc ^= xa), (xc ^= xb) + + ans = min(max(xa, max(xb, xc)) - min(xa, min(xb, xc)), ans) + } + + return ans + + function dfs(i) { + let ans = nums[i] + visited[i] = true + + for (let p of par) childs[p][i] = true // Defining this node as the child of all its parents + + par.push(i) + + for (let child of adj[i] || []) + if (!visited[child]) { + pc.push([i, child]) + ans ^= dfs(child) // Recurcively calculating xors + } + + par.pop() + + return (child_xor[i] = ans) + } +} + +// another + +/** + * @param {number[]} nums + * @param {number[][]} edges + * @return {number} + */ +const minimumScore = function (nums, edges) { + const n = nums.length, + m = edges.length + const graph = {}, + degree = Array(n).fill(0) + const children = [], + vArr = nums.slice() + for (let i = 0; i < n; i++) children[i] = new Set() + for (const [u, v] of edges) { + if (graph[u] == null) graph[u] = [] + if (graph[v] == null) graph[v] = [] + graph[u].push(v) + graph[v].push(u) + degree[u]++ + degree[v]++ + } + let v = 0, + q = [] + const seen = new Set() + for (let i = 0; i < n; i++) { + v ^= nums[i] + if (degree[i] === 1) { + q.push(i) + seen.add(i) + } + } + + while (q.length) { + const tmp = [] + const size = q.length + for (let i = 0; i < size; i++) { + const cur = q[i] + for (const nxt of graph[cur]) { + // chidlren + // vArr + if (!seen.has(nxt)) { + children[nxt].add(cur) + children[nxt] = mergeSet(children[nxt], children[cur]) + vArr[nxt] ^= vArr[cur] + } + degree[nxt]-- + if (degree[nxt] === 1) { + tmp.push(nxt) + seen.add(nxt) + } + } + } + + q = tmp + } + + let res = Infinity + for (let i = 0; i < m - 1; i++) { + for (let j = i + 1; j < m; j++) { + let [a, b] = edges[i] + if (children[a].has(b)) { + ;[a, b] = [b, a] + } + let [c, d] = edges[j] + if (children[c].has(d)) { + ;[c, d] = [d, c] + } + if (children[c].has(a)) { + const tmp = [vArr[a], vArr[c] ^ vArr[a], v ^ vArr[c]] + res = Math.min(res, Math.max(...tmp) - Math.min(...tmp)) + } else if (children[a].has(c)) { + const tmp = [vArr[c], vArr[a] ^ vArr[c], v ^ vArr[a]] + res = Math.min(res, Math.max(...tmp) - Math.min(...tmp)) + } else { + const tmp = [vArr[a], vArr[c], v ^ vArr[a] ^ vArr[c]] + res = Math.min(res, Math.max(...tmp) - Math.min(...tmp)) + } + } + } + + return res +} + +function mergeSet(s, t) { + for (const e of t) { + s.add(e) + } + return s +} + diff --git a/2325-decode-the-message.js b/2325-decode-the-message.js new file mode 100644 index 00000000..f6673016 --- /dev/null +++ b/2325-decode-the-message.js @@ -0,0 +1,31 @@ +/** + * @param {string} key + * @param {string} message + * @return {string} + */ +var decodeMessage = function(key, message) { + const set = new Set() + for(const ch of key) { + if(ch !== ' ') set.add(ch) + if(set.size === 26) break + } + const arr = Array.from(set).map((e, i) => [e, i]) + const hash = {} + for(const [e, i] of arr) { + hash[e] = i + } + // console.log(arr) + const a = 'a'.charCodeAt(0) + let res = '' + for(const ch of message) { + if(ch === ' ') { + res += ' ' + continue + } + const idx = hash[ch] + const tmp = String.fromCharCode(a + idx) + res += tmp + } + + return res +}; diff --git a/2326-spiral-matrix-iv.js b/2326-spiral-matrix-iv.js new file mode 100644 index 00000000..66ad0233 --- /dev/null +++ b/2326-spiral-matrix-iv.js @@ -0,0 +1,51 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {number} m + * @param {number} n + * @param {ListNode} head + * @return {number[][]} + */ +const spiralMatrix = function (m, n, head) { + const mat = Array.from({ length: m }, () => Array(n).fill(-1)); + let cur = head; + const dirs = [ + [0, 1], + [1, 0], + [0, -1], + [-1, 0], + ]; + let i = 0, + j = 0, + left = 0, + right = n - 1, + top = 0, + bottom = m - 1, + idx = 0; + while (cur) { + mat[i][j] = cur.val; + if (idx === 0 && j === right) { + idx = (idx + 1) % 4; + right--; + } else if (idx === 1 && i === bottom) { + idx = (idx + 1) % 4; + bottom--; + } else if (idx === 2 && j === left) { + idx = (idx + 1) % 4; + left++; + } else if (idx === 3 && i === top + 1) { + idx = (idx + 1) % 4; + top++; + } + i += dirs[idx][0]; + j += dirs[idx][1]; + cur = cur.next; + } + + return mat; +}; diff --git a/2327-number-of-people-aware-of-a-secret.js b/2327-number-of-people-aware-of-a-secret.js new file mode 100644 index 00000000..8339fb12 --- /dev/null +++ b/2327-number-of-people-aware-of-a-secret.js @@ -0,0 +1,77 @@ +/** + * @param {number} n + * @param {number} delay + * @param {number} forget + * @return {number} + */ +const peopleAwareOfSecret = function(n, delay, forget) { + const dp = Array(n + 1).fill(0) + const mod = 1e9 + 7 + + dp[1] = 1 + for(let i = 1; i <= n; i++) { + for(let j = i + delay; j < i + forget; j++) { + if(j > n) break + dp[j] += dp[i] + dp[j] %= mod + } + } + + let res = 0 + for(let i = n - forget + 1; i <= n; i++) { + res = (dp[i] + res) % mod + } + + return res +}; + +// another + +/** + * @param {number} n + * @param {number} delay + * @param {number} forget + * @return {number} + */ +const peopleAwareOfSecret = function(n, delay, forget) { + let cnt = new Array(n+1).fill(0); + cnt[1] = 1; + let i = 1; + let MOD = 1_000_000_007; + while (i+delay <= n) { + for (let j = i+delay; j <= Math.min(n, i+forget-1); j++) { + cnt[j] = (cnt[j]+cnt[i])%MOD; + } + i++; + } + let res = 0; + for (let j = n; j > n-forget; j--) { + res = (res + cnt[j])%MOD; + } + return res; +}; + +// another + +/** + * @param {number} n + * @param {number} delay + * @param {number} forget + * @return {number} + */ + const peopleAwareOfSecret = function(n, delay, forget) { + const mod = 1e9 + 7 + const dp = Array(n + 1).fill(0) + const { max } = Math + dp[1] = 1 + let share = 0 + for(let i = 2; i <= n; i++) { + share = (share + dp[max(0, i - delay)] - dp[max(i - forget, 0)] + mod) % mod + dp[i] = share + } + let res = 0 + for(let i = n - forget + 1; i <= n; i++) { + res = (res + dp[i]) % mod + } + return res +}; diff --git a/2328-number-of-increasing-paths-in-a-grid.js b/2328-number-of-increasing-paths-in-a-grid.js new file mode 100644 index 00000000..e6b76dd6 --- /dev/null +++ b/2328-number-of-increasing-paths-in-a-grid.js @@ -0,0 +1,83 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const countPaths = function (grid) { + const mod = 1e9 + 7 + const m = grid.length, n = grid[0].length + let res = 0 + const dirs = [[1,0], [-1,0], [0, 1], [0, -1]] + const memo = Array.from({ length: m }, () => Array(n).fill(0)) + for(let i = 0; i = 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] > grid[i][j]) { + res = (res + dfs(nx, ny)) % mod + } + } + + memo[i][j] = res + + return res + } +} + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +var countPaths = function (grid) { + const MOD = 1e9 + 7 + let res = 0 + const M = grid.length, + N = grid[0].length + + const dp = Array.from({ length: M }, () => Array(N)) + + for (let r = 0; r < M; r++) { + for (let c = 0; c < N; c++) { + res = (res + dfs(r, c)) % MOD + } + } + return res + + function dfs(r, c) { + if (dp[r][c] != null) { + return dp[r][c] + } + let res = 1 + + for (const dir of [ + [-1, 0], + [0, -1], + [1, 0], + [0, 1], + ]) { + const nr = r + dir[0], + nc = c + dir[1] + if ( + nr < 0 || + nr >= M || + nc < 0 || + nc >= N || + grid[nr][nc] <= grid[r][c] + ) { + continue + } + res = (res + dfs(nr, nc)) % MOD + } + dp[r][c] = res + return res + } +} diff --git a/233-number-of-digit-one.js b/233-number-of-digit-one.js index 5b8abf11..d3df405e 100644 --- a/233-number-of-digit-one.js +++ b/233-number-of-digit-one.js @@ -1,3 +1,87 @@ +/** + * @param {number} n + * @return {number} + */ +const countDigitOne = function(n) { + let res = 0 + const s = `${n}` + const len = s.length, {floor, pow} = Math + + for(let i = 1; i <= len; i++) { + const np = pow(10, i - 1) + const pre = floor(n / pow(10, i)) + const remain = n % np + + res += pre * np + const e = +s[len - i] + if(e > 1) { + res += np + } else if(e === 1) { + res += remain + 1 + } + } + + return res +}; + + +// another + + +/** + * @param {number} n + * @return {number} + */ +const countDigitOne = function(n) { + let res = 0 + const str = `${n}` + const len = str.length, { pow } = Math + + for(let i = 1; i <= len; i++) { + const pre = ~~(n / pow(10, i)) + const remain = n % (pow(10, i - 1)) + const post = pow(10, i - 1) + res += pre * post + const e = +(str[len - i]) + if(e > 1) { + res += pow(10, i - 1) + } else if(e === 1) { + res += remain + 1 + } + } + + return res +}; + + +// another + +/** + * @param {number} n + * @return {number} + */ +const countDigitOne = function(n) { + return countNum(1, n + 1) +}; + +// Counts the number of `digit` in the range [0, limit) +function countNum( digit, limit) { + let count = 0; + let factor = 1; + let tail = 0; + while (limit >= 10) { + let d = limit % 10; + limit = ~~(limit / 10); + count += limit * factor; + count += d > digit ? factor : d == digit ? tail : 0; + tail += d * factor; + factor *= 10; + } + return count + (limit > digit ? factor : limit == digit ? tail : 0); +} + +// another + /** * @param {number} n * @return {number} @@ -24,11 +108,11 @@ const countDigitOne = function(n) { * @param {number} n * @return {number} */ -const countDigitOne = function(n) { +const countDigitOne = function (n) { if (n <= 0) return 0 let ones = 0 for (let i = 1, q = n; i <= n; i *= 10, q = (q / 10) >> 0) { - let pre = (n / (i * 10)) >> 0, + const pre = (n / (i * 10)) >> 0, cur = q % 10, suf = n % i ones += pre * i @@ -36,3 +120,32 @@ const countDigitOne = function(n) { } return ones } + +// another + +/** + * @param {number} n + * @return {number} + */ +const countDigitOne = function(n) { + let res = 0, factor = 1, lower = 0, cur = 0, higher = 0 + while(~~(n / factor) !== 0) { + lower = n - (~~(n / factor)) * factor + cur = (~~(n / factor)) % 10 + higher = ~~(n / (factor * 10)) + switch(cur) { + case 0: + res += higher * factor + break + case 1: + res += higher * factor + lower + 1 + break + default: + res += (higher + 1) * factor + break + } + factor *= 10 + } + + return res +}; diff --git a/2332-the-latest-time-to-catch-a-bus.js b/2332-the-latest-time-to-catch-a-bus.js new file mode 100644 index 00000000..8b99c6bf --- /dev/null +++ b/2332-the-latest-time-to-catch-a-bus.js @@ -0,0 +1,42 @@ +/** + * @param {number[]} buses + * @param {number[]} passengers + * @param {number} capacity + * @return {number} + */ +const latestTimeCatchTheBus = function(buses, passengers, capacity) { + buses.sort((b1, b2) => b1 - b2) + passengers.sort((p1, p2) => p1 - p2) + + const passengersSet = new Set(passengers) + + let j = 0 + let lastBus = [] + for (let i = 0; i < buses.length; i++) { + let k = j + let currentBus = [] + while (k - j < capacity && passengers[k] <= buses[i]) { + currentBus.push(passengers[k]) + k++ + } + lastBus = currentBus + j = k + } + + let lastArrival + if (lastBus.length == capacity) { + lastArrival = lastBus[capacity - 1] + while (passengersSet.has(lastArrival)) { + lastArrival-- + } + } else { + lastArrival = buses[buses.length - 1] + + while (passengersSet.has(lastArrival)) { + lastArrival-- + } + } + + + return lastArrival +}; diff --git a/2333-minimum-sum-of-squared-difference.js b/2333-minimum-sum-of-squared-difference.js new file mode 100644 index 00000000..0837f9ac --- /dev/null +++ b/2333-minimum-sum-of-squared-difference.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k1 + * @param {number} k2 + * @return {number} + */ +const minSumSquareDiff = function (nums1, nums2, k1, k2) { + const n = nums1.length + const diff = Array(n).fill(0) + for (let i = 0; i < n; ++i) { + diff[i] = Math.abs(nums1[i] - nums2[i]) + } + const M = Math.max(...diff) + const bucket = Array(M + 1).fill(0) + for (let i = 0; i < n; i++) { + bucket[diff[i]]++ + } + let k = k1 + k2 + for (let i = M; i > 0 && k; i--) { + if (bucket[i] > 0) { + const minus = Math.min(bucket[i], k) + bucket[i] -= minus + bucket[i - 1] += minus + k -= minus + } + } + let res = 0 + for (let i = M; i > 0; --i) { + res += bucket[i] * i * i + } + return res +} diff --git a/2334-subarray-with-elements-greater-than-varying-threshold.js b/2334-subarray-with-elements-greater-than-varying-threshold.js new file mode 100644 index 00000000..81da647a --- /dev/null +++ b/2334-subarray-with-elements-greater-than-varying-threshold.js @@ -0,0 +1,50 @@ +/** + * @param {number[]} nums + * @param {number} threshold + * @return {number} + */ +const validSubarraySize = function (nums, threshold) { + const n = nums.length + + let stk = [] + // used for storing next and previous smaller elements + const nextS = Array(n).fill(-1) + const prevS = Array(n).fill(-1) + + // firstly, let's find out the next smaller elements + for (let i = 0; i < n; i++) { + while (stk.length && nums[i] < nums[back(stk)]) { + nextS[back(stk)] = i + stk.pop() + } + stk.push(i) + } + + stk = [] + + // find out the previous smaller elements for each index + for (let i = n - 1; i >= 0; i--) { + while (stk.length && nums[i] < nums[back(stk)]) { + prevS[back(stk)] = i + stk.pop() + } + stk.push(i) + } + + for (let i = 0; i < n; i++) { + // left boundary + const left = prevS[i] + // right boundary + const right = nextS[i] == -1 ? n : nextS[i] + // length of subarray formed with nums[i] as minimum + const len = right - left - 1 + + if (nums[i] > threshold / len) return len + } + + return -1 + + function back(arr) { + return arr[arr.length - 1] + } +} diff --git a/2335-minimum-amount-of-time-to-fill-cups.js b/2335-minimum-amount-of-time-to-fill-cups.js new file mode 100644 index 00000000..7d0c385b --- /dev/null +++ b/2335-minimum-amount-of-time-to-fill-cups.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} amount + * @return {number} + */ +const fillCups = function(amount) { + amount.sort((a, b) => a- b) + let res = 0; + while (amount[2] !== 0) { + res++; + amount[2]--; + if (amount[1] > 0) { + amount[1]--; + } + amount.sort((a, b) => a- b) + } + return res; +}; diff --git a/2336-smallest-number-in-infinite-set.js b/2336-smallest-number-in-infinite-set.js new file mode 100644 index 00000000..1d550dfc --- /dev/null +++ b/2336-smallest-number-in-infinite-set.js @@ -0,0 +1,33 @@ + +const SmallestInfiniteSet = function() { + this.nums = new Set(Array.from({ length: 1001 }, (e, i) => i + 1)) + this.tmp = new Set() +}; + +/** + * @return {number} + */ +SmallestInfiniteSet.prototype.popSmallest = function() { + const min = Math.min(...this.nums) + this.nums.delete(min) + this.tmp.add(min) + return min +}; + +/** + * @param {number} num + * @return {void} + */ +SmallestInfiniteSet.prototype.addBack = function(num) { + if(this.tmp.has(num)) { + this.tmp.delete(num) + this.nums.add(num) + } +}; + +/** + * Your SmallestInfiniteSet object will be instantiated and called as such: + * var obj = new SmallestInfiniteSet() + * var param_1 = obj.popSmallest() + * obj.addBack(num) + */ diff --git a/2337-move-pieces-to-obtain-a-string.js b/2337-move-pieces-to-obtain-a-string.js new file mode 100644 index 00000000..51679d87 --- /dev/null +++ b/2337-move-pieces-to-obtain-a-string.js @@ -0,0 +1,31 @@ +/** + * @param {string} start + * @param {string} target + * @return {boolean} + */ +const canChange = function(start, target) { + const n=target.length; + let i=0,j=0; + while(i<=n && j<=n){ + + while(i p == 0 && q == 0 ? 1 : comb(p + q - 1, q); +const comb_init = () => { + fact[0] = ifact[0] = inv[1] = 1n; // factorial, inverse factorial + for (let i = 2; i < N; i++) inv[i] = (mod - mod / ll(i)) * inv[mod % ll(i)] % mod; + for (let i = 1; i < N; i++) { + fact[i] = fact[i - 1] * ll(i) % mod; + ifact[i] = ifact[i - 1] * inv[i] % mod; + } +}; + +// combination mod pick k from n +const comb = (n, k) => { + if (n < k || k < 0) return 0; + return fact[n] * ifact[k] % mod * ifact[n - k] % mod; +}; + +/* +prerequisite: +(number of factors) +https://www.codechef.com/LTIME01/problems/NUMFACT +*/ +const number_factor = (n) => { + let m = new Map(); + for (let i = 2; i * i <= n; i++) { + while (n % i == 0) { + n /= i; + m.set(i, m.get(i) + 1 || 1); + } + } + if (n > 1) m.set(n, m.get(n) + 1 || 1); + return m; +}; + +let fact, ifact, inv; +const idealArrays = (n, maxValue) => { + fact = Array(N).fill(0), ifact = Array(N).fill(0), inv = Array(N).fill(0); + comb_init(); + let res = 0n; + for (let x = 1; x <= maxValue; x++) { + let perm = 1n, m = number_factor(x); + for (const [x, occ] of m) { + perm = perm * hcomb(n, occ) % mod; + } + res += perm; + } + return res % mod; +}; diff --git a/2340-minimum-adjacent-swaps-to-make-a-valid-array.js b/2340-minimum-adjacent-swaps-to-make-a-valid-array.js new file mode 100644 index 00000000..9163ca49 --- /dev/null +++ b/2340-minimum-adjacent-swaps-to-make-a-valid-array.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumSwaps = function (nums) { + const mi = Math.min(...nums) + const ma = Math.max(...nums) + let minIdx = -1, maxIdx = -1 + const n = nums.length + for(let i = 0; i < n; i++) { + if(nums[i] === mi) { + minIdx = i + break + } + } + for(let i = n - 1; i >= 0; i--) { + if(nums[i] === ma) { + maxIdx = i + break + } + } + + const num = minIdx + n - 1 - maxIdx + return minIdx > maxIdx ? num - 1 : num +} diff --git a/2341-maximum-number-of-pairs-in-array.js b/2341-maximum-number-of-pairs-in-array.js new file mode 100644 index 00000000..98771fc3 --- /dev/null +++ b/2341-maximum-number-of-pairs-in-array.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var numberOfPairs = function(nums) { + const n = nums.length + let res = 0 + const hash = {} + for(const e of nums) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + if(hash[e] === 2) { + res++ + hash[e] = 0 + } + } + + return [res, n - res * 2] +}; diff --git a/2342-max-sum-of-a-pair-with-equal-sum-of-digits.js b/2342-max-sum-of-a-pair-with-equal-sum-of-digits.js new file mode 100644 index 00000000..1c9f1b10 --- /dev/null +++ b/2342-max-sum-of-a-pair-with-equal-sum-of-digits.js @@ -0,0 +1,48 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maximumSum = function(nums) { + const map = new Map() + for(const e of nums) { + const k = dSum(e) + add(map, k, e) + } + // console.log(map) + let res = -1 + for(const [k, v] of map) { + if(v.length === 2) { + res = Math.max(res, v[0] + v[1]) + } + } + + return res + + + function add(map, k, v) { + if(!map.has(k)) { + map.set(k, [v]) + } else { + if(map.get(k).length === 1) { + map.get(k).push(v) + } else { + const arr = map.get(k) + arr.push(v) + arr.sort((a, b) => b - a) + arr.splice(2, 1) + } + } + } + + function dSum(num) { + let res = 0 + + let cur = num + while(cur) { + res += cur % 10 + cur = ~~(cur / 10) + } + + return res + } +}; diff --git a/2343-query-kth-smallest-trimmed-number.js b/2343-query-kth-smallest-trimmed-number.js new file mode 100644 index 00000000..5d0b7085 --- /dev/null +++ b/2343-query-kth-smallest-trimmed-number.js @@ -0,0 +1,32 @@ +/** + * @param {string[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +const smallestTrimmedNumbers = function(nums, queries) { + const m = nums.length, n = queries.length, len = nums[0].length + const res = [] + + for(const [k, trim] of queries) { + const tmp = nums.map(e => e.slice(trim>len?0:len - trim)) + // console.log(trim, tmp) + const clone = tmp.slice().map((e,i) => ({v:e,i})) + clone.sort((a, b) => { + a = BigInt(a.v) + b = BigInt(b.v) + if(a > b) { + return 1; + } else if (a < b){ + return -1; + } else { + return 0; + } + }) + // console.log(clone) + const el = clone[k - 1] + // const idx = tmp.lastIndexOf(el) + res.push(el.i) + } + + return res +}; diff --git a/2344-minimum-deletions-to-make-array-divisible.js b/2344-minimum-deletions-to-make-array-divisible.js new file mode 100644 index 00000000..cf3025b7 --- /dev/null +++ b/2344-minimum-deletions-to-make-array-divisible.js @@ -0,0 +1,60 @@ +/** + * @param {number[]} nums + * @param {number[]} numsDivide + * @return {number} + */ +const minOperations = function (nums, numsDivide) { + nums.sort((a, b) => a - b) + let gcdVal = numsDivide[0] + + for(let i = 1, n = numsDivide.length; i < n; i++) { + gcdVal = gcd(gcdVal, numsDivide[i]) + } + + for(let i = 0, n = nums.length; i < n && nums[i] <= gcdVal; i++) { + if(gcdVal % nums[i] === 0) return i + } + + return -1 + + + function gcd(a,b) { + return b === 0 ? a : gcd(b, a % b) + } +} + +// another + +/** + * @param {number[]} nums + * @param {number[]} numsDivide + * @return {number} + */ +var minOperations = function(nums, numsDivide) { + let div = numsDivide[0], min = Infinity + for(let i = 1, n = numsDivide.length; i < n; i++) { + div = Math.min(div, gcd(numsDivide[i], div)) + min = Math.min(min, numsDivide[i]) + } + // console.log(div) + + nums.sort((a, b) => a - b) + if(div === 1 && nums[0] !== 1) return -1 + let res = 0 + for(const e of nums) { + if(e > min) break + if(div % e === 0) { + return res + } + if(e % div !== 0) res++ + else { + return res + } + } + + return -1 + + function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) + } +}; diff --git a/2347-best-poker-hand.js b/2347-best-poker-hand.js new file mode 100644 index 00000000..15e5e320 --- /dev/null +++ b/2347-best-poker-hand.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} ranks + * @param {character[]} suits + * @return {string} + */ +const bestHand = function(ranks, suits) { + let isFlush = false + const freq = {} + for(const e of suits) { + if(freq[e] == null) freq[e] = 0 + freq[e]++ + if(freq[e] >= 5) return 'Flush' + } + const rankHash = {} + for(const e of ranks) { + if(rankHash[e] == null) rankHash[e] = 0 + rankHash[e]++ + if(rankHash[e] >= 3) return 'Three of a Kind' + } + const rankKeys = Object.keys(rankHash) + for(const k of rankKeys) { + if(rankHash[k] >= 2) return 'Pair' + } + return 'High Card' +}; diff --git a/2348-number-of-zero-filled-subarrays.js b/2348-number-of-zero-filled-subarrays.js new file mode 100644 index 00000000..98d5fc95 --- /dev/null +++ b/2348-number-of-zero-filled-subarrays.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const zeroFilledSubarray = function(nums) { + let res = 0 + let idx = -1 + const n = nums.length + for(let i = 0; i < n; i++) { + const e = nums[i] + if(e !== 0) { + const len = (i - 1) - idx + res += helper(len) + idx = i + } else { + continue + } + } + if(idx !== n - 1) { + res += helper(n - 1 - idx) + } + + + return res + + function helper(n) { + let res = 0 + for(let i = 1; i <= n; i++) { + res += i + } + + return res + } +}; diff --git a/235-lowest-common-ancestor-of-a-binary-search-tree.js b/235-lowest-common-ancestor-of-a-binary-search-tree.js index 482f92e0..f6716919 100644 --- a/235-lowest-common-ancestor-of-a-binary-search-tree.js +++ b/235-lowest-common-ancestor-of-a-binary-search-tree.js @@ -5,6 +5,7 @@ * this.left = this.right = null; * } */ + /** * @param {TreeNode} root * @param {TreeNode} p @@ -12,8 +13,32 @@ * @return {TreeNode} */ const lowestCommonAncestor = function(root, p, q) { - while((root.val - p.val) * (root.val - q.val) > 0) { - root = root.val > p.val ? root.left : root.right - } - return root + if(root == null || root == p || root == q) return root + const left = lowestCommonAncestor(root.left, p, q) + const right = lowestCommonAncestor(root.right, p, q) + if(left && right) return root + return left || right +}; + +// another + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ + +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +const lowestCommonAncestor = function(root, p, q) { + while((root.val - p.val) * (root.val - q.val) > 0) { + root = p.val < root.val ? root.left : root.right + } + return root }; diff --git a/2350-shortest-impossible-sequence-of-rolls.js b/2350-shortest-impossible-sequence-of-rolls.js new file mode 100644 index 00000000..d7bcc54d --- /dev/null +++ b/2350-shortest-impossible-sequence-of-rolls.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} rolls + * @param {number} k + * @return {number} + */ +const shortestSequence = function (rolls, k) { + let res = 1 + let set = new Set() + + for (let i of rolls) { + set.add(i) + if (set.size === k) { + res++ + set = new Set() + } + } + return res +} diff --git a/2351-first-letter-to-appear-twice.js b/2351-first-letter-to-appear-twice.js new file mode 100644 index 00000000..4304af5f --- /dev/null +++ b/2351-first-letter-to-appear-twice.js @@ -0,0 +1,12 @@ +/** + * @param {string} s + * @return {character} + */ +var repeatedCharacter = function(s) { + const set = new Set() + + for(const e of s) { + if(set.has(e)) return e + else set.add(e) + } +}; diff --git a/2352-equal-row-and-column-pairs.js b/2352-equal-row-and-column-pairs.js new file mode 100644 index 00000000..75c12119 --- /dev/null +++ b/2352-equal-row-and-column-pairs.js @@ -0,0 +1,23 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var equalPairs = function(grid) { + let res = 0 + + const n = grid.length + for(let i = 0; i { + if (x[0] != y[0]) return y[0] - x[0]; // first priority: high rate comes first + return x[1].localeCompare(y[1]); // second priority: lexical smaller comes first + } + }); + cm.set(cuisines[i], pq); + } + cm.get(cuisines[i]).enqueue([ratings[i], foods[i]]) + } + return { changeRating, highestRated } + function changeRating(food, newRating) { + let cur = fm.get(food), cuisine = cur[0]; + cur[1] = newRating; + fm.set(food, cur); + cm.get(cuisine).enqueue([newRating, food]); + } + function highestRated(cuisine) { + let pq = cm.get(cuisine); + while (fm.get(pq.front()[1])[1] != pq.front()[0]) pq.dequeue(); // lazy remove + return pq.front()[1]; + } +}; + + +/** + * Your FoodRatings object will be instantiated and called as such: + * var obj = new FoodRatings(foods, cuisines, ratings) + * obj.changeRating(food,newRating) + * var param_2 = obj.highestRated(cuisine) + */ + diff --git a/2354-number-of-excellent-pairs.js b/2354-number-of-excellent-pairs.js new file mode 100644 index 00000000..1907ddcb --- /dev/null +++ b/2354-number-of-excellent-pairs.js @@ -0,0 +1,108 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countExcellentPairs = function(nums, k) { + const n = nums.length, set = new Set() + for(const e of nums) set.add(e) + const cnt = Array(30).fill(0) + for(const e of set) { + const bc = bitCnt(e) + if(cnt[bc] == null) cnt[bc] = 0 + cnt[bc] += 1 + } + let res = 0 + for(let i = 0; i < 30; i++) { + for(let j = 0; j < 30; j++) { + if(i + j >= k) res += cnt[i] * cnt[j] + } + } + + return res + + function bitCnt(num) { + let res = 0 + while(num) { + if(num & 1) res++ + num = num >> 1 + } + + return res + } +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countExcellentPairs = function(nums, k) { + const cnt = Array(31).fill(0), set = new Set(nums) + for(const e of set) { + cnt[setBits(e)]++ + } + let res = 0 + + for(let i = 1; i < 31; i++) { + for(let j = 1; j < 31; j++) { + if(i + j >= k) res += cnt[i] * cnt[j] + } + } + + return res + + function setBits(num) { + let res = 0 + while(num) { + res += num % 2 + num = num >> 1 + } + return res + } +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countExcellentPairs = function(nums, k) { + const arr = [], set = new Set(nums) + for(const e of set) { + arr.push(setBits(e)) + } + + arr.sort((a, b) => a - b) + let res = 0 + for(let i = 0, n = arr.length; i < n; i++) { + const idx = bs(arr, k - arr[i]) + res += n - idx + } + return res + + + function bs(arr, target) { + let l = 0, r = arr.length + + while(l < r) { + const mid = (l + r) >> 1 + if(arr[mid] < target) l = mid + 1 + else r = mid + } + + return l + } + function setBits(num) { + let res = 0 + while(num) { + res += num % 2 + num = num >> 1 + } + return res + } +}; diff --git a/2355-maximum-number-of-books-you-can-take.js b/2355-maximum-number-of-books-you-can-take.js new file mode 100644 index 00000000..585b0b78 --- /dev/null +++ b/2355-maximum-number-of-books-you-can-take.js @@ -0,0 +1,49 @@ +/** + * @param {number[]} books + * @return {number} + */ +var maximumBooks = function (books) { + const len = books.length + const dp = new Array(len).fill(0) + + // dp[i] represents max number of books that can be taken + // between shelf 0 and shelf i (both inclusive) + + // use monotonic stack to populate dp array; for every index i, + // find the nearest break point j < i such that books[i - j] < + // books[i] - i + j + + // this becomes the restraining point for picking books as now + // instead of picking (books[i] - i + j) books, we can only pick + // books[i - j] books; so we will pick the maximum dp[j] books + + // (books[i] + books[i] - 1 + books[i] - 2 + ... + books[i] - (i - j - 1)) + const stack = [] + let maxBooks = 0 + + for (let i = 0; i < len; i++) { + while (stack.length && books[peek(stack)] >= books[i] - i + peek(stack)) + stack.pop() + + // pick dp[j] books and (books[i] + books[i] - 1 + ... + books[i] - + // (i - j - 1)) books, where j is the current stack top; the latter + // expression can be rewritten as a difference of two n-summations + dp[i] = + (stack.length === 0 ? 0 : dp[peek(stack)]) + + getSummation(books[i]) - + getSummation(books[i] - i + (stack.length === 0 ? -1 : peek(stack))) + + maxBooks = Math.max(maxBooks, dp[i]) + stack.push(i) + } + + return maxBooks +} + +function getSummation(n) { + if (n < 0) return 0 + return (n * (n + 1)) / 2 +} + +function peek(arr) { + return arr[arr.length - 1] +} diff --git a/2357-make-array-zero-by-subtracting-equal-amounts.js b/2357-make-array-zero-by-subtracting-equal-amounts.js new file mode 100644 index 00000000..8a733003 --- /dev/null +++ b/2357-make-array-zero-by-subtracting-equal-amounts.js @@ -0,0 +1,32 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumOperations = function(nums) { + + let res = 0 + + while(!allZero(nums)) { + const sub = minNonZero(nums) + nums = nums.map(e => e - sub) + + res++ + } + + return res + + function minNonZero(arr) { + let res = 0 + const f = arr.filter(e => e > 0) + + + return Math.min(...f) + } + + function allZero(arr) { + for(const e of arr) { + if(e > 0) return false + } + return true + } +}; diff --git a/2358-maximum-number-of-groups-entering-a-competition.js b/2358-maximum-number-of-groups-entering-a-competition.js new file mode 100644 index 00000000..3813ab8d --- /dev/null +++ b/2358-maximum-number-of-groups-entering-a-competition.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} grades + * @return {number} + */ +const maximumGroups = function(grades) { + grades.sort((a, b) => a - b) + let res = 0 + let pre = 0, preNum = 0, cur = 0, curNum = 0 + const n = grades.length + for(let i = 0; i < n; i++) { + cur += grades[i] + curNum++ + if(cur > pre && curNum > preNum) { + res++ + pre = cur + preNum = curNum + cur = 0 + curNum = 0 + } + } + + + return res +}; diff --git a/2359-find-closest-node-to-given-two-nodes.js b/2359-find-closest-node-to-given-two-nodes.js new file mode 100644 index 00000000..8de57cc7 --- /dev/null +++ b/2359-find-closest-node-to-given-two-nodes.js @@ -0,0 +1,62 @@ +/** + * @param {number[]} edges + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ +const closestMeetingNode = function(edges, node1, node2) { + const graph = {} + const n = edges.length + for(let i = 0; i < n; i++) { + const e = edges[i] + if(graph[i] == null) graph[i] = new Set() + if(e !== -1) graph[i].add(e) + } + + const dis1 = bfs(node1), dis2 = bfs(node2) + // console.log(dis1, dis2) + let min = Infinity, res= -1 + + for(let i = 0; i < n; i++) { + const disa = dis1[i], disb = dis2[i] + if(disa !== Infinity && disb !== Infinity) { + const tmp = Math.min(min, Math.max(disa, disb)) + if(tmp < min) { + res = i + min = tmp + } + } + + } + + return res + + function bfs(node) { + const dis1 = Array(n).fill(Infinity) + dis1[node] = 0 + const visited = new Set() + visited.add(node) + let q = [node], dis = 0 + + while(q.length) { + const size = q.length + const nxt = [] + dis++ + for(let i = 0; i < size; i++) { + const cur = q[i] + const tmp = graph[cur] + if(tmp) { + for(const e of tmp) { + if(visited.has(e)) continue + nxt.push(e) + visited.add(e) + dis1[e] = dis + } + } + } + q = nxt + } + return dis1 + } + +}; diff --git a/236-lowest-common-ancestor-of-a-binary-tree.js b/236-lowest-common-ancestor-of-a-binary-tree.js index 002557fa..c0b40692 100644 --- a/236-lowest-common-ancestor-of-a-binary-tree.js +++ b/236-lowest-common-ancestor-of-a-binary-tree.js @@ -55,3 +55,26 @@ const lowestCommonAncestor = function(root, p, q) { if(left && right) return root; return left ? left : right; }; + +// another + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ +const lowestCommonAncestor = function(root, p, q) { + if(root == null || root === p || root === q) return root + const left = lowestCommonAncestor(root.left, p, q) + const right = lowestCommonAncestor(root.right, p, q) + if(left && right) return root + return left || right +}; diff --git a/2360-longest-cycle-in-a-graph.js b/2360-longest-cycle-in-a-graph.js new file mode 100644 index 00000000..32eed7a3 --- /dev/null +++ b/2360-longest-cycle-in-a-graph.js @@ -0,0 +1,82 @@ +/** + * @param {number[]} edges + * @return {number} + */ +const longestCycle = function(edges) { + const n = edges.length; + const visited = new Array(n).fill(false); + const ind = new Array(n).fill(0); + for (let i = 0; i < n; i++) { + if (edges[i] !== -1) { + ind[edges[i]]++; + } + } + let q = [] + for(let i = 0; i < n; i++) { + if (ind[i] === 0) { + q.push(i); + } + } + while(q.length) { + const node = q.pop() + visited[node] = true; + const nxt = edges[node]; + if(nxt !== -1) { + ind[nxt]--; + if (ind[nxt] === 0) { + q.push(nxt); + } + } + } + let res = -1 + for(let i = 0; i < n; i++) { + if (!visited[i]) { + let cnt = 0 + let cur = i + while (!visited[cur]) { + visited[cur] = true + cur = edges[cur] + cnt++ + } + res = Math.max(res, cnt) + } + } + + return res +}; + +// another + +/** + * @param {number[]} edges + * @return {number} + */ +const longestCycle = function(edges) { + const n = edges.length, colors = Array(n).fill(0), dis = Array(n).fill(0) + let res = -1 + + for(let i = 0; i < n; i++) { + if(colors[i] === 0) { + res = Math.max(res, dfs(i, 0)) + } + } + + return res + + function dfs(u, d) { + let ans = -1 + dis[u] = d + colors[u] = 1 + + if(edges[u] !== -1) { + if(colors[edges[u]] == 1) { + return dis[u] - dis[edges[u]] + 1 + } else if(colors[edges[u]] === 0) { + ans = Math.max(ans, dfs(edges[u], d + 1)) + } + } + + colors[u] = 2 + return ans + } +}; diff --git a/2365-task-scheduler-ii.js b/2365-task-scheduler-ii.js new file mode 100644 index 00000000..28b9371c --- /dev/null +++ b/2365-task-scheduler-ii.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} tasks + * @param {number} space + * @return {number} + */ +const taskSchedulerII = function(tasks, space) { + const last = new Map();; + let res = 0; + for (const a of tasks) + if (last.has(a)) { + res = Math.max(res, last.get(a) + space) + 1 + last.set(a, res); + } else { + res++ + last.set(a, res); + } + return res; +}; diff --git a/2366-minimum-replacements-to-sort-the-array.js b/2366-minimum-replacements-to-sort-the-array.js new file mode 100644 index 00000000..70d9854d --- /dev/null +++ b/2366-minimum-replacements-to-sort-the-array.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumReplacement = function(nums) { + const n = nums.length + let prev = nums[n - 1];; + let ans = 0; + for(let i = n - 2; i >= 0; i--){ + let noOfTime = ~~(nums[i] / prev); + if((nums[i]) % prev != 0){ + noOfTime++; + prev = ~~(nums[i] / noOfTime); + } + ans += noOfTime - 1; + } + return ans; +}; diff --git a/2367-count-number-of-bad-pairs.js b/2367-count-number-of-bad-pairs.js new file mode 100644 index 00000000..f7c8997d --- /dev/null +++ b/2367-count-number-of-bad-pairs.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const countBadPairs = function (nums) { + let cnt = 0 + const n = nums.length + const mp = {} + for (let i = 0; i < n; i++) { + const prev = mp[i - nums[i]] || 0 + cnt += prev + mp[i - nums[i]] = prev + 1 + } + return (n * (n - 1)) / 2 - cnt +} diff --git a/2367-number-of-arithmetic-triplets.js b/2367-number-of-arithmetic-triplets.js new file mode 100644 index 00000000..bbfec1db --- /dev/null +++ b/2367-number-of-arithmetic-triplets.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @param {number} diff + * @return {number} + */ +var arithmeticTriplets = function(nums, diff) { + let res = 0 + const n = nums.length + for(let i = 0;i < n - 2; i++) { + for(let j = i + 1; j < n - 1; j++) { + for(let k = j + 1; k < n; k++) { + if(nums[j] - nums[i] === diff && nums[k] - nums[j] === diff) { + res++ + } + } + } + } + return res +}; diff --git a/2368-reachable-nodes-with-restrictions.js b/2368-reachable-nodes-with-restrictions.js new file mode 100644 index 00000000..2cdc408f --- /dev/null +++ b/2368-reachable-nodes-with-restrictions.js @@ -0,0 +1,41 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} restricted + * @return {number} + */ +const reachableNodes = function(n, edges, restricted) { + const graph = {} + for(const [u, v] of edges) { + if(graph[u] == null) graph[u] = new Set() + if(graph[v] == null) graph[v] = new Set() + graph[u].add(v) + graph[v].add(u) + } + const forbid = new Set(restricted) + const visited = new Set() + let res = 0 + let q = [] + if(!forbid.has(0)) q.push(0) + visited.add(0) + while(q.length) { + const size = q.length + const tmp = [] + for(let i = 0; i < size; i++) { + const cur = q[i] + res++ + for(const e of (graph[cur] || [])) { + if(!forbid.has(e) && !visited.has(e)) { + tmp.push(e) + visited.add(e) + } + } + + } + + q = tmp + } + + + return res +}; diff --git a/2369-check-if-there-is-a-valid-partition-for-the-array.js b/2369-check-if-there-is-a-valid-partition-for-the-array.js new file mode 100644 index 00000000..bd17e045 --- /dev/null +++ b/2369-check-if-there-is-a-valid-partition-for-the-array.js @@ -0,0 +1,51 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +var validPartition = function(nums) { + const n = nums.length + const memo = {} + function dfs(i, cur) { + // console.log(i,cur) + if(i === n) { + if(chk1(cur) || chk2(cur) || chk3(cur) || cur.length === 0) return true + return false + } + const k = `${i}_${cur.join(',')}` + if(memo[k] != null) return memo[k] + let res + if(cur.length === 0) { + cur.push(nums[i]) + res = dfs(i + 1, cur) + } else if(cur.length === 1) { + cur.push(nums[i]) + res = dfs(i + 1, cur) + } else if(cur.length === 2) { + let r1 = false + if(chk1(cur)) { + r1 = dfs(i + 1, [nums[i]]) + } + cur.push(nums[i]) + let r2 = dfs(i + 1, cur) + res = r1 || r2 + } else if(cur.length === 3) { + if(chk2(cur) || chk3(cur)) { + res = dfs(i + 1, [nums[i]]) + }else res = false + } + memo[k] = res + return res + } + + return dfs(0, []) + + function chk1(arr) { + return arr.length === 2 && arr[0] === arr[1] + } + function chk2(arr) { + return arr.length === 3 && arr[0] === arr[1] && arr[2] === arr[1] + } + function chk3(arr) { + return arr.length === 3 && arr[1] - arr[0] === 1 && arr[2] - arr[1] === 1 + } +}; diff --git a/2370-longest-ideal-subsequence.js b/2370-longest-ideal-subsequence.js new file mode 100644 index 00000000..b9f66ca6 --- /dev/null +++ b/2370-longest-ideal-subsequence.js @@ -0,0 +1,50 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const longestIdealString = function(s, k) { + const n = s.length, a = 'a'.charCodeAt(0) + const dp = Array(26).fill(0) + let res = 0 + + for(let i = 0; i < n; i++) { + const cur = s[i], curCode = cur.charCodeAt(0) + const tmp = helper(curCode - a) + 1 + dp[curCode - a] = tmp + res = Math.max(res, tmp) + } + // console.log(dp) + return res + + function helper(end) { + let res = 0 + for(let i = Math.max(0, end - k), e = Math.min(25, end + k); i <= e; i++) { + if(dp[i] > res) res = dp[i] + } + + return res + } +}; + + +// another + +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const longestIdealString = function(s, k) { + const n = s.length + const arr = [], a = 'a'.charCodeAt(0) + for(const ch of s) { + arr.push(ch.charCodeAt(0) - a) + } + const dp = Array(26).fill(0) + for(const e of arr) { + dp[e] = 1 + Math.max(...dp.slice(Math.max(0, e - k), e + k + 1)) + } + return Math.max(...dp) +}; + diff --git a/2372-calculate-the-influence-of-each-salesperson.sql b/2372-calculate-the-influence-of-each-salesperson.sql new file mode 100644 index 00000000..5ff847f0 --- /dev/null +++ b/2372-calculate-the-influence-of-each-salesperson.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +SELECT + sp.salesperson_id, + name, + SUM(IF(price IS NULL, 0, price)) AS total +FROM Salesperson sp +LEFT JOIN Customer c ON sp.salesperson_id = c.salesperson_id +LEFT JOIN Sales s ON c.customer_id = s.customer_id +GROUP BY sp.salesperson_id, name diff --git a/2373-largest-local-values-in-a-matrix.js b/2373-largest-local-values-in-a-matrix.js new file mode 100644 index 00000000..59874826 --- /dev/null +++ b/2373-largest-local-values-in-a-matrix.js @@ -0,0 +1,29 @@ +/** + * @param {number[][]} grid + * @return {number[][]} + */ +var largestLocal = function(grid) { + const n = grid.length + const res = Array.from({ length: n - 2 }, () => Array(n - 2).fill(0)) + + for(let i = 0; i < n - 2; i++) { + for(let j = 0; j < n - 2; j++) { + res[i][j] = helper(i, j) + } + } + + return res + + function helper(i, j) { + let res = 0 + for(let ii = i; ii < 3 + i; ii++) { + for(let jj = j; jj < 3 + j; jj++) { + if(grid[ii][jj] > res) { + res = grid[ii][jj] + } + } + } + + return res + } +}; diff --git a/2374-node-with-highest-edge-score.js b/2374-node-with-highest-edge-score.js new file mode 100644 index 00000000..41b5d73a --- /dev/null +++ b/2374-node-with-highest-edge-score.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} edges + * @return {number} + */ +var edgeScore = function(edges) { + const n = edges.length + const score = Array(n).fill(0) + for(let i = 0; i < n; i++) { + const from = i, to = edges[i] + score[to] += from + } + const max = Math.max(...score) + for(let i = 0; i < n; i++) { + const e = score[i] + if(e === max) return i + } +}; diff --git a/2375-construct-smallest-number-from-di-string.js b/2375-construct-smallest-number-from-di-string.js new file mode 100644 index 00000000..425f2116 --- /dev/null +++ b/2375-construct-smallest-number-from-di-string.js @@ -0,0 +1,39 @@ +/** + * @param {string} pattern + * @return {string} + */ +var smallestNumber = function(pattern) { + const n = pattern.length + let res = '' + dfs('', new Set()) + + return res + + function dfs(str, set) { + if(str.length === n + 1) { + if(valid(str)) { + if(res === '') res = str + else if(str < res) res = str + } + return + } + + for(let i = 1; i <= 9; i++) { + if(set.has(i)) continue + set.add(i) + dfs(str + i, set) + set.delete(i) + } + + } + + + function valid(str) { + for(let i = 0; i < n; i++) { + if(pattern[i] === 'I' && str[i] >= str[i + 1]) return false + if(pattern[i] === 'D' && str[i] <= str[i + 1]) return false + } + + return true + } +}; diff --git a/2376-count-special-integers.js b/2376-count-special-integers.js new file mode 100644 index 00000000..af386f2f --- /dev/null +++ b/2376-count-special-integers.js @@ -0,0 +1,116 @@ +/** + * @param {number} n + * @return {number} + */ +var countSpecialNumbers = function(n) { + const L = []; + for (let x = n + 1; x > 0; x = Math.floor(x / 10)) L.unshift(x % 10); + + // Count the number with digits < N + let res = 0, + limit = L.length; + for (let i = 1; i < limit; ++i) res += 9 * A(9, i - 1); + + const seen = new Set(); + for (let i = 0; i < limit; ++i) { + for (let j = i > 0 ? 0 : 1; j < L[i]; ++j) + if (!seen.has(j)) res += A(9 - i, limit - i - 1); + if (seen.has(L[i])) break; + seen.add(L[i]); + } + return res; +}; + + +function A(m, n) { + return n === 0 ? 1 : A(m, n - 1) * (m - n + 1); +} + +// another + +/** + * @param {number} n + * @return {number} + */ +const countSpecialNumbers = function (n) { + const s = '' + n + const dp = Array.from({ length: 11 }, () => + Array.from({ length: 2 }, () => Array(1024).fill(-1)) + ) + + return helper(0, 1, 0, s) + function helper(idx, tight = 1, mask = 0, digits) { + if (idx == digits.length) return mask !== 0 ? 1 : 0 + + if (dp[idx][tight][mask] != -1) return dp[idx][tight][mask] + + let k = tight ? +digits[idx] : 9 + let ans = 0 + + for (let i = 0; i <= k; i++) { + if (mask & (1 << i)) continue + let newMask = mask == 0 && i == 0 ? mask : mask | (1 << i) + + let nextTight = tight && i == digits[idx] ? 1 : 0 + ans += helper(idx + 1, nextTight, newMask, digits) + } + + return (dp[idx][tight][mask] = ans) + } +} + +// another + +const dp = Array.from({ length: 11 }, () => + Array.from({ length: 2 }, () => Array(1024).fill(-1)), +) + +function gogo(s, tight = 1, pos = 0, mask = 0) { + // Base case + if (pos === s.length) { + // Mask = 0, represents 00000...0 which should not be counted + return mask !== 0 + } + + // DP state + if (dp[pos][tight][mask] !== -1) { + return dp[pos][tight][mask] + } + + let ans = 0 + + if (tight === 1) { + // Limit the current digit + for (let i = 0; i <= s[pos] - '0'; i++) { + // Check if digit repeated, ie, present in the mask + if (mask & (1 << i)) continue + + const newMask = mask === 0 && i === 0 ? mask : mask | (1 << i) + + if (i === s[pos] - '0') { + // Tight case + ans += gogo(s, 1, pos + 1, newMask) + } else { + ans += gogo(s, 0, pos + 1, newMask) + } + } + } else { + for (let i = 0; i <= 9; i++) { + // Check if digit repeated, ie, present in the mask + if (mask & (1 << i)) continue + + const newMask = mask === 0 && i === 0 ? mask : mask | (1 << i) + ans += gogo(s, 0, pos + 1, newMask) + } + } + return (dp[pos][tight][mask] = ans) +} +/** + * @param {number} n + * @return {number} + */ +var countSpecialNumbers = function (n) { + const s = n.toString() + dp.forEach((arr) => arr.forEach((innerArr) => innerArr.fill(-1))) + return gogo(s) +} diff --git a/238-product-of-array-except-self.js b/238-product-of-array-except-self.js index ded9a69a..ccf2aa3e 100755 --- a/238-product-of-array-except-self.js +++ b/238-product-of-array-except-self.js @@ -3,10 +3,10 @@ * @return {number[]} */ const productExceptSelf = function(nums) { - let zeroIdxArr = []; + const zeroIdx = new Set(); const p = nums.reduce((ac, el, idx) => { if (el === 0) { - zeroIdxArr.push(idx); + zeroIdx.add(idx); return ac; } else { return ac * el; @@ -14,13 +14,14 @@ const productExceptSelf = function(nums) { }, 1); const res = []; for (let i = 0; i < nums.length; i++) { - if (zeroIdxArr.length > 1) { + if (zeroIdx.size > 1) { res.push(0); - } else if (zeroIdxArr.length === 1) { - res.push(i === zeroIdxArr[0] ? p : 0); + } else if (zeroIdx.size === 1) { + res.push(i === [...zeroIdx.values()][0] ? p : 0); } else { res.push(p / nums[i]); } } return res; }; + diff --git a/2380-time-needed-to-rearrange-a-binary-string.js b/2380-time-needed-to-rearrange-a-binary-string.js new file mode 100644 index 00000000..08f3cfc3 --- /dev/null +++ b/2380-time-needed-to-rearrange-a-binary-string.js @@ -0,0 +1,35 @@ +/** + * @param {string} s + * @return {number} + */ +const secondsToRemoveOccurrences = function(s) { + let zeros = 0 + const n = s.length, { max } = Math + let res = 0 + + for(let i = 0; i < n; i++) { + if(s[i] === '0') zeros++ + if(s[i] === '1' && zeros > 0) { + res = max(res + 1, zeros) + } + } + return res +}; + +// another + + +/** + * @param {string} s + * @return {number} + */ +var secondsToRemoveOccurrences = function(s) { + const n = s.length + let zeros = 0, seconds = 0; + for (let i = 0; i < n; ++i) { + zeros += s.charAt(i) == '0' ? 1 : 0; + if (s.charAt(i) == '1' && zeros > 0) + seconds = Math.max(seconds + 1, zeros); + } + return seconds; +}; diff --git a/2381-shifting-letters-ii.js b/2381-shifting-letters-ii.js new file mode 100644 index 00000000..630d5b58 --- /dev/null +++ b/2381-shifting-letters-ii.js @@ -0,0 +1,26 @@ +/** + * @param {string} s + * @param {number[][]} shifts + * @return {string} + */ +const shiftingLetters = function(s, shifts) { + const n = s.length + const arr = Array(n + 1).fill(0) + const a = 'a'.charCodeAt(0) + const chToCode = ch => ch.charCodeAt(0) + const codeToCh = code => String.fromCharCode(code) + for(const [s, e, d] of shifts) { + const delta = d === 1 ? 1 : -1 + arr[s] += delta + arr[e + 1] -= delta + } + for(let i = 1; i < n + 1; i++) { + arr[i] = arr[i - 1] + arr[i] + } + const codes = s.split('').map(e => chToCode(e)) + for(let i = 0; i < n; i++) { + codes[i] += arr[i] + codes[i] = a + (codes[i] - a + 26 * n) % 26 + } + return codes.map(c => codeToCh(c)).join('') +}; diff --git a/2382-maximum-segment-sum-after-removals.js b/2382-maximum-segment-sum-after-removals.js new file mode 100644 index 00000000..6ce1bf3e --- /dev/null +++ b/2382-maximum-segment-sum-after-removals.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @param {number[]} removeQueries + * @return {number[]} + */ +const maximumSegmentSum = function(nums, removeQueries) { + removeQueries.reverse() + const rev = removeQueries + const hash = {} + const res = [] + let cur = 0 + for(const idx of rev) { + hash[idx] = [nums[idx], 1] + const [lv, ll] = (hash[idx - 1] || [0, 0]) + const [rv, rl] = (hash[idx + 1] || [0, 0]) + + const val = nums[idx] + lv + rv + hash[idx + rl] = [val, ll + rl + 1] + hash[idx - ll] = [val, ll + rl + 1] + + cur = Math.max(cur, val) + res.push(cur) + } + res.pop() + res.reverse() + res.push(0) + + return res +}; + diff --git a/2383-minimum-hours-of-training-to-win-a-competition.js b/2383-minimum-hours-of-training-to-win-a-competition.js new file mode 100644 index 00000000..120f96bd --- /dev/null +++ b/2383-minimum-hours-of-training-to-win-a-competition.js @@ -0,0 +1,27 @@ +/** + * @param {number} initialEnergy + * @param {number} initialExperience + * @param {number[]} energy + * @param {number[]} experience + * @return {number} + */ +const minNumberOfHours = function(initialEnergy, initialExperience, energy, experience) { + let hours = 0 + + for(let i = 0; i < energy.length; i++) { + if (initialEnergy > energy[i]) { + initialEnergy -= energy[i] + } else { + hours += energy[i] - initialEnergy + 1 + initialEnergy = 1 + } + + if (initialExperience <= experience[i]) { + hours += experience[i] - initialExperience + 1 + initialExperience += experience[i] - initialExperience + 1 + } + + initialExperience += experience[i] + } + return hours +}; diff --git a/2384-largest-palindromic-number.js b/2384-largest-palindromic-number.js new file mode 100644 index 00000000..fcf5da00 --- /dev/null +++ b/2384-largest-palindromic-number.js @@ -0,0 +1,36 @@ +/** + * @param {string} num + * @return {string} + */ +const largestPalindromic = function(num) { + let cnt = new Array(10).fill(0); + for (let i = 0; i < num.length; i++) { + let c = +num[i]; + cnt[c]++; + } + + let list = []; + for (let i = 9; i >= 0; i--) { + if (i == 0 && list.length == 0) { + break; + } + while (cnt[i] >= 2) { + list.push(i); + cnt[i] -= 2; + } + } + let sb = ''; + for (let n of list) { + sb += n; + } + for (let i = 9; i >= 0; i--) { + if (cnt[i] > 0) { + sb += i; + break; + } + } + for (let i = list.length - 1; i >= 0; i--) { + sb += list[i]; + } + return sb; +}; diff --git a/2385-amount-of-time-for-binary-tree-to-be-infected.js b/2385-amount-of-time-for-binary-tree-to-be-infected.js new file mode 100644 index 00000000..0b8b48a1 --- /dev/null +++ b/2385-amount-of-time-for-binary-tree-to-be-infected.js @@ -0,0 +1,58 @@ +/** + * 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 + * @param {number} start + * @return {number} + */ +var amountOfTime = function(root, start) { + const graph = new Map() + dfs(root) + + // console.log(graph) + const visited = new Set([start]) + let q = [start] + let res = 0 + while(q.length) { + const tmp = [] + const size = q.length + // console.log(q) + for(let i = 0; i < size; i++) { + const cur = q[i] + for(const nxt of (graph.get(cur) || [])) { + if(visited.has(nxt)) continue + tmp.push(nxt) + visited.add(nxt) + } + } + + q = tmp + res++ + } + + return res - 1 + + function dfs(node) { + if(node == null) return + if(node.left) { + if(!graph.has(node.left.val)) graph.set(node.left.val, new Set()) + if(!graph.has(node.val)) graph.set(node.val, new Set()) + graph.get(node.val).add(node.left.val) + graph.get(node.left.val).add(node.val) + dfs(node.left) + } + if(node.right) { + if(!graph.has(node.right.val)) graph.set(node.right.val, new Set()) + if(!graph.has(node.val)) graph.set(node.val, new Set()) + graph.get(node.val).add(node.right.val) + graph.get(node.right.val).add(node.val) + dfs(node.right) + } + } +}; diff --git a/2386-find-the-k-sum-of-an-array.js b/2386-find-the-k-sum-of-an-array.js new file mode 100644 index 00000000..491ad86b --- /dev/null +++ b/2386-find-the-k-sum-of-an-array.js @@ -0,0 +1,125 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var kSum = function(nums, k) { + let sum = 0, n = nums.length, pq = new MaxPriorityQueue({ compare: (x, y) => y[0] - x[0] }); + for (let i = 0; i < n; i++) { + if (nums[i] < 0) { + nums[i] *= -1; + } else { + sum += nums[i]; + } + } + if (k == 1) return sum; + nums.sort((x, y) => x - y); + pq.enqueue([sum - nums[0], 0]); + for (let i = 2; i < k; i++) { + let [x, idx] = pq.dequeue(); + if (idx + 1 < n) { + pq.enqueue([x + nums[idx] - nums[idx + 1], idx + 1]); + pq.enqueue([x - nums[idx + 1], idx + 1]); + } + } + return pq.front()[0]; +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const kSum = function (nums, k) { + let sum = 0, + n = nums.length, + pq = new PriorityQueue((x, y) => y[0] < x[0]) + for (let i = 0; i < n; i++) { + if (nums[i] < 0) { + nums[i] *= -1 + } else { + sum += nums[i] + } + } + if (k == 1) return sum + nums.sort((x, y) => x - y) + pq.push([sum - nums[0], 0]) + for (let i = 2; i < k; i++) { + let [x, idx] = pq.pop() + if (idx + 1 < n) { + pq.push([x + nums[idx] - nums[idx + 1], idx + 1]) + pq.push([x - nums[idx + 1], idx + 1]) + } + } + return pq.peek()[0] +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2389-longest-subsequence-with-limited-sum.js b/2389-longest-subsequence-with-limited-sum.js new file mode 100644 index 00000000..def2fdd4 --- /dev/null +++ b/2389-longest-subsequence-with-limited-sum.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @param {number[]} queries + * @return {number[]} + */ +var answerQueries = function(nums, queries) { + const n = nums, m = queries.length + const arr = Array(n).fill(0) + nums.sort((a, b) => a - b) + + const res = [] + for(const e of queries) { + let sum = 0, i = 0 + while(sum <= e) { + sum += nums[i] + i++ + } + res.push(i===0? 0 :i - 1) + } + + return res +}; diff --git a/239-sliding-window-maximum.js b/239-sliding-window-maximum.js index e34610a7..3fdf50a4 100644 --- a/239-sliding-window-maximum.js +++ b/239-sliding-window-maximum.js @@ -4,24 +4,89 @@ * @return {number[]} */ const maxSlidingWindow = function(nums, k) { - let n = nums.length - if (n === 0) { - return nums - } - let result = [] - - let dq = [] - for (let i = 0; i < n; i++) { - if (dq.length && dq[0] < i - k + 1) { - dq.shift() + const n = nums.length + const stk = [] + const res = [] + + for(let i = 0; i < n; i++) { + while(stk.length && stk[0] < i - k + 1) { + stk.shift() } - while (dq.length && nums[i] >= nums[dq[dq.length - 1]]) { - dq.pop() + while(stk.length && nums[stk[stk.length - 1]] <= nums[i]) { + stk.pop() } - dq.push(i) - if (i - k + 1 >= 0) { - result[i - k + 1] = nums[dq[0]] + stk.push(i) + if(i >= k - 1) { + res.push(nums[stk[0]]) } } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +var maxSlidingWindow = function (nums, k) { + if (k === 0) return [] + const deque = new Deque() + for (let i = 0; i < k - 1; i++) { + while (!deque.isEmpty() && deque.last().val <= nums[i]) deque.pop() + deque.enqueue({ val: nums[i], idx: i }) + } + const result = [] + for (let i = k - 1; i < nums.length; i++) { + if (!deque.isEmpty() && deque.first().idx <= i - k) deque.dequeue() + while (!deque.isEmpty() && deque.last().val <= nums[i]) deque.pop() + deque.enqueue({ val: nums[i], idx: i }) + result.push(deque.first().val) + } return result } + +class Deque { + constructor() { + this.head = new Node() + this.tail = this.head + } + + isEmpty() { + return this.head.next === null + } + + first() { + return this.head.next.value + } + + last() { + return this.tail.value + } + + dequeue() { + this.head = this.head.next + this.head.prev = null + } + + enqueue(value) { + this.tail.next = new Node(value) + this.tail.next.prev = this.tail + this.tail = this.tail.next + } + + pop() { + this.tail = this.tail.prev + this.tail.next = null + } +} + +class Node { + constructor(value) { + this.value = value + this.next = null + this.prev = null + } +} diff --git a/2390-removing-stars-from-a-string.js b/2390-removing-stars-from-a-string.js new file mode 100644 index 00000000..f79f8abf --- /dev/null +++ b/2390-removing-stars-from-a-string.js @@ -0,0 +1,14 @@ +/** + * @param {string} s + * @return {string} + */ +var removeStars = function(s) { + const stk = [] + for(const e of s) { + if(e !== '*') stk.push(e) + else { + stk.pop() + } + } + return stk.join('') +}; diff --git a/2391-minimum-amount-of-time-to-collect-garbage.js b/2391-minimum-amount-of-time-to-collect-garbage.js new file mode 100644 index 00000000..153f1846 --- /dev/null +++ b/2391-minimum-amount-of-time-to-collect-garbage.js @@ -0,0 +1,35 @@ +/** + * @param {string[]} garbage + * @param {number[]} travel + * @return {number} + */ +const garbageCollection = function(garbage, travel) { + let res1 = 0, res2 = 0, res3 = 0 + const n = garbage.length + // P + res1 = helper('P') + res2 = helper('M') + res3 = helper('G') + return res1 + res2 + res3 + + function helper(target) { + const arr = [] + for(let i = 0; i < n; i++) { + const str = garbage[i] + for(const e of str) { + if(e === target) arr.push(e) + } + if(i + 1 < n) arr.push(travel[i]) + } + const idx = arr.indexOf(target) + const lastIdx =arr.lastIndexOf(target) + let tmp = 0 + // console.log(arr, idx, lastIdx) + for(let i = 0; i >= 0 && i<=lastIdx; i++) { + const e = arr[i] + if(e === target) tmp += 1 + else tmp += e + } + return tmp + } +}; diff --git a/2392-build-a-matrix-with-conditions.js b/2392-build-a-matrix-with-conditions.js new file mode 100644 index 00000000..a18b14d3 --- /dev/null +++ b/2392-build-a-matrix-with-conditions.js @@ -0,0 +1,196 @@ +/** + * @param {number} k + * @param {number[][]} rowConditions + * @param {number[][]} colConditions + * @return {number[][]} + */ +const buildMatrix = function(k, rowConditions, colConditions) { + const col = topo(k, colConditions); + const row = topo(k, rowConditions); + if(col.length === 0 || row.length === 0) return [] + + const res = Array.from({length: k}, () => Array.from({length: k}, () => 0)); + const colHash = {}, rowHash = {}; + for(let i = 0; i < k; i++) { + colHash[col[i]] = i; + rowHash[row[i]] = i; + } + for(let i = 1; i <= k; i++) { + res[rowHash[i]][colHash[i]] = i + } + + return res + + function topo(k, conditions) { + const n = conditions.length; + const ind = new Array(k + 1).fill(0); + const adj = Array.from({length: k + 1}, () => []); + for(let i = 0; i < n; i++) { + const [a, b] = conditions[i]; + adj[a].push(b); + ind[b]++; + } + // console.log(adj, ind) + let q = [] + for(let i = 1; i <= k; i++) { + if (ind[i] === 0) { + q.push(i); + } + } + const res = [] + + while(q.length) { + const size = q.length + const tmp = [] + for(let i = 0; i < size; i++) { + + const node = q[i] + res.push(node) + for(const nxt of adj[node]) { + ind[nxt]--; + if (ind[nxt] === 0) { + tmp.push(nxt); + } + } + } + q = tmp + } + // console.log(res) + if(res.length !== k) return [] + return res + } +}; + +// another + + +/** + * @param {number} k + * @param {number[][]} rowConditions + * @param {number[][]} colConditions + * @return {number[][]} + */ +const buildMatrix = function (k, rowConditions, colConditions) { + const res = Array.from({ length: k }, () => Array(k).fill(0)) + + const row = khansAlgo(rowConditions, k) + if (row.length != k) return [] + + const col = khansAlgo(colConditions, k) + if (col.length != k) return [] + + const idx = Array(k + 1).fill(0) + for (let j = 0; j < col.length; j++) { + idx[col[j]] = j + } + for (let i = 0; i < k; i++) { + res[i][idx[row[i]]] = row[i] + } + return res + + function khansAlgo(r, k) { + const indegree = Array(k + 1).fill(0) + const adj = Array.from({ length: k + 1 }, () => Array()) + + for (let x of r) { + indegree[x[1]]++ + adj[x[0]].push(x[1]) + } + const row = [] + const q = [] + for (let i = 1; i <= k; i++) { + if (indegree[i] == 0) { + q.push(i) + } + } + while (q.length) { + let t = q.pop() + + row.push(t) + for (let x of adj[t] || []) { + indegree[x]-- + if (indegree[x] == 0) { + q.push(x) + } + } + } + return row + } +} + + + +// another + +/** + * @param {number} k + * @param {number[][]} rowConditions + * @param {number[][]} colConditions + * @return {number[][]} + */ +const initializeGraph = (n) => { + let g = [] + for (let i = 0; i < n; i++) { + g.push([]) + } + return g +} +const packDGInDegree = (g, edges, indegree) => { + for (const [u, v] of edges) { + g[u].unshift(v) + indegree[v]++ + } +} +const initialize2DArray = (n, m) => { + let d = [] + for (let i = 0; i < n; i++) { + let t = Array(m).fill(0) + d.push(t) + } + return d +} + +const buildMatrix = (k, rowConditions, colConditions) => { + let gr = make(k, rowConditions), + gc = make(k, colConditions), + d = initialize2DArray(k, 2), + res = initialize2DArray(k, k) + if (gr.length == 0 || gc.length == 0) return [] + for (let i = 0; i < k; i++) { + d[gr[i] - 1][0] = i + d[gc[i] - 1][1] = i + } + for (let i = 0; i < k; i++) { + let [x, y] = d[i] + res[x][y] = i + 1 + } + return res +} + +const make = (n, edges) => { + let g = initializeGraph(n + 1), + deg = Array(n + 1).fill(0) + packDGInDegree(g, edges, deg) + return topologicalSort_start_1(g, deg) +} + +const topologicalSort_start_1 = (g, indegree) => { + let res = [], + q = [], + n = g.length - 1 + for (let i = 1; i <= n; i++) { + if (indegree[i] == 0) q.push(i) + } + while (q.length) { + let cur = q.shift() + res.push(cur) + for (const child of g[cur]) { + indegree[child]-- + if (indegree[child] == 0) q.push(child) + } + } + for (let i = 1; i <= n; i++) { + if (indegree[i] > 0) return [] + } + return res +} diff --git a/2397-maximum-rows-covered-by-columns.js b/2397-maximum-rows-covered-by-columns.js new file mode 100644 index 00000000..8d2e4f5d --- /dev/null +++ b/2397-maximum-rows-covered-by-columns.js @@ -0,0 +1,38 @@ +/** + * @param {number[][]} matrix + * @param {number} numSelect + * @return {number} + */ +const maximumRows = function(matrix, numSelect) { + const m = matrix.length, n = matrix[0].length + const limit = 1 << n + + let res = 0 + + for(let mask = 1; mask < limit; mask++) { + if(bitCnt(mask) > numSelect) continue + let num = 0 + for(let i = 0; i < m; i++) { + let mark = true + for(let j = n - 1; j >= 0; j--) { + if(matrix[i][j] === 1 && (mask & (1 << j)) === 0) { + mark = false + break + } + } + if(mark) num++ + } + res = Math.max(res, num) + } + + return res + + function bitCnt(num) { + let res = 0 + while(num) { + num = num & (num - 1) + res++ + } + return res + } +}; diff --git a/2398-maximum-number-of-robots-within-budget.js b/2398-maximum-number-of-robots-within-budget.js new file mode 100644 index 00000000..9e33245e --- /dev/null +++ b/2398-maximum-number-of-robots-within-budget.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} chargeTimes + * @param {number[]} runningCosts + * @param {number} budget + * @return {number} + */ +const maximumRobots = function(chargeTimes, runningCosts, budget) { + const times = chargeTimes, costs = runningCosts + let sum = 0, res = 0, j = 0 + const q = [], n = times.length + for(let i = 0; i < n; i++) { + sum += costs[i] + while(q.length && times[q[q.length - 1]] <= times[i]) q.pop() + q.push(i) + + if(q.length && times[q[0]] + (i - j + 1) * sum > budget) { + if(q[0] === j) q.shift() + sum -= costs[j] + j++ + } + res = Math.max(res, i - j + 1) + } + + return res +}; + diff --git a/2399-check-distances-between-same-letters.js b/2399-check-distances-between-same-letters.js new file mode 100644 index 00000000..5c877a9b --- /dev/null +++ b/2399-check-distances-between-same-letters.js @@ -0,0 +1,21 @@ +/** + * @param {string} s + * @param {number[]} distance + * @return {boolean} + */ +var checkDistances = function(s, distance) { + const hash = {} + const a = 'a'.charCodeAt(0) + const n = s.length + for(let i = 0; i < n; i++) { + if(hash[s[i]] == null) hash[s[i]] = [] + hash[s[i]].push(i) + } + const keys = Object.keys(hash) + for(let i = 0; i < keys.length; i++) { + const k = keys[i] + const idx = k.charCodeAt(0) - a + if(hash[k][1] - hash[k][0] !== distance[idx] + 1) return false + } + return true +}; diff --git a/2400-number-of-ways-to-reach-a-position-after-exactly-k-steps.js b/2400-number-of-ways-to-reach-a-position-after-exactly-k-steps.js new file mode 100644 index 00000000..e11d1929 --- /dev/null +++ b/2400-number-of-ways-to-reach-a-position-after-exactly-k-steps.js @@ -0,0 +1,60 @@ +const dp = Array.from({ length: 1000 + 1 }, () => Array(1000 + 1).fill(0)) +const mod = 1e9 + 7 +/** + * @param {number} startPos + * @param {number} endPos + * @param {number} k + * @return {number} + */ +const numberOfWays = function(startPos, endPos, k) { + const { abs } = Math + if (dp[1][1] == 0) { + for (let k = 1; k <= 1000; ++k) { + dp[k][k] = 1; + for (let i = 0; i < k; ++i) { + dp[k][i] = ((i === 0 ? dp[k - 1][1] : dp[k - 1][i - 1]) + dp[k - 1][i + 1]) % mod; + } + } + } + + return dp[k][abs(startPos - endPos)]; +}; + +// another + +/** + * @param {number} startPos + * @param {number} endPos + * @param {number} k + * @return {number} + */ +var numberOfWays = function(startPos, endPos, k) { + const ll = BigInt, mod = ll(1e9 + 7), N = 1005; + + let fact, ifact, inv; + const comb_init = () => { + fact = Array(N).fill(0); + ifact = Array(N).fill(0); + inv = Array(N).fill(0); + fact[0] = ifact[0] = inv[1] = 1n; + for (let i = 2; i < N; i++) inv[i] = (mod - mod / ll(i)) * inv[mod % ll(i)] % mod; + for (let i = 1; i < N; i++) { + fact[i] = fact[i - 1] * ll(i) % mod; + ifact[i] = ifact[i - 1] * inv[i] % mod; + } + }; + + const comb = (n, k) => { + if (n < k || k < 0) return 0; + return fact[n] * ifact[k] % mod * ifact[n - k] % mod; + }; + + comb_init(); + let res = 0n; + for (let i = 0; i <= k; i++) { + let moveRight = i, moveLeft = k - i; + if (startPos + moveRight - moveLeft == endPos) res += comb(k, i); + } + return res; + +}; diff --git a/2401-longest-nice-subarray.js b/2401-longest-nice-subarray.js new file mode 100644 index 00000000..b6200957 --- /dev/null +++ b/2401-longest-nice-subarray.js @@ -0,0 +1,74 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const longestNiceSubarray = function (nums) { + const n = nums.length + let i = 0, mask = 0, res = 0 + for(let j = 0; j < n; j++) { + const e = nums[j] + while((mask & e) !== 0) { + mask ^= nums[i] + i++ + } + mask |= e + res = Math.max(res, j - i + 1) + } + return res +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const longestNiceSubarray = function (nums) { + let res = 1, i = 0, j = 0, mask = 0 + const n = nums.length + for(i = 0; i < n; i++) { + const cur = nums[i] + while((cur & mask) !== 0) { + mask ^= nums[j] + j++ + } + mask |= cur + // console.log(i, j, mask, i - j +1) + res = Math.max(res, i - j + 1) + } + + return res +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +var longestNiceSubarray = function(nums) { + let max = 1; + let stack = []; + for(let i =0;i a[1] === b[1] ? a[0] < b[0] : a[1] < b[1]) + const avail = new PQ((a, b) => a[0] < b[0]) + for(let i = 0; i < n; i++) { + avail.push([i, 0]) + } + meetings.sort((a, b) => a[0] - b[0]) + + for(let i = 0, len = meetings.length; i < len; i++) { + const [s, e] = meetings[i] + while(!busy.isEmpty() && busy.peek()[1] <= s) { + avail.push(busy.pop()) + } + if(!avail.isEmpty()) { + const r = avail.pop() + r[1] = e + rooms[r[0]]++ + busy.push(r) + } else { + const r = busy.pop() + r[1] += e - s + rooms[r[0]]++ + busy.push(r) + } + } + let res = 0 + // console.log(meetings.length, rooms) + const maxNum = Math.max(...rooms) + for(let i = 0; i < n; i++) { + if(rooms[i] === maxNum) { + res = i + break + } + } + return res +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number} n + * @param {number[][]} meetings + * @return {number} + */ +var mostBooked = function(n, meetings) { + const count = new Array(n).fill(0); + const freeTime = new Array(n).fill(0); + meetings.sort((a, b) => a[0] - b[0]); + for(let i = 0 ; i < meetings.length ; i++){ + let minRoom = -1; + let minTime = Number.MAX_SAFE_INTEGER; + for(let j = 0 ; j < n ; j++){ + if(freeTime[j] <= meetings[i][0]){ + count[j]++; + freeTime[j] = meetings[i][1]; + minRoom = -1; + break; + } + if(freeTime[j] < minTime){ + minTime = freeTime[j]; + minRoom = j; + } + } + if(minRoom !== -1){ + count[minRoom]++; + freeTime[minRoom] += meetings[i][1] - meetings[i][0]; + } + } + + let ans = 0; + let maxCount = count[0]; + for(let i = 1 ; i < n ; i++){ + if(count[i] > maxCount){ + ans = i; + maxCount = count[i]; + } + } + return ans; +}; diff --git a/2403-minimum-time-to-kill-all-monsters.js b/2403-minimum-time-to-kill-all-monsters.js new file mode 100644 index 00000000..b91a3541 --- /dev/null +++ b/2403-minimum-time-to-kill-all-monsters.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} power + * @return {number} + */ +const minimumTime = function(power) { + const n = power.length + const limit = 1 << n + const dp = new Array(limit).fill(Infinity) + dp[0] = 0 + for(let mask = 1; mask < limit; mask++) { + const k = cnt(mask) + for(let i = 0; i < n; i++) { + if((mask >> i) & 1) { + dp[mask] = Math.min(dp[mask], dp[mask - (1 << i)] + Math.ceil(power[i] / k) ) + } + } + } + // console.log(dp) + return dp[limit - 1] + + function cnt(num) { + let res = 0 + while(num) { + if(num & 1) res++ + num = num >> 1 + } + + return res + } +}; diff --git a/2404-most-frequent-even-element.js b/2404-most-frequent-even-element.js new file mode 100644 index 00000000..608206cd --- /dev/null +++ b/2404-most-frequent-even-element.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var mostFrequentEven = function(nums) { + const hash = {} + for(const e of nums) { + if(e % 2 === 0) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + } + const entries = Object.entries(hash) + if(entries.length === 0) return -1 + entries.sort((a, b) => b[1] - a[1]) + const v = entries[0][1] + const keys = Object.keys(hash).map(e => +e).sort((a, b) => a - b) +// console.log(hash) + for(const k of keys) { + if(hash[k] === v) return k + } + + return -1 +}; diff --git a/2405-optimal-partition-of-string.js b/2405-optimal-partition-of-string.js new file mode 100644 index 00000000..0faa98e7 --- /dev/null +++ b/2405-optimal-partition-of-string.js @@ -0,0 +1,22 @@ +/** + * @param {string} s + * @return {number} + */ +var partitionString = function(s) { + let res = 0, n = s.length + let i = 0, j = 0, num = 0 + const set = new Set() + for(let i = 0; i < n; i++) { + const ch = s[i] + if(set.has(ch)) { + res++ + num = 1 + set.clear() + } else { + + } + set.add(ch) + } + + return res + 1 +}; diff --git a/2406.divide-intervals-into-minimum-number-of-groups.js b/2406.divide-intervals-into-minimum-number-of-groups.js new file mode 100644 index 00000000..aaecb9aa --- /dev/null +++ b/2406.divide-intervals-into-minimum-number-of-groups.js @@ -0,0 +1,48 @@ +/** + * @param {number[][]} intervals + * @return {number} + */ +var minGroups = function(intervals) { + const hash = {} + for(let [s, e] of intervals) { + e = e + 1 + hash[s] = (hash[s] || 0) + 1 + hash[e] = (hash[e] || 0) - 1 + } + let res = 0, cur = 0 + const keys = Object.keys(hash).map(e => +e) + keys.sort((a, b) => a - b) + for(const k of keys) { + cur += hash[k] + res = Math.max(res, cur) + } + return res +}; + +// another + +/** + * @param {number[][]} intervals + * @return {number} + */ +const minGroups = function(intervals) { + const hash = {} + for(const [s, e] of intervals) { + if(hash[s] == null) hash[s] = 0 + if(hash[e + 1] == null) hash[e + 1] = 0 + hash[s]++ + hash[e + 1]-- + } + const keys = Object.keys(hash) + keys.sort((a, b) => a - b) + const n = keys.length + + const arr = Array(n).fill(0) + arr[0] = hash[keys[0]] + let res = arr[0] + for(let i = 1; i < n; i++) { + arr[i] = hash[keys[i]] + arr[i - 1] + res = Math.max(res, arr[i]) + } + return res +}; diff --git a/2407.longest-increasing-subsequence-ii.js b/2407.longest-increasing-subsequence-ii.js new file mode 100644 index 00000000..f84fe50b --- /dev/null +++ b/2407.longest-increasing-subsequence-ii.js @@ -0,0 +1,70 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const lengthOfLIS = (nums, k) => { + const a = nums + let max = Math.max(...a), st = new SegmentTreeRMQ(max + 3), res = 0; + for (const x of a) { + let l = Math.max(x-k, 0), r = x; + let min = st.minx(l, r), maxL = min == Number.MAX_SAFE_INTEGER ? 0 : -min; + maxL++; + res = Math.max(res, maxL); + st.update(x, -maxL); + } + return res; +}; +///////////////////////////////////////////// Template /////////////////////////////////////////////////////////// +// using array format +function SegmentTreeRMQ(n) { + let h = Math.ceil(Math.log2(n)), len = 2 * 2 ** h, a = Array(len).fill(Number.MAX_SAFE_INTEGER); + h = 2 ** h; + return { update, minx, indexOf, tree } + function update(pos, v) { + a[h + pos] = v; + for (let i = parent(h + pos); i >= 1; i = parent(i)) propagate(i); + } + function propagate(i) { + a[i] = Math.min(a[left(i)], a[right(i)]); + } + function minx(l, r) { + let min = Number.MAX_SAFE_INTEGER; + if (l >= r) return min; + l += h; + r += h; + for (; l < r; l = parent(l), r = parent(r)) { + if (l & 1) min = Math.min(min, a[l++]); + if (r & 1) min = Math.min(min, a[--r]); + } + return min; + } + function indexOf(l, v) { + if (l >= h) return -1; + let cur = h + l; + while (1) { + if (a[cur] <= v) { + if (cur >= h) return cur - h; + cur = left(cur); + } else { + cur++; + if ((cur & cur - 1) == 0) return -1; + if (cur % 2 == 0) cur = parent(cur); + } + } + } + function parent(i) { + return i >> 1; + } + function left(i) { + return 2 * i; + } + function right(i) { + return 2 * i + 1; + } + function tree() { + return a; + } +} +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/2411-smallest-subarrays-with-maximum-bitwise-or.js b/2411-smallest-subarrays-with-maximum-bitwise-or.js new file mode 100644 index 00000000..6f00bf51 --- /dev/null +++ b/2411-smallest-subarrays-with-maximum-bitwise-or.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const smallestSubarrays = function (nums) { + const n = nums.length, + last = Array(30).fill(0), + res = [] + for (let i = n - 1; i >= 0; i--) { + res[i] = 1 + for (let j = 0; j < 30; j++) { + if ((nums[i] & (1 << j)) > 0) last[j] = i + res[i] = Math.max(res[i], last[j] - i + 1) + } + } + return res +} diff --git a/2412-minimum-money-required-before-transactions.js b/2412-minimum-money-required-before-transactions.js new file mode 100644 index 00000000..42fcb831 --- /dev/null +++ b/2412-minimum-money-required-before-transactions.js @@ -0,0 +1,13 @@ +/** + * @param {number[][]} transactions + * @return {number} + */ +const minimumMoney = function(transactions) { + let res = 0; + let v = 0; + for (const a of transactions) { + v = Math.max(v, Math.min(a[0], a[1])); + res += Math.max(a[0] - a[1], 0); + } + return res + v; +}; diff --git a/2413-smallest-even-multiple.js b/2413-smallest-even-multiple.js new file mode 100644 index 00000000..fe2f27b0 --- /dev/null +++ b/2413-smallest-even-multiple.js @@ -0,0 +1,7 @@ +/** + * @param {number} n + * @return {number} + */ +var smallestEvenMultiple = function(n) { + return n % 2 === 0 ? n : 2 * n +}; diff --git a/2414-length-of-the-longest-alphabetical-continuous-substring.js b/2414-length-of-the-longest-alphabetical-continuous-substring.js new file mode 100644 index 00000000..6abbe1e4 --- /dev/null +++ b/2414-length-of-the-longest-alphabetical-continuous-substring.js @@ -0,0 +1,23 @@ +/** + * @param {string} s + * @return {number} + */ +var longestContinuousSubstring = function(s) { + let res = 1 + let tmp = 1 + const n = s.length + let pre = s[0] + for(let i = 1;i < n; i++) { + const ch = s[i] + if(ch.charCodeAt(0) - pre.charCodeAt(0) === 1) { + tmp++ + pre = ch + res = Math.max(res, tmp) + } else { + pre = ch + tmp = 1 + } + } + + return res +}; diff --git a/2415-reverse-odd-levels-of-binary-tree.js b/2415-reverse-odd-levels-of-binary-tree.js new file mode 100644 index 00000000..8a7e57e1 --- /dev/null +++ b/2415-reverse-odd-levels-of-binary-tree.js @@ -0,0 +1,40 @@ +/** + * 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 {TreeNode} + */ +var reverseOddLevels = function(root) { + + let q = [root] + let level = 0 + + while(q.length) { + const nxt = [] + for(let i = 0; i < q.length; i++) { + const cur = q[i] + if(cur.left) nxt.push(cur.left) + if(cur.right) nxt.push(cur.right) + } + if(level % 2 === 1) { + const arr = q.map(e => e.val) + arr.reverse() + for(let i = 0; i < q.length; i++) { + q[i].val = arr[i] + } + } + + level++ + q = nxt + } + + // dfs(root, 0) + return root + +}; diff --git a/2416-sum-of-prefix-scores-of-strings.js b/2416-sum-of-prefix-scores-of-strings.js new file mode 100644 index 00000000..b9b48503 --- /dev/null +++ b/2416-sum-of-prefix-scores-of-strings.js @@ -0,0 +1,135 @@ +/** + * @param {string[]} words + * @return {number[]} + */ +const sumPrefixScores = function(words) { + const root = new Node() + const n = words.length + for(const w of words) { + let cur = root + for(const ch of w) { + if(!cur.children.has(ch)) cur.children.set(ch, new Node()) + const node = cur.children.get(ch) + node.cnt++ + cur = node + } + } + + const res = [] + + for(const w of words) { + let cur = root + let tmp = 0 + for(const ch of w) { + if(cur.children.has(ch)) { + const node = cur.children.get(ch) + tmp += node.cnt + cur = node + } else break + } + res.push(tmp) + } + + return res +}; + +class Node { + constructor() { + this.children = new Map() + this.cnt = 0 + } +} + +// another + +/** + * @param {string[]} words + * @return {number[]} + */ +const sumPrefixScores = (words) => { + const n = words.length + const trie = { _count: 0 } + const result = [] + + // Create our own custom trie with _count property. + // We are storing how many time we passed current node. + for (let i = 0; i < n; i++) { + const word = words[i] + + let node = trie + for (let j = 0; j < word.length; j++) { + if (!node[word[j]]) node[word[j]] = {} + node = node[word[j]] + node._count = (node._count || 0) + 1 + } + } + + // Collect all _count values together as a result + for (let i = 0; i < n; i++) { + const word = words[i] + let count = 0 + + let node = trie + for (let j = 0; j < word.length; j++) { + node = node[word[j]] + count += node._count || 0 + } + + result[i] = count + } + + return result +} + +// another + +/** + * @param {string[]} words + * @return {number[]} + */ +const sumPrefixScores = function(words) { + let trie = new Trie(); + for (let word of words) { + trie.add(word); + } + + let n = words.length, res = Array(n); + for (let i = 0; i < words.length; i++) { + res[i] = trie.getScore(words[i]); + } + return res; +}; + +class TrieNode { + constructor() { + this.children = {}; + this.count = 0; + } +} + +class Trie { + constructor() { + this.root = new TrieNode(); + } + add(word) { + let node = this.root; + for (let i = 0; i < word.length; i++) { + node = node.children; + let char = word[i]; + if (!node[char]) node[char] = new TrieNode(); + node = node[char]; + node.count++; + } + } + getScore(word) { + let node = this.root, score = 0; + for (let i = 0; i < word.length; i++) { + node = node.children; + let char = word[i]; + if (!node[char]) return score; + node = node[char]; + score += node.count; + } + return score; + } +}; diff --git a/2418-sort-the-people.js b/2418-sort-the-people.js new file mode 100644 index 00000000..5eebafe6 --- /dev/null +++ b/2418-sort-the-people.js @@ -0,0 +1,16 @@ +/** + * @param {string[]} names + * @param {number[]} heights + * @return {string[]} + */ +var sortPeople = function(names, heights) { + const n = names.length + const arr = [] + for(let i = 0; i a[1] - b[1]) + arr.reverse() + return arr.map(e => e[0]) +}; diff --git a/2419-longest-subarray-with-maximum-bitwise-and.js b/2419-longest-subarray-with-maximum-bitwise-and.js new file mode 100644 index 00000000..9decbac8 --- /dev/null +++ b/2419-longest-subarray-with-maximum-bitwise-and.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const longestSubarray = function(nums) { + const max = Math.max(...nums) + const arr = [] + for(let i = 0; i < nums.length; i++) { + if(nums[i] === max) arr.push(i) + } + let res = 1, cur = 1 + for(let i = 1; i < arr.length; i++) { + if(arr[i] - arr[i - 1] === 1) cur++ + else { + cur = 1 + } + + res = Math.max(res, cur) + } + + return res +}; diff --git a/2420-find-all-good-indices.js b/2420-find-all-good-indices.js new file mode 100644 index 00000000..e2e4ded1 --- /dev/null +++ b/2420-find-all-good-indices.js @@ -0,0 +1,38 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +const goodIndices = function(nums, k) { + const n = nums.length + const pre = Array(n).fill(1), post = Array(n).fill(1) + + let preV = nums[0], cnt = 1 + for(let i = 1; i < n; i++) { + if(nums[i] <= preV) cnt++ + else { + cnt = 1 + } + pre[i] = cnt + preV = nums[i] + } + + preV = nums[n - 1], cnt = 1 + for(let i = n - 2; i >= 0; i--) { + if(nums[i] <= preV) cnt++ + else { + cnt = 1 + } + post[i] = cnt + preV = nums[i] + } + // console.log(pre, post) + + const res = [] + + for(let i = 1; i < n; i++) { + if(pre[i - 1] >= k && post[i + 1] >= k) res.push(i) + } + + return res +}; diff --git a/2421-number-of-good-paths.js b/2421-number-of-good-paths.js new file mode 100644 index 00000000..cffbdb15 --- /dev/null +++ b/2421-number-of-good-paths.js @@ -0,0 +1,63 @@ +/** + * @param {number[]} vals + * @param {number[][]} edges + * @return {number} + */ +const numberOfGoodPaths = function (vals, edges) { + const n = vals.length + let res = 0 + const adj = Array.from({ length: n }, () => []) + const sameValues = new Map() + const valWithIdx = vals.map((v, i) => [v, i]) + valWithIdx.sort((a, b) => a[0] - b[0]) + for (let i = 0; i < n; i++) { + const [val, idx] = valWithIdx[i] + if (sameValues.get(val) == null) sameValues.set(val, []) + sameValues.get(val).push(idx) + } + for (const e of edges) { + const [u, v] = e + if (vals[u] >= vals[v]) { + adj[u].push(v) + } else if (vals[v] >= vals[u]) { + adj[v].push(u) + } + } + const uf = new UF(n) + for (const [_, allNodes] of sameValues) { + for (let u of allNodes) { + for (const v of adj[u]) { + uf.union(u, v) + } + } + const group = {} + for (let u of allNodes) { + const uroot = uf.find(u) + if (group[uroot] == null) group[uroot] = 0 + group[uroot]++ + } + res += allNodes.length + for (let [_, size] of Object.entries(group)) { + res += (size * (size - 1)) / 2 + } + } + return res +} +class UF { + constructor(n) { + this.root = Array(n) + .fill(null) + .map((_, i) => i) + } + find(x) { + if (this.root[x] !== x) { + this.root[x] = this.find(this.root[x]) + } + return this.root[x] + } + union(x, y) { + const xr = this.find(x) + const yr = this.find(y) + this.root[yr] = xr + } +} diff --git a/2422-merge-operations-to-turn-array-into-a-palindrome.js b/2422-merge-operations-to-turn-array-into-a-palindrome.js new file mode 100644 index 00000000..cc6be2d3 --- /dev/null +++ b/2422-merge-operations-to-turn-array-into-a-palindrome.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumOperations = function(nums) { + const n = nums.length + let left = nums[0], right = nums[n - 1] + let cnt = 0; + for (let i = 0, j = n - 1; i < j;) { + if (left === right) { + i++; + j--; + left = nums[i]; + right = nums[j]; + } else if (left < right) { + i++; + left += nums[i]; + cnt++; + } else if (left > right) { + j--; + right += nums[j]; + cnt++; + } + } + return cnt; +}; diff --git a/2423-remove-letter-to-equalize-frequency.js b/2423-remove-letter-to-equalize-frequency.js new file mode 100644 index 00000000..57163f53 --- /dev/null +++ b/2423-remove-letter-to-equalize-frequency.js @@ -0,0 +1,23 @@ +/** + * @param {string} word + * @return {boolean} + */ +const equalFrequency = function (word) { + const cnt = {} + for(const ch of word) { + if(cnt[ch] == null) cnt[ch] = 0 + cnt[ch]++ + } + + for(const ch of word) { + cnt[ch]-- + if(cnt[ch] === 0) delete cnt[ch] + const s = new Set([...Object.values(cnt)]) + if(s.size === 1) return true + + if(cnt[ch] == null) cnt[ch] = 0 + cnt[ch]++ + } + + return false +} diff --git a/2426-number-of-pairs-satisfying-inequality.js b/2426-number-of-pairs-satisfying-inequality.js new file mode 100644 index 00000000..942eb56b --- /dev/null +++ b/2426-number-of-pairs-satisfying-inequality.js @@ -0,0 +1,46 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} diff + * @return {number} + */ +const numberOfPairs = function (nums1, nums2, diff) { + const n = nums1.length, limit = 6 * 1e4, add = 3 * 1e4 + const bit = new BIT(limit) + + let res = 0 + for(let j = 0; j < n; j++) { + const d = nums1[j] - nums2[j] + add + res += bit.query(d + diff) + bit.update(d, 1) + } + + return res +} + +function lowBit(x) { + return x & -x +} +class BIT { + constructor(n) { + this.arr = Array(n + 1).fill(0) + } + + update(i, delta) { + if(i < 1) return + while (i < this.arr.length) { + this.arr[i] += delta + i += lowBit(i) + } + } + + query(i) { + let res = 0 + if(i < 1) return res + while (i > 0) { + res += this.arr[i] + i -= lowBit(i) + } + return res + } +} diff --git a/2427-number-of-common-factors.js b/2427-number-of-common-factors.js new file mode 100644 index 00000000..162cba4a --- /dev/null +++ b/2427-number-of-common-factors.js @@ -0,0 +1,14 @@ +/** + * @param {number} a + * @param {number} b + * @return {number} + */ +var commonFactors = function(a, b) { + let res = 0 + const r = Math.max(a, b) + for(let i = 1; i <= r; i++) { + if(a % i === 0 && b % i === 0) res++ + } + + return res +}; diff --git a/2428-maximum-sum-of-an-hourglass.js b/2428-maximum-sum-of-an-hourglass.js new file mode 100644 index 00000000..41f63b48 --- /dev/null +++ b/2428-maximum-sum-of-an-hourglass.js @@ -0,0 +1,30 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var maxSum = function(grid) { + let res = 0 + const m = grid.length, n = grid[0].length + + for(let i = 0; i < m - 2; i++) { + for(let j = 0; j < n - 2; j++) { + res = Math.max(res, helper(i, j)) + } + } + + return res + + function helper(i, j) { + let sum = 0 + for(let r = i; r < i + 3; r++) { + for(let c = j; c < j + 3; c++) { + sum += grid[r][c] + } + } + sum -= grid[i + 1][j] + sum -= grid[i + 1][j + 2] + // console.log(sum) + + return sum + } +}; diff --git a/2429-minimize-xor.js b/2429-minimize-xor.js new file mode 100644 index 00000000..7677bf01 --- /dev/null +++ b/2429-minimize-xor.js @@ -0,0 +1,37 @@ +/** + * @param {number} num1 + * @param {number} num2 + * @return {number} + */ +const minimizeXor = function(num1, num2) { + let num = 0 + let n2 = num2 + while(n2 > 0) { + if(n2 & 1 === 1) num++ + n2 = n2 >>> 1 + } + + let arr1 = num1.toString(2).split('').map(e => +e) + // console.log(arr1) + let res = Array(arr1.length).fill(0) + for(let i = 0; i < arr1.length && num > 0; i++) { + if(arr1[i] === 1) { + num-- + res[i] = 1 + } + } + + for(let i = arr1.length - 1; i >= 0 && num > 0; i--) { + if(arr1[i] === 0) { + num-- + res[i] = 1 + } + } + + while(num) { + res.unshift(1) + num-- + } + + return Number.parseInt(res.join(''), 2) +}; diff --git a/243-shortest-word-distance.js b/243-shortest-word-distance.js new file mode 100644 index 00000000..324015ff --- /dev/null +++ b/243-shortest-word-distance.js @@ -0,0 +1,40 @@ +/** + +Given a list of words and two words word1 and word2, +return the shortest distance between these two words in the list. + +Example: +Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. + +Input: word1 = “coding”, word2 = “practice” +Output: 3 +Input: word1 = "makes", word2 = "coding" +Output: 1 + +Note: +You may assume that word1 does not equal to word2, and word1 and word2 are both in the list. + +*/ + +/** + * @param {string[]} words + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const shortestDistance = function(words, word1, word2) { + let w1 = -1 + let w2 = -1 + let min = Number.MAX_VALUE + for (let i = 0; i < words.length; i++) { + if (words[i] === word1) { + w1 = i + } else if (words[i] === word2) { + w2 = i + } + if (w1 >= 0 && w2 >= 0) { + min = Math.min(min, Math.abs(w1 - w2)) + } + } + return min +} diff --git a/2430-maximum-deletions-on-a-string.js b/2430-maximum-deletions-on-a-string.js new file mode 100644 index 00000000..4f04ae64 --- /dev/null +++ b/2430-maximum-deletions-on-a-string.js @@ -0,0 +1,86 @@ +/** + * @param {string} s + * @return {number} + */ +const deleteString = function (s) { + const dp = Array(4000).fill(0) + const n = s.length + return helper(0) + + function helper(i) { + if(dp[i] === 0) { + dp[i] = 1 + for(let len = 1; dp[i] <= n - i - len; len++) { + if(s.slice(i, i + len) === s.slice(i + len, i + 2 * len)) { + dp[i] = Math.max(dp[i], 1 + helper(i + len)) + } + } + } + return dp[i] + } +} + +// another + +/** + * @param {string} s + * @return {number} + */ +const deleteString = function (s) { + const dp = Array(4000).fill(0), lps = Array(4000).fill(0) + for (let k = s.length - 1; k >= 0; --k) { + dp[k] = 1; + for (let i = 1, j = 0; dp[k] <= s.length - i - k + 1; ++i) { + while (j && s[i + k] != s[j + k]) j = Math.max(0, lps[j] - 1); + j += s[i + k] == s[j + k]; + lps[i] = j; + if (i % 2) { + const len = ~~((i + 1) / 2); + if (lps[len * 2 - 1] == len) { + dp[k] = Math.max(dp[k], 1 + dp[k + len]); + } + } + } + } + return dp[0]; +} + + +// another + + +/** + * @param {string} s + * @return {number} + */ +const deleteString = function (t) { + let n = t.length + const set = new Set(t.split('')) + if (set.size == 1) return n + + let s = t.split('') + if (n === 1 || (n === 2 && s[0] !== s[1])) return 1 + if (n === 2 && s[0] === s[1]) return 2 + if (n === 3 && s[0] === s[1]) return s[1] === s[2] ? 3 : 2 + else if (n === 3) return 1 + const f = new Array(n).fill(null) + dfsSearchWithMemory(0) + return f[0] + + function dfsSearchWithMemory(i) { + if (i >= n) return 0 + if (f[i] !== null) return f[i] + if (i === n - 1) return (f[i] = 1) + let max = 0, + cur = 0, + j = i + 1 + for (j = i + 1; j <= ~~((n - i) / 2 + i); j++) { + if (t.slice(j).startsWith(t.slice(i, j))) { + cur = 1 + dfsSearchWithMemory(j) + if (cur > max) max = cur + } + } + if (j > (n - i) / 2 + i && max === 0) return (f[i] = 1) + return (f[i] = max) + } +} diff --git a/2432-the-employee-that-worked-on-the-longest-task.js b/2432-the-employee-that-worked-on-the-longest-task.js new file mode 100644 index 00000000..fd203058 --- /dev/null +++ b/2432-the-employee-that-worked-on-the-longest-task.js @@ -0,0 +1,19 @@ +/** + * @param {number} n + * @param {number[][]} logs + * @return {number} + */ +var hardestWorker = function(n, logs) { + const arr = Array(n).fill(0) + const m = logs.length + let pre = 0 + for(let i = 0; i < m; i++) { + const [id, leave] = logs[i] + arr[id] = Math.max(arr[id], leave - pre) + pre = leave + } + // console.log(arr) + const max = Math.max(...arr) + + return arr.indexOf(max) +}; diff --git a/2433-find-the-original-array-of-prefix-xor.js b/2433-find-the-original-array-of-prefix-xor.js new file mode 100644 index 00000000..5d86d3fe --- /dev/null +++ b/2433-find-the-original-array-of-prefix-xor.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} pref + * @return {number[]} + */ +const findArray = function(pref) { + const n = pref.length + if(n == 0 || n==1) return pref + const res = [pref[0]] + let xor = pref[0] + for(let i = 1; i < n; i++) { + const v = pref[i] + // v = xor ^ e + // v ^ xor = e + const tmp = v ^ xor + res.push(tmp) + xor = xor ^ tmp + } + + return res +}; diff --git a/2434-using-a-robot-to-print-the-lexicographically-smallest-string.js b/2434-using-a-robot-to-print-the-lexicographically-smallest-string.js new file mode 100644 index 00000000..9ffd6f29 --- /dev/null +++ b/2434-using-a-robot-to-print-the-lexicographically-smallest-string.js @@ -0,0 +1,75 @@ +/** + * @param {string} s + * @return {string} + */ +const robotWithString = function (s) { + const stk = [] + const freq = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for (const ch of s) { + freq[ch.charCodeAt(0) - a]++ + } + + let res = '' + + for (const ch of s) { + stk.push(ch) + freq[ch.charCodeAt(0) - a]-- + while (stk.length && stk[stk.length - 1] <= helper(freq)) { + const e = stk.pop() + res += e + } + } + + while (stk.length) { + res += stk.pop() + } + + return res + + function helper(arr) { + const a = 'a'.charCodeAt(0) + for (let i = 0; i < 26; i++) { + if (arr[i] !== 0) return String.fromCharCode(a + i) + } + + return '' + } +} + + +// another + +const ord = (c) => c.charCodeAt(); +const char = (ascii) => String.fromCharCode(ascii); +/** + * @param {string} s + * @return {string} + */ + +const robotWithString = (s) => { + let f = Array(26).fill(0), t = [], res = ''; + for (const c of s) f[ord(c) - 97]++; + for (const c of s) { + f[ord(c) - 97]--; + t.push(c); + while (t.length) { + let find = false; + for (let i = 0; i < 26; i++) { + let curC = char(i + 97); + if (curC < t[t.length - 1]) { // check if can find smaller char < t's last char, in the rest of S + if (f[i] > 0) { + find = true; + break; + } + } + } + if (find) { // find means there is lexical smaller one, by moving much more right + break; + } else { // not find, current is lexical smaller + res += t.pop(); + } + } + } + return res; +}; diff --git a/2435-paths-in-matrix-whose-sum-is-divisible-by-k.js b/2435-paths-in-matrix-whose-sum-is-divisible-by-k.js new file mode 100644 index 00000000..b3954370 --- /dev/null +++ b/2435-paths-in-matrix-whose-sum-is-divisible-by-k.js @@ -0,0 +1,24 @@ +const initialize3DArray = (n, m, p) => { let r = []; for (let i = 0; i < n; i++) { let d = []; for (let j = 0; j < m; j++) { let t = Array(p).fill(0); d.push(t); } r.push(d); } return r; }; + +const mod = 1e9 + 7; +/** + * @param {number[][]} grid + * @param {number} k + * @return {number} + */ +const numberOfPaths = (grid, k) => { + const g = grid, K = k + let n = g.length, m = g[0].length, dp = initialize3DArray(n + 1, m + 1, K); + dp[0][1][0] = 1; + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + for (let k = 0; k < K; k++) { + dp[i + 1][j + 1][(k + g[i][j]) % K] += dp[i][j + 1][k]; + dp[i + 1][j + 1][(k + g[i][j]) % K] %= mod; + dp[i + 1][j + 1][(k + g[i][j]) % K] += dp[i + 1][j][k]; + dp[i + 1][j + 1][(k + g[i][j]) % K] %= mod; + } + } + } + return dp[n][m][0]; +}; diff --git a/2438-range-product-queries-of-powers.js b/2438-range-product-queries-of-powers.js new file mode 100644 index 00000000..1d4235f4 --- /dev/null +++ b/2438-range-product-queries-of-powers.js @@ -0,0 +1,29 @@ +/** + * @param {number} n + * @param {number[][]} queries + * @return {number[]} + */ +const productQueries = function(n, queries) { + const mod = 1e9 + 7 + const powers = [] + let pow = 1 + while(n) { + const tmp = (n & 1) * pow + if(tmp) powers.push(tmp) + n = n >> 1 + pow *= 2 + } + + // console.log(powers) + const res = [] + + for(const [s, e] of queries) { + let tmp = 1 + for(let i = s; i <= e; i++) { + tmp = (tmp * powers[i]) % mod + } + res.push(tmp) + } + + return res +}; diff --git a/2439-minimize-maximum-of-array.js b/2439-minimize-maximum-of-array.js new file mode 100644 index 00000000..cc3c1bcf --- /dev/null +++ b/2439-minimize-maximum-of-array.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimizeArrayValue = function(nums) { + const n = nums.length + let sum = 0, res = 0; + for (let i = 0; i < n; ++i) { + sum += nums[i]; + res = Math.max(res, Math.ceil(sum / (i + 1))); + } + return res; +}; diff --git a/244-shortest-word-distance-ii.js b/244-shortest-word-distance-ii.js new file mode 100644 index 00000000..7bf6f7c1 --- /dev/null +++ b/244-shortest-word-distance-ii.js @@ -0,0 +1,37 @@ +/** + * @param {string[]} words + */ +const WordDistance = function(words) { + this.wordMap = {} + for (let i = 0; i < words.length; i++) { + const word = words[i] + if (!this.wordMap[word]) this.wordMap[word] = [] + this.wordMap[word].push(i) + } +} + +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +WordDistance.prototype.shortest = function(word1, word2) { + let min = Infinity + const iList = this.wordMap[word1] + const jList = this.wordMap[word2] + for (let i = 0, j = 0; i < iList.length && j < jList.length; ) { + min = Math.min(min, Math.abs(iList[i] - jList[j])) + if (iList[i] < jList[j]) { + i++ + } else { + j++ + } + } + return min +} + +/** + * Your WordDistance object will be instantiated and called as such: + * var obj = new WordDistance(words) + * var param_1 = obj.shortest(word1,word2) + */ diff --git a/2440-create-components-with-same-value.js b/2440-create-components-with-same-value.js new file mode 100644 index 00000000..06735c00 --- /dev/null +++ b/2440-create-components-with-same-value.js @@ -0,0 +1,115 @@ +/** + * @param {number[]} nums + * @param {number[][]} edges + * @return {number} + */ +var componentValue = function(nums, edges) { + const n = nums.length; + if(n === 1) return 0; + const total = nums.reduce((a, b) => a + b, 0); + const g = Array.from({ length: n }, () => []); + const indegree = Array(n).fill(0); + for (const [u, v] of edges) { + g[u].push(v); + g[v].push(u); + indegree[u]++; + indegree[v]++; + } + const sums = [] + for(let s = 1; s * s <= total; s++) { + if(total % s === 0) { + sums.push(s); + sums.push(total / s); + } + } + sums.sort((a, b) => a - b); + let res = 0 + for(const s of sums) { + const ind = [...indegree]; + const q = []; + const visited = Array(n).fill(false); + const sum = [...nums]; + for(let i = 0; i < n; i++) { + if(ind[i] === 1) { + q.push(i); + visited[i] = true; + } + } + let flag = true; + while(q.length) { + const cur = q.shift(); + if(sum[cur] > s) { + flag = false; + break; + } else if(sum[cur] === s) { + sum[cur] = 0 + } + for(const next of g[cur]) { + if(visited[next]) continue; + sum[next] += sum[cur]; + ind[next]--; + if(ind[next] === 1) { + q.push(next); + visited[next] = true; + } + } + } + if(flag) return total / s - 1; + + } + return 0 +}; + +// another + + +/** + * @param {number[]} nums + * @param {number[][]} edges + * @return {number} + */ +const componentValue = function(nums, edges) { + const n = nums.length, sum = nums.reduce((ac, e) => ac + e, 0) + const graph = {}, degree = Array(n).fill(0) + const { min } = Math, mi = min(...nums) + for(const [u, v] of edges) { + if(graph[u] == null) graph[u] = [] + if(graph[v] == null) graph[v] = [] + graph[u].push(v) + graph[v].push(u) + degree[u]++ + degree[v]++ + } + + + for(let t = mi; t < sum; t++) { + if((sum % t === 0) && bfs(t)) return sum / t - 1 + } + + return 0 + + + function bfs(target) { + const vertices = nums.slice(0), deg = degree.slice(0), q = [] + for(let i = 0; i < n; i++) { + if(deg[i] === 1) { + q.push(i) + } + } + + while(q.length) { + const cur = q.shift() + deg[cur] = 0 + const nxt = graph[cur] || [] + for(const e of nxt) { + if(vertices[cur] !== target) vertices[e] += vertices[cur] + deg[e]-- + + if(deg[e] === 0) return vertices[e] === target + else if(deg[e] === 1) q.push(e) + } + } + return false + } +}; + diff --git a/2441-largest-positive-integer-that-exists-with-its-negative.js b/2441-largest-positive-integer-that-exists-with-its-negative.js new file mode 100644 index 00000000..47214a1a --- /dev/null +++ b/2441-largest-positive-integer-that-exists-with-its-negative.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var findMaxK = function(nums) { + nums.sort((a, b) => a - b) + const n = nums.length + for(let i = n - 1; i > 0; i--) { + const cur = nums[i] + if(nums.indexOf(-cur) !== -1) return cur + } + return -1 +}; diff --git a/2442-count-number-of-distinct-integers-after-reverse-operations.js b/2442-count-number-of-distinct-integers-after-reverse-operations.js new file mode 100644 index 00000000..884b1c23 --- /dev/null +++ b/2442-count-number-of-distinct-integers-after-reverse-operations.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var countDistinctIntegers = function(nums) { + const set = new Set() + + for(const e of nums) set.add(e) + for(const e of nums) set.add(reverse(e)) + return set.size + + function reverse(num) { + return parseInt(('' + num).split('').reverse().join('')) + } +}; diff --git a/2443-sum-of-number-and-its-reverse.js b/2443-sum-of-number-and-its-reverse.js new file mode 100644 index 00000000..686d2a4c --- /dev/null +++ b/2443-sum-of-number-and-its-reverse.js @@ -0,0 +1,24 @@ +/** + * @param {number} num + * @return {boolean} + */ +var sumOfNumberAndReverse = function(num) { + // let l = 0, r = num + // while(l < r) { + // const mid = ~~((l + r) / 2) + // if(valid(mid) === 0) return true + // else if(valid(mid) < 0) l = mid + 1 + // else r = mid - 1 + // } + for(let i = 0; i <= num; i++) { + if(valid(i) === 0) { + // console.log(i) + return true + } + } + return false + + function valid(n) { + return n + (parseInt( (''+n).split('').reverse().join('') ) ) - num + } +}; diff --git a/2444-count-subarrays-with-fixed-bounds.js b/2444-count-subarrays-with-fixed-bounds.js new file mode 100644 index 00000000..9ad838c7 --- /dev/null +++ b/2444-count-subarrays-with-fixed-bounds.js @@ -0,0 +1,47 @@ +/** + * @param {number[]} nums + * @param {number} minK + * @param {number} maxK + * @return {number} + */ +const countSubarrays = function(nums, minK, maxK) { + let res = 0, n = nums.length + let minIdx = -1, maxIdx = -1 + + for(let i = 0, j = 0; i < n; i++) { + if(nums[i] < minK || nums[i] > maxK) { + minIdx = -1 + maxIdx = -1 + j = i + 1 + } + if(nums[i] === minK) minIdx = i + if(nums[i] === maxK) maxIdx = i + if(minIdx !== -1 && maxIdx !== -1) { + res += Math.min(minIdx, maxIdx) - j + 1 + } + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} minK + * @param {number} maxK + * @return {number} + */ +var countSubarrays = function(nums, minK, maxK) { + let res = 0, j = 0, jmin = -1, jmax = -1, n = nums.length; + for (let i = 0; i < n; ++i) { + if (nums[i] < minK || nums[i] > maxK) { + jmin = jmax = -1; + j = i + 1; + } + if (nums[i] == minK) jmin = i; + if (nums[i] == maxK) jmax = i; + res += Math.max(0, Math.min(jmin, jmax) - j + 1); + } + return res; +}; diff --git a/2447-number-of-subarrays-with-gcd-equal-to-k.js b/2447-number-of-subarrays-with-gcd-equal-to-k.js new file mode 100644 index 00000000..7611c8ec --- /dev/null +++ b/2447-number-of-subarrays-with-gcd-equal-to-k.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const subarrayGCD = function (nums, k) { + let res = 0 + const n = nums.length + for (let i = 0; i < n; i++) { + let cur = nums[i] + for (let j = i; j < n; j++) { + if (nums[j] % k !== 0) break + cur = gcd(cur, nums[j]) + if (cur === k) res++ + } + } + + return res + + function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) + } +} diff --git a/2448-minimum-cost-to-make-array-equal.js b/2448-minimum-cost-to-make-array-equal.js new file mode 100644 index 00000000..39f0e560 --- /dev/null +++ b/2448-minimum-cost-to-make-array-equal.js @@ -0,0 +1,72 @@ +/** + * @param {number[]} nums + * @param {number[]} cost + * @return {number} + */ +const minCost = function (nums, cost) { + const n = nums.length + let l = Math.min(...nums) + let r = Math.max(...nums) + + while(l < r) { + const mid = Math.floor((l + r) / 2) + const v1 = calc(mid) + const v2 = calc(mid + 1) + if(v1 < v2) { + r = mid + } else { + l = mid + 1 + } + } + + return calc(l) + + function calc(v) { + let res = 0 + for (let i = 0; i < n; i++) { + res += Math.abs(nums[i] - v) * cost[i] + } + return res + } +} + +// another + +/** + * @param {number[]} nums + * @param {number[]} cost + * @return {number} + */ +const minCost = function(nums, cost) { + const n = nums.length + const {min, max, abs, floor} = Math + let l = Infinity, r = -Infinity + + for(const e of nums) { + l = min(e, l) + r = max(e, r) + } + let res = calcCost(l) + while(l < r) { + const mid = floor((l + r) / 2) + const v1 = calcCost(mid) + const v2 = calcCost(mid + 1) + res = min(res, v1, v2) + if(v1 < v2) { + r = mid + } else { + l = mid + 1 + } + } + + return res + + + function calcCost(x) { + let res = 0 + for(let i = 0; i < n; i++) { + res += abs(nums[i] - x) * cost[i] + } + return res + } +}; diff --git a/2449-minimum-number-of-operations-to-make-arrays-similar.js b/2449-minimum-number-of-operations-to-make-arrays-similar.js new file mode 100644 index 00000000..18b5b93f --- /dev/null +++ b/2449-minimum-number-of-operations-to-make-arrays-similar.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @param {number[]} target + * @return {number} + */ +const makeSimilar = function (nums, target) { + const odd = [], even = [] + const todd = [], teven = [] + for(const e of nums) { + if(e % 2 === 0) even.push(e) + else odd.push(e) + } + for(const e of target) { + if(e % 2 === 0) teven.push(e) + else todd.push(e) + } + const sfn = (a, b) => a - b + odd.sort(sfn) + todd.sort(sfn) + even.sort(sfn) + teven.sort(sfn) + let res = 0 + for(let i = 0, n = odd.length; i < n; i++) { + res += Math.abs(odd[i] - todd[i]) / 2 + } + for(let i = 0, n = even.length; i < n; i++) { + res += Math.abs(even[i] - teven[i]) / 2 + } + return res / 2 +} diff --git a/245-shortest-word-distance-iii.js b/245-shortest-word-distance-iii.js new file mode 100644 index 00000000..4fae325c --- /dev/null +++ b/245-shortest-word-distance-iii.js @@ -0,0 +1,24 @@ +/** + * @param {string[]} words + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const shortestWordDistance = function(words, word1, word2) { + let l = Infinity + let r = Infinity + let res = Infinity + const same = word1 === word2 + for (let i = 0; i < words.length; i++) { + if (same) r = l + if (words[i] === word1) { + l = i + } else if (words[i] === word2) { + r = i + } else { + continue + } + res = Math.min(res, Math.abs(l - r)) + } + return res +} diff --git a/2453-destroy-sequential-targets.js b/2453-destroy-sequential-targets.js new file mode 100644 index 00000000..8e0b486e --- /dev/null +++ b/2453-destroy-sequential-targets.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @param {number} space + * @return {number} + */ +const destroyTargets = function(nums, space) { + let maxCount = -Infinity; + const map = {}; + + for (const num of nums) { + const reminder = num % space; + map[reminder] = (map[reminder] || 0) + 1; + maxCount = Math.max(maxCount, map[reminder]); + } + + let ans = Infinity; + for (const num of nums) { + if (map[num % space] === maxCount) { + ans = Math.min(ans, num); + } + } + + return ans; +}; diff --git a/2454-next-greater-element-iv.js b/2454-next-greater-element-iv.js new file mode 100644 index 00000000..b172eaa0 --- /dev/null +++ b/2454-next-greater-element-iv.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var secondGreaterElement = function(nums) { + let n = nums.length, res = new Array(n).fill(-1); + const s1 = [], s2 = [], tmp = []; + for (let i = 0; i < n; i++) { + while (s2.length && nums[s2.at(-1)] < nums[i]) res[s2.pop()] = nums[i]; + while (s1.length && nums[s1.at(-1)] < nums[i]) tmp.push(s1.pop()); + while (tmp.length) s2.push(tmp.pop()); + s1.push(i); + } + return res; +}; diff --git a/2457-minimum-addition-to-make-integer-beautiful.js b/2457-minimum-addition-to-make-integer-beautiful.js new file mode 100644 index 00000000..d1d9189f --- /dev/null +++ b/2457-minimum-addition-to-make-integer-beautiful.js @@ -0,0 +1,34 @@ +/** + * @param {number} n + * @param {number} target + * @return {number} + */ +const makeIntegerBeautiful = function(n, target) { + let res = 0, carry = 0 + const arr = [] + while(n) { + if(digitSum(n) <= target) break + const remain = (n % 10) + if(remain === 0) { + arr.push(0) + carry = 0 + } else { + arr.push(10 - remain) + carry = 1 + } + + n = (Math.floor(n / 10)) + carry + } + if(arr.length === 0) return 0 + arr.reverse() + return +arr.map(e => '' + e).join('') + + function digitSum(num) { + let res = 0 + while(num > 0) { + res += (num % 10) + num = Math.floor(num/10) + } + return res + } +}; diff --git a/2458-height-of-binary-tree-after-subtree-removal-queries.js b/2458-height-of-binary-tree-after-subtree-removal-queries.js new file mode 100644 index 00000000..15e3aad3 --- /dev/null +++ b/2458-height-of-binary-tree-after-subtree-removal-queries.js @@ -0,0 +1,101 @@ +/** + * 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 + * @param {number[]} queries + * @return {number[]} + */ +const treeQueries = function(root, queries) { + const depth = [], height = [], depthHash = [] + dfs(root, 0) + const res = [] + for(const e of queries) { + const d = depth[e], h = height[e], row = depthHash[d] + if(row.length === 1) { + res.push(d - 1) + } else if(h === row[0]) { + res.push(d + row[1]) + } else { + res.push(d + row[0]) + } + } + return res + + function dfs(node, d) { + if(node == null) return 0 + const {val} = node + const h = Math.max(dfs(node.left, d + 1), dfs(node.right, d + 1)) + depth[val] = d + height[val] = h + if(depthHash[d] == null) depthHash[d] = [] + depthHash[d].push(h) + keepLargestTwo(depthHash[d]) + return h + 1 + } + function keepLargestTwo(arr) { + arr.sort((a,b) => b - a) + if(arr.length > 2) { + arr.splice(2, arr.length - 2) + } + } +}; + +// another + + +/** + * 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 + * @param {number[]} queries + * @return {number[]} + */ +const treeQueries = function(root, queries) { + const height = [], depth = [], { max } = Math + dfs(root, 0) + + function dfs(node, dep) { + if(node == null) return 0 + depth[node.val] = dep + const h = max(dfs(node.left, dep + 1), dfs(node.right, dep + 1)) + height[node.val] = h + return h + 1 + } + // console.log(height, depth) + + const neighbors = [] + for(let i = 1; i < height.length; i++) { + if(height[i] == null) continue + const d = depth[i] + if(neighbors[d] == null) neighbors[d] = [] + neighbors[d].push([height[i], i]) + neighbors[d].sort((a, b) => b[0] - a[0]) + if(neighbors[d].length > 2) neighbors[d].pop() + } + // console.log(neighbors) + const res = [] + for(const q of queries) { + const d = depth[q] + if(neighbors[d].length === 1) res.push(d - 1) + else if(q === neighbors[d][0][1]) { + // console.log('in', d) + res.push(d + neighbors[d][1][0]) + } else { + res.push(d + neighbors[d][0][0]) + } + } + + return res +}; diff --git a/246-strobogrammatic-number.js b/246-strobogrammatic-number.js new file mode 100644 index 00000000..c02c9772 --- /dev/null +++ b/246-strobogrammatic-number.js @@ -0,0 +1,44 @@ +/** + * @param {string} num + * @return {boolean} + */ +const isStrobogrammatic = function(num) { + const m = { + 0: 0, + 1: 1, + 2: null, + 3: null, + 4: null, + 5: null, + 6: 9, + 7: null, + 8: 8, + 9: 6 + } + const arr = num.split('') + for(let i = 0, len = arr.length; i < len; i++) { + if(m[arr[i]] === null) return false + else arr[i] = m[arr[i]] + } + return num === arr.reverse().join('') +}; + +// another + +const isStrobogrammatic = function(num) { + const map = { 0: '0', 1: '1', 8: '8', 6: '9', 9: '6' } + let left = 0 + let right = num.length - 1 + + while (left < right) { + const leftNum = num[left] + const rightNum = num[right] + if (map[leftNum] != rightNum) return false + left++ + right-- + } + if (right == left) { + if (!map[num[right]] || num[right] == '9' || num[right] == '6') return false + } + return true +} diff --git a/2460-apply-operations-to-an-array.js b/2460-apply-operations-to-an-array.js new file mode 100644 index 00000000..01ac392e --- /dev/null +++ b/2460-apply-operations-to-an-array.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var applyOperations = function(nums) { + const n = nums.length + for(let i = 0; i < n - 1; i++) { + if(nums[i] === nums[i + 1]) { + nums[i] *= 2 + nums[i + 1] = 0 + } + } + const res = nums.filter(e => e !== 0) + while(res.length !== n) res.push(0) + return res +}; diff --git a/2461-maximum-sum-of-distinct-subarrays-with-length-k.js b/2461-maximum-sum-of-distinct-subarrays-with-length-k.js new file mode 100644 index 00000000..a9700555 --- /dev/null +++ b/2461-maximum-sum-of-distinct-subarrays-with-length-k.js @@ -0,0 +1,111 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumSubarraySum = function(nums, k) { + let res = 0, i = 0, sum = 0 + const map = new Map(), n = nums.length + for(let j = 0; j < k; j++) { + const e = nums[j] + if(map.get(e) == null) map.set(e, 0) + map.set(e, (map.get(e) || 0) + 1) + sum += e + } + if(map.size === k) res = sum + for(let j = k; j < n; j++) { + const e = nums[j] + if(map.get(e) == null) map.set(e, 0) + map.set(e, (map.get(e) || 0) + 1) + sum += e + + // pre + const tmp = nums[i] + map.set(tmp, map.get(tmp) - 1) + if(map.get(tmp) === 0) map.delete(tmp) + sum -= tmp + i++ + + if(map.size === k) res = Math.max(res, sum) + } + + return res +}; + +// another + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumSubarraySum = function (nums, k) { + const map = new Map(), n = nums.length + let i = 0, res = 0, sum = 0 + + while(i < n && i < k) { + const cur = nums[i] + map.set(cur, (map.get(cur) || 0) + 1 ) + sum += cur + i++ + } + if(map.size === k) res = sum + + for(i = k; i < n; i++) { + const cur = nums[i] + map.set(cur, (map.get(cur) || 0) + 1) + const pre = nums[i - k] + map.set(pre, (map.get(pre) || 0) - 1) + if(map.get(pre) === 0) map.delete(pre) + + sum += cur + sum -= nums[i - k] + + if(map.size === k) res = Math.max(res, sum) + } + + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumSubarraySum = function(nums, k) { + let res = 0 + const n = nums.length + + const preSum = Array(n).fill(0) + preSum[0] = nums[0] + for(let i = 1; i < n; i++) { + preSum[i] = preSum[i - 1] + nums[i] + } + + const set = new Set() + + const lastHash = {} + + for(let i = 0; i < n; i++) { + const cur = nums[i] + lastHash[cur] = i + if(i < k - 1) set.add(cur) + else if(i === k - 1) { + set.add(cur) + if(set.size === k) { + res = preSum[i] + } + } else { + if(lastHash[nums[i - k]] == i - k) set.delete(nums[i - k]) + set.add(nums[i]) + if(set.size === k) { + res = Math.max(res, preSum[i] - preSum[i - k]) + } + } + } + + return res +}; diff --git a/2462-total-cost-to-hire-k-workers.js b/2462-total-cost-to-hire-k-workers.js new file mode 100644 index 00000000..017f4c3e --- /dev/null +++ b/2462-total-cost-to-hire-k-workers.js @@ -0,0 +1,138 @@ +/** + * @param {number[]} costs + * @param {number} k + * @param {number} candidates + * @return {number} + */ +const totalCost = function(costs, k, candidates) { + const fn = (a, b) => a[0] === b[0] ? a[1] < b[1] : a[0] < b[0] + const n = costs.length + let l = 0, r = n - 1 + const first = new PriorityQueue(fn) + const last = new PriorityQueue(fn) + + for(let i = 0; i < Math.min(candidates, n); i++) { + first.push([costs[i], i]) + l = i + } + + for(let i = n - 1; i > Math.max(0, candidates - 1, n - 1 - candidates); i--) { + last.push([costs[i], i]) + r = i + } + + // console.log(first, last) + + let res = 0 + let num = k + while(num) { + const ft = first.peek() + const lt = last.peek() + + if(ft && lt) { + if(ft[0] < lt[0]) { + first.pop() + res += ft[0] + if(r - l > 1) { + l++ + first.push([costs[l], l]) + } + } else if(ft[0] > lt[0]) { + last.pop() + res += lt[0] + if(r - l > 1) { + r-- + last.push([costs[r], r]) + } + } else { + first.pop() + res += ft[0] + if(r - l > 1) { + l++ + first.push([costs[l], l]) + } + } + } else if(ft) { + first.pop() + res += ft[0] + } else if(lt) { + last.pop() + res += lt[0] + } + // console.log(res) + num-- + } + + + return res + +}; + + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2463-minimum-total-distance-traveled.js b/2463-minimum-total-distance-traveled.js new file mode 100644 index 00000000..5eadfe65 --- /dev/null +++ b/2463-minimum-total-distance-traveled.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} robot + * @param {number[][]} factory + * @return {number} + */ +const minimumTotalDistance = function(robot, factory) { + robot.sort((a, b) => a - b) + factory.sort((a, b) => a[0] - b[0]) + const facs = [] + for(const f of factory) { + for(let i = 0; i < f[1]; i++) facs.push(f[0]) + } + const n = facs.length + let dp = Array(n + 1).fill(0) + for(let i = 0; i < robot.length; i++) { + const nxt = Array(n + 1).fill(Infinity) + for(let j = 0; j < n; j++) { + nxt[j + 1] = Math.min(nxt[j], dp[j] + Math.abs(robot[i] - facs[j])) + } + dp = nxt + } + + + return dp[n] +}; + diff --git a/2467-most-profitable-path-in-a-tree.js b/2467-most-profitable-path-in-a-tree.js new file mode 100644 index 00000000..9f0b827c --- /dev/null +++ b/2467-most-profitable-path-in-a-tree.js @@ -0,0 +1,48 @@ +/** + * @param {number[][]} edges + * @param {number} bob + * @param {number[]} amount + * @return {number} + */ +const mostProfitablePath = function(edges, bob, amount) { + const graph = [], depth = [], parent = [] + for(const [u, v] of edges) { + if(graph[u] == null) graph[u] = [] + if(graph[v] == null) graph[v] = [] + graph[u].push(v) + graph[v].push(u) + } + dfs(0) + let cur = bob, bobh = 0 + while(cur) { + if(depth[cur] > bobh) amount[cur] = 0 + else if(depth[cur] === bobh) amount[cur] /= 2 + + bobh++ + cur = parent[cur] + } + + // console.log(depth, parent, amount) + + return dfs2(0) + + function dfs(node, p = 0, d = 0) { + parent[node] = p + depth[node] = d + for(const e of graph[node]) { + if(e === p) continue + dfs(e, node, d + 1) + } + } + + function dfs2(node, p = 0) { + let res = amount[node] + let ma = -Infinity + for(const e of graph[node]) { + if(e === p) continue + ma = Math.max(ma, dfs2(e, node)) + } + if(ma === -Infinity) return res + return res + ma + } +}; diff --git a/2469-convert-the-temperature.js b/2469-convert-the-temperature.js new file mode 100644 index 00000000..bafc470d --- /dev/null +++ b/2469-convert-the-temperature.js @@ -0,0 +1,7 @@ +/** + * @param {number} celsius + * @return {number[]} + */ +var convertTemperature = function(celsius) { + return [celsius + 273.15, celsius * 1.8 + 32] +}; diff --git a/247-strobogrammatic-number-ii.js b/247-strobogrammatic-number-ii.js new file mode 100644 index 00000000..17d7e188 --- /dev/null +++ b/247-strobogrammatic-number-ii.js @@ -0,0 +1,45 @@ +/** + * @param {number} n + * @return {string[]} + */ +const findStrobogrammatic = function(n) { + return recursionHelper(n, n) +} +const recursionHelper = function(n, m) { + if (n === 0) return [''] + if (n === 1) return ['0', '1', '8'] + let rtnArr = recursionHelper(n - 2, m) + let res = [] + for (let i = 0; i < rtnArr.length; i++) { + if (n !== m) res.push('0' + rtnArr[i] + '0') + res.push('1' + rtnArr[i] + '1') + res.push('6' + rtnArr[i] + '9') + res.push('8' + rtnArr[i] + '8') + res.push('9' + rtnArr[i] + '6') + } + return res +} + +// another + +/** + * @param {number} n + * @return {string[]} + */ +const findStrobogrammatic = function(n) { + let cur, ans + ans = (n & 1) == 0 ? [''] : ['0', '1', '8'] + if (n < 2) return ans + for (; n > 1; n -= 2) { + cur = ans + ans = [] + for (let i of cur) { + if (n > 3) ans.push('0' + i + '0') + ans.push('1' + i + '1') + ans.push('8' + i + '8') + ans.push('6' + i + '9') + ans.push('9' + i + '6') + } + } + return ans +} diff --git a/2470-number-of-subarrays-with-lcm-equal-to-k.js b/2470-number-of-subarrays-with-lcm-equal-to-k.js new file mode 100644 index 00000000..ddab1984 --- /dev/null +++ b/2470-number-of-subarrays-with-lcm-equal-to-k.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var subarrayLCM = function(nums, k) { + let res = 0 + const n = nums.length + + for(let i = 0; i < n; i++) { + let tmp = nums[i] + for(let j = i; j < n; j++) { + if(k % nums[j] !== 0) break + if(lcm(tmp, nums[j]) === k) res++ + tmp = Math.max(tmp, nums[j]) + } + } + + return res +}; + + +function lcm(a, b) { + return a * b / gcd(a, b); +} + +function gcd(a, b) { + return b ? gcd(b, a % b) : a +} diff --git a/2471-minimum-number-of-operations-to-sort-a-binary-tree-by-level.js b/2471-minimum-number-of-operations-to-sort-a-binary-tree-by-level.js new file mode 100644 index 00000000..2350da34 --- /dev/null +++ b/2471-minimum-number-of-operations-to-sort-a-binary-tree-by-level.js @@ -0,0 +1,79 @@ +/** + * 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 {number} + */ +var minimumOperations = function (root) { + let res = 0 + let q = [] + q.push(root) + + while (q.length) { + const nxt = [] + res += minSwaps( + q.map((e) => e.val), + q.length + ) + const len = q.length + + for (let i = 0; i < len; i++) { + const cur = q[i] + if (cur.left) nxt.push(cur.left) + if (cur.right) nxt.push(cur.right) + } + + q = nxt + } + + return res +} + +function swap(arr, i, j) { + const temp = arr[i] + arr[i] = arr[j] + arr[j] = temp +} + +// Return the minimum number +// of swaps required to sort +// the array +function minSwaps(arr, len) { + let ans = 0 + const temp = arr.slice() + + // Hashmap which stores the + // indexes of the input array + const h = new Map() + + temp.sort((a, b) => a - b) + for (let i = 0; i < len; i++) { + h.set(arr[i], i) + } + for (let i = 0; i < len; i++) { + // This is checking whether + // the current element is + // at the right place or not + if (arr[i] !== temp[i]) { + ans++ + const init = arr[i] + + // If not, swap this element + // with the index of the + // element which should come here + swap(arr, i, h.get(temp[i])) + + // Update the indexes in + // the hashmap accordingly + h.set(init, h.get(temp[i])) + h.set(temp[i], i) + } + } + return ans +} diff --git a/2472-maximum-number-of-non-overlapping-palindrome-substrings.js b/2472-maximum-number-of-non-overlapping-palindrome-substrings.js new file mode 100644 index 00000000..e262fe6a --- /dev/null +++ b/2472-maximum-number-of-non-overlapping-palindrome-substrings.js @@ -0,0 +1,29 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const maxPalindromes = function(s, k) { + const len = s.length; + // dp[i] 表示s[0 .. i - 1] 中的不重叠回文子字符串的最大数目 + const dp = new Array(len + 1).fill(0); + // 如果s[i]不在回文字符串内,dp[i+1]=dp[i]; + // 如果s[l..r]是回文字符串且长度不小于k,那么dp[r+1]=max(dp[r+1],dp[l]+1) + + // 中心扩展法 + // 回文中心:len个单字符和len-1个双字符 + for (let center = 0; center < 2 * len - 1; center++) { + let l = center >> 1, + r = l + (center % 2); + dp[l + 1] = Math.max(dp[l + 1], dp[l]); + while (l >= 0 && r < len && s[l] === s[r]) { + if (r - l + 1 >= k) { + dp[r + 1] = Math.max(dp[r + 1], dp[l] + 1); + } + // expand from center + l--, r++; + } + } + + return dp[len]; +}; diff --git a/2475-number-of-unequal-triplets-in-array.js b/2475-number-of-unequal-triplets-in-array.js new file mode 100644 index 00000000..9bcacaaf --- /dev/null +++ b/2475-number-of-unequal-triplets-in-array.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const unequalTriplets = function(nums) { + let res = 0 + const n = nums.length + + for(let i = 0; i < n; i++) { + for(let j = i + 1; j < n; j++) { + for(let k = j + 1; k < n; k++) { + if(nums[i] !== nums[j] && nums[j] !== nums[k] && nums[i] !== nums[k]) res++ + } + } + } + + return res +}; diff --git a/2476-closest-nodes-queries-in-a-binary-search-tree.js b/2476-closest-nodes-queries-in-a-binary-search-tree.js new file mode 100644 index 00000000..afa8ba99 --- /dev/null +++ b/2476-closest-nodes-queries-in-a-binary-search-tree.js @@ -0,0 +1,63 @@ +/** + * 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 + * @param {number[]} queries + * @return {number[][]} + */ +var closestNodes = function(root, queries) { + const arr = [] + function dfs(node) { + if(node == null) return + dfs(node.left) + arr.push(node.val) + dfs(node.right) + } + dfs(root) + const res = [] + // console.log(arr) + for(const q of queries) { + const tmp = [] + tmp[0] = ceil(arr, q) + tmp[1] = floor(arr, q) + res.push(tmp) + } + + return res + // maxIdx that <= target + function ceil(arr, q) { + const n = arr.length + let l = 0, r = n - 1 + while(l < r) { + const mid = r - (~~((r - l) / 2)) + if(arr[mid] <= q) { + l = mid + } else { + r = mid - 1 + } + } + + return arr[l] <= q ? arr[l] : -1 + } + // minIdx that >= target + function floor(arr, q) { + const n = arr.length + let l = 0, r = n - 1 + while(l < r) { + const mid = ~~((r + l) / 2) + if(arr[mid] < q) { + l = mid + 1 + } else { + r = mid + } + } + + return arr[l] >= q ? arr[l] : -1 + } +}; diff --git a/2477-minimum-fuel-cost-to-report-to-the-capital.js b/2477-minimum-fuel-cost-to-report-to-the-capital.js new file mode 100644 index 00000000..04e99f78 --- /dev/null +++ b/2477-minimum-fuel-cost-to-report-to-the-capital.js @@ -0,0 +1,57 @@ +/** + * @param {number[][]} roads + * @param {number} seats + * @return {number} + */ +const minimumFuelCost = function(roads, seats) { + const n = roads.length + 1 + const graph = {}, inDegree = Array(n).fill(0) + const nodes = Array(n).fill(null).map((e, i) => ([i, 1, 0])) + for(const [u, v] of roads) { + if(graph[u] == null) graph[u] = new Set() + if(graph[v] == null) graph[v] = new Set() + graph[u].add(nodes[v]) + graph[v].add(nodes[u]) + + inDegree[u]++ + inDegree[v]++ + } + const { ceil } = Math + let q = [] + + for(let i = 0; i < n; i++) { + if(inDegree[i] === 1) q.push([i, 1, 0]) + } + // console.log(q) + let res = 0 + const visited = new Set() + + while(q.length) { + const nxt = [] + const len = q.length + for(let i = 0; i < len; i++) { + const [c, num, sum] = q[i] + if(c === 0) continue + for(const node of (graph[c] || [])) { + const [e] = node + if(visited.has(e)) continue + inDegree[e]-- + // console.log(c, e, sum, num, res) + if(e === 0) res += ceil(num/ seats) + sum + else { + node[1] += num + node[2] += ceil(num / seats) + sum + if(inDegree[e] === 1) nxt.push(node) + } + // console.log(res) + } + visited.add(c) + } + + q = nxt + // console.log(q, visited) + } + + + return res +}; diff --git a/2478-number-of-beautiful-partitions.js b/2478-number-of-beautiful-partitions.js new file mode 100644 index 00000000..6f6ec63b --- /dev/null +++ b/2478-number-of-beautiful-partitions.js @@ -0,0 +1,56 @@ +/** + * @param {string} s + * @param {number} k + * @param {number} minLength + * @return {number} + */ +const beautifulPartitions = function (s, k, minLength) { + const mod = 1e9 + 7 + const p = new Set(['2', '3', '5', '7']) + + function isPrime(x) { + return p.has(x) + } + + let n = s.length + const dp = Array.from({ length: k + 1 }, () => Array(n).fill(0)) + + for (let j = 0; j < n; ++j) { + dp[1][j] = isPrime(s[0]) && !isPrime(s[j]) + } + let previous_row = Array(n).fill(0) + for (let i = 0; i + 1 < n; ++i) { + if (isPrime(s[i + 1])) previous_row[i] = dp[1][i] // update IFF next_index is prime and capable of starting a substring + if (i - 1 >= 0) + previous_row[i] = (previous_row[i] + previous_row[i - 1]) % mod + } + for (let i = 2; i <= k; ++i) { + let current_row = Array(n).fill(0) + for (let end = i * minLength - 1; end < n; ++end) { + if (isPrime(s[end])) continue + + // optimization usage + let prefixsum = previous_row[end - minLength] + let start = (i - 1) * minLength - 1 + if (start - 1 >= 0) + prefixsum = (prefixsum - previous_row[start - 1] + mod) % mod + dp[i][end] = (dp[i][end] + prefixsum) % mod + + // update current_row's column only if the next_index is a prime and capable of starting a substring + if (end + 1 < n && isPrime(s[end + 1])) + current_row[end] = (current_row[end] + dp[i][end]) % mod + } + // re-calclate prefix sum of current row dp values for each column + for (let c = 1; c <= n - 1; ++c) { + current_row[c] = (current_row[c] + current_row[c - 1]) % mod + } + + // swap previous_row dp values and current_row dp values. why ? + // Because current row will become previous row for next row + // swap(previous_row, current_row); + let tmp = current_row + current_row = previous_row + previous_row = tmp + } + return dp[k][n - 1] +} diff --git a/2479-maximum-xor-of-two-non-overlapping-subtrees.js b/2479-maximum-xor-of-two-non-overlapping-subtrees.js new file mode 100644 index 00000000..1ffd85a5 --- /dev/null +++ b/2479-maximum-xor-of-two-non-overlapping-subtrees.js @@ -0,0 +1,102 @@ +class TrieNode { + constructor() { + this.next = [null, null] + } +} +const bigIntMinAndMax = (...args) => { + return args.reduce( + ([min, max], e) => { + return [e < min ? e : min, e > max ? e : max] + }, + [args[0], args[0]], + ) +} +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} values + * @return {number} + */ +const maxXor = function (n, edges, values) { + const ins = new Solution() + return Number(ins.maxXor(n, edges, values)) +} + +class Solution { + constructor() { + this.next = [] + this.val = [] + this.values = [] + this.root = null + this.ret = 0n + } + + insert(num) { + let node = this.root + num = BigInt(num) + for (let i = 63n; i >= 0n; i--) { + const d = (num >> i) & 1n + if (node.next[d] === null) { + node.next[d] = new TrieNode() + } + node = node.next[d] + } + } + + find(num) { + num = BigInt(num) + let node = this.root + if (this.root.next[0] === null && this.root.next[1] === null) { + return 0 + } + let ret = 0n + for (let i = 63n; i >= 0n; i--) { + const d = (num >> i) & 1n + if (node.next[1n - d] !== null) { + ret += 1n << i + node = node.next[1n - d] + } else { + ret += 0n + node = node.next[d] + } + } + return ret + } + + maxXor(n, edges, values) { + this.values = values + for (let i = 0; i < n; i++) { + this.next[i] = [] + } + for (let i = 0; i < edges.length; i++) { + const [a, b] = edges[i] + this.next[a].push(b) + this.next[b].push(a) + } + this.root = new TrieNode() + this.dfs(0, -1) + this.dfs2(0, -1) + return this.ret + } + + dfs(cur, parent) { + let v = this.values[cur] + for (let i = 0; i < this.next[cur].length; i++) { + const nxt = this.next[cur][i] + if (nxt === parent) continue + v += this.dfs(nxt, cur) + } + this.val[cur] = v + return v + } + + dfs2(cur, parent) { + for (let i = 0; i < this.next[cur].length; i++) { + const nxt = this.next[cur][i] + if (nxt === parent) continue + this.ret = bigIntMinAndMax(this.ret, this.find(this.val[nxt]))[1] + this.dfs2(nxt, cur) + this.insert(this.val[nxt]) + } + } +} diff --git a/248-strobogrammatic-number-iii.js b/248-strobogrammatic-number-iii.js new file mode 100644 index 00000000..c3701d02 --- /dev/null +++ b/248-strobogrammatic-number-iii.js @@ -0,0 +1,43 @@ +/** + * @param {string} low + * @param {string} high + * @return {number} + */ +const strobogrammaticInRange = function(low, high) { + const pairs = [ + ['0', '0'], + ['1', '1'], + ['6', '9'], + ['8', '8'], + ['9', '6'] + ] + let count = 0 + function dfs(left, right, current) { + if (left > right) { + const s = current.join('') + if ( + (s.length === low.length && s < low) || + (s.length === high.length && s > high) + ) { + return + } + count++ + return + } + for (const [p1, p2] of pairs) { + current[left] = p1 + current[right] = p2 + if (left === right && p1 !== p2) { + continue + } + if (current.length !== 1 && current[0] === '0') { + continue + } + dfs(left + 1, right - 1, current) + } + } + for (let i = low.length; i <= high.length; i++) { + dfs(0, i - 1, Array(i).fill('')) + } + return count +} diff --git a/2483-minimum-penalty-for-a-shop.js b/2483-minimum-penalty-for-a-shop.js new file mode 100644 index 00000000..ed7948fa --- /dev/null +++ b/2483-minimum-penalty-for-a-shop.js @@ -0,0 +1,20 @@ +/** + * @param {string} customers + * @return {number} + */ +const bestClosingTime = function (customers) { + const n = customers.length, {min} = Math + let penalty = n, idx = -1, ma = 0 + for(let i = 0, save = 0; i < n; i++) { + const ch = customers[i] + if(ch === 'Y') save++ + else save-- + + if(save > ma) { + idx = i + ma = save + } + } + + return idx + 1 +} diff --git a/2484-count-palindromic-subsequences.js b/2484-count-palindromic-subsequences.js new file mode 100644 index 00000000..fef523ab --- /dev/null +++ b/2484-count-palindromic-subsequences.js @@ -0,0 +1,31 @@ +const initialize2DArray = (n, m) => { + let d = [] + for (let i = 0; i < n; i++) { + let t = Array(m).fill(0) + d.push(t) + } + return d +} + +const mod = 1e9 + 7 +/** + * @param {string} s + * @return {number} + */ +const countPalindromes = (s) => { + let res = 0, + n = s.length, + cnt = Array(10).fill(0) + for (let i = 0; i < n; i++) { + let tot = 0 + for (let j = n - 1; j > i; j--) { + if (s[i] == s[j]) { + res += tot * (j - i - 1) + res %= mod + } + tot += cnt[s[j] - "0"] + } + cnt[s[i] - "0"]++ + } + return res +} diff --git a/2485-find-the-pivot-integer.js b/2485-find-the-pivot-integer.js new file mode 100644 index 00000000..ca073e25 --- /dev/null +++ b/2485-find-the-pivot-integer.js @@ -0,0 +1,14 @@ +/** + * @param {number} n + * @return {number} + */ +var pivotInteger = function(n) { + const sum = (1 + n) * n / 2 + let tmp = 0 + for(let i = 1; i <= n; i++) { + tmp += i + if(tmp === sum - tmp + i) return i + } + + return -1 +}; diff --git a/2486-append-characters-to-string-to-make-subsequence.js b/2486-append-characters-to-string-to-make-subsequence.js new file mode 100644 index 00000000..a3f588be --- /dev/null +++ b/2486-append-characters-to-string-to-make-subsequence.js @@ -0,0 +1,19 @@ +/** + * @param {string} s + * @param {string} t + * @return {number} + */ +var appendCharacters = function(s, t) { + let i = 0, j = 0 + const m = s.length, n = t.length + while(i < m && j < n) { + if(s[i] === t[j]) { + i++ + j++ + } else { + i++ + } + } + + return n - 1 - (j - 1) +}; diff --git a/2487-remove-nodes-from-linked-list.js b/2487-remove-nodes-from-linked-list.js new file mode 100644 index 00000000..4945be49 --- /dev/null +++ b/2487-remove-nodes-from-linked-list.js @@ -0,0 +1,34 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const removeNodes = function(head) { + const arr = [] + let cur = head + while(cur) { + arr.push(cur) + cur = cur.next + } + + const stk = [] + for(const e of arr) { + while(stk.length && e.val > stk[stk.length - 1].val) { + stk.pop() + } + stk.push(e) + } + + for(let i = 0; i < stk.length - 1; i++) { + const cur = stk[i] + cur.next = stk[i + 1] + } + + return stk[0] +}; diff --git a/2488-count-subarrays-with-median-k.js b/2488-count-subarrays-with-median-k.js new file mode 100644 index 00000000..fadcdcb5 --- /dev/null +++ b/2488-count-subarrays-with-median-k.js @@ -0,0 +1,63 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countSubarrays = (a, k) => permutationArrayWithMedianK(a, k); + +const permutationArrayWithMedianK = (a, k) => { + const m = new Map([[0, 1]]) + let find = false, balance = 0, res = 0; + for (const x of a) { + if (x < k) { + balance--; + } else if (x > k) { + balance++; + } else { + find = true; + } + if (find) { + // balance - 1, subarray length is even, has one more right + res += (m.get(balance) || 0) + (m.get(balance - 1) || 0); + } else { + m.set(balance, (m.get(balance) || 0) + 1); + } + } + return res; +}; + + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var countSubarrays = function(nums, k) { + const n = nums.length; + for(let i = 0; i < n; i++) { + nums[i] = nums[i] < k ? -1 : nums[i] === k ? 0 : 1 + } + const evenSum = {} + const oddSum = {} + evenSum[0] = 1 + let sum = 0 + let res = 0 + for(let i = 0; i < n; i++) { + sum += nums[i] + if(i % 2 === 0) { + if(evenSum[sum] != null) res += evenSum[sum] + if(oddSum[sum - 1] != null) res += oddSum[sum - 1] + if(oddSum[sum] == null) oddSum[sum] = 0 + oddSum[sum]++ + } else { + if(oddSum[sum] != null) res += oddSum[sum] + if(evenSum[sum - 1] != null) res += evenSum[sum - 1] + if(evenSum[sum] == null) evenSum[sum] = 0 + evenSum[sum]++ + } + } + // console.log(evenSum, oddSum, nums) + return res +}; diff --git a/249-group-shifted-strings.js b/249-group-shifted-strings.js new file mode 100644 index 00000000..54f6abec --- /dev/null +++ b/249-group-shifted-strings.js @@ -0,0 +1,28 @@ +/** + * @param {string[]} strings + * @return {string[][]} + */ +const groupStrings = function(strings) { + const m = {} + for(let e of strings) { + const key = gkey(e) + let list + if(m.hasOwnProperty(key)) { + list = m[key] + } else { + list = [] + } + list.push(e) + m[key] = list + } + return Object.values(m) +}; + +function gkey(str) { + let res = '' + for(let i = 1, len = str.length; i < len; i++) { + const diff = str.charCodeAt(i) - str.charCodeAt(i - 1) + res += `${diff < 0 ? diff + 26 : diff},` + } + return res +} diff --git a/2490-circular-sentence.js b/2490-circular-sentence.js new file mode 100644 index 00000000..b4764941 --- /dev/null +++ b/2490-circular-sentence.js @@ -0,0 +1,16 @@ +/** + * @param {string} sentence + * @return {boolean} + */ +var isCircularSentence = function(sentence) { + const arr = sentence.split(' ') + const n = arr.length + for(let i = 0; i < n; i++) { + if(i === n - 1) { + if(arr[i][arr[i].length - 1] !== arr[0][0]) return false + } else { + if(arr[i][arr[i].length - 1] !== arr[i + 1][0]) return false + } + } + return true +}; diff --git a/2491-divide-players-into-teams-of-equal-skill.js b/2491-divide-players-into-teams-of-equal-skill.js new file mode 100644 index 00000000..d4ca89ac --- /dev/null +++ b/2491-divide-players-into-teams-of-equal-skill.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} skill + * @return {number} + */ +const dividePlayers = function(skill) { + skill.sort((a, b) => a - b) + const n = skill.length + const sum = skill[0] + skill[skill.length - 1] + for(let i = 1; i < n / 2; i++) { + const j = n - 1 - i + if(skill[i] + skill[j] !== sum) return -1 + } + let res = skill[0] * skill[skill.length - 1] + for(let i = 1; i < n / 2; i++) { + const j = n - 1 - i + res += skill[i] * skill[j] + } + + return res +}; diff --git a/2492-minimum-score-of-a-path-between-two-cities.js b/2492-minimum-score-of-a-path-between-two-cities.js new file mode 100644 index 00000000..43c7f362 --- /dev/null +++ b/2492-minimum-score-of-a-path-between-two-cities.js @@ -0,0 +1,89 @@ +/** + * @param {number} n + * @param {number[][]} roads + * @return {number} + */ +const minScore = function(n, roads) { + const g = {}, visited = Array(n + 1).fill(0) + let res = Infinity + for(const [u, v, d] of roads) { + if(g[u] == null) g[u] = [] + if(g[v] == null) g[v] = [] + + g[u].push([v, d]) + g[v].push([u, d]) + } + + dfs(1) + + return res + + function dfs(node) { + visited[node] = 1 + for(const [nxt, dis] of (g[node] || [])) { + res = Math.min(res, dis) + if(visited[nxt] === 0) { + dfs(nxt) + } + } + } +}; + +// another + +class UnionFind { + constructor() { + this.sizes = new Map() + this.parents = new Map() + } + + find(x){ + if (x !== (this.parents.get(x) ?? x)) { + this.parents.set(x, this.find(this.parents.get(x) ?? x)); + } + return this.parents.get(x) ?? x; + } + size(x) { + return (this.sizes.get(this.find(x)) ?? 1); + } + connected(p, q) { + return this.find(p) == this.find(q); + } + union(a, b) { + const fa = this.find(a); + const fb = this.find(b); + if (fa == fb) { + return; + } + const sa = this.sizes.get(fa) ?? 1; + const sb = this.sizes.get(fb) ?? 1; + + if (sa < sb) { + this.parents.set(fa, fb); + this.sizes.set(fb, sb + sa); + } else { + this.parents.set(fb, fa); + this.sizes.set(fa, sb + sa); + } + } +} +/** + * @param {number} n + * @param {number[][]} roads + * @return {number} + */ +var minScore = function(n, roads) { + const uf = new UnionFind(); + + for (const [a, b] of roads) { + uf.union(a, b); + } + let ans = Infinity; + + for (const [i, j, d] of roads) { + if (uf.connected(1, i) && uf.connected(1, j)) { + ans = Math.min(ans, d); + } + } + return ans; +}; diff --git a/2493-divide-nodes-into-the-maximum-number-of-groups.js b/2493-divide-nodes-into-the-maximum-number-of-groups.js new file mode 100644 index 00000000..371bf321 --- /dev/null +++ b/2493-divide-nodes-into-the-maximum-number-of-groups.js @@ -0,0 +1,188 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +const magnificentSets = function (n, edges) { + function getComponents(n) { + let visited = Array(n + 1).fill(false); + let ans = []; + for (let i = 1; i <= n; i++) { + if (!visited[i]) { + ans.push(visit(i, [], visited)); + } + } + return ans; + } + + function visit(cur, nodes, visited) { + visited[cur] = true; + nodes.push(cur); + for (let next of map.get(cur)) { + // skip if you have already visited this node + if (visited[next]) continue; + visit(next, nodes, visited); + } + return nodes; + } + + function find(node, n) { + let group = Array(n + 1).fill(-1); + + let queue = []; + queue.push(node); + let groups = 0; + while (queue.length > 0) { + let k = queue.length; + // store nodes in set to avoid duplicates + let set = new Set(); + while (k-- > 0) { + let cur = queue.shift(); + // this case occurs when 2 nodes in the same level are connected + // so, return -1 + if (group[cur] != -1) return -1; + group[cur] = groups; + for (let next of map.get(cur)) { + if (group[next] == -1) { + set.add(next); + } + } + } + for (let val of set) queue.push(val); + groups++; + } + return groups; + } + + let map = new Map(); // Integer -> List + for (let i = 1; i <= n; i++) { + map.set(i, []); + } + // adjacency list + for (let edge of edges) { + let u = edge[0], + v = edge[1]; + map.get(u).push(v); + map.get(v).push(u); + } + + // get all components as Graph can be disconnected + let components = getComponents(n); + + let ans = 0; + /* + - Take each component and get max groups can be formed from that component + - return -1 if you can't form groups from any one of the components + */ + for (let component of components) { + let groups = -1; + for (let node of component) { + groups = Math.max(groups, find(node, n)); + } + if (groups == -1) return -1; + ans += groups; + } + + return ans; +}; + +// another + +/////////////////////// Template //////////////////////////////////////// +const initializeGraph = (n) => { let g = []; for (let i = 0; i < n; i++) { g.push([]); } return g; }; +const packUG = (g, edges) => { for (const [u, v] of edges) { g[u].push(v); g[v].push(u); } }; +const initialize2DArray = (n, m) => { let d = []; for (let i = 0; i < n; i++) { let t = Array(m).fill(Number.MAX_SAFE_INTEGER); d.push(t); } return d; }; + +function DJSet(n) { + // parent[i] < 0, -parent[i] is the group size which root is i. example: (i -> parent[i] -> parent[parent[i]] -> parent[parent[parent[i]]] ...) + // parent[i] >= 0, i is not the root and parent[i] is i's parent. example: (... parent[parent[parent[i]]] -> parent[parent[i]] -> parent[i] -> i) + let parent = Array(n).fill(-1); + return { find, union, count, equiv, par } + function find(x) { + return parent[x] < 0 ? x : parent[x] = find(parent[x]); + } + function union(x, y) { + x = find(x); + y = find(y); + if (x != y) { + if (parent[x] < parent[y]) [x, y] = [y, x]; + parent[x] += parent[y]; + parent[y] = x; + } + return x == y; + } + function count() { // total groups + return parent.filter(v => v < 0).length; + } + function equiv(x, y) { // isConnected + return find(x) == find(y); + } + function par() { + return parent; + } +} + +const isBipartite = (g) => { + let n = g.length, start = 1, visit = Array(n).fill(false), q = [], color = Array(n).fill(0); // 0: no color, 1: red -1: blue + for (let i = start; i < n; i++) { + if (color[i] != 0) continue; + q.push(i); + color[i] = 1; + if (visit[i]) continue; + while (q.length) { + let cur = q.shift(); + if (visit[cur]) continue; + for (const child of g[cur]) { + if (color[child] == color[cur]) return false; + if (color[child]) continue; + color[child] = -color[cur]; + q.push(child); + } + } + } + return true; +}; +//////////////////////////////////////////////////////////////////// +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +const magnificentSets = (n, edges) => { + let g = initializeGraph(n + 1), ds = new DJSet(n + 1); + packUG(g, edges); + if (!isBipartite(g)) return -1; + let d = initialize2DArray(n + 1, n + 1), res = Array(n + 1).fill(0); + for (let i = 1; i <= n; i++) d[i][i] = 0; + for (const [u, v] of edges) { + d[u][v] = 1; + d[v][u] = 1; + ds.union(u, v); + } + wf(d); + for (let i = 1; i <= n; i++) { + let max = 0; + for (let j = 1; j <= n; j++) { + if (d[i][j] >= Number.MAX_SAFE_INTEGER) continue; + max = Math.max(max, d[i][j]); + } + let par = ds.find(i); + res[par] = Math.max(res[par], max + 1); + } + let ans = 0; + for (let i = 1; i <= n; i++) ans += res[i]; + return ans; +}; + +const wf = (g) => { + let n = g.length; + for (let k = 0; k < n; k++) { + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (g[i][j] > g[i][k] + g[k][j]) { + g[i][j] = g[i][k] + g[k][j]; + } + } + } + } +}; diff --git a/2498-frog-jump-ii.js b/2498-frog-jump-ii.js new file mode 100644 index 00000000..e9fc24fc --- /dev/null +++ b/2498-frog-jump-ii.js @@ -0,0 +1,11 @@ +/** + * @param {number[]} stones + * @return {number} + */ +var maxJump = function(stones) { + let res = stones[1]-stones[0]; + const {max} = Math + for(let i = 3; i < stones.length; i+=2) res = max(res, stones[i]-stones[i-2]); + for(let i = 2; i < stones.length; i+=2) res = max(res, stones[i]-stones[i-2]); + return res; +}; diff --git a/2499-minimum-total-cost-to-make-arrays-unequal.js b/2499-minimum-total-cost-to-make-arrays-unequal.js new file mode 100644 index 00000000..a759f069 --- /dev/null +++ b/2499-minimum-total-cost-to-make-arrays-unequal.js @@ -0,0 +1,35 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +var minimumTotalCost = function(nums1, nums2) { + const n = nums1.length, {floor, max} = Math + let res = 0 + const freq = new Map() + let maxFreq = 0, maxFreqVal = 0, toSwap = 0 + for(let i = 0; i < n; i++) { + if(nums1[i] === nums2[i]) { + const e = nums1[i] + freq.set(e, (freq.get(e) || 0) + 1) + res += i + const f = freq.get(e) + toSwap++ + if(f > maxFreq) { + maxFreqVal = e + } + maxFreq = max(maxFreq, f) + } + } + + for(let i = 0; i < n; i++) { + if(maxFreq > floor(toSwap / 2) && nums1[i] !== nums2[i] && nums1[i] !== maxFreqVal && nums2[i] !== maxFreqVal) { + toSwap++ + res += i + } + } + + if(maxFreq > floor(toSwap / 2)) return -1 + + return res +}; diff --git a/25-reverse-nodes-in-k-group.js b/25-reverse-nodes-in-k-group.js new file mode 100644 index 00000000..bf6a75e2 --- /dev/null +++ b/25-reverse-nodes-in-k-group.js @@ -0,0 +1,157 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ +const reverseKGroup = function(head, k) { + let n = 0 + for (let i = head; i != null; n++, i = i.next); + let dmy = new ListNode(0) + dmy.next = head + for (let prev = dmy, tail = head; n >= k; n -= k) { + for (let i = 1; i < k; i++) { + let next = tail.next.next + tail.next.next = prev.next + prev.next = tail.next + tail.next = next + } + + prev = tail + tail = tail.next + } + return dmy.next +} + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ +const reverseKGroup = function (head, k) { + if(head == null) return head + const dummy = new ListNode() + dummy.next = head + let n = 0, cur = head + while(cur) { + n++ + cur = cur.next + } + if(n < k) return head + let pre = dummy, tail = head + + for(let i = 0; i + k <= n; i += k) { + for(let j = 1; j < k; j++) { + const tmp = pre.next + pre.next = tail.next + tail.next = tail.next.next + pre.next.next = tmp + } + pre = tail + tail = tail.next + } + + return dummy.next +} + + + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ +const reverseKGroup = function (head, k) { + let ptr = head + let ktail = null + + // Head of the final, moified linked list + let new_head = null + + // Keep going until there are nodes in the list + while (ptr != null) { + let count = 0 + + // Start counting nodes from the head + ptr = head + + // Find the head of the next k nodes + while (count < k && ptr != null) { + ptr = ptr.next + count += 1 + } + + // If we counted k nodes, reverse them + if (count == k) { + // Reverse k nodes and get the new head + let revHead = reverseLinkedList(head, k) + + // new_head is the head of the final linked list + if (new_head == null) new_head = revHead + + // ktail is the tail of the previous block of + // reversed k nodes + if (ktail != null) ktail.next = revHead + + ktail = head + head = ptr + } + } + + // attach the final, possibly un-reversed portion + if (ktail != null) ktail.next = head + + return new_head == null ? head : new_head +} + +function reverseLinkedList(head, k) { + // Reverse k nodes of the given linked list. + // This function assumes that the list contains + // atleast k nodes. + let new_head = null + let ptr = head + + while (k > 0) { + // Keep track of the next node to process in the + // original list + let next_node = ptr.next + + // Insert the node pointed to by "ptr" + // at the beginning of the reversed list + ptr.next = new_head + new_head = ptr + + // Move on to the next node + ptr = next_node + + // Decrement the count of nodes to be reversed by 1 + k-- + } + + // Return the head of the reversed list + return new_head +} diff --git a/250-count-univalue-subtrees.js b/250-count-univalue-subtrees.js new file mode 100644 index 00000000..88a14625 --- /dev/null +++ b/250-count-univalue-subtrees.js @@ -0,0 +1,53 @@ +/** + +Given a binary tree, count the number of uni-value subtrees. + +A Uni-value subtree means all nodes of the subtree have the same value. + +Example : + +Input: root = [5,1,5,5,5,null,5] + + 5 + / \ + 1 5 + / \ \ + 5 5 5 + +Output: 4 + +*/ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const countUnivalSubtrees = function(root) { + let res = { num: 0 } + chk(root, null, res) + return res.num +} + +function chk(node, pVal, obj) { + if (node == null) return true + const left = chk(node.left, node.val, obj) + const right = chk(node.right, node.val, obj) + if (left && right) { + if (node.left !== null && node.val !== node.left.val) { + return false; + } + if (node.right !== null && node.val !== node.right.val) { + return false; + } + obj.num++ + return true + } + return false +} + diff --git a/2503-maximum-number-of-points-from-grid-queries.js b/2503-maximum-number-of-points-from-grid-queries.js new file mode 100644 index 00000000..af835d99 --- /dev/null +++ b/2503-maximum-number-of-points-from-grid-queries.js @@ -0,0 +1,156 @@ +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +/** + * @param {number[][]} grid + * @param {number[]} queries + * @return {number[]} + */ +const maxPoints = function (grid, queries) { + const m = grid.length, n = grid[0].length, k = queries.length + const q = [...queries] + const pq = new PQ((a, b) => a[1] < b[1]) + const dirs = [[0, 1],[0, -1],[1, 0],[-1,0]] + + q.sort((a, b) => a - b) + const hash = {} + const visited = Array.from({ length: m }, () => Array(n).fill(false)) + + pq.push([[0, 0], grid[0][0]]) + visited[0][0] = true + + let cnt = 0 + for(const e of q) { + while(!pq.isEmpty()) { + const [coord, v] = pq.peek() + const [r, c] = coord + if(e <= v) break + pq.pop() + for(const [dr, dc] of dirs) { + const nr = r + dr, nc = c + dc + if(nr >= 0 && nr < m && nc >= 0 && nc < n && visited[nr][nc] === false) { + visited[nr][nc] = true + pq.push([[nr, nc], grid[nr][nc]]) + } + } + cnt++ + } + + hash[e] = cnt + } +// console.log(hash) + return queries.map(e => hash[e]) +} + +// another + + +/** + * @param {number[][]} grid + * @param {number[]} queries + * @return {number[]} + */ +const maxPoints = function (grid, queries) { + const heap = new MinPriorityQueue({ + compare: ({ value: valueA }, { value: valueB }) => valueA - valueB, + }) + + const enqueue = (r, c) => { + if ( + 0 <= r && + r < grid.length && + 0 <= c && + c < grid[0].length && + grid[r][c] !== null + ) { + heap.enqueue({ row: r, col: c, value: grid[r][c] }) + grid[r][c] = null + } + } + enqueue(0, 0) + let count = 0 + const map = {} + const sortedQueries = [...queries].sort((x, y) => x - y) + + for (const query of sortedQueries) { + while (!heap.isEmpty()) { + const { row, col, value } = heap.front() + if (query <= value) break + heap.dequeue() + enqueue(row + 1, col) + enqueue(row - 1, col) + enqueue(row, col + 1) + enqueue(row, col - 1) + ++count + } + + map[query] = count + } + + return queries.map((query) => map[query]) +} diff --git a/2508-add-edges-to-make-degrees-of-all-nodes-even.js b/2508-add-edges-to-make-degrees-of-all-nodes-even.js new file mode 100644 index 00000000..f360018a --- /dev/null +++ b/2508-add-edges-to-make-degrees-of-all-nodes-even.js @@ -0,0 +1,55 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {boolean} + */ +const isPossible = (n, edges) => { + const g = initializeGraphSet(n) + packUG_Set(g, edges) + return canAddAtMost2EdgesMakeALLNodesDegreeEven(g) +} + +function initializeGraphSet(n) { + const g = [] + for (let i = 0; i < n; i++) { + g.push(new Set()) + } + return g +} +function packUG_Set(g, edges) { + for (const [u, v] of edges) { + g[u - 1].add(v - 1) + g[v - 1].add(u - 1) + } +} + +function canAddAtMost2EdgesMakeALLNodesDegreeEven(g) { + const oddNodes = [] + for (let i = 0; i < g.length; i++) { + let deg = g[i].size + if (deg % 2 == 1) { + oddNodes.push(i) + } + } + if (oddNodes.length == 0) { + // add no edge + return true + } else if (oddNodes.length == 2) { + // add one edge + let [a, b] = oddNodes + for (let k = 0; k < g.length; k++) { + // a <-> k b <-> k (k as transition node) + if (!g[a].has(k) && !g[b].has(k)) return true + } + return false + } else if (oddNodes.length == 4) { + // add two edges + let [a, b, c, d] = oddNodes // find two matched pairs valid + if (!g[a].has(b) && !g[c].has(d)) return true + if (!g[a].has(c) && !g[b].has(d)) return true + if (!g[a].has(d) && !g[c].has(b)) return true + return false + } else { + return false + } +} diff --git a/251-flatten-2d-vector.js b/251-flatten-2d-vector.js new file mode 100644 index 00000000..1a1e2f76 --- /dev/null +++ b/251-flatten-2d-vector.js @@ -0,0 +1,64 @@ +/** + * @param {number[][]} v + */ +const Vector2D = function(v) { + this.a = [] + this.idx = 0 + v.forEach(el => this.a.push(...el)) +}; + +/** + * @return {number} + */ +Vector2D.prototype.next = function() { + return this.a[this.idx++] +}; + +/** + * @return {boolean} + */ +Vector2D.prototype.hasNext = function() { + return this.idx <= this.a.length - 1 +}; + +/** + * Your Vector2D object will be instantiated and called as such: + * var obj = new Vector2D(v) + * var param_1 = obj.next() + * var param_2 = obj.hasNext() + */ + +// another + +/** + * @param {number[][]} v + */ +const Vector2D = function(v) { + this.iterator = v[Symbol.iterator]() + this.row = this.iterator.next() + this.idx = 0 +} +/** + * @return {number} + */ +Vector2D.prototype.next = function() { + if (this.hasNext()) { + return this.row.value[this.idx++] + } +} +/** + * @return {boolean} + */ +Vector2D.prototype.hasNext = function() { + while (this.row.done == false && this.idx == this.row.value.length) { + this.row = this.iterator.next() + this.idx = 0 + } + return this.row.done == false +} +/** + * Your Vector2D object will be instantiated and called as such: + * var obj = new Vector2D(v) + * var param_1 = obj.next() + * var param_2 = obj.hasNext() + */ diff --git a/2513-minimize-the-maximum-of-two-arrays.js b/2513-minimize-the-maximum-of-two-arrays.js new file mode 100644 index 00000000..b894fd36 --- /dev/null +++ b/2513-minimize-the-maximum-of-two-arrays.js @@ -0,0 +1,42 @@ +/** + * @param {number} divisor1 + * @param {number} divisor2 + * @param {number} uniqueCnt1 + * @param {number} uniqueCnt2 + * @return {number} + */ +var minimizeSet = function(divisor1, divisor2, uniqueCnt1, uniqueCnt2) { + let l = 1, r = 1e18 + const {floor: flr} = Math + while(l < r) { + const mid = l + flr((r - l) / 2) + if(notEnough(mid)) l = mid + 1 + else r = mid + } + return l + + + function notEnough(n) { + const a = n - flr(n / divisor1) + const b = n - flr(n / divisor2) + const c = n - (flr(n / divisor1) + flr(n / divisor2) - flr( n / lcm(divisor1, divisor2))) + if(a < uniqueCnt1) return true + if(b < uniqueCnt2) return true + if(a + b - c < uniqueCnt1 + uniqueCnt2) return true + return false + } +}; + +function gcd(a, b) { + while (b !== 0) { + [a, b] = [b, a % b]; + } + return a; +} + +function lcm(a, b) { + return (a / gcd(a, b)) * b; +} + + + diff --git a/2514-count-anagrams.js b/2514-count-anagrams.js new file mode 100644 index 00000000..a8b4e197 --- /dev/null +++ b/2514-count-anagrams.js @@ -0,0 +1,60 @@ +const mod = 1e9 + 7 +const fact = Array(1e5 + 2) +getfact() +// console.log(fact) +/** + * @param {string} s + * @return {number} + */ +const countAnagrams = function (s) { + let ans = 1 + const arr = s.trim().split(' ') + for (const word of arr) { + ans = modmul(ans, ways(word)) + } + + return ans +} + +function modmul(a, b) { + const big = BigInt + return Number(((big(a) % big(mod)) * (big(b) % big(mod))) % big(mod)) +} + +function binExpo(a, b) { + if (b === 0) return 1 + let res = binExpo(a, Math.floor(b / 2)) + if (b & 1) { + return modmul(a, modmul(res, res)) + } else { + return modmul(res, res) + } +} + +function modmulinv(a) { + return binExpo(a, mod - 2) +} + +function getfact() { + fact[0] = 1 + for (let i = 1; i <= 100001; i++) { + fact[i] = modmul(fact[i - 1], i) + } +} + +function ways(str) { + const freq = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for (let i = 0; i < str.length; i++) { + freq[str.charCodeAt(i) - a]++ + } + + let totalWays = fact[str.length] + + let factR = 1 + for (let i = 0; i < 26; i++) { + factR = modmul(factR, fact[freq[i]]) + } + // console.log(freq, totalWays, factR) + return modmul(totalWays, modmulinv(factR)) +} diff --git a/2516-take-k-of-each-character-from-left-and-right.js b/2516-take-k-of-each-character-from-left-and-right.js new file mode 100644 index 00000000..3ef81ae2 --- /dev/null +++ b/2516-take-k-of-each-character-from-left-and-right.js @@ -0,0 +1,70 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const takeCharacters = function(s, k) { + const n = s.length + const cnt = Array(3).fill(0) + const a = 'a'.charCodeAt(0) + for(const ch of s) { + cnt[ch.charCodeAt(0) - a]++ + } + const target = Array(3).fill(0) + for(let i = 0; i < 3; i++) { + target[i] = cnt[i] - k + } + for(let e of target) { + if(e < 0) return -1 + } + const arr = Array(3).fill(0) + let res = 0 + let i = 0 + for(let j = 0; j < n; j++) { + const idx = s[j].charCodeAt(0) - a + arr[idx]++ + while(!valid()) { + const ii = s[i].charCodeAt(0) - a + arr[ii]-- + i++ + } + res = Math.max(res, j - i + 1) + } + + return n - res + + function valid() { + return arr.every((e, i) => e <= target[i]) + } +}; + +// another + +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const takeCharacters = function(s, k) { + const cnt = {a: 0, b: 0, c: 0} + const n = s.length + for(const ch of s) { + cnt[ch]++ + } + if(cnt.a < k || cnt.b < k || cnt.c < k) return -1 + const limits = { a: cnt.a - k, b: cnt.b - k, c: cnt.c - k } + let l = 0, r = 0, res = 0 + const hash = {a: 0, b: 0, c: 0} + for(; r < n; r++) { + const cur = s[r] + hash[cur]++ + while(hash[cur] > limits[cur]) { + hash[s[l]]-- + l++ + } + + res = Math.max(res, r - l + 1) + } + + return n - res +}; diff --git a/2518-number-of-great-partitions.js b/2518-number-of-great-partitions.js new file mode 100644 index 00000000..6823b1af --- /dev/null +++ b/2518-number-of-great-partitions.js @@ -0,0 +1,98 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +function countPartitions(nums, k) { + const bi = BigInt + const mod = bi(1e9 + 7) + const n = nums.length, total = bi(2 ** n) + const sum = nums.reduce((ac, e) => ac + e, 0) + if(sum < 2 * k) return 0 + const dp = Array.from({ length: n + 1}, () => Array(k).fill(0n)) + for(let i = 0; i <= n; i++) dp[i][0] = 1n + + for(let i = 1; i <= n; i++) { + const e = nums[i - 1] + for(let j = 1; j < k; j++) { + dp[i][j] = dp[i - 1][j] + if(j >= e) dp[i][j] = bi(dp[i][j] + dp[i - 1][j - e]) % mod + } + } + const tmp = dp[n].reduce((ac, e) => ac + bi(e), 0n) + return (total - tmp * 2n) % mod +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +function countPartitions(nums, k) { + const mod = 1e9 + 7 + let total = 0 + let res = 1 + const dp = new Array(k).fill(0) + dp[0] = 1 + + for (let a of nums) { + for (let i = k - 1 - a; i >= 0; i--) { + dp[i + a] = (dp[i + a] + dp[i]) % mod + } + res = (res * 2) % mod + total += a + } + + for (let i = 0; i < k; i++) { + res -= total - i < k ? dp[i] : dp[i] * 2 + } + + return ((res % mod) + mod) % mod +} + +// another + + + +const ll = BigInt, + mod = 1e9 + 7, + bmod = ll(mod) +const sm = (a) => a.reduce((x, y) => x + y, 0) +const powmod = (a, b, mod) => { + let r = 1n + while (b > 0n) { + if (b % 2n == 1) r = (r * a) % mod + b >>= 1n + a = (a * a) % mod + } + return r +} +const minus_mod = (x, y, mod) => (((x - y) % mod) + mod) % mod +const knapsack_01 = (a, k) => { + if (sm(a) < 2 * k) return 0 + let dp = Array(k).fill(0) + dp[0] = 1 + for (const x of a) { + for (let j = k - 1; j > x - 1; j--) { + dp[j] += dp[j - x] + dp[j] %= mod + } + } + let bad = ll(sm(dp) * 2), + tot = powmod(2n, ll(a.length), bmod), + good = minus_mod(tot, bad, bmod) + return good +} +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countPartitions = function(nums, k) { + return knapsack_01(nums, k) +}; + + + diff --git a/252-meeting-rooms.js b/252-meeting-rooms.js new file mode 100644 index 00000000..fdb29954 --- /dev/null +++ b/252-meeting-rooms.js @@ -0,0 +1,29 @@ +/** + +Given an array of meeting time intervals consisting of +start and end times [[s1,e1],[s2,e2],...] (si < ei), +determine if a person could attend all meetings. + +Example 1: + +Input: [[0,30],[5,10],[15,20]] +Output: false +Example 2: + +Input: [[7,10],[2,4]] +Output: true + +*/ + +/** + * @param {number[][]} intervals + * @return {boolean} + */ +const canAttendMeetings = function(intervals) { + if(intervals == null || intervals.length === 0) return true + intervals.sort((a,b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]); + for (let i = 0; i < intervals.length - 1; i++) { + if (intervals[i][1] > intervals[i+1][0]) return false; + } + return true; +}; diff --git a/2521-distinct-prime-factors-of-product-of-array.js b/2521-distinct-prime-factors-of-product-of-array.js new file mode 100644 index 00000000..cf2c349b --- /dev/null +++ b/2521-distinct-prime-factors-of-product-of-array.js @@ -0,0 +1,40 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var distinctPrimeFactors = function(nums) { + const primes = getPrime(1000) + const ans = new Set() + nums.forEach(it => { + let cur = it + ans.add(primes[cur]) + while (primes[cur] != 1) { + ans.add(primes[cur]) + cur /= primes[cur] + } + ans.add(cur) + }) + ans.delete(1) + + return ans.size + + function getPrime(k) { + const minPrime = new Array(k + 1).fill(1) + let p = 2 + while (p <= k) { + let i = p + while (p <= k / i) { + if (minPrime[i * p] == 1) { + minPrime[i * p] = p + } + i++ + } + p++ + while (p <= k) { + if (minPrime[p] == 1) break + p++ + } + } + return minPrime + } +}; diff --git a/2522-partition-string-into-substrings-with-values-at-most-k.js b/2522-partition-string-into-substrings-with-values-at-most-k.js new file mode 100644 index 00000000..706d07c7 --- /dev/null +++ b/2522-partition-string-into-substrings-with-values-at-most-k.js @@ -0,0 +1,22 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const minimumPartition = function(s, k) { + const n = s.length, m = `${k}`.length + const dp = Array(n + 1).fill(0) + for(let i = 0; i < n; i++) { + if(m === 1 && +s[i] > k) return -1 + } + s = '#' + s + for(let i = 1; i <= n; i++) { + if(i - m + 1 > 0 && s.slice(i - m + 1, i + 1) <= k) { + dp[i] = dp[i - m] + 1 + } else { + dp[i] = dp[Math.max(0, i - m + 1)] + 1 + } + } + + return dp[n] +}; diff --git a/2523-closest-prime-numbers-in-range.js b/2523-closest-prime-numbers-in-range.js new file mode 100644 index 00000000..4b06cc56 --- /dev/null +++ b/2523-closest-prime-numbers-in-range.js @@ -0,0 +1,34 @@ +/** + * @param {number} left + * @param {number} right + * @return {number[]} + */ +var closestPrimes = function(left, right) { + let primeArr = []; + let res = [-1, -1]; + let minDiff = Infinity; + + for(let i=left; i<=right; i++){ + if(isPrime(i)) primeArr.push(i) + } + + for(let i=1; i= 0) sum -= sc[i - r - 1] + if(sum >= m) continue + const diff = m - sum + if(k < diff) return false + sc[min(n - 1, i + r)] += diff + sum = m + k -= diff + } + + return true + } + +}; diff --git a/2529-maximum-count-of-positive-integer-and-negative-integer.js b/2529-maximum-count-of-positive-integer-and-negative-integer.js new file mode 100644 index 00000000..d8f6a42f --- /dev/null +++ b/2529-maximum-count-of-positive-integer-and-negative-integer.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maximumCount = function(nums) { + let pos = 0, neg = 0 + + for(const e of nums) { + if(e > 0) pos++ + else if(e < 0) neg++ + } + + return Math.max(pos, neg) +}; diff --git a/253-meeting-rooms-ii.js b/253-meeting-rooms-ii.js new file mode 100644 index 00000000..fb5d5915 --- /dev/null +++ b/253-meeting-rooms-ii.js @@ -0,0 +1,161 @@ +/** + +Given an array of meeting time intervals consisting of +start and end times [[s1,e1],[s2,e2],...] (si < ei), +find the minimum number of conference rooms required. + +Example 1: + +Input: [[0, 30],[5, 10],[15, 20]] +Output: 2 +Example 2: + +Input: [[7,10],[2,4]] +Output: 1 + + */ + +/** + * @param {number[][]} intervals + * @return {number} + */ +const minMeetingRooms = function(intervals) { + const arr = Array(1e6 + 2).fill(0) + for(const [s, e] of intervals) { + arr[s]++ + arr[e]-- + } + let res = arr[0] + for(let i = 1; i < arr.length; i++) { + arr[i] += arr[i - 1] + res = Math.max(res, arr[i]) + } + + return res +}; + +// another + +/** + * @param {number[][]} intervals + * @return {number} + */ +const minMeetingRooms = function(intervals) { + const n = intervals.length + const start = Array(n), end = Array(n) + for(let i = 0; i < n; i++) { + start[i] = intervals[i][0] + end[i] = intervals[i][1] + } + start.sort((a, b) => a - b) + end.sort((a, b) => a - b) + + let res = 0, endIdx = 0 + for(let i = 0; i < n; i++) { + if(start[i] < end[endIdx]) res++ + else endIdx++ + } + + return res +} + + +// another + +/** + * @param {number[][]} intervals + * @return {number} + */ +const minMeetingRooms = function(intervals) { + let res = 0 + const sArr = [], eArr = [], n = intervals.length + for(const [s, e] of intervals) { + sArr.push(s) + eArr.push(e) + } + sArr.sort((a, b) => a - b) + eArr.sort((a, b) => a - b) + for(let i = 0, j = 0; i < n && j < n;) { + const s = sArr[i], e = eArr[j] + if(s < e) { + res++ + i++ + } else { + j++ + i++ + } + } + + return res +} + +// another + +/** + * @param {number[][]} intervals + * @return {number} + */ +const minMeetingRooms = function(intervals) { + intervals.sort((a, b) => a[0] - b[0] || a[1] - b[1]) + const n = intervals.length + const pq = new MinPriorityQueue() + let res = 0 + for(const [s, e] of intervals) { + while(!pq.isEmpty() && s >= pq.front().element) { + pq.dequeue() + } + pq.enqueue(e) + res = Math.max(res, pq.size()) + } + + return res +} + +// another + +/** + * @param {number[][]} intervals + * @return {number} + */ +const minMeetingRooms = function(intervals) { + const hash = {} + for(const [s, e] of intervals) { + hash[s] = (hash[s] || 0) + 1 + hash[e] = (hash[e] || 0) - 1 + } + let res = 0, cur = 0 + const keys = Object.keys(hash).map(e => +e) + keys.sort((a, b) => a - b) + for(const k of keys) { + cur += hash[k] + res = Math.max(res, cur) + } + return res +}; + +// another + +/** + * @param {number[][]} intervals + * @return {number} + */ +const minMeetingRooms = function(intervals) { + const n = intervals.length + const limit = 1e6 + 1 + const arr = Array(limit).fill(0) + let res = 0 + + for(const [start, end] of intervals) { + arr[start]++ + arr[end]-- + } + + for(let i = 1; i < limit; i++) { + arr[i] += arr[i - 1] + } + for(let i = 0; i < limit; i++) { + res = Math.max(res, arr[i]) + } + + return res +}; diff --git a/2530-maximal-score-after-applying-k-operations.js b/2530-maximal-score-after-applying-k-operations.js new file mode 100644 index 00000000..951db8f0 --- /dev/null +++ b/2530-maximal-score-after-applying-k-operations.js @@ -0,0 +1,86 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var maxKelements = function(nums, k) { + const pq = new PQ((a, b) => a > b) + for(const e of nums) pq.push(e) + let res = 0 + while(k) { + const tmp = pq.pop() + res += tmp + pq.push(Math.ceil(tmp / 3)) + k-- + } + + return res +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2531-make-number-of-distinct-characters-equal.js b/2531-make-number-of-distinct-characters-equal.js new file mode 100644 index 00000000..df247fbf --- /dev/null +++ b/2531-make-number-of-distinct-characters-equal.js @@ -0,0 +1,53 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {boolean} + */ +const isItPossible = function(word1, word2) { + const map1 = new Array(26).fill(0); + const map2 = new Array(26).fill(0); + + const a = 'a'.charCodeAt(0) + // store frequency of characters + for (const ch of word1) map1[ch.charCodeAt(0)-a]++; + for (const ch of word2) map2[ch.charCodeAt(0)-a]++; + + for (let i = 0; i < 26; i++) { + if (map1[i] === 0) continue; + for (let j = 0; j < 26; j++) { + if (map2[j] === 0) continue; + + // increase freq of char2 and decrease freq of char1 in map1 + map1[j]++; + map1[i]--; + + // increase freq of char1 and decrease freq of char2 in map2 + map2[i]++; + map2[j]--; + + // if equal number of unique characters, return true + if (same(map1, map2)) return true; + + // revert back changes + map1[j]--; + map1[i]++; + map2[i]--; + map2[j]++; + } + } + + return false; + + // check if both maps contain equal number of unique characters + function same( map1, map2) { + let count1 = 0; + let count2 = 0; + for (let i = 0; i < 26; i++) { + if (map1[i] > 0) count1++; + if (map2[i] > 0) count2++; + } + + return count1 === count2; + } +}; + diff --git a/2537-count-the-number-of-good-subarrays.js b/2537-count-the-number-of-good-subarrays.js new file mode 100644 index 00000000..59b89eff --- /dev/null +++ b/2537-count-the-number-of-good-subarrays.js @@ -0,0 +1,123 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countGood = function(nums, k) { + let res = 0; + const count = new Map(); + for(let i = 0, j = 0; j < nums.length; j++){ + k -= count.get(nums[j]) || 0; + count.set(nums[j], (count.get(nums[j]) || 0)+1); + + while(k <= 0){ + count.set(nums[i],count.get(nums[i])-1); + k += count.get(nums[i]); + i++ + } + res += i; + } + return res; +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countGood = function(nums, k) { + let res = 0, total = 0 + const cnt = {}, n = nums.length + + for(let i = 0, j = 0; i < n; i++) { + + while(j < n && total < k) { + total += diff(nums[j], 1) + cnt[nums[j]] = (cnt[nums[j]] || 0) + 1 + j++ + } + + if(total >= k) { + res += n - j + 1 + } + total += diff(nums[i], -1) + cnt[nums[i]]-- + } + + return res + + function diff(num, delta) { + const pre = cnt[num] || 0 + const old = pre * (pre - 1) / 2 + const post = pre + delta + const cur = post * (post - 1) / 2 + + return cur - old + } +}; + +// another + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countGood = function(nums, k) { + let res = 0; + const count = new Map() + for(let i = 0, j = 0; j < nums.length; ++j){ + k -= count.get(nums[j]) || 0; + count.set(nums[j], (count.get(nums[j]) || 0) + 1); + while(k <= 0) { + count.set(nums[i],count.get(nums[i]) - 1); + k += count.get(nums[i]); + i++ + } + res += i; + } + return res; +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countGood = function(nums, k) { + let res = 0 + let total = 0 + let i = 0, j = 0 + const n = nums.length + const cnt = {} + while(i < n) { + while(j < n && total < k) { + total += calc(cnt, nums[j], 1) + cnt[nums[j]] = (cnt[nums[j]] || 0) + 1 + j++ + } + if(total >= k) { + res += n - j + 1 + } + total += calc(cnt, nums[i], -1) + cnt[nums[i]]-- + + i++ + } + + return res + + function calc(cnt, num, delta) { + const tmp = cnt[num] || 0 + let res = tmp * (tmp - 1) / 2 + const tmp1 = tmp + delta + const tmp2 = tmp1 * (tmp1 - 1) / 2 + res = tmp2 - res + return res + } +}; diff --git a/2538-difference-between-maximum-and-minimum-price-sum.js b/2538-difference-between-maximum-and-minimum-price-sum.js new file mode 100644 index 00000000..ba08e423 --- /dev/null +++ b/2538-difference-between-maximum-and-minimum-price-sum.js @@ -0,0 +1,34 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} price + * @return {number} + */ +const maxOutput = function(n, edges, price) { + const tree = []; + const memo = []; + for (let i = 0; i < n; i++) tree[i] = []; + for (const [a, b] of edges) { + tree[a].push(b); + tree[b].push(a); + } + + let result = 0; + dfs(0, -1); + + function dfs(node, parent) { + const max = [price[node], 0]; + const nodes = tree[node] ?? []; + for (const child of nodes) { + if (child === parent) continue; + const sub = dfs(child, node); + result = Math.max(result, max[0] + sub[1]); + result = Math.max(result, max[1] + sub[0]); + max[0] = Math.max(max[0], sub[0] + price[node]); + max[1] = Math.max(max[1], sub[1] + price[node]); + } + return max; + } + + return result; +}; diff --git a/254-factor-combinations.js b/254-factor-combinations.js new file mode 100644 index 00000000..e7f906aa --- /dev/null +++ b/254-factor-combinations.js @@ -0,0 +1,69 @@ +/** + +Numbers can be regarded as product of its factors. For example, + +8 = 2 x 2 x 2; + = 2 x 4. +Write a function that takes an integer n and return all possible combinations of its factors. + +Note: + +You may assume that n is always positive. +Factors should be greater than 1 and less than n. +Example 1: + +Input: 1 +Output: [] +Example 2: + +Input: 37 +Output:[] +Example 3: + +Input: 12 +Output: +[ + [2, 6], + [2, 2, 3], + [3, 4] +] +Example 4: + +Input: 32 +Output: +[ + [2, 16], + [2, 2, 8], + [2, 2, 2, 4], + [2, 2, 2, 2, 2], + [2, 4, 4], + [4, 8] +] + +*/ + +/** + * @param {number} n + * @return {number[][]} + */ +const getFactors = function(n) { + if (n <= 0) { + return [] + } + const result = [] + helper(n, result, [], 2) + return result +} +const helper = (n, result, list, start) => { + for (let i = start; i * i <= n; i++) { + if (n % i === 0) { + list.push(i) + list.push(n / i) + result.push(list.slice()) + list.pop() + helper(n / i, result, list, i) + list.pop() + } + } +} + diff --git a/2542-maximum-subsequence-score.js b/2542-maximum-subsequence-score.js new file mode 100644 index 00000000..caadb31d --- /dev/null +++ b/2542-maximum-subsequence-score.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ +const maxScore = function(nums1, nums2, k) { + const pq = new MinPriorityQueue({ priority: e => e }) + const n = nums1.length + const arr = [] + + for(let i = 0; i < n; i++) { + arr.push([nums1[i], nums2[i]]) + } + + arr.sort((a, b) => b[1] - a[1]) + let res = 0, left = 0 + for(let i = 0; i < n; i++) { + const cur = arr[i] + pq.enqueue(cur[0]) + left += cur[0] + if(pq.size() > k) { + const tmp = pq.dequeue().element + left -= tmp + } + + if(pq.size() === k) { + res = Math.max(res, left * cur[1]) + } + } + + return res +}; diff --git a/2543-check-if-point-is-reachable.js b/2543-check-if-point-is-reachable.js new file mode 100644 index 00000000..c10a2f9f --- /dev/null +++ b/2543-check-if-point-is-reachable.js @@ -0,0 +1,13 @@ +/** + * @param {number} targetX + * @param {number} targetY + * @return {boolean} + */ +const isReachable = function(targetX, targetY) { + const g = gcd(targetX, targetY) + return (g & (g - 1)) === 0 + + function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) + } +}; diff --git a/2547-minimum-cost-to-split-an-array.js b/2547-minimum-cost-to-split-an-array.js new file mode 100644 index 00000000..8ff46ae8 --- /dev/null +++ b/2547-minimum-cost-to-split-an-array.js @@ -0,0 +1,52 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minCost = function (nums, k) { + const n = nums.length + const dp = Array(n + 1).fill(Infinity) + for(let i = 0; i < n; i++) { + let score = 0, hash = {} + for(let j = i; j >= 0; j--) { + const e = nums[j] + if(hash[e] == null) hash[e] = 0 + hash[e]++ + if(hash[e] === 2) score += 2 + else if(hash[e] > 2) score++ + + if(j > 0) dp[i] = Math.min(dp[i], dp[j - 1] + score + k) + else dp[i] = Math.min(dp[i], score + k) + } + } + + return dp[n - 1] +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minCost = function (nums, k) { + const n = nums.length, + max = Math.max(...nums), + dp = Array(n + 1).fill(Number.MAX_SAFE_INTEGER) + dp[0] = 0 + for (let i = 0; i < n; i++) { + let f = Array(max + 1).fill(0), + cost = 0 + for (let j = i; j < n; j++) { + f[nums[j]]++ + if (f[nums[j]] == 2) { + cost += 2 + } else if (f[nums[j]] > 2) { + cost++ + } + dp[j + 1] = Math.min(dp[i] + cost + k, dp[j + 1]) + } + } + return dp[n] +} diff --git a/255-verify-preorder-sequence-in-binary-search-tree.js b/255-verify-preorder-sequence-in-binary-search-tree.js new file mode 100644 index 00000000..4457702c --- /dev/null +++ b/255-verify-preorder-sequence-in-binary-search-tree.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} preorder + * @return {boolean} + */ +const verifyPreorder = function(preorder) { + let low = Number.MIN_VALUE, + i = -1 + for (let p of preorder) { + if (p < low) return false + while (i >= 0 && p > preorder[i]) low = preorder[i--] + preorder[++i] = p + } + return true +} diff --git a/2551-put-marbles-in-bags.js b/2551-put-marbles-in-bags.js new file mode 100644 index 00000000..860094d5 --- /dev/null +++ b/2551-put-marbles-in-bags.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} weights + * @param {number} k + * @return {number} + */ +const putMarbles = function (weights, k) { + if (weights.length === k) return 0 + let getEdgeWeights = weights.map((n, i, a) => + i < a.length - 1 ? n + a[i + 1] : 0 + ) + getEdgeWeights = getEdgeWeights.slice(0, weights.length - 1) + getEdgeWeights = getEdgeWeights.sort((a, b) => a - b) + let maxScores = getEdgeWeights + .slice(getEdgeWeights.length - k + 1) + .reduce((a, b) => a + b, 0) + let minScores = getEdgeWeights.slice(0, k - 1).reduce((a, b) => a + b, 0) + return maxScores - minScores +} diff --git a/2552-count-increasing-quadruplets.js b/2552-count-increasing-quadruplets.js new file mode 100644 index 00000000..89e05c6e --- /dev/null +++ b/2552-count-increasing-quadruplets.js @@ -0,0 +1,50 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const countQuadruplets = function(nums) { + let res = 0, n = nums.length + const cnt = Array(n).fill(0) + + for(let j = 0; j < n; j++) { + let preSmall = 0 + for(let i = 0; i < j; i++) { + if(nums[i] < nums[j]) { + preSmall++ + res += cnt[i] + } else if(nums[j] < nums[i]) { + cnt[i] += preSmall + } + } + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const countQuadruplets = function(nums) { + const B = new Array(nums.length + 1).fill(0); + let quadruplets = 0; + + for (let i = 0; i < nums.length; i += 1) { + let countSmaller = 0; + + for (let j = 0; j < i; j += 1) { + if (nums[j] < nums[i]) { + countSmaller += 1; + quadruplets += B[nums[j]]; + } else { + // countSmaller is all the As nums[j] is the B, nums[i] is C + // so nums[j] is apart of countSmaller A-B-C relationships with nums[i] + B[nums[j]] += countSmaller; + } + } + } + + return quadruplets +}; diff --git a/2555-maximize-win-from-two-segments.js b/2555-maximize-win-from-two-segments.js new file mode 100644 index 00000000..a2d06c88 --- /dev/null +++ b/2555-maximize-win-from-two-segments.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} prizePositions + * @param {number} k + * @return {number} + */ +const maximizeWin = function(prizePositions, k) { + let res = 0, j = 0 + const n = prizePositions.length, dp = new Array(n + 1).fill(0); + for (let i = 0; i < n; ++i) { + while (prizePositions[j] < prizePositions[i] - k) ++j; + dp[i + 1] = Math.max(dp[i], i - j + 1); + res = Math.max(res, i - j + 1 + dp[j]); + } + return res; +}; diff --git a/2556-disconnect-path-in-a-binary-matrix-by-at-most-one-flip.js b/2556-disconnect-path-in-a-binary-matrix-by-at-most-one-flip.js new file mode 100644 index 00000000..ddec85ef --- /dev/null +++ b/2556-disconnect-path-in-a-binary-matrix-by-at-most-one-flip.js @@ -0,0 +1,42 @@ +/** + * @param {number[][]} grid + * @return {boolean} + */ +const isPossibleToCutPath = function(grid) { + const m = grid.length, n = grid[0].length + const pre = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)) + const suf = Array.from({ length: m + 2 }, () => Array(n + 2).fill(0)) + + for(let i = 1; i <= m; i++) { + for(let j = 1; j <= n; j++) { + if(i === 1 && j === 1) pre[i][j] = 1 + else if(grid[i - 1][j - 1] === 1) { + pre[i][j] = pre[i - 1][j] + pre[i][j - 1] + } + } + } + + for(let i = m; i > 0; i--) { + for(let j = n; j > 0; j--) { + if(i === m && j === n) suf[i][j] = 1 + else if(grid[i - 1][j - 1] === 1) { + suf[i][j] = suf[i + 1][j] + suf[i][j + 1] + } + } + } + // console.log(pre, suf) + + const target = pre[m][n] + + for(let i = 1; i <= m; i++) { + for(let j = 1; j <= n; j++) { + if(i === 1 && j === 1) continue + if(i === m && j === n) continue + if(pre[i][j] * suf[i][j] === target) { + return true + } + } + } + + return false +}; diff --git a/2557-maximum-number-of-integers-to-choose-from-a-range-ii.js b/2557-maximum-number-of-integers-to-choose-from-a-range-ii.js new file mode 100644 index 00000000..376d4586 --- /dev/null +++ b/2557-maximum-number-of-integers-to-choose-from-a-range-ii.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} banned + * @param {number} n + * @param {number} maxSum + * @return {number} + */ +var maxCount = function(banned, n, maxSum) { + const set = new Set(banned); + + let low = 0; + let high = n; + let possibleVal = 0; + while (low <= high) { + const mid = Math.floor((low + high) / 2); + let totalSum = (mid * (mid + 1)) / 2; + for (const val of set) { + if (val <= mid) totalSum -= val; + } + + if (totalSum <= maxSum) { + possibleVal = mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + + let ans = possibleVal; + for (const val of set) { + if (val <= possibleVal) ans--; + } + + return ans; +}; diff --git a/2558-take-gifts-from-the-richest-pile.js b/2558-take-gifts-from-the-richest-pile.js new file mode 100644 index 00000000..2efda9f0 --- /dev/null +++ b/2558-take-gifts-from-the-richest-pile.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} gifts + * @param {number} k + * @return {number} + */ +const pickGifts = function(gifts, k) { + + const n = gifts.length + while(k > 0) { + + const max = Math.max(...gifts) + const idx = gifts.indexOf(max) + gifts[idx] = ~~(Math.sqrt(max)) + + k-- + } + + return gifts.reduce((ac, e) => ac + e, 0) +}; diff --git a/2559-count-vowel-strings-in-ranges.js b/2559-count-vowel-strings-in-ranges.js new file mode 100644 index 00000000..ff31c5be --- /dev/null +++ b/2559-count-vowel-strings-in-ranges.js @@ -0,0 +1,27 @@ +/** + * @param {string[]} words + * @param {number[][]} queries + * @return {number[]} + */ +const vowelStrings = function(words, queries) { + const n = words.length + const pre = Array(n + 1).fill(0) + const set = new Set(['a', 'e', 'i', 'o', 'u']) + for(let i = 0; i < n; i++) { + const cur = words[i] + if(set.has(cur[0]) && set.has(cur[cur.length - 1])) pre[i + 1] = 1 + } + + const cnt = Array(n + 1).fill(0) + for(let i = 1; i <= n; i++) { + cnt[i] = cnt[i - 1] + pre[i] + } + + const res = [] + + for(const [l, r] of queries) { + res.push(cnt[r + 1] - cnt[l]) + } + + return res +}; diff --git a/256-paint-house.js b/256-paint-house.js new file mode 100644 index 00000000..8ec40906 --- /dev/null +++ b/256-paint-house.js @@ -0,0 +1,17 @@ +/** + * @param {number[][]} costs + * @return {number} + */ +const minCost = function(costs) { + if (!costs || costs.length < 1) return 0 + const n = costs.length + for (let i = 1; i < n; i++) { + const c = costs[i], + cPrev = costs[i - 1] + c[0] += Math.min(cPrev[1], cPrev[2]) + c[1] += Math.min(cPrev[0], cPrev[2]) + c[2] += Math.min(cPrev[0], cPrev[1]) + } + const cLast = costs[n - 1] + return Math.min(cLast[0], cLast[1], cLast[2]) +} diff --git a/2560-house-robber-iv.js b/2560-house-robber-iv.js new file mode 100644 index 00000000..3a297193 --- /dev/null +++ b/2560-house-robber-iv.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minCapability = function(nums, k) { + const n = nums.length + let l = 1, r = 1e9 + while(l < r) { + const mid = Math.floor((l + r) / 2) + let cnt = 0 + for(let i = 0; i < n; i++) { + if(nums[i] <= mid) { + cnt++ + i++ + } + } + if(cnt >= k) r = mid + else l = mid + 1 + } + return l +}; diff --git a/2561-rearranging-fruits.js b/2561-rearranging-fruits.js new file mode 100644 index 00000000..1b630ba9 --- /dev/null +++ b/2561-rearranging-fruits.js @@ -0,0 +1,53 @@ +/** + * @param {number[]} basket1 + * @param {number[]} basket2 + * @return {number} + */ +const minCost = function (basket1, basket2) { + const [map1, map2] = [new Map(), new Map()] + let minVal = Number.MAX_SAFE_INTEGER + + for (const val of basket1) { + if (!map1.has(val)) map1.set(val, 0) + map1.set(val, map1.get(val) + 1) + minVal = Math.min(minVal, val) + } + for (const val of basket2) { + if (!map2.has(val)) map2.set(val, 0) + map2.set(val, map2.get(val) + 1) + minVal = Math.min(minVal, val) + } + + const [swapList1, swapList2] = [[], []] + for (const [key, c1] of map1.entries()) { + const c2 = map2.get(key) || 0 + if ((c1 + c2) % 2) return -1 + if (c1 > c2) { + let addCnt = (c1 - c2) >> 1 + while (addCnt--) { + swapList1.push(key) + } + } + } + for (const [key, c2] of map2.entries()) { + const c1 = map1.get(key) || 0 + if ((c1 + c2) % 2) return -1 + if (c2 > c1) { + let addCnt = (c2 - c1) >> 1 + while (addCnt--) { + swapList2.push(key) + } + } + } + + swapList1.sort((a, b) => a - b) + swapList2.sort((a, b) => b - a) + const n = swapList1.length + + let res = 0 + for (let i = 0; i < n; i++) { + res += Math.min(2 * minVal, swapList1[i], swapList2[i]) + } + + return res +} diff --git a/2563-count-the-number-of-fair-pairs.js b/2563-count-the-number-of-fair-pairs.js new file mode 100644 index 00000000..3db06363 --- /dev/null +++ b/2563-count-the-number-of-fair-pairs.js @@ -0,0 +1,69 @@ +/** + * @param {number[]} nums + * @param {number} lower + * @param {number} upper + * @return {number} + */ +const countFairPairs = function(nums, lower, upper) { + const n = nums.length + nums.sort((a, b) => a - b) + + let total = BigInt(n * (n - 1)) / 2n + return Number(total - BigInt(large(nums, upper) + low(nums, lower))) +}; + + +function large(arr, target) { + let count = 0; + for (let lo = 0, hi = arr.length - 1; lo < hi; ) { + if (arr[lo] + arr[hi] > target) { + count += (hi - lo); + hi--; + } else { + lo++; + } + } + return count; +} + +function low(arr, target) { + let count = 0; + for (let lo = 0, hi = arr.length - 1; lo < hi; ) { + if (arr[lo] + arr[hi] < target) { + count += (hi - lo); + lo++; + } else { + hi--; + } + } + return count; +} + +// another + +/** + * @param {number[]} nums + * @param {number} lower + * @param {number} upper + * @return {number} + */ +const countFairPairs = function(nums, lower, upper) { + nums.sort((a, b) => a - b) + return lowerBound(nums, upper + 1) - lowerBound(nums, lower) +}; + +function lowerBound(nums, value) { + let l = 0, r = nums.length - 1 + let res = 0 + while(l < r) { + const sum = nums[l] + nums[r] + if(sum < value) { + res += r - l + l++ + } else { + r-- + } + } + + return res +} diff --git a/2564-substring-xor-queries.js b/2564-substring-xor-queries.js new file mode 100644 index 00000000..f689aefb --- /dev/null +++ b/2564-substring-xor-queries.js @@ -0,0 +1,30 @@ +/** + * @param {string} s + * @param {number[][]} queries + * @return {number[][]} + */ +const substringXorQueries = function(s, queries) { + const n = s.length, q = queries.length + const res = [] + const map = {}, { max, min } = Math, int = parseInt, big = BigInt + + for(let i = 0; i < n; i++) { + if(s[i] === '0') { + if(map[0] == null) map[0] = [i, i] + continue + } + let num = 0n + for(let j = i; j <= min(i + 32, n - 1); j++) { + num = (num << 1n) + big(int(s[j])) + if(map[num] == null) map[num] = [i, j] + } + } + for(let i = 0; i < q; i++) { + const [fir, sec] = queries[i] + const num = fir ^ sec + if(map[num] != null) res.push([...map[num]]) + else res.push([-1, -1]) + } + + return res +}; diff --git a/2565-subsequence-with-the-minimum-score.js b/2565-subsequence-with-the-minimum-score.js new file mode 100644 index 00000000..e3dc5adc --- /dev/null +++ b/2565-subsequence-with-the-minimum-score.js @@ -0,0 +1,22 @@ +/** + * @param {string} s + * @param {string} t + * @return {number} + */ +var minimumScore = function(s, t) { + let sl = s.length, tl = t.length, k = tl - 1; + const dp = new Array(tl).fill(-1); + for (let i = sl - 1; i >= 0 && k >= 0; --i) { + if (s.charAt(i) === t.charAt(k)) dp[k--] = i; + } + let res = k + 1; + for (let i = 0, j = 0; i < sl && j < tl && res > 0; ++i) { + if (s.charAt(i) === t.charAt(j)) { + while(k < tl && dp[k] <= i) k++ + j++ + res = Math.min(res, k - j); + } + } + + return res; +}; diff --git a/2567-minimum-score-by-changing-two-elements.js b/2567-minimum-score-by-changing-two-elements.js new file mode 100644 index 00000000..cf2a5321 --- /dev/null +++ b/2567-minimum-score-by-changing-two-elements.js @@ -0,0 +1,51 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimizeSum = function(nums) { + let s1 = Infinity, s2 = Infinity, s3 = Infinity + let l1 = -1, l2 = -1, l3 = -1 + const { max, min } = Math + // s1, s2, s3, ..., l3, l2, l1 + for(const e of nums) { + if(s1 > e) { + s3 = s2; + s2 = s1; + s1 = e; + } else if(s2 > e) { + s3 = s2 + s2 = e + } else if(s3 > e) { + s3 = e + } + + if(e > l1) { + l3 = l2 + l2 = l1 + l1 = e + } else if(e > l2) { + l3 = l2 + l2 = e + } else if(e > l3) { + l3 = e + } + } + + return min(l1 - s3, l2 - s2, l3 - s1) +}; + +// another + + +/** + * @param {number[]} nums + * @return {number} + */ +const minimizeSum = function(nums) { + nums.sort((a, b) => a - b) + const { max, min, abs } = Math + const res1 = nums.at(-1) - nums[2] + const res2 = nums.at(-2) - nums[1] + const res3 = nums.at(-3) - nums[0] + return min(res1, res2, res3) +}; diff --git a/2568-minimum-impossible-or.js b/2568-minimum-impossible-or.js new file mode 100644 index 00000000..a5609aab --- /dev/null +++ b/2568-minimum-impossible-or.js @@ -0,0 +1,11 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minImpossibleOR = function(nums) { + const s = new Set(); + for (const e of nums) s.add(e); + let res = 1; + while (s.has(res)) res <<= 1; + return res; +}; diff --git a/2570-merge-two-2d-arrays-by-summing-values.js b/2570-merge-two-2d-arrays-by-summing-values.js new file mode 100644 index 00000000..5b87f11c --- /dev/null +++ b/2570-merge-two-2d-arrays-by-summing-values.js @@ -0,0 +1,19 @@ +/** + * @param {number[][]} nums1 + * @param {number[][]} nums2 + * @return {number[][]} + */ +var mergeArrays = function(nums1, nums2) { + const map = new Map() + for(const [id, val] of nums1) { + if(!map.has(id)) map.set(id, 0) + map.set(id, map.get(id) + val) + } + for(const [id, val] of nums2) { + if(!map.has(id)) map.set(id, 0) + map.set(id, map.get(id) + val) + } + const entries = [...map.entries()] + entries.sort((a, b) => a[0] - b[0]) + return entries +}; diff --git a/2571-minimum-operations-to-reduce-an-integer-to-0.js b/2571-minimum-operations-to-reduce-an-integer-to-0.js new file mode 100644 index 00000000..70758216 --- /dev/null +++ b/2571-minimum-operations-to-reduce-an-integer-to-0.js @@ -0,0 +1,54 @@ +function dec2bin(dec) { + return (dec >>> 0).toString(2); +} +function bitCnt(s) { + let res = 0 + for(const e of s) { + if(e === '1') res++ + } + return res +} +function cnt(num) { + return bitCnt(dec2bin(num)) +} +/** + * @param {number} n + * @return {number} + */ +const minOperations = function(n) { + let res = 0 + for(let i = 0; i < 14; i++) { + if(cnt(n + (1 << i)) < cnt(n)) { + res++ + n += (1 << i) + } + } + + return res + cnt(n) +}; + +// another + + +function dec2bin(dec) { + return (dec >>> 0).toString(2); +} +function bitCnt(s) { + let res = 0 + for(const e of s) { + if(e === '1') res++ + } + return res +} +/** + * @param {number} n + * @return {number} + */ +var minOperations = function(n) { + if(n === 0) return 0 + if(bitCnt(dec2bin(n)) === 1) return 1 + const lowBit = n & -n + let low = minOperations(n + lowBit); + let high = minOperations(n - lowBit); + return Math.min(low, high) + 1; +}; diff --git a/2572-count-the-number-of-square-free-subsets.js b/2572-count-the-number-of-square-free-subsets.js new file mode 100644 index 00000000..2100de59 --- /dev/null +++ b/2572-count-the-number-of-square-free-subsets.js @@ -0,0 +1,48 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const squareFreeSubsets = function(nums) { + const primes = [2,3,5,7,11,13,17,19,23,29] + const n = nums.length + const limit = 1 << primes.length, mod = 1e9 + 7 + const dp = Array.from({ length: n + 1 }, () => Array(limit).fill(0)) + dp[0][0] = 1 + const arr = [0, ...nums] + let res = 0 + for(let i = 1; i <= n; i++) { + const cur = arr[i] + for(let mask = 0; mask < limit; mask++) { + if(cur === 1) { + dp[i][mask] = (dp[i - 1][mask] * 2) % mod + } else { + dp[i][mask] = dp[i - 1][mask] + const sub = helper(cur) + if(sub !== -1 && (mask & sub) === sub) { + dp[i][mask] = (dp[i][mask] + dp[i - 1][mask - sub]) % mod + } + } + if(i === n) { + res = (res + dp[i][mask]) % mod + } + } + } + + return (res + mod - 1) % mod + + function helper(x) { + let res = 0 + for(let i = 0; i < primes.length; i++) { + let cnt = 0 + while(x && (x % primes[i] === 0)) { + cnt++ + x = x / primes[i] + } + if(cnt > 1) return -1 + else if(cnt === 1) { + res = res | (1 << i) + } + } + return res + } +}; diff --git a/2572-find-the-divisibility-array-of-a-string.js b/2572-find-the-divisibility-array-of-a-string.js new file mode 100644 index 00000000..b9934b8a --- /dev/null +++ b/2572-find-the-divisibility-array-of-a-string.js @@ -0,0 +1,14 @@ +/** + * @param {string} word + * @param {number} m + * @return {number[]} + */ +const divisibilityArray = function(word, m) { + let ans = []; + let cur = 0; + for (let i = 0; i < word.length; i++) { + cur = (cur * 10 + Number(word[i])) % m; + ans.push(cur === 0 ? 1 : 0); + } + return ans; +}; diff --git a/2573-find-the-string-with-lcp.js b/2573-find-the-string-with-lcp.js new file mode 100644 index 00000000..83ab6c20 --- /dev/null +++ b/2573-find-the-string-with-lcp.js @@ -0,0 +1,27 @@ +/** + * @param {number[][]} lcp + * @return {string} + */ +const findTheString = function (lcp) { + const n = lcp.length + let c = 0 + const arr = new Array(n).fill(0) + for (let i = 0; i < n; ++i) { + if (arr[i] > 0) continue + if (++c > 26) return '' + for (let j = i; j < n; ++j) { + if (lcp[i][j] > 0) arr[j] = c + } + } + for (let i = 0; i < n; ++i) { + for (let j = 0; j < n; ++j) { + let v = i + 1 < n && j + 1 < n ? lcp[i + 1][j + 1] : 0 + v = arr[i] === arr[j] ? v + 1 : 0 + if (lcp[i][j] != v) return '' + } + } + const res = [] + const ac = 'a'.charCodeAt(0) + for (let a of arr) res.push(String.fromCharCode(ac + a - 1)) + return res.join('') +} diff --git a/2574-left-and-right-sum-differences.js b/2574-left-and-right-sum-differences.js new file mode 100644 index 00000000..f3fa4833 --- /dev/null +++ b/2574-left-and-right-sum-differences.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const leftRigthDifference = function(nums) { + const {abs} = Math + const n = nums.length + + const pre = new Array(n + 2).fill(0) + const post = new Array(n + 2).fill(0) + const res = [] + for(let i = 1, cur = 0; i <= n; i++) { + pre[i] = cur + cur += nums[i - 1] + } + + for(let i = n, cur = 0; i >= 1; i--) { + post[i] = cur + cur += nums[i - 1] + } + + for(let i = 1; i <= n; i++) { + res[i - 1] = abs(pre[i] - post[i]) + } + + return res +}; diff --git a/2576-find-the-maximum-number-of-marked-indices.js b/2576-find-the-maximum-number-of-marked-indices.js new file mode 100644 index 00000000..2672d5af --- /dev/null +++ b/2576-find-the-maximum-number-of-marked-indices.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maxNumOfMarkedIndices = function(nums) { + let res = 0 + const n = nums.length + nums.sort((a, b) => a - b) + for(let i = 0, j = Math.floor((n + 1) / 2); j < n; j++) { + if(nums[i] * 2 <= nums[j]) { + res += 2 + i++ + } + } + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxNumOfMarkedIndices = function(nums) { + let i = 0, n = nums.length; + nums.sort((a, b) => a - b) + for (let j = n - (~~(n / 2)); j < n; ++j) { + i += 2 * nums[i] <= nums[j] ? 1 : 0; + } + return i * 2; +}; diff --git a/2577-minimum-time-to-visit-a-cell-in-a-grid.js b/2577-minimum-time-to-visit-a-cell-in-a-grid.js new file mode 100644 index 00000000..765f81e5 --- /dev/null +++ b/2577-minimum-time-to-visit-a-cell-in-a-grid.js @@ -0,0 +1,255 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var minimumTime = function(grid) { + if(grid[0][0] > 0) return -1 + if(grid[0][1] > 1 && grid[1][0] > 1) return -1 + const m = grid.length, n = grid[0].length; + const pq = new PQ((a, b) => a[0] < b[0]); + pq.push([0, 0, 0]); + const dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]]; + const dist = Array.from({ length: m }, () => Array(n).fill(-1)); + + while (!pq.isEmpty()) { + const [t, i, j] = pq.pop(); + if (dist[i][j] !== -1) continue; + dist[i][j] = t + if (i === m - 1 && j === n - 1) break; + for(const [di, dj] of dirs) { + const ni = i + di, nj = j + dj; + if (ni < 0 || ni >= m || nj < 0 || nj >= n) continue; + if (dist[ni][nj] !== -1) continue; + if(grid[ni][nj] <= t + 1) { + pq.push([t + 1, ni, nj]); + } else if ((grid[ni][nj] - t) % 2 === 0) { + pq.push([grid[ni][nj] + 1, ni, nj]); + } else { + pq.push([grid[ni][nj], ni, nj]); + } + } + } + + return dist[m - 1][n - 1]; +}; + + +// another + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +/** + * @param {number[][]} grid + * @return {number} + */ +const minimumTime = function (grid) { + if (grid[0][1] > 1 && grid[1][0] > 1) return -1; + const dirs = [ + [-1, 0], + [0, 1], + [1, 0], + [0, -1], + ] + let m = grid.length, + n = grid[0].length + const visited = Array.from({ length: m }, () => Array(n).fill(false)) + const pq = new PQ((a, b) => a[0] < b[0]) + pq.push([grid[0][0], 0, 0]) + + while(!pq.isEmpty()) { + const [v, r, c] = pq.pop() + if(r === m - 1 && c === n - 1) return v + if(visited[r][c]) continue + visited[r][c] = true + for(const [dr, dc] of dirs) { + const nr = r + dr, nc = c + dc + if(nr >= 0 && nr < m && nc >= 0 && nc < n && visited[nr][nc] === false) { + const wait = (grid[nr][nc] - v) % 2 === 0 ? 1 : 0 + pq.push([Math.max(v + 1, grid[nr][nc] + wait), nr, nc]) + } + } + } + + return -1 +} + + +// another + + +/** + * @param {number[][]} grid + * @return {number} + */ +const minimumTime = function (grid) { + const directions = [ + [-1, 0], + [0, 1], + [1, 0], + [0, -1], + ] + let m = grid.length, + n = grid[0].length + if (grid[0][1] > 1 && grid[1][0] > 1) return -1 + let dist = Array(m) + .fill(0) + .map(() => Array(n).fill(Infinity)) + let heap = new Heap((a, b) => a[2] - b[2]) + heap.add([0, 0, 0]) + dist[0][0] = 0 + + while (!heap.isEmpty()) { + let [row, col, time] = heap.remove() + if (dist[row][col] < time) continue + if (row === m - 1 && col === n - 1) return time + for (let [x, y] of directions) { + let newRow = row + x, + newCol = col + y + if (newRow < 0 || newRow >= m || newCol < 0 || newCol >= n) continue + let diff = grid[newRow][newCol] - time + let moves = diff % 2 === 1 ? diff : diff + 1 + let weight = grid[newRow][newCol] <= time + 1 ? 1 : moves + if (dist[newRow][newCol] > time + weight) { + dist[newRow][newCol] = Math.min(dist[newRow][newCol], time + weight) + heap.add([newRow, newCol, time + weight]) + } + } + } +} + +class Heap { + constructor(comparator = (a, b) => a - b) { + this.values = [] + this.comparator = comparator + this.size = 0 + } + add(val) { + this.size++ + this.values.push(val) + let idx = this.size - 1, + parentIdx = Math.floor((idx - 1) / 2) + while ( + parentIdx >= 0 && + this.comparator(this.values[parentIdx], this.values[idx]) > 0 + ) { + ;[this.values[parentIdx], this.values[idx]] = [ + this.values[idx], + this.values[parentIdx], + ] + idx = parentIdx + parentIdx = Math.floor((idx - 1) / 2) + } + } + remove() { + if (this.size === 0) return -1 + this.size-- + if (this.size === 0) return this.values.pop() + let removedVal = this.values[0] + this.values[0] = this.values.pop() + let idx = 0 + while (idx < this.size && idx < Math.floor(this.size / 2)) { + let leftIdx = idx * 2 + 1, + rightIdx = idx * 2 + 2 + if (rightIdx === this.size) { + if (this.comparator(this.values[leftIdx], this.values[idx]) > 0) break + ;[this.values[leftIdx], this.values[idx]] = [ + this.values[idx], + this.values[leftIdx], + ] + idx = leftIdx + } else if ( + this.comparator(this.values[leftIdx], this.values[idx]) < 0 || + this.comparator(this.values[rightIdx], this.values[idx]) < 0 + ) { + if (this.comparator(this.values[leftIdx], this.values[rightIdx]) <= 0) { + ;[this.values[leftIdx], this.values[idx]] = [ + this.values[idx], + this.values[leftIdx], + ] + idx = leftIdx + } else { + ;[this.values[rightIdx], this.values[idx]] = [ + this.values[idx], + this.values[rightIdx], + ] + idx = rightIdx + } + } else { + break + } + } + return removedVal + } + top() { + return this.values[0] + } + isEmpty() { + return this.size === 0 + } +} diff --git a/258-add-digits.js b/258-add-digits.js index 21cbdbab..510713b0 100755 --- a/258-add-digits.js +++ b/258-add-digits.js @@ -13,5 +13,15 @@ const addDigits = function(num) { return +res; }; +// another + +/** + * @param {number} num + * @return {number} + */ +const addDigits = function(num) { + return 1 + (num - 1) % 9; +}; + console.log(addDigits(0)); console.log(addDigits(38)); diff --git a/2580-count-ways-to-group-overlapping-ranges.js b/2580-count-ways-to-group-overlapping-ranges.js new file mode 100644 index 00000000..11817f76 --- /dev/null +++ b/2580-count-ways-to-group-overlapping-ranges.js @@ -0,0 +1,15 @@ +/** + * @param {number[][]} ranges + * @return {number} + */ +const countWays = function(ranges) { + const mod = 1e9 + 7 + const n = ranges.length + ranges.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) + let last = -1, res = 1 + for (const r of ranges) { + if (last < r[0]) res = res * 2 % mod; + last = Math.max(last, r[1]); + } + return res +}; diff --git a/2581-count-number-of-possible-root-nodes.js b/2581-count-number-of-possible-root-nodes.js new file mode 100644 index 00000000..49c2615c --- /dev/null +++ b/2581-count-number-of-possible-root-nodes.js @@ -0,0 +1,45 @@ +/** + * @param {number[][]} edges + * @param {number[][]} guesses + * @param {number} k + * @return {number} + */ +const rootCount = function (edges, guesses, k) { + const lookup = new Set(guesses.map(([a, b]) => a * 1_000_000 + b)) + const adjList = edges.reduce( + (adjList, [a, b]) => { + adjList[a].push(b) + adjList[b].push(a) + return adjList + }, + new Array(edges.length + 1).fill(0).map(() => []), + ) + + const guessed = (a, b) => (lookup.has(a * 1_000_000 + b) ? 1 : 0) + + const getCorrect = (node, parent) => + adjList[node].reduce( + (total, child) => + child === parent + ? total + : total + guessed(node, child) + getCorrect(child, node), + 0, + ) + + const getTotal = (node, parent, correct) => + (correct >= k ? 1 : 0) + + adjList[node].reduce( + (total, child) => + child === parent + ? total + : total + + getTotal( + child, + node, + correct - guessed(node, child) + guessed(child, node), + ), + 0, + ) + + return getTotal(0, -1, getCorrect(0, -1)) +} diff --git a/2582-pass-the-pillow.js b/2582-pass-the-pillow.js new file mode 100644 index 00000000..52ad735c --- /dev/null +++ b/2582-pass-the-pillow.js @@ -0,0 +1,11 @@ +/** + * @param {number} n + * @param {number} time + * @return {number} + */ +const passThePillow = function(n, time) { + const k = ~~(time / (n - 1)) + const r = time % (n - 1) + + return k % 2 === 1 ? n - r : r + 1 +}; diff --git a/2583-kth-largest-sum-in-a-binary-tree.js b/2583-kth-largest-sum-in-a-binary-tree.js new file mode 100644 index 00000000..214b31f6 --- /dev/null +++ b/2583-kth-largest-sum-in-a-binary-tree.js @@ -0,0 +1,102 @@ +/** + * 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 + * @param {number} k + * @return {number} + */ +const kthLargestLevelSum = function(root, k) { + let row = [root] + const pq = new PQ((a, b) => a < b) + while(row.length) { + let sum = 0 + const nxt = [] + const len = row.length + for(let i = 0; i < len; i++) { + const cur = row[i] + sum += cur.val + if(cur.left) nxt.push(cur.left) + if(cur.right) nxt.push(cur.right) + } + + pq.push(sum) + if(pq.size() > k) pq.pop() + row = nxt + } + + return pq.size() < k ? -1 : pq.peek() +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2584-split-the-array-to-make-coprime-products.js b/2584-split-the-array-to-make-coprime-products.js new file mode 100644 index 00000000..dae2db5e --- /dev/null +++ b/2584-split-the-array-to-make-coprime-products.js @@ -0,0 +1,159 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var findValidSplit = function(nums) { + const rightCounter = new Map(); + + for (const num of nums) { + for (const [prime, count] of getPrimesCount(num)) { + rightCounter.set(prime, (rightCounter.get(prime) ?? 0) + count); + } + } + + const leftCounter = new Map(); + const common = new Set(); + + for (let i = 0; i < nums.length - 1; i++) { + for (const [prime, count] of getPrimesCount(nums[i])) { + leftCounter.set(prime, (leftCounter.get(prime) ?? 0) + count); + rightCounter.set(prime, rightCounter.get(prime) - count); + + if (rightCounter.get(prime) > 0) common.add(prime); + if (rightCounter.get(prime) === 0) common.delete(prime); + } + + if (common.size === 0) return i; + } + + return -1; +}; + +function getPrimesCount(n) { + const count = new Map(); + + for (let i = 2; (i * i) <= n; i++) { + while (n % i === 0) { + count.set(i, (count.get(i) ?? 0) + 1); + n /= i; + } + } + + if (n > 1) { + count.set(n, (count.get(n) ?? 0) + 1); + } + + return count; +} + +// another + + +/** + * @param {number[]} nums + * @return {number} + */ +const findValidSplit = function(nums) { + const n = nums.length, right = {}; + for (let i = 0; i < n; i++) { + const primeFactorsCount = getPrimeFactors(nums[i]); + for (let prime in primeFactorsCount) { + const count = primeFactorsCount[prime]; + right[prime] = (right[prime] || 0) + count; + } + } + const left = {}, common = new Set(); + for (let i = 0; i <= n - 2; i++) { + const primesFactorsCount = getPrimeFactors(nums[i]); + for (const prime in primesFactorsCount) { + const count = primesFactorsCount[prime]; + left[prime] = (left[prime] || 0) + count; + right[prime] -= count; + if (right[prime] > 0) common.add(prime); + else if (right[prime] === 0) common.delete(prime); + } + if (common.size === 0) return i; + } + return -1; +}; + +function getPrimeFactors(n) { + const counts = {}; + for (let x = 2; (x * x) <= n; x++) { + while (n % x === 0) { + counts[x] = (counts[x] || 0) + 1; + n /= x; + } + } + if (n > 1) counts[n] = (counts[n] || 0) + 1; + return counts; +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const findValidSplit = function (nums) { + const map = new Map() + const n = nums.length + const max = Math.max(...nums) + const primes = Eratosthenes(max) + + for (let i = 0; i < n; i++) { + let x = nums[i] + for (const p of primes) { + if (p * p > x && x > 1) { + if (!map.has(x)) { + map.set(x, [i, i]) + } + map.get(x)[1] = i + break + } + + if (x % p === 0) { + if (!map.has(p)) { + map.set(p, [i, i]) + } + const a = map.get(p) + a[1] = i + } + while (x % p === 0) x = x / p + } + } + + const diff = Array(n + 1).fill(0) + for (const [k, v] of map) { + const [s, e] = v + // if(s === e) continue + diff[s] += 1 + diff[e] -= 1 + } + // console.log(diff) + let sum = 0 + for (let i = 0; i < n - 1; i++) { + sum += diff[i] + if (sum === 0) return i + } + + return -1 +} + +function Eratosthenes(n) { + const q = Array(n + 1).fill(0) + const primes = [] + for (let i = 2; i <= Math.sqrt(n); i++) { + if (q[i] == 1) continue + let j = i * 2 + while (j <= n) { + q[j] = 1 + j += i + } + } + for (let i = 2; i <= n; i++) { + if (q[i] == 0) primes.push(i) + } + return primes +} + diff --git a/2585-number-of-ways-to-earn-points.js b/2585-number-of-ways-to-earn-points.js new file mode 100644 index 00000000..a2abffef --- /dev/null +++ b/2585-number-of-ways-to-earn-points.js @@ -0,0 +1,23 @@ +/** + * @param {number} target + * @param {number[][]} types + * @return {number} + */ +const waysToReachTarget = function(target, types) { + const n = types.length + const dp = Array.from({ length: n + 1 }, () => Array(target + 1).fill(0)) + const mod = 1e9 + 7 + let res = 0 + dp[0][0] = 1 + for(let i = 1; i <= n; i++) { + const [cnt, mark] = types[i - 1] + for(let j = 0, tmp = 0; j <= cnt; j++) { + const tmp = mark * j + for(let k = tmp; k <= target; k++) { + dp[i][k] = (dp[i][k] + dp[i - 1][k - tmp]) % mod + } + } + } + + return dp[n][target] % mod +}; diff --git a/2588-count-the-number-of-beautiful-subarrays.js b/2588-count-the-number-of-beautiful-subarrays.js new file mode 100644 index 00000000..62786c7b --- /dev/null +++ b/2588-count-the-number-of-beautiful-subarrays.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const beautifulSubarrays = function (nums) { + const map = new Map() + map.set(0, 1) + let res = 0 + const n = nums.length + for(let i = 0, mask = 0; i < n; i++) { + const cur = nums[i] + mask ^= cur + if(map.has(mask)) { + res += map.get(mask) + } + map.set(mask, (map.get(mask) || 0) + 1) + } + + return res +} diff --git a/2589-minimum-time-to-complete-all-tasks.js b/2589-minimum-time-to-complete-all-tasks.js new file mode 100644 index 00000000..9f9f7cb8 --- /dev/null +++ b/2589-minimum-time-to-complete-all-tasks.js @@ -0,0 +1,66 @@ +/** + * @param {number[][]} tasks + * @return {number} + */ +const findMinimumTime = function(tasks) { + tasks.sort((a, b) => a[1] - b[1]) + const {max} = Math + let maxEnd = -1 + for(const [s,e,d] of tasks) maxEnd = max(maxEnd, e) + const arr = Array(maxEnd + 1).fill(0) + const n = tasks.length + + for(let i = 0; i < n; i++) { + let [s, e, d] = tasks[i] + let overlap = 0 + for(let j = e; j >= s; j--) { + if(arr[j]) overlap++ + } + if(overlap >= d) continue + let diff = d - overlap + for(let j = e; j >= s; j--) { + if(arr[j] === 0) { + diff-- + arr[j] = 1 + } else continue + if(diff === 0) break + } + + } + + return arr.reduce((ac, e) => ac + e, 0) +}; + +// another + +/** + * @param {number[][]} tasks + * @return {number} + */ +const findMinimumTime = function(tasks) { + let maxEnd = -Infinity + for(const [s,e,d] of tasks) { + maxEnd = Math.max(maxEnd, e) + } + // console.log(maxEnd) + const endSlots = Array(maxEnd + 1).fill(0) + tasks.sort((a, b) => a[1] - b[1]) + const n = tasks.length + for(let i = 0; i < n; i++) { + const cur = tasks[i] + let [s, e, d] = cur + for(let j = s; j <= e; j++) { + if(endSlots[j]) d-- + } + let t = e + while(d > 0) { + if(endSlots[t] === 0) { + endSlots[t] = 1 + d-- + } + t-- + } + } + + return endSlots.reduce((ac, e) => ac + e, 0) +}; diff --git a/259-3sum-smaller.js b/259-3sum-smaller.js new file mode 100644 index 00000000..8a41e731 --- /dev/null +++ b/259-3sum-smaller.js @@ -0,0 +1,38 @@ +/** + +Given an array of n integers nums and a target, +find the number of index triplets i, j, k with 0 <= i < j < k < n +that satisfy the condition nums[i] + nums[j] + nums[k] < target. + +Example: + +Input: nums = [-2,0,1,3], and target = 2 +Output: 2 +Explanation: Because there are two triplets which sums are less than 2: + [-2,0,1] + [-2,0,3] + +Follow up: Could you solve it in O(n2) runtime? + +*/ + +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const threeSumSmaller = function(nums, target) { + nums.sort((a, b) => a - b) + let res = 0 + for(let i = 0, len = nums.length; i < len - 2; i++) { + let lo = i + 1 + let hi = len - 1 + while(lo < hi) { + if(nums[i] + nums[lo] + nums[hi] < target) { + res += hi - lo + lo++ + } else hi-- + } + } + return res +}; diff --git a/2591-distribute-money-to-maximum-children.js b/2591-distribute-money-to-maximum-children.js new file mode 100644 index 00000000..52d9a5a6 --- /dev/null +++ b/2591-distribute-money-to-maximum-children.js @@ -0,0 +1,27 @@ +/** + * @param {number} money + * @param {number} children + * @return {number} + */ +const distMoney = function(money, children) { + let m = money, n = children + if(m < n) return -1 + let res = 0 + for(let num = 1; num <= n && num * 8 <= m; num++) { + if(valid(num)) res = num + } + + return res + + function valid(num) { + if(m < num * 8) return false + let remain = m - num * 8 + let slots = n - num + if(slots === 0 && remain) return false + if(slots > remain) return false + remain = remain - slots + if(remain === 3 && slots === 1) return false + return true + } + +}; diff --git a/2597-the-number-of-beautiful-subsets.js b/2597-the-number-of-beautiful-subsets.js new file mode 100644 index 00000000..308352a3 --- /dev/null +++ b/2597-the-number-of-beautiful-subsets.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var beautifulSubsets = function (nums, k) { + let output = 0 + const pick = function (nums, k) { + if (nums.length > 0) { + for (let i = 0; i < nums.length; i++) { + output++ + let arr = nums.slice(i + 1) + arr = arr.filter((e) => Math.abs(e - nums[i]) != k) + pick(arr, k) + } + } + } + pick(nums, k) + return output +} diff --git a/2598-smallest-missing-non-negative-integer-after-operations.js b/2598-smallest-missing-non-negative-integer-after-operations.js new file mode 100644 index 00000000..a0cbc404 --- /dev/null +++ b/2598-smallest-missing-non-negative-integer-after-operations.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @param {number} value + * @return {number} + */ +const findSmallestInteger = function(nums, value) { + const hash = {}, n = nums.length + for(const e of nums) { + let remain = e % value + if(remain < 0) remain = value + remain + if(hash[remain] == null) hash[remain] = 0 + hash[remain]++ + } + for(let i = 0; i < n; i++) { + const re = i % value + if(hash[re] == null) return i + hash[re]-- + if(hash[re] === 0) delete hash[re] + } + return n +}; diff --git a/2599-make-the-prefix-sum-non-negative.js b/2599-make-the-prefix-sum-non-negative.js new file mode 100644 index 00000000..5025c1ac --- /dev/null +++ b/2599-make-the-prefix-sum-non-negative.js @@ -0,0 +1,88 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const makePrefSumNonNegative = function(nums) { + const pq = new PQ((a, b) => a < b) + let sum = 0, res = 0 + for(const e of nums) { + sum += e + if(e < 0) { + pq.push(e) + if(sum < 0) { + sum -= pq.pop() + res++ + } + } + } + + return res +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/260-single-number-III.js b/260-single-number-III.js index a6659a76..de88fee7 100755 --- a/260-single-number-III.js +++ b/260-single-number-III.js @@ -14,3 +14,38 @@ const singleNumber = function(nums) { }); return Object.keys(hash).map(el => +el); }; + +// another + +/** + * @param {number[]} nums + * @return {number[]} + */ +const singleNumber = function(nums) { + const s = new Set() + for(let el of nums) { + if(s.has(el)) s.delete(el) + else s.add(el) + } + return Array.from(s) +}; + +// another + +/** + * @param {number[]} nums + * @return {number[]} + */ +const singleNumber = function (nums) { + const res = Array(2).fill(0) + const x = nums.reduce((acc, v) => acc ^ v, 0) + const partition = x & ~(x - 1) + for (let i = 0; i < nums.length; i++) { + if (partition & nums[i]) { + res[1] ^= nums[i] + } else { + res[0] ^= nums[i] + } + } + return res +} diff --git a/2603-collect-coins-in-a-tree.js b/2603-collect-coins-in-a-tree.js new file mode 100644 index 00000000..7b174eb3 --- /dev/null +++ b/2603-collect-coins-in-a-tree.js @@ -0,0 +1,101 @@ +/** + * @param {number[]} coins + * @param {number[][]} edges + * @return {number} + */ +var collectTheCoins = function(coins, edges) { + let n = coins.length; + let next = Array.from({ length: n }, () => new Set()); + + let degree = new Array(n).fill(0); + for (let edge of edges) { + let a = edge[0], + b = edge[1]; + next[a].add(b); + next[b].add(a); + degree[a]++; + degree[b]++; + } + + let deleted = new Array(n).fill(0); + let q = []; + for (let i = 0; i < n; i++) { + if (degree[i] === 1 && coins[i] === 0) q.push(i); + } + while (q.length > 0) { + let len = q.length; + while (len--) { + let cur = q.shift(); + deleted[cur] = 1; + for (let nxt of next[cur]) { + degree[nxt]--; + next[nxt].delete(cur); + if (degree[nxt] === 1 && coins[nxt] === 0) q.push(nxt); + } + } + } + + let depth = new Array(n).fill(-1); + for (let i = 0; i < n; i++) { + if (degree[i] === 1 && deleted[i] === 0) { + q.push(i); + depth[i] = 1; + } + } + while (q.length > 0) { + let len = q.length; + while (len--) { + let cur = q.shift(); + for (let nxt of next[cur]) { + degree[nxt]--; + next[nxt].delete(cur); + depth[nxt] = Math.max(depth[nxt], depth[cur] + 1); + if (degree[nxt] === 1) q.push(nxt); + } + } + } + + let ret = 0; + for (let i = 0; i < n; i++) ret += depth[i] >= 3; + + if (ret >= 1) return (ret - 1) * 2; + else return 0; +}; + +// another + +let a, cum, res, v, sum, g; +const initializeGraph = (n) => { let g = []; for (let i = 0; i < n; i++) { g.push([]); } return g; }; +const packUG = (g, edges) => { for (const [u, v] of edges) { g[u].push(v); g[v].push(u); } }; +const sm = (a) => a.reduce(((x, y) => x + y), 0); +const tree_dp = (cur, par) => { + v[cur] = a[cur]; + for (const child of g[cur]) { + if (child != par) { + v[cur] += tree_dp(child, cur); + } + } + if (cur != par) { + let x = v[cur] + cum[par] - a[cur]; + let y = (sum - v[cur]) + cum[cur] - a[par]; + if (x != sum && y != sum) res += 2; + } + return v[cur]; +}; +/** + * @param {number[]} coins + * @param {number[][]} edges + * @return {number} + */ +const collectTheCoins = function(coins, edges) { + let n = coins.length; + g = initializeGraph(n), a = coins, res = 0, cum = Array(n), v = Array(n), sum = sm(a); + packUG(g, edges); + for (let i = 0; i < n; i++) { + cum[i] = a[i]; + for (const child of g[i]) cum[i] += a[child]; + } + tree_dp(0, 0); + return res; + +}; diff --git a/2604-minimum-time-to-eat-all-grains.js b/2604-minimum-time-to-eat-all-grains.js new file mode 100644 index 00000000..33762836 --- /dev/null +++ b/2604-minimum-time-to-eat-all-grains.js @@ -0,0 +1,32 @@ +/** + * @param {number[]} hens + * @param {number[]} grains + * @return {number} + */ +var minimumTime = function (hens, grains) { + hens.sort((a, b) => a - b) + grains.sort((a, b) => a - b) + let lo = 0, + hi = 1e9 + while (lo < hi) { + let mid = Math.floor(lo + (hi - lo) / 2), + i = 0 + for (let h of hens) { + for ( + let ii = i; + i < grains.length && + ((grains[i] <= h && h - grains[i] <= mid) || + (h <= grains[ii] && grains[i] - h <= mid) || + (grains[ii] <= h && + h <= grains[i] && + grains[i] - grains[ii] + Math.min(grains[i] - h, h - grains[ii]) <= + mid)); + ++i + ); + } + + if (i == grains.length) hi = mid + else lo = mid + 1 + } + return lo +} diff --git a/2607-make-k-subarray-sums-equal.js b/2607-make-k-subarray-sums-equal.js new file mode 100644 index 00000000..a208b2f7 --- /dev/null +++ b/2607-make-k-subarray-sums-equal.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ +const makeSubKSumEqual = function(arr, k) { + let res = 0 + const n = arr.length + for(let i = 0; i < n; i++) { + const tmp = [] + for(let j = i; arr[j] !== 0; j = (j + k) % n) { + tmp.push(arr[j]) + arr[j] = 0 + } + tmp.sort((a, b) => a - b) + const mid = tmp[~~(tmp.length / 2)] + for(const e of tmp) { + res += Math.abs(e - mid) + } + } + + + return res +}; diff --git a/2608-shortest-cycle-in-a-graph.js b/2608-shortest-cycle-in-a-graph.js new file mode 100644 index 00000000..77057b20 --- /dev/null +++ b/2608-shortest-cycle-in-a-graph.js @@ -0,0 +1,40 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +const findShortestCycle = function(n, edges) { + let res = Infinity + const graph = new Map() + for(const [u, v] of edges) { + if(graph.get(u) == null) graph.set(u, []) + if(graph.get(v) == null) graph.set(v, []) + graph.get(u).push(v) + graph.get(v).push(u) + } + for(let i = 0; i < n; i++) { + bfs(i) + } + + if(res === Infinity) return -1 + return res + + function bfs(src) { + const parent = Array(n), dis = Array(n).fill(Infinity) + let q = [] + dis[src] = 0 + q.push(src) + while(q.length) { + const node = q.shift() + for(const nxt of (graph.get(node) || [])) { + if(dis[nxt] === Infinity) { + dis[nxt] = dis[node] + 1 + parent[nxt] = node + q.push(nxt) + } else if(parent[node] !== nxt && parent[nxt] !== node) { + res = Math.min(res, dis[nxt] + dis[node] + 1) + } + } + } + } +}; diff --git a/2609-find-the-longest-balanced-substring-of-a-binary-string.js b/2609-find-the-longest-balanced-substring-of-a-binary-string.js new file mode 100644 index 00000000..1f3ad65e --- /dev/null +++ b/2609-find-the-longest-balanced-substring-of-a-binary-string.js @@ -0,0 +1,29 @@ +/** + * @param {string} s + * @return {number} + */ +const findTheLongestBalancedSubstring = function(s) { + let res = 0 + + const n = s.length + for(let i = 0; i < n - 1; i++) { + for(let j = i + 1; j < n; j++) { + const str = s.slice(i, j + 1) + if(valid(str)) { + res = Math.max(res, str.length) + } + } + } + + return res + + function valid(str) { + let res = true + const len = str.length + if(len % 2 === 1) return false + const lastZeroIdx = str.lastIndexOf('0') + const firstOneIdx = str.indexOf('1') + + return firstOneIdx - lastZeroIdx === 1 && len / 2 === firstOneIdx + } +}; diff --git a/261-graph-valid-tree.js b/261-graph-valid-tree.js new file mode 100644 index 00000000..5347da57 --- /dev/null +++ b/261-graph-valid-tree.js @@ -0,0 +1,57 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {boolean} + */ +const validTree = function(n, edges) { + const nums = Array(n).fill(-1) + for(let i = 0; i < edges.length; i++) { + const x = find(nums, edges[i][0]) + const y = find(nums, edges[i][1]) + if(x === y) return false + nums[x] = y + } + return edges.length === n - 1 + function find(arr, i) { + if(arr[i] === -1) return i + return find(arr, arr[i]) + } +}; + +// another + +/** + * @param {number} n + * @param {number[][]} edges + * @return {boolean} + */ +const validTree = function(n, edges) { + if (edges.length !== n - 1) { + return false + } + const graph = {} + edges.forEach(edge => { + if (!graph[edge[0]]) { + graph[edge[0]] = [] + } + if (!graph[edge[1]]) { + graph[edge[1]] = [] + } + graph[edge[0]].push(edge[1]) + graph[edge[1]].push(edge[0]) + }) + const queue = [0], + visited = new Set() + while (queue.length) { + const currentNode = queue.shift() + visited.add(currentNode) + if (graph[currentNode]) { + graph[currentNode].forEach(node => { + if (!visited.has(node)) { + queue.push(node) + } + }) + } + } + return visited.size === n +} diff --git a/2610-convert-an-array-into-a-2d-array-with-conditions.js b/2610-convert-an-array-into-a-2d-array-with-conditions.js new file mode 100644 index 00000000..040edf6c --- /dev/null +++ b/2610-convert-an-array-into-a-2d-array-with-conditions.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @return {number[][]} + */ +const findMatrix = function(nums) { + + const hash = new Map() + for(const e of nums) { + if(!hash.has(e)) hash.set(e, 0) + hash.set(e, hash.get(e) + 1) + } + + const arr = [] + for(const [k, v] of hash) { + arr.push([v, k]) + } + + arr.sort((a, b) => b[0] - a[0]) + + const res = [] + for(let i = 0, len = arr.length; i < len; i++) { + const [freq, val] = arr[i] + for(let j = 0; j < freq; j++) { + if(res[j] == null) res[j] = [] + res[j].push(val) + } + } + + return res +}; diff --git a/2611-mice-and-cheese.js b/2611-mice-and-cheese.js new file mode 100644 index 00000000..f8ddd497 --- /dev/null +++ b/2611-mice-and-cheese.js @@ -0,0 +1,100 @@ +/** + * @param {number[]} reward1 + * @param {number[]} reward2 + * @param {number} k + * @return {number} + */ +const miceAndCheese = function(reward1, reward2, k) { + const pq = new PQ((a, b) => a[2] > b[2]) + + const n = reward1.length + + for(let i = 0; i < n; i++) { + const tmp = [reward1[i], reward2[i], reward1[i] - reward2[i]] + pq.push(tmp) + } + + let res = 0 + while(k) { + const [v1, v2, delta] = pq.pop() + res += v1 + + k-- + } + + while(!pq.isEmpty()) { + const [v1, v2] = pq.pop() + res += v2 + } + + + return res +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2612-minimum-reverse-operations.js b/2612-minimum-reverse-operations.js new file mode 100644 index 00000000..76c1dec0 --- /dev/null +++ b/2612-minimum-reverse-operations.js @@ -0,0 +1,93 @@ +////////////////////////// Template //////////////////////////////////// +function Bisect() { + return { insort_right, insort_left, bisect_left, bisect_right } + function insort_right(a, x, lo = 0, hi = null) { + lo = bisect_right(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_right(a, x, lo = 0, hi = null) { + // > upper_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + a[mid] > x ? (hi = mid) : (lo = mid + 1) + } + return lo + } + function insort_left(a, x, lo = 0, hi = null) { + lo = bisect_left(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_left(a, x, lo = 0, hi = null) { + // >= lower_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + a[mid] < x ? (lo = mid + 1) : (hi = mid) + } + return lo + } +} +/////////////////////////////////////////////////////////////////// + +/** + * @param {number} n + * @param {number} p + * @param {number[]} banned + * @param {number} k + * @return {number[]} + */ +var minReverseOperations = function (n, p, banned, k) { + const distances = new Array(n).fill(Number.MAX_SAFE_INTEGER) + for (const x of banned) { + distances[x] = -1 + } + + const nodes = [p], + newNodes = [] + distances[p] = 0 + + while (nodes.length > 0) { + let iMin = Number.MAX_SAFE_INTEGER + let iMax = Number.MIN_SAFE_INTEGER + + for (const node of nodes) { + const base = node - k + 1 + + // j: segment start position + // i: update position + const j2i = (j) => base + (j - base) * 2 + + const update = (i) => { + if (distances[i] === Number.MAX_SAFE_INTEGER) { + distances[i] = distances[node] + 1 + newNodes.push(i) + } + } + + // inclusive + const lo = j2i(Math.max(0, base)) + const hi = j2i(Math.min(node + k, n) - k) + for (let i = lo; i <= Math.min(hi, iMin - 2); i += 2) { + update(i) + } + for (let i = Math.max(lo, iMax + 2); i <= hi; i += 2) { + update(i) + } + iMin = Math.min(iMin, lo) + iMax = Math.max(iMax, hi) + } + + nodes.splice(0, nodes.length, ...newNodes) + newNodes.length = 0 + } + + for (let i = 0; i < n; i++) { + if (distances[i] === Number.MAX_SAFE_INTEGER) { + distances[i] = -1 + } + } + return distances +} diff --git a/2614-prime-in-diagonal.js b/2614-prime-in-diagonal.js new file mode 100644 index 00000000..d214e379 --- /dev/null +++ b/2614-prime-in-diagonal.js @@ -0,0 +1,30 @@ +const isPrime = num => { + for(let i = 2, s = Math.sqrt(num); i <= s; i++) { + if(num % i === 0) return false; + } + return num > 1; +} +/** + * @param {number[][]} nums + * @return {number} + */ +var diagonalPrime = function(nums) { + const n = nums.length + let res = 0 + for(let i = 0; i < n; i++) { + if(isPrime(nums[i][i])) { + res = Math.max(res, nums[i][i]) + } + } + + for(let i = 0; i < n; i++) { + if(isPrime(nums[i][n - 1 - i])) { + res = Math.max(res, nums[i][n - 1 - i]) + } + } + + + return res + + +}; diff --git a/2615-sum-of-distances.js b/2615-sum-of-distances.js new file mode 100644 index 00000000..6ac7000e --- /dev/null +++ b/2615-sum-of-distances.js @@ -0,0 +1,74 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const distance = function(nums) { + const res = [] + const hash = {}, n = nums.length + for(let i = 0; i < n; i++) { + const e = nums[i] + if(hash[e] == null) hash[e] = [] + hash[e].push(i) + } + + for(const [_, arr] of Object.entries(hash)) { + helper(arr) + } + + return res + + function helper(arr) { + let sum = 0 + const len = arr.length + for(let i = 1; i < len; i++) { + sum += arr[i] - arr[0] + } + const first = arr[0] + res[first] = sum + for(let i = 1; i < len; i++) { + const preIdx = arr[i - 1] + const pre = res[preIdx], diff = arr[i] - arr[i - 1] + const val = pre + i * diff - diff * (len - i) + res[arr[i]] = val + } + } +}; + +// another + +/** + * @param {number[]} nums + * @return {number[]} + */ +const distance = function(nums) { + const n = nums.length + const res = Array(n).fill(0) + const hash = {} + for(let i = 0; i < n; i++) { + const e = nums[i] + if(hash[e] == null) hash[e] = [] + hash[e].push(i) + } + + const keys = Object.keys(hash) + for(const k of keys) { + const arr = hash[k] + const totalSum = arr.reduce((ac, e) => ac + e, 0) + let preSum = 0 + if(arr.length < 2) continue + for(let i = 0, len = arr.length; i < len; i++) { + const idx = arr[i] + const postSum = totalSum - (preSum + idx) + + res[idx] += idx * i + res[idx] -= preSum + res[idx] -= idx * (len - 1 - i) + res[idx] += postSum + + preSum += idx + } + } + + + return res +}; diff --git a/2616-minimize-the-maximum-difference-of-pairs.js b/2616-minimize-the-maximum-difference-of-pairs.js new file mode 100644 index 00000000..c96d82b0 --- /dev/null +++ b/2616-minimize-the-maximum-difference-of-pairs.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ +const minimizeMax = function(nums, p) { + nums.sort((a, b) => a - b) + const n = nums.length + let l = 0, r = nums.at(-1) - nums[0] + + while(l < r) { + const mid = Math.floor(l + (r - l) / 2) + let k = 0 + for(let i = 1; i < n;) { + if(nums[i] - nums[i - 1] <= mid) { + k++ + i += 2 + } else { + i++ + } + } + + if(k >= p) { + r = mid + } else { + l = mid + 1 + } + } + + return l +}; diff --git a/2617-minimum-number-of-visited-cells-in-a-grid.js b/2617-minimum-number-of-visited-cells-in-a-grid.js new file mode 100644 index 00000000..c29802c8 --- /dev/null +++ b/2617-minimum-number-of-visited-cells-in-a-grid.js @@ -0,0 +1,56 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var minimumVisitedCells = function (grid) { + const m = grid.length, + n = grid[0].length + const dp = Array(m) + .fill(0) + .map(() => Array(n).fill(Infinity)), + colStacks = Array(n) + .fill(0) + .map(() => []) // colStacks[j] = stack of row indexes for column j + dp[m - 1][n - 1] = 1 + colStacks[n - 1].push(m - 1) + + for (let i = m - 1; i >= 0; i--) { + let rowStack = i === m - 1 ? [n - 1] : [] // stack of column indexes for row i + for (let j = n - 1; j >= 0; j--) { + let colIndex = findIndex(rowStack, grid[i][j] + j) + if (colIndex >= 0) + dp[i][j] = Math.min(dp[i][j], 1 + dp[i][rowStack[colIndex]]) + let colStack = colStacks[j], + rowIndex = findIndex(colStack, grid[i][j] + i) + if (rowIndex >= 0) + dp[i][j] = Math.min(dp[i][j], 1 + dp[colStack[rowIndex]][j]) + + while ( + rowStack.length && + dp[i][rowStack[rowStack.length - 1]] >= dp[i][j] + ) + rowStack.pop() + rowStack.push(j) + while ( + colStack.length && + dp[colStack[colStack.length - 1]][j] >= dp[i][j] + ) + colStack.pop() + colStack.push(i) + } + } + return dp[0][0] === Infinity ? -1 : dp[0][0] + } + + function findIndex(stack, maxIndex) { + if (!stack.length) return -1 + let low = 0, + high = stack.length - 1 + while (low < high) { + let mid = Math.floor((low + high) / 2) + if (stack[mid] <= maxIndex) high = mid + else low = mid + 1 + } + return stack[low] <= maxIndex ? low : -1 + } + diff --git a/2619-array-prototype-last.js b/2619-array-prototype-last.js new file mode 100644 index 00000000..acd8a636 --- /dev/null +++ b/2619-array-prototype-last.js @@ -0,0 +1,8 @@ +Array.prototype.last = function() { + return this.at(-1) ?? -1 +}; + +/** + * const arr = [1, 2, 3]; + * arr.last(); // 3 + */ diff --git a/2626-array-reduce-transformation.js b/2626-array-reduce-transformation.js new file mode 100644 index 00000000..cfc6ea20 --- /dev/null +++ b/2626-array-reduce-transformation.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @param {Function} fn + * @param {number} init + * @return {number} + */ +const reduce = function(nums, fn, init) { + let res = init + + for(let i = 0; i < nums.length; i++) { + res = fn(res, nums[i]) + } + + return res +}; diff --git a/2627-debounce.js b/2627-debounce.js new file mode 100644 index 00000000..15d16dfb --- /dev/null +++ b/2627-debounce.js @@ -0,0 +1,21 @@ +/** + * @param {Function} fn + * @param {number} t milliseconds + * @return {Function} + */ +const debounce = function(fn, t) { + let timer = null + return function(...args) { + clearTimeout(timer) + timer = setTimeout(() => { + fn(...args) + }, t) + } +}; + +/** + * const log = debounce(console.log, 100); + * log('Hello'); // cancelled + * log('Hello'); // cancelled + * log('Hello'); // Logged at t=100ms + */ diff --git a/263-ugly-number.js b/263-ugly-number.js new file mode 100644 index 00000000..c518079d --- /dev/null +++ b/263-ugly-number.js @@ -0,0 +1,14 @@ +/** + * @param {number} num + * @return {boolean} + */ +const isUgly = function(num) { + if (num < 1) return false + while (num >= 2) { + if (num % 2 === 0) num = num / 2 + else if (num % 3 === 0) num = num / 3 + else if (num % 5 === 0) num = num / 5 + else return false + } + return true +} diff --git a/2630-memoize-ii.js b/2630-memoize-ii.js new file mode 100644 index 00000000..93519d2b --- /dev/null +++ b/2630-memoize-ii.js @@ -0,0 +1,36 @@ +const RES = Symbol("res"); +/** + * @param {Function} fn + */ +function memoize(fn) { + const globalCache = new Map(); + + return (...params) => { + let currentCache = globalCache; + for(const param of params) { + if (!currentCache.has(param)) { + currentCache.set(param, new Map()); + } + currentCache = currentCache.get(param); + } + + if (currentCache.has(RES)) return currentCache.get(RES); + + const result = fn(...params); + + currentCache.set(RES, result); + return result; + } +} + + +/** + * let callCount = 0; + * const memoizedFn = memoize(function (a, b) { + * callCount += 1; + * return a + b; + * }) + * memoizedFn(2, 3) // 5 + * memoizedFn(2, 3) // 5 + * console.log(callCount) // 1 + */ diff --git a/2632-curry.js b/2632-curry.js new file mode 100644 index 00000000..10272274 --- /dev/null +++ b/2632-curry.js @@ -0,0 +1,16 @@ +/** + * @param {Function} fn + * @return {Function} + */ +const curry = function(fn) { + return function curried(...args) { + if(args.length >= fn.length) return fn(...args) + return (...params) => curried(...args, ...params) + }; +}; + +/** + * function sum(a, b) { return a + b; } + * const csum = curry(sum); + * csum(1)(2) // 3 + */ diff --git a/2636-promise-pool.js b/2636-promise-pool.js new file mode 100644 index 00000000..0c86a9cb --- /dev/null +++ b/2636-promise-pool.js @@ -0,0 +1,29 @@ +/** + * @param {Function[]} functions + * @param {number} n + * @return {Function} + */ +const promisePool = async function(functions, n) { + const it = functions[Symbol.iterator]() + + const add = async () => { + const { value, done } = it.next() + if(value) { + await value() + await add() + } + } + + const arr = [] + for(let i = 0; i < n; i++) { + arr.push(add()) + } + + return Promise.all(arr) +}; + +/** + * const sleep = (t) => new Promise(res => setTimeout(res, t)); + * promisePool([() => sleep(500), () => sleep(400)], 1) + * .then(console.log) // After 900ms + */ diff --git a/2638-count-the-number-of-k-free-subsets.js b/2638-count-the-number-of-k-free-subsets.js new file mode 100644 index 00000000..5005da89 --- /dev/null +++ b/2638-count-the-number-of-k-free-subsets.js @@ -0,0 +1,36 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countTheNumOfKFreeSubsets = function (nums, k) { + let res = 1 + const marr = Array.from({ length: k }, () => Array()) + for (const e of nums) { + marr[e % k].push(e) + } + + for (let i = 0; i < k; i++) { + res *= helper(marr[i]) + } + + return res + + function helper(arr) { + arr.sort((a, b) => a - b) + let take = 0, + no_take = 1 + for (let i = 0; i < arr.length; i++) { + let take_temp = take, + no_take_temp = no_take + if (i >= 1 && arr[i] == arr[i - 1] + k) { + take = no_take_temp + no_take = take_temp + no_take_temp + } else { + take = take_temp + no_take_temp + no_take = take_temp + no_take_temp + } + } + return take + no_take + } +} diff --git a/264-ugly-number-ii.js b/264-ugly-number-ii.js new file mode 100644 index 00000000..af94e904 --- /dev/null +++ b/264-ugly-number-ii.js @@ -0,0 +1,20 @@ +/** + * @param {number} n + * @return {number} + */ +const nthUglyNumber = function (n) { + if (n <= 0) return false + if (n === 1) return true + let t2 = 0, + t3 = 0, + t5 = 0 + const k = Array(n).fill(1) + k[0] = 1 + for (let i = 1; i < n; i++) { + k[i] = Math.min(k[t2] * 2, k[t3] * 3, k[t5] * 5) + if (k[i] == k[t2] * 2) t2++ + if (k[i] == k[t3] * 3) t3++ + if (k[i] == k[t5] * 5) t5++ + } + return k[n - 1] +} diff --git a/2640-find-the-score-of-all-prefixes-of-an-array.js b/2640-find-the-score-of-all-prefixes-of-an-array.js new file mode 100644 index 00000000..e07e4517 --- /dev/null +++ b/2640-find-the-score-of-all-prefixes-of-an-array.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const findPrefixScore = function(nums) { + const { max } = Math + const res = [] + let ma = 0, sum = 0 + for(const e of nums) { + ma = max(e, ma) + sum += ma + e + res.push(sum) + } + + return res +}; diff --git a/2642-design-graph-with-shortest-path-calculator.js b/2642-design-graph-with-shortest-path-calculator.js new file mode 100644 index 00000000..41a0be10 --- /dev/null +++ b/2642-design-graph-with-shortest-path-calculator.js @@ -0,0 +1,135 @@ +/** + * Your Graph object will be instantiated and called as such: + * var obj = new Graph(n, edges) + * obj.addEdge(edge) + * var param_2 = obj.shortestPath(node1,node2) + */ +/** + * @param {number} n + * @param {number[][]} edges + */ +const Graph = function (n, edges) { + this.map = new Map() + const map = this.map + for (let i = 0; i < edges.length; i++) { + let edge = edges[i] + let from = edge[0] + let to = edge[1] + let cost = edge[2] + if (!map.has(from)) { + map.set(from, new Set()) + } + + map.get(from).add({ to, cost }) + } +} + +/** + * @param {number[]} edge + * @return {void} + */ +Graph.prototype.addEdge = function (edge) { + let map = this.map + let from = edge[0] + let to = edge[1] + let cost = edge[2] + if (!map.has(from)) { + map.set(from, new Set()) + } + + map.get(from).add({ to, cost }) +} + +/** + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ +Graph.prototype.shortestPath = function (node1, node2) { + const heap = new MinPriorityQueue() + heap.enqueue({ node: node1, cost: 0 }, 0) + let visited = new Set() + + while (heap.size() > 0) { + const top = heap.dequeue().element + + if (visited.has(top.node)) { + continue + } + visited.add(top.node) + if (top.node === node2) { + return top.cost + } + let next = this.map.get(top.node) + if (next) { + for (let n of next) { + heap.enqueue({ node: n.to, cost: top.cost + n.cost }, top.cost + n.cost) + } + } + } + + return -1 +} + +/** + * Your Graph object will be instantiated and called as such: + * var obj = new Graph(n, edges) + * obj.addEdge(edge) + * var param_2 = obj.shortestPath(node1,node2) + */ + +// another + +/** + * @param {number} n + * @param {number[][]} edges + */ +const Graph = function(n, edges) { + const matrix = Array.from({ length: n }, () => Array(n).fill(1e12)) + this.mat = matrix + this.n = n + for(let i = 0; i < n; i++) { + this.mat[i][i] = 0 + } + for(const [u,v,c] of edges) { + this.mat[u][v] = c + } + for(let k = 0; k < n; k++) { + for(let i = 0; i < n; i++) { + for(let j = 0; j < n; j++) { + this.mat[i][j] = Math.min(this.mat[i][j], this.mat[i][k] + this.mat[k][j]) + } + } + } +}; + +/** + * @param {number[]} edge + * @return {void} + */ +Graph.prototype.addEdge = function(edge) { + const [u, v, c] = edge + this.mat[u][v] = Math.min(this.mat[u][v], c) + const n = this.n + for(let i = 0; i < n; i++) { + for(let j = 0; j < n; j++) { + this.mat[i][j] = Math.min(this.mat[i][j], this.mat[i][u] + this.mat[v][j] + c) + } + } +}; + +/** + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ +Graph.prototype.shortestPath = function(node1, node2) { + return this.mat[node1][node2] === 1e12 ? -1 : this.mat[node1][node2] +}; + +/** + * Your Graph object will be instantiated and called as such: + * var obj = new Graph(n, edges) + * obj.addEdge(edge) + * var param_2 = obj.shortestPath(node1,node2) + */ diff --git a/2643-row-with-maximum-ones.js b/2643-row-with-maximum-ones.js new file mode 100644 index 00000000..b7ebf790 --- /dev/null +++ b/2643-row-with-maximum-ones.js @@ -0,0 +1,21 @@ +/** + * @param {number[][]} mat + * @return {number[]} + */ +var rowAndMaximumOnes = function(mat) { + const arr= [] + const m = mat.length, n = mat[0].length + let ma = 0 + for(let i = 0; i < m; i++) { + let cnt = 0 + for(let j = 0; j < n; j++) { + if(mat[i][j] === 1) cnt++ + } + arr[i] = cnt + ma = Math.max(ma, cnt) + } + + for(let i = 0; i < m; i++) { + if(arr[i] === ma) return [i, ma] + } +}; diff --git a/2644-find-the-maximum-divisibility-score.js b/2644-find-the-maximum-divisibility-score.js new file mode 100644 index 00000000..78832000 --- /dev/null +++ b/2644-find-the-maximum-divisibility-score.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @param {number[]} divisors + * @return {number} + */ +var maxDivScore = function(nums, divisors) { + divisors.sort((a, b) => a - b) + nums.sort((a, b) => a - b) + + let arr = [], ma = 0 + for(let i = 0; i < divisors.length; i++) { + const div = divisors[i] + let cnt = 0 + for(let j = 0; j < nums.length; j++) { + if(nums[j] % div === 0) cnt++ + } + arr[i] = cnt + ma = Math.max(ma, cnt) + } + + for(let i = 0; i < divisors.length; i++) { + if(arr[i] === ma) return divisors[i] + } +}; diff --git a/2645-minimum-additions-to-make-valid-string.js b/2645-minimum-additions-to-make-valid-string.js new file mode 100644 index 00000000..7e767f07 --- /dev/null +++ b/2645-minimum-additions-to-make-valid-string.js @@ -0,0 +1,23 @@ +/** + * @param {string} word + * @return {number} + */ +var addMinimum = function(word) { + let pattern = "abc" + let p1 = 0, p2 = 0 + let cnt = 0 + while( p1 < word.length) { + while( p1 < word.length && word[p1] != pattern[p2]) { + p2 = (p2 + 1) % 3 + cnt++ + } + p1++ + p2 = (p2 + 1) % 3 + } + if (p2 == 1) { + cnt += 2 + } else if (p2 == 2) { + cnt += 1 + } + return cnt +}; diff --git a/2646-minimize-the-total-price-of-the-trips.js b/2646-minimize-the-total-price-of-the-trips.js new file mode 100644 index 00000000..52600ad8 --- /dev/null +++ b/2646-minimize-the-total-price-of-the-trips.js @@ -0,0 +1,51 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} price + * @param {number[][]} trips + * @return {number} + */ +var minimumTotalPrice = function (n, edges, price, trips) { + const graph = [] + const { min, max } = Math + for (const [u, v] of edges) { + if (graph[u] == null) graph[u] = [] + if (graph[v] == null) graph[v] = [] + graph[u].push(v) + graph[v].push(u) + } + + const cnt = Array(n).fill(0) + + function dfs(p, i, e) { + if (i == e) { + ++cnt[i] + return true + } + for (const j of graph[i] || []) { + if (j != p && dfs(i, j, e)) { + ++cnt[i] + return true + } + } + return false + } + + for (const t of trips) dfs(-1, t[0], t[1]) + + const dp = Array.from({ length: n }, () => Array(2).fill(Infinity)) + + function minCost(pre, i, status) { + if (dp[i][status] == Infinity) { + dp[i][status] = (price[i] >> status) * cnt[i] + for (const j of graph[i] || []) { + if (j == pre) continue + if (status == 1) dp[i][status] += minCost(i, j, 0) + else dp[i][status] += min(minCost(i, j, 0), minCost(i, j, 1)) + } + } + return dp[i][status] + } + + return min(minCost(-1, 0, 0), minCost(-1, 0, 1)) +} diff --git a/265-paint-house-ii.js b/265-paint-house-ii.js new file mode 100644 index 00000000..c8b47547 --- /dev/null +++ b/265-paint-house-ii.js @@ -0,0 +1,33 @@ +/** + * @param {number[][]} costs + * @return {number} + */ +const minCostII = function(costs) { + if (costs == null || costs.length === 0 || costs[0].length === 0) return 0 + let n = costs.length, + k = costs[0].length + if (k === 1) return n === 1 ? costs[0][0] : -1 + + let prevMin = 0, + prevMinInd = -1, + prevSecMin = 0 + for (let i = 0; i < n; i++) { + let min = Number.MAX_VALUE, + minInd = -1, + secMin = Number.MAX_VALUE + for (let j = 0; j < k; j++) { + const val = costs[i][j] + (j == prevMinInd ? prevSecMin : prevMin) + if (val < min) { + secMin = min + min = val + minInd = j + } else if (val < secMin) { + secMin = val + } + } + prevMin = min + prevMinInd = minInd + prevSecMin = secMin + } + return prevMin +} diff --git a/2651-calculate-delayed-arrival-time.js b/2651-calculate-delayed-arrival-time.js new file mode 100644 index 00000000..e30c44e6 --- /dev/null +++ b/2651-calculate-delayed-arrival-time.js @@ -0,0 +1,8 @@ +/** + * @param {number} arrivalTime + * @param {number} delayedTime + * @return {number} + */ +var findDelayedArrivalTime = function(arrivalTime, delayedTime) { + return (arrivalTime + delayedTime) % 24 +}; diff --git a/2652-sum-multiples.js b/2652-sum-multiples.js new file mode 100644 index 00000000..e135636d --- /dev/null +++ b/2652-sum-multiples.js @@ -0,0 +1,25 @@ +/** + * @param {number} n + * @return {number} + */ +const sumOfMultiples = function(n) { + let res = 0 + const set = new Set() + for(let i = 3; i <= n; i += 3) { + set.add(i) + } + + for(let i = 5; i <= n; i += 5) { + set.add(i) + } + + for(let i = 7; i <= n; i += 7) { + set.add(i) + } + + for(const e of set) { + res += e + } + + return res +}; diff --git a/2653-sliding-subarray-beauty.js b/2653-sliding-subarray-beauty.js new file mode 100644 index 00000000..0450dda7 --- /dev/null +++ b/2653-sliding-subarray-beauty.js @@ -0,0 +1,65 @@ +/** + * @param {number[]} nums + * @param {number} k + * @param {number} x + * @return {number[]} + */ +const getSubarrayBeauty = function(nums, k, x) { + const arr = Array(101).fill(0) + const res = [], n = nums.length, delta = 50 + for(let i = 0; i < n; i++) { + const cur = nums[i] + const idx = cur + delta + arr[idx]++ + if(i < k - 1) continue + else if(i === k - 1) res.push(helper()) + else { + const prev = nums[i - k] + arr[prev + delta]-- + res.push(helper()) + } + } + + return res + + function helper() { + let res = 0, neg = 0 + // -50 ---> 0 + // -1 ---> 49 + for(let i = 0, len = arr.length; i < len; i++) { + if(i < delta && arr[i] > 0) neg += arr[i] + if(neg >= x) { + res = i - delta + break + } + } + + return res + } +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @param {number} x + * @return {number[]} + */ +const getSubarrayBeauty = function(nums, k, x) { + let counter = Array(50).fill(0), ans = new Array(nums.length - k + 1).fill(0); + for (let i = 0; i < nums.length; i++) { + if (nums[i] < 0) counter[nums[i] + 50]++; + if (i - k >= 0 && nums[i - k] < 0) counter[nums[i - k] + 50]--; + if (i - k + 1 < 0) continue; + let count = 0; + for (let j = 0; j < 50; j++) { + count += counter[j]; + if (count >= x) { + ans[i - k + 1] = j - 50; + break; + } + } + } + return ans; +}; diff --git a/2654-minimum-number-of-operations-to-make-all-array-elements-equal-to-1.js b/2654-minimum-number-of-operations-to-make-all-array-elements-equal-to-1.js new file mode 100644 index 00000000..498f4da2 --- /dev/null +++ b/2654-minimum-number-of-operations-to-make-all-array-elements-equal-to-1.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minOperations = function(nums) { + let n = nums.length; + + let ones = cntOnes(); + if (ones) return n - ones; + + for (let r = 2; r <= n; r++) { + for (let i = 0; i + r <= n; i++) { + let g = 0; + for (let j = i; j < i + r; j++) g = gcd(g, nums[j]); + if (g == 1) return r - 1 + n - 1; + } + } + + return -1; + + function cntOnes() { + let res = 0 + for(const e of nums) { + if(e === 1) res++ + } + return res + } + function gcd(a, b) { + return b ? gcd(b, a % b) : a + } +}; diff --git a/2658-maximum-number-of-fish-in-a-grid.js b/2658-maximum-number-of-fish-in-a-grid.js new file mode 100644 index 00000000..a46ab84b --- /dev/null +++ b/2658-maximum-number-of-fish-in-a-grid.js @@ -0,0 +1,62 @@ +const deepCopy2DArray = (g) => { + let d = [] + for (const a of g) d.push([...a]) + return d +} + +const dx = [1, -1, 0, 0], + dy = [0, 0, 1, -1] +const getAllAreasCoordinates = (g) => { + const forbid = 0, + floodFillMakeConnected = '*' // forbid is land cell + let n = g.length, + m = g[0].length, + res = [] + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + if (g[i][j] != forbid) { + let q = [[i, j]], + area = [] + while (q.length) { + let [x, y] = q.shift() + for (let k = 0; k < 4; k++) { + let nx = x + dx[k], + ny = y + dy[k] + if ( + nx < 0 || + nx >= n || + ny < 0 || + ny >= m || + g[nx][ny] == forbid || + g[nx][ny] == floodFillMakeConnected + ) + continue + g[nx][ny] = floodFillMakeConnected + area.push([nx, ny]) + q.push([nx, ny]) + } + } + if (area.length == 0 && g[i][j] != floodFillMakeConnected) + area.push([i, j]) + res.push(area) + } + } + } + return res +} + +/** + * @param {number[][]} grid + * @return {number} + */ +const findMaxFish = (g) => { + let areas = getAllAreasCoordinates(deepCopy2DArray(g)), + res = 0 + for (const area of areas) { + let sum = 0 + for (const [x, y] of area) sum += g[x][y] + res = Math.max(res, sum) + } + return res +} + diff --git a/2659-make-array-empty.js b/2659-make-array-empty.js new file mode 100644 index 00000000..4bef4f3f --- /dev/null +++ b/2659-make-array-empty.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var countOperationsToEmptyArray = function(nums) { + const pos = new Map() + const n = nums.length + let res = n + + for (let i = 0; i < n; ++i) { + pos.set(nums[i], i) + } + + nums.sort((a, b) => a - b) + + for (let i = 1; i < n; ++i) { + if (pos.get(nums[i]) < pos.get(nums[i - 1])) { + res += n - i + } + } + + return res +}; diff --git a/266-palindrome-permutation.js b/266-palindrome-permutation.js new file mode 100644 index 00000000..c8e86728 --- /dev/null +++ b/266-palindrome-permutation.js @@ -0,0 +1,37 @@ +/** + +Given a string, determine if a permutation of the string could form a palindrome. + +Example 1: + +Input: "code" +Output: false +Example 2: + +Input: "aab" +Output: true +Example 3: + +Input: "carerac" +Output: true + +*/ + +/** + * @param {string} s + * @return {boolean} + */ +const canPermutePalindrome = function(s) { + const m = {} + for(let i = 0, len = s.length; i < len; i++) { + if(m[s[i]] == null || m[s[i]] === 0) m[s[i]] = 1 + else m[s[i]] -= 1 + } + let num = 0 + for(let el in m) { + if(m.hasOwnProperty(el)) { + if(m[el] > 0) num++ + } + } + return num === 0 || num === 1 +}; diff --git a/2660-determine-the-winner-of-a-bowling-game.js b/2660-determine-the-winner-of-a-bowling-game.js new file mode 100644 index 00000000..c51e7e18 --- /dev/null +++ b/2660-determine-the-winner-of-a-bowling-game.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} player1 + * @param {number[]} player2 + * @return {number} + */ +var isWinner = function(player1, player2) { + const n = player1.length + let sum1 = 0, sum2 = 0 + // 1 + for(let i = 0; i < n; i++) { + const cur = player1[i] + sum1 += cur + if( (i >= 1 && player1[i - 1] === 10) || (i >= 2 && player1[i - 2] === 10) ) { + sum1 += cur + } + } + + + // 2 + for(let i = 0; i < n; i++) { + const cur = player2[i] + sum2 += cur + if( (i >= 1 && player2[i - 1] === 10) || (i >= 2 && player2[i - 2] === 10) ) { + sum2 += cur + } + } + + return sum1 === sum2 ? 0 : (sum1 > sum2 ? 1 : 2) +}; diff --git a/2661-first-completely-painted-row-or-column.js b/2661-first-completely-painted-row-or-column.js new file mode 100644 index 00000000..373ccd52 --- /dev/null +++ b/2661-first-completely-painted-row-or-column.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} arr + * @param {number[][]} mat + * @return {number} + */ +const firstCompleteIndex = function(arr, mat) { + const map = new Map() + const m = mat.length, n = mat[0].length + + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + map.set(mat[i][j], [i, j]) + } + } + + const rows = Array(m).fill(0) + const cols = Array(n).fill(0) + + for(let i = 0; i < m * n; i++) { + const e = arr[i] + const [r, c] = map.get(e) + rows[r]++ + cols[c]++ + // console.log(r, c, rows, cols, m, n) + if(rows[r] === n) return i + if(cols[c] === m) return i + } + +}; diff --git a/2662-minimum-cost-of-a-path-with-special-roads.js b/2662-minimum-cost-of-a-path-with-special-roads.js new file mode 100644 index 00000000..0133ae63 --- /dev/null +++ b/2662-minimum-cost-of-a-path-with-special-roads.js @@ -0,0 +1,274 @@ +/** + * @param {number[]} start + * @param {number[]} target + * @param {number[][]} specialRoads + * @return {number} + */ +const minimumCost = function(start, target, specialRoads) { + const n = specialRoads.length; + let res = Infinity; + const pq = new PQ((a, b) => a[0] < b[0]); + const dist = Array(n).fill(Infinity); + const { abs } = Math; + for(let i = 0; i < n; i++) { + const [x, y, x2, y2, cost] = specialRoads[i]; + dist[i] = abs(start[0] - x) + abs(start[1] - y) + cost; + pq.push([dist[i], i]); + } + res = abs(target[0] - start[0]) + abs(target[1] - start[1]) + while(!pq.isEmpty()) { + const [d, i] = pq.pop(); + if(d !== dist[i]) continue; + const e = specialRoads[i]; + res = Math.min(res, d + abs(target[0] - e[2]) + abs(target[1] - e[3])); + for(let j = 0; j < n; j++) { + const w = abs(e[2] - specialRoads[j][0]) + abs(e[3] - specialRoads[j][1]) + specialRoads[j][4]; + if(d + w < dist[j]) { + dist[j] = d + w; + pq.push([dist[j], j]); + } + } + } + + return res +}; + +// another + + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} +/** + * @param {number[]} start + * @param {number[]} target + * @param {number[][]} specialRoads + * @return {number} + */ +const minimumCost = function(start, target, specialRoads) { + const n = specialRoads.length, INF = Number.MAX_SAFE_INTEGER + + const {abs, min, max} = Math + const dis = Array(n).fill(INF) + const pq = new PQ((a,b) => a[0] < b[0]) + + let res = abs(start[0] - target[0]) + abs(start[1] - target[1]) + for(let i = 0; i < n; i++) { + const e = specialRoads[i] + const tmp = abs(e[0] - start[0]) + abs(e[1] - start[1]) + e[4] + dis[i] = tmp + pq.push([tmp, i]) + } + + while(!pq.isEmpty()) { + const [d, i] = pq.pop() + if(d > dis[i]) continue + res = min(res, d + abs(target[0] - specialRoads[i][2]) + abs(target[1] - specialRoads[i][3])) + + for(let nxt = 0; nxt < n; nxt++) { + const nv = abs(specialRoads[nxt][0] - specialRoads[i][2]) + abs(specialRoads[nxt][1] - specialRoads[i][3]) + specialRoads[nxt][4] + if(d + nv < dis[nxt]) { + dis[nxt] = d + nv + pq.push([dis[nxt], nxt]) + } + } + } + + return res +}; + + +// another + + +/** + * @param {number[]} start + * @param {number[]} target + * @param {number[][]} specialRoads + * @return {number} + */ +var minimumCost = function (start, target, specialRoads) { + const INF = 1e9 + 10 + let n = specialRoads.length + const { abs, min, max } = Math + + // Initialize the distance of each special road to infinity + const d = Array(n).fill(INF) + + // Create a priority queue and push the distance from start to each special road + const pq = new PQ((a, b) => a[0] < b[0]) + for (let i = 0; i < n; i++) { + d[i] = + abs(start[0] - specialRoads[i][0]) + + abs(start[1] - specialRoads[i][1]) + + specialRoads[i][4] + pq.push([d[i], i]) + } + + // Initialize the answer with the manhattan distance between start and target + let ans = abs(start[0] - target[0]) + abs(start[1] - target[1]) + + // Continue to search for the shortest path until the priority queue is empty + while (pq.size()) { + // Pop the pair with smallest distance + let [d_c, c] = pq.pop() + + // If the distance stored in d is not equal to the current distance d_c, skip this node + if (d_c != d[c]) continue + + // Update the answer by finding the distance from the current special road to the target + ans = min( + ans, + d_c + + abs(target[0] - specialRoads[c][2]) + + abs(target[1] - specialRoads[c][3]) + ) + + // For each special road that can be reached from the current special road, update its distance + for (let nxt = 0; nxt < n; nxt++) { + let w = + abs(specialRoads[c][2] - specialRoads[nxt][0]) + + abs(specialRoads[c][3] - specialRoads[nxt][1]) + + specialRoads[nxt][4] + if (d_c + w < d[nxt]) { + d[nxt] = d_c + w + pq.push([d[nxt], nxt]) + } + } + } + + // Return the minimum cost of reaching the target + return ans +} + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2663-lexicographically-smallest-beautiful-string.js b/2663-lexicographically-smallest-beautiful-string.js new file mode 100644 index 00000000..9c6d0067 --- /dev/null +++ b/2663-lexicographically-smallest-beautiful-string.js @@ -0,0 +1,85 @@ +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const smallestBeautifulString = function(s, k) { + const n = s.length + const original = s + const chars = s.split(''), a = 'a'.charCodeAt(0), z = 'z'.charCodeAt(0) + const codeToCh = code => String.fromCharCode(code) + let flag = false + for(let i = n - 1; i >= 0; i--) { + const code = chars[i].charCodeAt(0) + for(let j = code + 1; j < a + k && j <= z; j++) { + if(!valid(i, codeToCh(j))) continue + chars[i] = codeToCh(j) + for(let nxt = i + 1; nxt < n; nxt++) { + for(let c = a; c < a + k; c++) { + if(valid(nxt, codeToCh(c))) { + chars[nxt] = codeToCh(c) + break + } + } + } + flag = true + break + } + if(flag) break + } + + const res = chars.join('') + if(res === original) return '' + return res + + function valid(idx, ch) { + if(idx >= 1 && ch === chars[idx - 1]) return false + if(idx >= 2 && ch === chars[idx - 2]) return false + return true + } +}; + +// another + + +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const smallestBeautifulString = function (s, k) { + const chars = s.split('') + + for (let i = chars.length - 1; i >= 0; i--) { + chars[i] = String.fromCharCode(chars[i].charCodeAt(0) + 1) + while (containsPalindrome(chars, i)) { + chars[i] = String.fromCharCode(chars[i].charCodeAt(0) + 1) + } + if (chars[i] < String.fromCharCode('a'.charCodeAt(0) + k)) { + // If s[i] is among the first k letters, then change the letters after + // s[i] to the smallest ones that don't form any palindrome substring. + return changeSuffix(chars, i + 1) + } + } + + return '' + + // Returns true if chars[0..i] contains palindrome. + function containsPalindrome(chars, i) { + return ( + (i > 0 && chars[i] == chars[i - 1]) || (i > 1 && chars[i] == chars[i - 2]) + ) + } + + // Returns string where chars[i..] replaced with the smallest letters that + // don't form any palindrome substring. + function changeSuffix(chars, i) { + for (let j = i; j < chars.length; j++) { + chars[j] = 'a' + while (containsPalindrome(chars, j)) { + chars[j] = String.fromCharCode(chars[j].charCodeAt(0) + 1) + } + } + return chars.join('') + } +} diff --git a/2667-create-hello-world-function.js b/2667-create-hello-world-function.js new file mode 100644 index 00000000..d4dcdbfa --- /dev/null +++ b/2667-create-hello-world-function.js @@ -0,0 +1,13 @@ +/** + * @return {Function} + */ +var createHelloWorld = function() { + return function(...args) { + return 'Hello World' + } +}; + +/** + * const f = createHelloWorld(); + * f(); // "Hello World" + */ diff --git a/267-palindrome-permutation-ii.js b/267-palindrome-permutation-ii.js new file mode 100644 index 00000000..1afa5e02 --- /dev/null +++ b/267-palindrome-permutation-ii.js @@ -0,0 +1,58 @@ +/** + +Given a string s, return all the palindromic permutations (without duplicates) of it. +Return an empty list if no palindromic permutation could be form. + +Example 1: + +Input: "aabb" +Output: ["abba", "baab"] +Example 2: + +Input: "abc" +Output: [] + +*/ + +/** + * @param {string} s + * @return {string[]} + */ +const generatePalindromes = function(s) { + const ans = [] + const count = Array(256).fill(0) + let odds = 0 + for (let c of s) count[c.charCodeAt(0)]++ + for (let c of count) if (c % 2 !== 0) odds++ + if (odds <= 1) { + let center = null + for (let idx = 0; idx < count.length; idx++) { + if (count[idx] % 2 === 1) { + center = String.fromCharCode(idx) + count[idx]-- + break + } + } + generate(ans, count, center != null ? center : '', s.length) + } + return ans +} + +function generate(ans, count, build, len) { + if (build.length === len) { + ans.push(build) + return + } + for (let idx = 0; idx < count.length; idx++) { + if (count[idx] > 0) { + count[idx] -= 2 + generate( + ans, + count, + String.fromCharCode(idx) + build + String.fromCharCode(idx), + len + ) + count[idx] += 2 + } + } +} diff --git a/2670-find-the-distinct-difference-array.js b/2670-find-the-distinct-difference-array.js new file mode 100644 index 00000000..4148bf6c --- /dev/null +++ b/2670-find-the-distinct-difference-array.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const distinctDifferenceArray = function(nums) { + const res = [] + + for(let i = 0, n = nums.length; i < n; i++) { + const pre = nums.slice(0, i + 1), suf = nums.slice(i + 1) + res[i] = new Set(pre).size - new Set(suf).size + } + + return res +}; diff --git a/2671-frequency-tracker.js b/2671-frequency-tracker.js new file mode 100644 index 00000000..74362ddb --- /dev/null +++ b/2671-frequency-tracker.js @@ -0,0 +1,51 @@ +let cnt = {}, freq = {} +var FrequencyTracker = function() { + cnt = {} + freq = {} +}; + +/** + * @param {number} number + * @return {void} + */ +FrequencyTracker.prototype.add = function(number) { + const c = cnt[number] ?? 0 + if(cnt[number] == null) cnt[number] = 0 + if(freq[c] == null) freq[c] = 0 + --freq[cnt[number]]; + if(cnt[number] == null) cnt[number] = 0 + ++cnt[number]; + if(freq[cnt[number]] == null) freq[cnt[number]] = 0 + ++freq[cnt[number]]; +}; + +/** + * @param {number} number + * @return {void} + */ +FrequencyTracker.prototype.deleteOne = function(number) { + if(cnt[number] == null) cnt[number] = 0 + if (cnt[number] > 0) { + if(freq[cnt[number]] == null) freq[cnt[number]] = 0 + --freq[cnt[number]]; + --cnt[number]; + if(freq[cnt[number]] == null) freq[cnt[number]] = 0 + ++freq[cnt[number]]; + } +}; + +/** + * @param {number} frequency + * @return {boolean} + */ +FrequencyTracker.prototype.hasFrequency = function(frequency) { + return freq[frequency] > 0; +}; + +/** + * Your FrequencyTracker object will be instantiated and called as such: + * var obj = new FrequencyTracker() + * obj.add(number) + * obj.deleteOne(number) + * var param_3 = obj.hasFrequency(frequency) + */ diff --git a/2672-number-of-adjacent-elements-with-the-same-color.js b/2672-number-of-adjacent-elements-with-the-same-color.js new file mode 100644 index 00000000..1ca04f3c --- /dev/null +++ b/2672-number-of-adjacent-elements-with-the-same-color.js @@ -0,0 +1,72 @@ +/** + * @param {number} n + * @param {number[][]} queries + * @return {number[]} + */ +const colorTheArray = function(n, queries) { + let res = [] + const arr = Array(n).fill(0) + const [idx, val] = queries[0] + arr[idx] = val + res.push(0) + const len = queries.length + for(let i = 1; i < len; i++) { + helper(queries[i]) + } + + return res + + function helper([idx, val]) { + const pre = res[res.length - 1] + let cur = pre + if(arr[idx] !== val) { + if(arr[idx] !== 0) { + if(idx > 0 && arr[idx - 1] === val) cur++ + if(idx + 1 < n && arr[idx + 1] === val) cur++ + if(idx > 0 && arr[idx - 1] === arr[idx]) { + cur-- + } + if(idx + 1 < n && arr[idx + 1] === arr[idx]) { + cur-- + } + } else { + // not set + if(idx > 0 && arr[idx - 1] === val) cur++ + if(idx + 1 < n && arr[idx + 1] === val) cur++ + } + } + arr[idx] = val + + res.push(cur) + } +}; + +// another + +/** + * @param {number} n + * @param {number[][]} queries + * @return {number[]} + */ +var colorTheArray = function(n, queries) { + let color = {}; + let ans = []; + let cnt = 0; + for (const q of queries) { + if (get(color, q[0])!=q[1]) { + if (get(color, q[0])!=0){ + if (get(color, q[0]-1) == get(color, q[0])) --cnt; + if (get(color, q[0]+1) == get(color, q[0])) --cnt; + } + color[q[0]]=q[1]; + if (get(color, q[0]-1) == color[q[0]]) ++cnt; + if (get(color, q[0]+1) == color[q[0]]) ++cnt; + } + ans.push(cnt); + } + return ans; + + function get(hash, key) { + return hash[key] == null ? 0 : hash[key] + } +}; diff --git a/2673-make-costs-of-paths-equal-in-a-binary-tree.js b/2673-make-costs-of-paths-equal-in-a-binary-tree.js new file mode 100644 index 00000000..b429fb98 --- /dev/null +++ b/2673-make-costs-of-paths-equal-in-a-binary-tree.js @@ -0,0 +1,36 @@ +/** + * @param {number} n + * @param {number[]} cost + * @return {number} + */ +const minIncrements = function(n, cost) { + let res = 0 + dfs(1) + return res + + function dfs(node) { + if(node > n) return 0 + const l = dfs(2 * node) + const r = dfs(2 * node + 1) + res += Math.abs(l - r) + return Math.max(l, r) + cost[node - 1] + } +}; + +// another + +/** + * @param {number} n + * @param {number[]} cost + * @return {number} + */ +var minIncrements = function(n, cost) { + let ans = 0; + const {abs, max} = Math + for (let i = n >> 1; i > 0; ) { + let r = i<<1, l = r-1; + ans += abs(cost[l]-cost[r]); + cost[--i] += max(cost[l], cost[r]); + } + return ans; +}; diff --git a/268-missing-number.js b/268-missing-number.js index da2b79ad..56870d19 100755 --- a/268-missing-number.js +++ b/268-missing-number.js @@ -1,3 +1,30 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var missingNumber = function(nums) { + nums.push(null) + const m = nums.length + + for(let i = 0; i < m; i++) { + while(nums[i] >= 0 && nums[i] <= m - 1 && nums[i] !== nums[nums[i]]) { + swap(nums, i, nums[i]) + } + + } + + for(let i = 0; i < m; i++) { + if(nums[i] !== i) return i + } + return m + + function swap(arr, i, j) { + ;[nums[i], nums[j]] = [nums[j], nums[i]] + } +}; + +// another + /** * @param {number[]} nums * @return {number} @@ -23,3 +50,15 @@ const missingNumber = function(nums) { function sum(arr) { return arr.reduce((ac, el) => ac + el, 0); } + +// another +/** + * @param {number[]} nums + * @return {number} + */ +var missingNumber = function(nums) { + const n = nums.length + const sum = nums.reduce((ac, e) => ac + e, 0) + const target = (n + 1) * n / 2 + return target - sum +}; diff --git a/2680-maximum-or.js b/2680-maximum-or.js new file mode 100644 index 00000000..8a5abec4 --- /dev/null +++ b/2680-maximum-or.js @@ -0,0 +1,61 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumOr = function(nums, k) { + let res = 0n + const n = nums.length, pre = Array(n).fill(0), suf = Array(n).fill(0) + pre[0] = nums[0] + suf[n - 1] = nums.at(-1) + for(let i = 1; i < n; i++) { + const e = nums[i] + pre[i] = pre[i - 1] | e + suf[n - 1 - i] = suf[n - i] | nums[n - 1 - i] + } + + k = bi(k) + for(let i = 0; i < n; i++) { + const e = bi(nums[i]) + let tmp = e << k + if(i - 1 >= 0) tmp |= bi(pre[i - 1]) + if(i + 1 < n) tmp |= bi(suf[i + 1]) + + res = max(res, tmp) + } + + return Number(res) +}; +function bi(num) { + return BigInt(num) +} +function max(a, b) { + return a > b ? a : b +} + +// another + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumOr = function(nums, k) { + let base = 0n, backup = 0n, best = 0n; + k = BigInt(k) + for (let num of nums) { + num = BigInt(num) + backup |= base & num; + base |= num; + } + for (let num of nums) { + num = BigInt(num) + best = max(best, base - num | backup | num << k); + } + return Number(best); +}; + +function max(a, b) { + return a > b ? a : b +} diff --git a/2681-power-of-heroes.js b/2681-power-of-heroes.js new file mode 100644 index 00000000..e76bf3da --- /dev/null +++ b/2681-power-of-heroes.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const sumOfPower = function(nums) { + const n = nums.length, mod = BigInt(1e9 + 7) + let res = 0n, sum = 0n + nums.sort((a, b) => a - b) + + for(let i = 0; i < n; i++) { + const e = BigInt(nums[i]) + const square = (e * e) % mod + + res = (res + sum * square + e * square) % mod + sum = (sum * 2n + e) % mod + } + + return res +}; diff --git a/2682-find-the-losers-of-the-circular-game.js b/2682-find-the-losers-of-the-circular-game.js new file mode 100644 index 00000000..27eab644 --- /dev/null +++ b/2682-find-the-losers-of-the-circular-game.js @@ -0,0 +1,19 @@ +/** + * @param {number} n + * @param {number} k + * @return {number[]} + */ +var circularGameLosers = function(n, k) { + const set = new Set() + let i = 0, turn = 1 + while(!set.has(i + 1)) { + set.add(i + 1) + i = (i + turn * k) % n + turn++ + } + const res = [] + for(let j = 1; j<=n;j++) { + if(!set.has(j)) res.push(j) + } + return res +}; diff --git a/2683-neighboring-bitwise-xor.js b/2683-neighboring-bitwise-xor.js new file mode 100644 index 00000000..bf83e34c --- /dev/null +++ b/2683-neighboring-bitwise-xor.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} derived + * @return {boolean} + */ +var doesValidArrayExist = function(derived) { + let n = derived.length + let r1 = Array(n).fill(0) + for (let i = 0; i < n-1; i++) { + r1[i+1] = derived[i] ^ r1[i] + } + if (r1[n-1]^r1[0] == derived[n-1]) { + return true + } + r1[0] = 1 + for (let i = 0; i < n-1; i++) { + r1[i+1] = derived[i] ^ r1[i] + } + if (r1[n-1]^r1[0] == derived[n-1]) { + return true + } + return false +}; diff --git a/2684-maximum-number-of-moves-in-a-grid.js b/2684-maximum-number-of-moves-in-a-grid.js new file mode 100644 index 00000000..b3760368 --- /dev/null +++ b/2684-maximum-number-of-moves-in-a-grid.js @@ -0,0 +1,39 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var maxMoves = function(g) { + let dirs = [ + [-1, 1], + [0, 1], + [1, 1], + ] + let grid = g + let m = grid.length, n = grid[0].length + let cachev1 = Array.from({ length: m }, () => Array(n).fill(null)) + const cache = {} + // const m = g.length; const n = g[0].length + const dx = [0, -1, 1]; const dy = [1, 1, 1] + + let ans = 0 + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + ans = Math.max(ans, dfs(i, j)) + } + } + return ans + + function dfs (i, j) { + if (cache[`${i}_${j}`]) return cache[`${i}_${j}`] + if (j === 0) return cache[`${i}_${j}`] = 0 + let s = -1 + for (let k = 0; k < 3; k++) { + const x = i - dx[k]; const y = j - dy[k] + if (x >= 0 && x < m && y >= 0 && y < n && g[i][j] > g[x][y]) { + s = Math.max(s, dfs(x, y)) + } + } + if (s === -1) return cache[`${i}_${j}`] = -1 + return cache[`${i}_${j}`] = s + 1 + } +}; diff --git a/2685-count-the-number-of-complete-components.js b/2685-count-the-number-of-complete-components.js new file mode 100644 index 00000000..f13b6657 --- /dev/null +++ b/2685-count-the-number-of-complete-components.js @@ -0,0 +1,48 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +var countCompleteComponents = function(n, edges) { + const ma = Array(n).fill(0).map((_, idx) => idx) + const e = {} + for (const [x, y] of edges) { + e[x] ??= new Set() + e[x].add(y) + e[y] ??= new Set() + e[y].add(x) + merge(x, y) + } + const f = []; const fs = {} + for (let i = 0; i < n; i++) { + s = get(i) + f.push(s) + fs[s] ??= [] + fs[s].push(i) + } + + let ans = 0 + for (const [_, t] of Object.entries(fs)) { + let ok = true + for (let i = 0; i < t.length; i++) { + if (!ok) break + for (let j = i + 1; j < t.length; j++) { + if (!e[t[i]].has(t[j])) { + ok = false + break + } + } + } + ans += ok + } + return ans + + function get(x) { + if (ma[x] === x) return x + return ma[x] = get(ma[x]) + } + function merge (x, y) { + const fx = get(x); const fy = get(y) + ma[fx] = fy + } +}; diff --git a/269-alien-dictionary.js b/269-alien-dictionary.js new file mode 100644 index 00000000..dcc879a9 --- /dev/null +++ b/269-alien-dictionary.js @@ -0,0 +1,84 @@ +/** + +There is a new alien language which uses the latin alphabet. +However, the order among letters are unknown to you. +You receive a list of non-empty words from the dictionary, +where words are sorted lexicographically by the rules of +this new language. Derive the order of letters in this language. + +Example 1: + +Input: +[ + "wrt", + "wrf", + "er", + "ett", + "rftt" +] + +Output: "wertf" +Example 2: + +Input: +[ + "z", + "x" +] + +Output: "zx" +Example 3: + +Input: +[ + "z", + "x", + "z" +] + +Output: "" + +Explanation: The order is invalid, so return "". +Note: + +You may assume all letters are in lowercase. +You may assume that if a is a prefix of b, then a must appear before b in the given dictionary. +If the order is invalid, return an empty string. +There may be multiple valid order of letters, return any one of them is fine. + +*/ + +/** + * @param {string[]} words + * @return {string} + */ +const alienOrder = function(words) { + const graph = {} + words.forEach(w => w.split('').forEach(ch => (graph[ch] = new Set()))) + words.reduce((prev, curr) => { + for (let i = 0; i < Math.min(prev.length, curr.length); i++) { + if (prev[i] !== curr[i]) { + graph[prev[i]].add(curr[i]) + break + } + } + return curr + }) + const marked = {}, + visited = {} + let str = '' + let hasCycle = false + Object.keys(graph).map(visit) + return hasCycle ? '' : str + function visit(n) { + if (marked[n]) return + if (visited[n]) { + hasCycle = true + return + } + visited[n] = true + graph[n].forEach(visit) + marked[n] = true + str = n + str + } +} diff --git a/2699-modify-graph-edge-weights.js b/2699-modify-graph-edge-weights.js new file mode 100644 index 00000000..73626624 --- /dev/null +++ b/2699-modify-graph-edge-weights.js @@ -0,0 +1,146 @@ +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} source + * @param {number} destination + * @param {number} target + * @return {number[][]} + */ +const modifiedGraphEdges = function (n, edges, source, destination, target) { + const kMax = 1e9 + const graph = Array(n) + .fill(null) + .map(() => []) + + for (const [u, v, w] of edges) { + if (w === -1) { + continue + } + graph[u].push([v, w]) + graph[v].push([u, w]) + } + + const distToDestination = dijkstra(graph, source, destination) + if (distToDestination < target) { + return [] + } + if (distToDestination === target) { + // Change the weights of negative edges to an impossible value. + for (const edge of edges) { + if (edge[2] === -1) { + edge[2] = kMax + } + } + return edges + } + + for (let i = 0; i < edges.length; i++) { + const [u, v, w] = edges[i] + if (w !== -1) { + continue + } + edges[i][2] = 1 + graph[u].push([v, 1]) + graph[v].push([u, 1]) + const distToDestination = dijkstra(graph, source, destination) + if (distToDestination <= target) { + edges[i][2] += target - distToDestination + // Change the weights of negative edges to an impossible value. + for (let j = i + 1; j < edges.length; j++) { + if (edges[j][2] === -1) { + edges[j][2] = kMax + } + } + return edges + } + } + + return [] +} + +function dijkstra(graph, src, dst) { + const dist = Array(graph.length).fill(Infinity) + const minHeap = new PQ((a, b) => a[0] < b[0]) + + dist[src] = 0 + minHeap.push([dist[src], src]) + + while (!minHeap.isEmpty()) { + const [d, u] = minHeap.pop() + for (const [v, w] of graph[u] || []) { + if (d + w < dist[v]) { + dist[v] = d + w + minHeap.push([dist[v], v]) + } + } + } + + return dist[dst] +} diff --git a/270-closest-binary-search-tree-value.js b/270-closest-binary-search-tree-value.js new file mode 100644 index 00000000..5bde4e8b --- /dev/null +++ b/270-closest-binary-search-tree-value.js @@ -0,0 +1,85 @@ +/** + +Given a non-empty binary search tree and a target value, +find the value in the BST that is closest to the target. + +Note: + +Given target value is a floating point. +You are guaranteed to have only one unique value +in the BST that is closest to the target. + +Example: + +Input: root = [4,2,5,1,3], target = 3.714286 + + 4 + / \ + 2 5 + / \ +1 3 + +Output: 4 + +*/ + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {number} target + * @return {number} + */ +const closestValue = function(root, target) { + let res = root.val + while(root) { + if(Math.abs(root.val - target) < Math.abs(res - target)) { + res = root.val + } + root = root.val > target ? root.left : root.right + } + return res +}; + +// another + +const closestValue = function(root, target) { + const child = target < root.val ? root.left : root.right; + if (!child) return root.val; + const closest = closestValue(child, target); + return Math.abs(closest - target) < Math.abs(root.val - target) + ? closest + : root.val; +}; + +// another + +const closestValue = function(root, target) { + if(root == null) return -1 + let node = root + const stack = [] + const res = [] + const K = 1 + while(node || stack.length) { + if(node) { + stack.push(node) + node = node.left + } else { + node = stack.pop() + if(res.length === K) { + if(Math.abs(res[0] - target) < Math.abs(node.val - target)) { + return res[0] + } + res.shift() + } + res.push(node.val) + node = node.right + } + } + return res[0] +}; diff --git a/2702-minimum-operations-to-make-numbers-non-positive.js b/2702-minimum-operations-to-make-numbers-non-positive.js new file mode 100644 index 00000000..1330b34b --- /dev/null +++ b/2702-minimum-operations-to-make-numbers-non-positive.js @@ -0,0 +1,36 @@ +/** + * @param {number[]} nums + * @param {number} x + * @param {number} y + * @return {number} + */ +const minOperations = function (nums, x, y) { + const { max, floor } = Math + let right = nums[0] + for (const v of nums) { + right = Math.max(v, right) + } + let left = 1 + right = floor(right / y) + 1 + x -= y + while (left <= right) { + let mid = (left + right) >> 1, + s = mid + for (let v of nums) { + let t = floor((v + y - 1) / y) + if (mid >= t) { + continue + } + s -= floor((v - mid * y + x - 1) / x) + if (s < 0) { + break + } + } + if (s >= 0) { + right = mid - 1 + } else { + left = mid + 1 + } + } + return right + 1 +} diff --git a/2709-greatest-common-divisor-traversal.js b/2709-greatest-common-divisor-traversal.js new file mode 100644 index 00000000..581401c6 --- /dev/null +++ b/2709-greatest-common-divisor-traversal.js @@ -0,0 +1,47 @@ +// max number in `nums` is 10^5. Only need primes up to sqrt(10^5) = 316 +const primes = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, + 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, + 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, +] + +/** + * @param {number[]} nums + * @return {boolean} + */ +const canTraverseAllPairs = function(nums) { + const n = nums.length + const uf = new Array(n).fill(-1) + const primeIdxs = {} + + const find = (i) => (uf[i] < 0 ? i : find(uf[i])) + + nums.forEach((num, i) => { + // find all prime factors of num + let primeFactors = [] + for (let p of primes) { + if (num % p === 0) { + primeFactors.push(p) + while (num % p === 0) num = Math.floor(num / p) + } + } + + if (num !== 1) primeFactors.push(num) + + for (let factor of primeFactors) { + if (factor in primeIdxs) { + let pi = find(i) + let pj = find(primeIdxs[factor]) + // union if not already merged + if (pi !== pj) { + if (uf[pi] > uf[pj]) [pi, pj] = [pj, pi] + uf[pi] += uf[pj] + uf[pj] = pi + } + } else primeIdxs[factor] = i + } + }) + + return Math.abs(Math.min(...uf)) === n +}; diff --git a/271-encode-and-decode-strings.js b/271-encode-and-decode-strings.js new file mode 100644 index 00000000..33e17adb --- /dev/null +++ b/271-encode-and-decode-strings.js @@ -0,0 +1,36 @@ +/** + * Encodes a list of strings to a single string. + * + * @param {string[]} strs + * @return {string} + */ +const encode = function(strs) { + let s = '' + for(let e of strs) { + s += e.length + '/' + e + } + return s +}; + +/** + * Decodes a single string to a list of strings. + * + * @param {string} s + * @return {string[]} + */ +const decode = function(s) { + const res = [] + let i = 0 + while(i < s.length) { + const idx = s.indexOf('/', i) + const size = s.slice(i, idx) + i = idx + (+size) + 1 + res.push(s.slice(idx + 1, i)) + } + return res +}; + +/** + * Your functions will be called as such: + * decode(encode(strs)); + */ diff --git a/2710-remove-trailing-zeros-from-a-string.js b/2710-remove-trailing-zeros-from-a-string.js new file mode 100644 index 00000000..960926be --- /dev/null +++ b/2710-remove-trailing-zeros-from-a-string.js @@ -0,0 +1,14 @@ +/** + * @param {string} num + * @return {string} + */ +var removeTrailingZeros = function(num) { + const n = num.length + let idx = n + for(let i = n - 1; i >= 0; i--) { + if(num[i] === '0') idx = i + else break + } + + return num.slice(0, idx) +}; diff --git a/2711-difference-of-number-of-distinct-values-on-diagonals.js b/2711-difference-of-number-of-distinct-values-on-diagonals.js new file mode 100644 index 00000000..03cabb3d --- /dev/null +++ b/2711-difference-of-number-of-distinct-values-on-diagonals.js @@ -0,0 +1,33 @@ +/** + * @param {number[][]} grid + * @return {number[][]} + */ +const differenceOfDistinctValues = function (grid) { + const m = grid.length, + n = grid[0].length, + { abs } = Math + const res = Array.from({ length: m }, () => Array(n).fill(0)) + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + const bottomRight = new Set() + const topLeft = new Set() + let x = i + 1 + let y = j + 1 + while (x >= 0 && x < m && y >= 0 && y < n) { + bottomRight.add(grid[x][y]) + x++ + y++ + } + x = i - 1 + y = j - 1 + while (x >= 0 && x < m && y >= 0 && y < n) { + topLeft.add(grid[x][y]) + x-- + y-- + } + + res[i][j] = abs(bottomRight.size - topLeft.size) + } + } + return res +} diff --git a/2712-minimum-cost-to-make-all-characters-equal.js b/2712-minimum-cost-to-make-all-characters-equal.js new file mode 100644 index 00000000..934c66bb --- /dev/null +++ b/2712-minimum-cost-to-make-all-characters-equal.js @@ -0,0 +1,34 @@ +/** + * @param {string} s + * @return {number} + */ +const minimumCost = function (s) { + const n = s.length, + { min } = Math + let res = Infinity + const dp = Array.from({ length: n + 1 }, () => Array(2).fill(0)) + const dp1 = Array.from({ length: n + 1 }, () => Array(2).fill(0)) + for (let i = 0; i < n; i++) { + if (s[i] === '0') { + dp[i + 1][0] = dp[i][0] + dp[i + 1][1] = dp[i][0] + (i + 1) + } else { + dp[i + 1][0] = dp[i][1] + (i + 1) + dp[i + 1][1] = dp[i][1] + } + } + + for (let i = n - 1; i >= 0; i--) { + if (s[i] === '0') { + dp1[i][0] = dp1[i + 1][0] + dp1[i][1] = dp1[i + 1][0] + (n - i) + } else { + dp1[i][0] = dp1[i + 1][1] + (n - i) + dp1[i][1] = dp1[i + 1][1] + } + } + for (let i = 0; i <= n; i++) { + res = min(res, dp[i][0] + dp1[i][0], dp[i][1] + dp1[i][1]) + } + return res +} diff --git a/2713-maximum-strictly-increasing-cells-in-a-matrix.js b/2713-maximum-strictly-increasing-cells-in-a-matrix.js new file mode 100644 index 00000000..e033e1f7 --- /dev/null +++ b/2713-maximum-strictly-increasing-cells-in-a-matrix.js @@ -0,0 +1,50 @@ +/** + * @param {number[][]} mat + * @return {number} + */ +const maxIncreasingCells = function (mat) { + let m = mat.length + let n = mat[0].length + + const p = Array.from({ length: m * n }, () => Array(2).fill(0)) + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + p[i * n + j][0] = i + p[i * n + j][1] = j + } + } + p.sort((a, b) => mat[a[0]][a[1]] - mat[b[0]][b[1]]) + + let rmax = new Array(m).fill(0) + + let cmax = new Array(n).fill(0) + let ans = 0 + let start = 0, + end = 0 + for (; start < m * n; start = end) { + let sv = mat[p[start][0]][p[start][1]] + + for (end = start + 1; end < m * n; end++) { + if (sv != mat[p[end][0]][p[end][1]]) { + break + } + } + + let list = [] + for (let t = start; t < end; t++) { + let i = p[t][0], + j = p[t][1] + let max = Math.max(rmax[i], cmax[j]) + 1 + list.push([i, j, max]) + ans = Math.max(ans, max) + } + for (let ints of list) { + let i = ints[0], + j = ints[1], + max = ints[2] + rmax[i] = Math.max(rmax[i], max) + cmax[j] = Math.max(cmax[j], max) + } + } + return ans +} diff --git a/2719-count-of-integers.js b/2719-count-of-integers.js new file mode 100644 index 00000000..0dae13c5 --- /dev/null +++ b/2719-count-of-integers.js @@ -0,0 +1,59 @@ +/** + * @param {string} num1 + * @param {string} num2 + * @param {number} min_sum + * @param {number} max_sum + * @return {number} + */ +const count = function (num1, num2, min_sum, max_sum) { + const mod = 1e9 + 7 + let res = 0 + res = + (cntNoGreater(num2, max_sum) - cntNoGreater(num2, min_sum - 1) + mod) % mod - + (cntNoGreater(num1, max_sum) - cntNoGreater(num1, min_sum - 1) + mod) % mod + res = (res + mod) % mod + const sum1 = calc(num1) + if (sum1 >= min_sum && sum1 <= max_sum) { + res = (res + 1) % mod + } + + return res + + function cntNoGreater(num, maxSum) { + const memo = Array.from({ length: 2 }, () => + Array.from({ length: 23 }, () => Array(401).fill(-1)) + ) + return dfs(num, maxSum, 0, 0, 1, memo) + } + function dfs(num, maxSum, idx, sum, isSame, memo) { + if(sum > maxSum) { + return 0 + } + if (idx === num.length) { + return 1 + } + if(memo[isSame][idx][sum] !== -1) { + return memo[isSame][idx][sum] + } + let res = 0 + if(isSame) { + for(let i = 0; i < num[idx]; i++) { + res = (res + dfs(num, maxSum, idx + 1, sum + i, 0, memo)) % mod + } + res = (res + dfs(num, maxSum, idx + 1, sum + +num[idx], 1, memo)) % mod + } else { + for (let i = 0; i <= 9; i++) { + res = (res + dfs(num, maxSum, idx + 1, sum + i, 0, memo)) % mod + } + } + + return memo[isSame][idx][sum] = res + } + function calc(num) { + let res = 0 + for (const e of num) { + res += +e + } + return res + } +} diff --git a/272-closest-binary-search-tree-value-ii.js b/272-closest-binary-search-tree-value-ii.js new file mode 100644 index 00000000..9573ea85 --- /dev/null +++ b/272-closest-binary-search-tree-value-ii.js @@ -0,0 +1,64 @@ +/** + +Given a non-empty binary search tree and a target value, +find k values in the BST that are closest to the target. + +Note: + +Given target value is a floating point. +You may assume k is always valid, that is: k ≤ total nodes. +You are guaranteed to have only one unique set of k values +in the BST that are closest to the target. +Example: + +Input: root = [4,2,5,1,3], target = 3.714286, and k = 2 + + 4 + / \ + 2 5 + / \ +1 3 + +Output: [4,3] +Follow up: +Assume that the BST is balanced, could you solve it in +less than O(n) runtime (where n = total nodes)? + +*/ + + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {number} target + * @param {number} k + * @return {number[]} + */ +const closestKValues = function(root, target, k) { + const res = [] + let node = root + const stack = [] + while (node || stack.length) { + if (node) { + stack.push(node) + node = node.left + } else { + node = stack.pop() + if (res.length === k) { + if (Math.abs(res[0] - target) <= Math.abs(node.val - target)) { + return res + } + res.shift() + } + res.push(node.val) + node = node.right + } + } + return res +} diff --git a/273-integer-to-english-words.js b/273-integer-to-english-words.js new file mode 100644 index 00000000..caa497c7 --- /dev/null +++ b/273-integer-to-english-words.js @@ -0,0 +1,59 @@ +/** + * @param {number} num + * @return {string} + */ +const numberToWords = function(num) { + if (num === 0) return "Zero"; + if (num <= 20) return translations.get(num); + const result = []; + + for (let [value, translation] of translations) { + const times = Math.floor(num / value); + if (times === 0) continue; + num -= times * value; + if (times === 1 && value >= 100) { + result.push("One", translation); + continue; + } + if (times === 1) { + result.push(translation); + continue; + } + result.push(numberToWords(times), translation); + } + return result.join(" "); +}; + +const translations = new Map([ + [1000000000, "Billion"], + [1000000, "Million"], + [1000, "Thousand"], + [100, "Hundred"], + [90, "Ninety"], + [80, "Eighty"], + [70, "Seventy"], + [60, "Sixty"], + [50, "Fifty"], + [40, "Forty"], + [30, "Thirty"], + [20, "Twenty"], + [19, "Nineteen"], + [18, "Eighteen"], + [17, "Seventeen"], + [16, "Sixteen"], + [15, "Fifteen"], + [14, "Fourteen"], + [13, "Thirteen"], + [12, "Twelve"], + [11, "Eleven"], + [10, "Ten"], + [9, "Nine"], + [8, "Eight"], + [7, "Seven"], + [6, "Six"], + [5, "Five"], + [4, "Four"], + [3, "Three"], + [2, "Two"], + [1, "One"] +]); diff --git a/2730-find-the-longest-semi-repetitive-substring.js b/2730-find-the-longest-semi-repetitive-substring.js new file mode 100644 index 00000000..cfb15f6b --- /dev/null +++ b/2730-find-the-longest-semi-repetitive-substring.js @@ -0,0 +1,19 @@ +/** + * @param {string} s + * @return {number} + */ +const longestSemiRepetitiveSubstring = function(s) { + let res = 1 + let i = 0, j = 1, last = 0 + while(j < s.length) { + if(s[j] === s[j - 1]) { + if(last) i = last + last = j + } + + res = Math.max(res, j - i + 1) + j++ + } + + return res +}; diff --git a/2736-maximum-sum-queries.js b/2736-maximum-sum-queries.js new file mode 100644 index 00000000..b3381012 --- /dev/null +++ b/2736-maximum-sum-queries.js @@ -0,0 +1,79 @@ +class SegmentTree { + constructor(n) { + this.size = n + this.segTree = Array(n * 2).fill(0) + } + update(index, val) { + let n = this.size, + idx = index + n + this.segTree[idx] = Math.max(this.segTree[idx], val) + idx = Math.floor(idx / 2) + + while (idx > 0) { + this.segTree[idx] = Math.max( + this.segTree[idx * 2], + this.segTree[idx * 2 + 1], + ) + idx = Math.floor(idx / 2) + } + } + maxRange(left, right) { + let n = this.size, + max = 0 + let left_idx = left + n, + right_idx = right + n + while (left_idx <= right_idx) { + if (left_idx % 2 === 1) max = Math.max(max, this.segTree[left_idx++]) + if (right_idx % 2 === 0) max = Math.max(max, this.segTree[right_idx--]) + left_idx = Math.floor(left_idx / 2) + right_idx = Math.floor(right_idx / 2) + } + return max + } +} + + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number[][]} queries + * @return {number[]} + */ +const maximumSumQueries = function (nums1, nums2, queries) { + let nums = [], + n = nums1.length, + indexMap = {} + for (let i = 0; i < n; i++) { + nums.push([nums1[i], nums2[i]]) + indexMap[nums2[i]] = 1 + } + nums.sort((a, b) => (a[0] === b[0] ? b[1] - a[1] : b[0] - a[0])) + for (let [_x, y] of queries) { + indexMap[y] = 1 + } + let index = 0 + for (let value in indexMap) { + indexMap[value] = index++ // assign a minimized index to each value + } + queries = queries + .map(([x, y], i) => [x, y, i]) + .sort((a, b) => (a[0] === b[0] ? b[1] - a[1] : b[0] - a[0])) + + let m = queries.length, + ans = Array(m) + let segTree = new SegmentTree(index), + numsIndex = 0 + for (let [x, y, queryIndex] of queries) { + while (numsIndex < n && nums[numsIndex][0] >= x) { + segTree.update( + indexMap[nums[numsIndex][1]], + nums[numsIndex][0] + nums[numsIndex][1], + ) + numsIndex++ + } + let max = segTree.maxRange(indexMap[y], index - 1) + ans[queryIndex] = max === 0 ? -1 : max + } + return ans +} + diff --git a/274-h-index.js b/274-h-index.js new file mode 100644 index 00000000..80218b8a --- /dev/null +++ b/274-h-index.js @@ -0,0 +1,48 @@ +/** + * @param {number[]} citations + * @return {number} + */ +const hIndex = function(citations) { + const n = citations.length + const arr = Array(n + 1).fill(0) + for(let e of citations) { + if(e >= n) arr[n]++ + else arr[e]++ + } + for(let i = n, sum = 0; i >= 0; i--) { + sum += arr[i] + if(sum >= i) return i + } + return 0 +}; + +// another + +/** + * @param {number[]} citations + * @return {number} + */ +const hIndex = function(citations) { + citations = citations.sort((a, b) => b - a) + + for (let i = 0, len = citations.length; i < len; i++) { + if (i >= citations[i]) return i + } + + return citations.length +} + +// another + + +const hIndex = function(citations) { + const buckets = Array(citations.length + 1).fill(0) + citations.forEach(citation => { + buckets[citation >= citations.length ? citations.length : citation]++ + }) + for (let i = citations.length, count = 0; i >= 0; i--) { + count += buckets[i] + if (count >= i) return i + } + return 0 +} diff --git a/2741-special-permutations.js b/2741-special-permutations.js new file mode 100644 index 00000000..5264811d --- /dev/null +++ b/2741-special-permutations.js @@ -0,0 +1,54 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const specialPerm = function (nums) { + const s = new Solution() + return s.specialPerm(nums) +} + +class Solution { + constructor() { + this.dp = [] + } + solve(nums, previdx, chosenIndices) { + if (chosenIndices.length === nums.length) { + return 1 + } + + let mask = 0 + for (let index of chosenIndices) { + mask |= 1 << index + } + + if (this.dp[previdx + 1][mask] !== -1) { + return this.dp[previdx + 1][mask] + } + + let tot = 0 + for (let j = 0; j < nums.length; j++) { + if (chosenIndices.includes(j)) { + continue + } + if ( + previdx === -1 || + nums[previdx] % nums[j] === 0 || + nums[j] % nums[previdx] === 0 + ) { + chosenIndices.push(j) + tot += this.solve(nums, j, chosenIndices) + tot %= 1000000007 + chosenIndices.pop() + } + } + return (this.dp[previdx + 1][mask] = tot) + } + + specialPerm(nums) { + this.dp = new Array(20) + .fill(-1) + .map(() => new Array((1 << nums.length) + 5).fill(-1)) + let chosenIndices = [] + return this.solve(nums, -1, chosenIndices) + } +} diff --git a/2742-painting-the-walls.js b/2742-painting-the-walls.js new file mode 100644 index 00000000..3bd19770 --- /dev/null +++ b/2742-painting-the-walls.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} cost + * @param {number[]} time + * @return {number} + */ +const paintWalls = function(cost, time) { + const n = cost.length + const cache = {} + + return dfs(n - 1, 0) + + function dfs(i, j) { + if(j > i) return 0 + if(i < 0) return Number.MAX_SAFE_INTEGER + const k = `${i},${j}` + if(cache[k] != null) return cache[k] + + const res = Math.min(dfs(i - 1, j + time[i]) + cost[i], dfs(i - 1, j - 1)) + cache[k] = res + return res + } +}; diff --git a/2745-construct-the-longest-new-string.js b/2745-construct-the-longest-new-string.js new file mode 100644 index 00000000..cc895595 --- /dev/null +++ b/2745-construct-the-longest-new-string.js @@ -0,0 +1,39 @@ +/** + * @param {number} x + * @param {number} y + * @param {number} z + * @return {number} + */ +var longestString = function(x, y, z) { + // x + y + // y + x + // y + z + // z + z + let res = 0 + const {min} = Math + const minXY = min(x, y) + if(x === y) res = 2 * x + 2 * y + 2 * z + else { + res = (minXY * 2 + (minXY + 1) * 2 + 2 * z) + } + + return res +}; + +// another + +/** + * @param {number} x + * @param {number} y + * @param {number} z + * @return {number} + */ +const longestString = function(x, y, z) { + const base = Math.min(x, y) + let extra = 0 + if(x !== y) { + extra = 1 + } + + return (base * 2 + z + extra) * 2 +}; diff --git a/2747-count-zero-request-servers.js b/2747-count-zero-request-servers.js new file mode 100644 index 00000000..58b6a4f9 --- /dev/null +++ b/2747-count-zero-request-servers.js @@ -0,0 +1,56 @@ +/** + * @param {number} n + * @param {number[][]} logs + * @param {number} x + * @param {number[]} queries + * @return {number[]} + */ +const countServers = function(n, logs, x, queries) { +let queryArr = [], + ans = [] +for (let i = 0; i < queries.length; i++) { + queryArr.push([i, queries[i]]) +} +queryArr.sort(function (a, b) { + return a[1] - b[1] +}) +logs.sort(function (a, b) { + return a[1] - b[1] +}) + +let sumOfServersInCurrentTimeWindow = 0, + serverFrequenceyInCurrentTimeWindow = [] +for (let i = 0, left = 0, right = 0; i < queryArr.length; i++) { + let queryIndex = queryArr[i][0] + let startTime = queryArr[i][1] - x //Start time for the current query + let endTime = queryArr[i][1] //End time for the current query + while (right < logs.length && logs[right][1] <= endTime) { + //Include all the servers till endTime + let s = logs[right][0] + if ( + serverFrequenceyInCurrentTimeWindow[s] === undefined || + serverFrequenceyInCurrentTimeWindow[s] === 0 + ) { + serverFrequenceyInCurrentTimeWindow[s] = 1 + sumOfServersInCurrentTimeWindow++ + } else { + serverFrequenceyInCurrentTimeWindow[s] += 1 + } + right++ + } + while (left < logs.length && logs[left][1] < startTime) { + //Exclude all the servers older than startTime + let s = logs[left][0] + if (serverFrequenceyInCurrentTimeWindow[s] === 1) { + serverFrequenceyInCurrentTimeWindow[s] = 0 + sumOfServersInCurrentTimeWindow-- + } else { + serverFrequenceyInCurrentTimeWindow[s] -= 1 + } + left++ + } + ans[queryIndex] = n - sumOfServersInCurrentTimeWindow +} +return ans + +}; diff --git a/2749-minimum-operations-to-make-the-integer-zero.js b/2749-minimum-operations-to-make-the-integer-zero.js new file mode 100644 index 00000000..884190c2 --- /dev/null +++ b/2749-minimum-operations-to-make-the-integer-zero.js @@ -0,0 +1,35 @@ +/** + * @param {number} num1 + * @param {number} num2 + * @return {number} + */ +const makeTheIntegerZero = (x, y) => { + for (let cnt = 0; cnt < 40; cnt++) { + let sum = x - cnt * y; + if (sum < 0) break; + let f = SumOfPower2Factorization(sum), min = f.size, max = sum; // max factorization is all 1's (2 ^ 0) + if (min <= cnt && cnt <= max) return cnt; + } + return -1; +}; + +// min factorization (smallest total cnt) +const SumOfPower2Factorization = (x) => { + let i = 0, bit = 2 ** i, v = [], res = new Set(), cur = x; + while (bit <= x) { + v.push(bit); + i++; + bit = 2 ** i; + } + while (cur != 0) { + let idx = v.findIndex((element) => element > cur); + if (idx === -1) { + idx = v.length - 1; + } else { + idx--; + } + res.add(idx); + cur -= v[idx]; + } + return res; +}; diff --git a/275-h-index-ii.js b/275-h-index-ii.js new file mode 100644 index 00000000..254aa6db --- /dev/null +++ b/275-h-index-ii.js @@ -0,0 +1,39 @@ +/** + * @param {number[]} citations + * @return {number} + */ +const hIndex = function(citations) { + let left = 0, + len = citations.length, + right = len - 1, + mid + while (left <= right) { + mid = left + ((right - left) >> 1) + if (citations[mid] >= len - mid) right = mid - 1 + else left = mid + 1 + } + return len - left +} + +// another + +/** + * @param {number[]} citations + * @return {number} + */ +const hIndex = function(citations) { + const len = citations.length + let lo = 0, + hi = len - 1 + while (lo <= hi) { + let med = lo + ((hi - lo) >> 1) + if (citations[med] === len - med) { + return len - med + } else if (citations[med] < len - med) { + lo = med + 1 + } else { + hi = med - 1 + } + } + return len - lo +} diff --git a/2751-robot-collisions.js b/2751-robot-collisions.js new file mode 100644 index 00000000..c45f2602 --- /dev/null +++ b/2751-robot-collisions.js @@ -0,0 +1,45 @@ +/** + * @param {number[]} positions + * @param {number[]} healths + * @param {string} directions + * @return {number[]} + */ +const survivedRobotsHealths = function (positions, healths, directions) { + const p = positions, + h = healths, + d = directions + let m = {}, + res = Array(p.length).fill(0) + p.map((x, i) => (m[x] = d[i] == 'R' ? [h[i], i] : [-h[i], i])) + let a = [] + for (const k in m) a.push(m[k]) + let v = asteroidCollision(a) + for (const [x, i] of v) res[i] = Math.abs(x) + return res.filter((x) => x != 0) +} + +function asteroidCollision(a) { + let st = [] + for (const [x, i] of a) { + st.push([x, i]) + let l, li, sl, sli + if (st.length >= 1) [l, li] = st[st.length - 1] + if (st.length >= 2) [sl, sli] = st[st.length - 2] + while (st.length >= 2 && l < 0 && sl > 0) { + st.pop() + st.pop() + let add, idx + if (-l > sl) { + add = -(-l - 1) + idx = li + } else if (-l < sl) { + add = sl - 1 + idx = sli + } + if (add) st.push([add, idx]) + if (st.length >= 1) [l, li] = st[st.length - 1] + if (st.length >= 2) [sl, sli] = st[st.length - 2] + } + } + return st +} diff --git a/276-paint-fence.js b/276-paint-fence.js new file mode 100644 index 00000000..e2670ce4 --- /dev/null +++ b/276-paint-fence.js @@ -0,0 +1,45 @@ +/** + +There is a fence with n posts, each post can be painted with one of the k colors. + +You have to paint all the posts such that no more than two adjacent fence posts have the same color. + +Return the total number of ways you can paint the fence. + +Note: +n and k are non-negative integers. + +Example: + +Input: n = 3, k = 2 +Output: 6 +Explanation: Take c1 as color 1, c2 as color 2. All possible ways are: + + post1 post2 post3 + ----- ----- ----- ----- + 1 c1 c1 c2 + 2 c1 c2 c1 + 3 c1 c2 c2 + 4 c2 c1 c1 + 5 c2 c1 c2 + 6 c2 c2 c1 + +*/ + +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const numWays = function(n, k) { + if (n === 0) return 0; + if (n === 1) return k; + let diff = k * (k - 1); + let same = k; + for (let i = 2; i < n; i ++) { + const temp = diff; + diff = (diff + same) * (k - 1); + same = temp; + } + return diff + same; +} diff --git a/2760-longest-even-odd-subarray-with-threshold.js b/2760-longest-even-odd-subarray-with-threshold.js new file mode 100644 index 00000000..690ff7f6 --- /dev/null +++ b/2760-longest-even-odd-subarray-with-threshold.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @param {number} threshold + * @return {number} + */ +var longestAlternatingSubarray = function(nums, threshold) { + let res = 0 + const n = nums.length + for(let i = 0; i < n; i++) { + const e = nums[i] + let j = i, s = i + if(e % 2 === 0 && e <= threshold) { + j++ + while(true) { + if(j >= n) break + if(nums[j] > threshold) break + if( (nums[j] % 2) === (nums[j - 1] % 2) ) break + j++ + } + } + res = Math.max(res, j - i) + } + + return res +}; diff --git a/2761-prime-pairs-with-target-sum.js b/2761-prime-pairs-with-target-sum.js new file mode 100644 index 00000000..ef9a6bba --- /dev/null +++ b/2761-prime-pairs-with-target-sum.js @@ -0,0 +1,28 @@ + +/** + * @param {number} n + * @return {number[][]} + */ +const findPrimePairs = function(n) { + const res = primes(n + 1, n) + return res +}; + +function primes(n, target) { + const arr = Array(n).fill(0) + + for(let i = 2; i * i < n; i++) { + if(arr[i] !== 0) continue + let j = i * i + while(j < n) { + arr[j] = 1 + j += i + } + } + + let res = [] + for(let i = 2; i < n; i++) { + if(arr[i] === 0 && target - i > 1 && target - i >= i && arr[target - i] === 0) res.push([i, target - i]) + } + return res +}; diff --git a/2762-continuous-subarrays.js b/2762-continuous-subarrays.js new file mode 100644 index 00000000..d812a6f4 --- /dev/null +++ b/2762-continuous-subarrays.js @@ -0,0 +1,99 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const continuousSubarrays = function(nums) { + let res = 0 + let l = 0 + let r = 0 + const mq1 = [], mq2 = [] + for(let r = 0; r < nums.length; r++) { + const e = nums[r] + while(mq1.length && nums[mq1.at(-1)] < e) mq1.pop() + mq1.push(r) + while(mq2.length && nums[mq2.at(-1)] > e) mq2.pop() + mq2.push(r) + + while(mq1.length && mq2.length && Math.abs(nums[mq1[0]] - nums[mq2[0]]) > 2) { + if(mq1.length && mq1[0] <= l) mq1.shift() + if(mq2.length && mq2[0] <= l) mq2.shift() + l++ + } + + res += r - l + 1 + } + return res +}; + + +// another + + +/** + * @param {number[]} nums + * @return {number} + */ +const continuousSubarrays = function(nums) { + let res = 0 + let l = 0 + let r = 0 + const mset = new MultiSet() + for(let r = 0; r < nums.length; r++) { + mset.add(nums[r]) + while (mset.max - mset.min > 2) { + mset.remove(nums[l]) + l++ + } + + res += r - l + 1 + } + return res +}; + +class MultiSet { + constructor() { + this.countMap = new Map() + this.valueList = [] + } + remove(value) { + if(!this.countMap.has(value)) return false + let index = binarySearch(this.valueList, value) + if (this.countMap.get(value) === 1) { + this.valueList.splice(index, 1) + this.countMap.delete(value) + } else { + this.countMap.set(value, (this.countMap.get(value) || 0) - 1) + } + return true + } + add(value) { + let index = binarySearch(this.valueList, value) + if (index < 0) { + this.valueList.splice(-index - 1, 0, value) + this.countMap.set(value, 1) + } else { + this.countMap.set(value, this.countMap.get(value) + 1) + } + } + get max() { + return this.valueList[this.valueList.length - 1] + } + get min() { + return this.valueList[0] + } +} + +function binarySearch(arr, val) { + let l = 0, r = arr.length + while( l < r ) { + const mid = Math.floor((l + r) / 2) + if(arr[mid] < val) { + l = mid + 1 + } else { + r = mid + } + } + if(arr[l] !== val) return -(l + 1) + + return l +} diff --git a/2763-sum-of-imbalance-numbers-of-all-subarrays.js b/2763-sum-of-imbalance-numbers-of-all-subarrays.js new file mode 100644 index 00000000..6bc83cc3 --- /dev/null +++ b/2763-sum-of-imbalance-numbers-of-all-subarrays.js @@ -0,0 +1,72 @@ +class MultiSet { + constructor() { + this.countMap = new Map() + this.valueList = [] + } + remove(value) { + if(!this.countMap.has(value)) return false + let index = binarySearch(this.valueList, value) + if (this.countMap.get(value) === 1) { + this.valueList.splice(index, 1) + this.countMap.delete(value) + } else { + this.countMap.set(value, (this.countMap.get(value) || 0) - 1) + } + return true + } + add(value) { + let index = binarySearch(this.valueList, value) + if (index < 0) { + this.valueList.splice(-index - 1, 0, value) + this.countMap.set(value, 1) + } else { + this.countMap.set(value, this.countMap.get(value) + 1) + } + } + has(value) { + return this.countMap.has(value) + } + get max() { + return this.valueList[this.valueList.length - 1] + } + get min() { + return this.valueList[0] + } +} + +function binarySearch(arr, val) { + let l = 0, r = arr.length + while( l < r ) { + const mid = Math.floor((l + r) / 2) + if(arr[mid] < val) { + l = mid + 1 + } else { + r = mid + } + } + if(arr[l] !== val) return -(l + 1) + + return l +} +/** + * @param {number[]} nums + * @return {number} + */ +const sumImbalanceNumbers = function (nums) { + let n = nums.length, res = 0; + for (let i = 0; i < n; i++) { + let tree = new MultiSet(), cnt = 0; + tree.add(nums[i]); + for (let j = i + 1; j < n; j++) { + let x = nums[j]; + if (!tree.has(x)) { + tree.add(x); + cnt++; + if (tree.has(x - 1)) cnt--; + if (tree.has(x + 1)) cnt--; + } + res += cnt; + } + } + return res; +} diff --git a/2764-is-array-a-preorder-of-some-binary-tree.js b/2764-is-array-a-preorder-of-some-binary-tree.js new file mode 100644 index 00000000..5054f1c8 --- /dev/null +++ b/2764-is-array-a-preorder-of-some-binary-tree.js @@ -0,0 +1,19 @@ +/** + * @param {number[][]} nodes + * @return {boolean} + */ +var isPreorder = function(nodes) { + const stack = []; + + for (const [curr, parent] of nodes) { + while (stack.length && stack[stack.length - 1] !== parent) { + stack.pop(); + } + if (!stack.length && parent !== -1) { + return false; + } + stack.push(curr); + } + + return true; +}; diff --git a/2768-number-of-black-blocks.js b/2768-number-of-black-blocks.js new file mode 100644 index 00000000..6f299cd7 --- /dev/null +++ b/2768-number-of-black-blocks.js @@ -0,0 +1,181 @@ +/** + * @param {number} m + * @param {number} n + * @param {number[][]} coordinates + * @return {number[]} + */ +var countBlackBlocks = function(m, n, coordinates) { + + const map = new Map(); + for (const [x, y] of coordinates) { + for(let i = x - 1; i <= x; i++) { + for(let j = y - 1; j <= y; j++) { + if(i >= 0 && j >= 0 && i < m - 1 && j < n - 1) { + const key = encode(i, j); + map.set(key, (map.get(key) || 0) + 1); + } + } + } + } + const res = Array(5).fill(0); + for (const count of map.values()) { + res[count]++; + } + + res[0] = (m - 1) * (n - 1) - res[1] - res[2] - res[3] - res[4]; + return res; + + function encode(x, y) { + return x * n + y; + } +}; + +// another + + +/** + * @param {number} m + * @param {number} n + * @param {number[][]} coordinates + * @return {number[]} + */ +const countBlackBlocks = function(m, n, coordinates) { + const hash = {} + const key = ([x, y]) => `${x},${y}` + for (const e of coordinates) { + const [x, y] = e + if(x === m - 1 && y === n - 1) { + if(hash[`${x - 1},${y - 1}`]==null) hash[`${x - 1},${y - 1}`] = 0 + hash[`${x - 1},${y - 1}`]++ + } else if(x === m - 1) { + if(hash[`${x - 1},${y - 1}`]==null) hash[`${x - 1},${y - 1}`] = 0 + if(hash[`${x - 1},${y}`]==null) hash[`${x - 1},${y}`] = 0 + hash[`${x - 1},${y}`]++ + hash[`${x - 1},${y - 1}`]++ + } else if(y === n - 1) { + if(hash[`${x - 1},${y - 1}`]==null) hash[`${x - 1},${y - 1}`] = 0 + if(hash[`${x},${y- 1}`]==null) hash[`${x},${y-1}`] = 0 + hash[`${x},${y-1}`]++ + hash[`${x-1},${y - 1}`]++ + } else { + if(hash[`${x - 1},${y - 1}`]==null) hash[`${x - 1},${y - 1}`] = 0 + if(hash[`${x},${y- 1}`]==null) hash[`${x},${y-1}`] = 0 + if(hash[`${x - 1},${y}`]==null) hash[`${x - 1},${y}`] = 0 + if(hash[`${x},${y}`]==null) hash[`${x},${y}`] = 0 + hash[`${x},${y}`]++ + hash[`${x},${y-1}`]++ + hash[`${x-1},${y}`]++ + hash[`${x-1},${y - 1}`]++ + } + } + // console.log(hash) + const res = Array(5).fill(0) + for(const [k, v] of Object.entries(hash)) { + const [x, y] = k.split(',').map(e => +e) + if(x >= 0 && y >= 0) res[v]++ + } + const sum = res.reduce((ac, e) => ac + e, 0) + res[0] = (m - 1) * (n - 1) - sum + return res +}; + +// another + +/** + * @param {number} m + * @param {number} n + * @param {number[][]} coordinates + * @return {number[]} + */ +const countBlackBlocks = function(m, n, coordinates) { + const block = {} + + for(const [i, j] of coordinates) { + helper(i, j) + } + + const arr = Array(5).fill(0) + for(const k in block) { + if(block.hasOwnProperty(k)) { + arr[block[k]]++ + } + } + arr[0] = (m - 1) * (n - 1) - arr.reduce((ac, e) => ac + e, 0) + return arr + + function helper(i, j) { + + if(i < m - 1 && j < n - 1) { + update(i, j) + if(i > 0) update(i - 1, j) + if(j > 0) update(i, j - 1) + if(i > 0 && j > 0) update(i - 1, j - 1) + } else if(i === m - 1 && j === n - 1) { + update(i - 1, j - 1) + } else if(i === m - 1) { + update(i - 1, j) + if(j > 0) update(i - 1, j - 1) + } else if(j === n - 1) { + update(i, j - 1) + if(i > 0) update(i - 1, j - 1) + } + + } + + function update(i, j, delta = 1) { + const key = `${i},${j}` + if(block[key] == null) block[key] = 0 + block[key]++ + } +}; + +// another + +/** + * @param {number} m + * @param {number} n + * @param {number[][]} coordinates + * @return {number[]} + */ +const countBlackBlocks = function (m, n, coordinates) { + let arr = new Array(5).fill(0) + arr[0] = (m - 1) * (n - 1) + let mat = {} + for (let [r, c] of coordinates) { + mat[r] ||= [] + mat[r][c] = true + } + for (let [r, c] of coordinates) { + for (let i = -1; i < 1; i++) { + for (let j = -1; j < 1; j++) { + let nextR = r + i + let nextC = c + j + if (nextR < 0 || nextC < 0 || (nextR >= m - 1) | (nextC >= n - 1)) + continue + let res = getRes(nextR, nextC, mat) + arr[res]++ + } + } + } + for (let i = 1; i < 5; i++) { + arr[i] = ~~(arr[i] / i) + } + let used = 0 + for (let i = 1; i < 5; i++) { + used += arr[i] + } + arr[0] -= used + return arr +} + +const getRes = (r, c, mat) => { + let res = 0 + for (let i = 0; i < 2; i++) { + for (let j = 0; j < 2; j++) { + let nextR = r + i + let nextC = c + j + if (mat[nextR]?.[nextC] === true) res++ + } + } + return res +} diff --git a/2769-find-the-maximum-achievable-number.js b/2769-find-the-maximum-achievable-number.js new file mode 100644 index 00000000..db0ac464 --- /dev/null +++ b/2769-find-the-maximum-achievable-number.js @@ -0,0 +1,8 @@ +/** + * @param {number} num + * @param {number} t + * @return {number} + */ +const theMaximumAchievableX = function(num, t) { + return 2 * t + num +}; diff --git a/277-find-the-celebrity.js b/277-find-the-celebrity.js new file mode 100644 index 00000000..c37e8bdd --- /dev/null +++ b/277-find-the-celebrity.js @@ -0,0 +1,79 @@ +/** + * Definition for knows() + * + * @param {integer} person a + * @param {integer} person b + * @return {boolean} whether a knows b + * knows = function(a, b) { + * ... + * }; + */ + +/** + * @param {function} knows() + * @return {function} + */ +const solution = function(knows) { + /** + * @param {integer} n Total people + * @return {integer} The celebrity + */ + return function(n) { + if (n < 1) return -1 + let celebrity = 0 + for (let i = 1; i < n; i++) { + if (knows(celebrity, i)) { + celebrity = i + } + } + for (let i = 0; i < celebrity; i++) { + if (knows(celebrity, i)) { + return -1 + } + } + for (let i = 0; i < n; i++) { + if (i != celebrity && !knows(i, celebrity)) { + return -1 + } + } + return celebrity + } +} + +// another + +/** + * Definition for knows() + * + * @param {integer} person a + * @param {integer} person b + * @return {boolean} whether a knows b + * knows = function(a, b) { + * ... + * }; + */ + +/** + * @param {function} knows() + * @return {function} + */ +const solution = function(knows) { + /** + * @param {integer} n Total people + * @return {integer} The celebrity + */ + return function(n) { + if (n < 1) return -1 + let candidate = 0 + for (let i = 1; i < n; i++) { + if (knows(candidate, i)) candidate = i + } + for (let i = 0; i < n; i++) { + if (i < candidate && (knows(candidate, i) || !knows(i, candidate))) + return -1 + if (i > candidate && !knows(i, candidate)) return -1 + } + return candidate + } +} + diff --git a/2770-maximum-number-of-jumps-to-reach-the-last-index.js b/2770-maximum-number-of-jumps-to-reach-the-last-index.js new file mode 100644 index 00000000..e1c26db5 --- /dev/null +++ b/2770-maximum-number-of-jumps-to-reach-the-last-index.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var maximumJumps = function(nums, target) { + const n = nums.length + const dp = Array(n).fill(-1) + dp[0] = 0 + for(let i = 0; i < n; i++) { + if(dp[i] === -1) continue + for(let j = i + 1; j < n; j++) { + if (nums[j] - nums[i] <= target && nums[j] - nums[i] >= -target) { + dp[j] = Math.max(dp[j], dp[i] + 1) + } + } + } + + return dp.at(-1) +}; + diff --git a/2771-longest-non-decreasing-subarray-from-two-arrays.js b/2771-longest-non-decreasing-subarray-from-two-arrays.js new file mode 100644 index 00000000..5435776a --- /dev/null +++ b/2771-longest-non-decreasing-subarray-from-two-arrays.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +var maxNonDecreasingLength = function(nums1, nums2) { + const n = nums1.length + let dp = Array(3).fill(1) + let ans = 1 + const { max } = Math + for(let i = 1; i < n; i++) { + const nextDp = Array(3).fill(1) + if (nums1[i] >= nums1[i - 1]) { + nextDp[1] = max(nextDp[1], dp[1] + 1) + } + if (nums1[i] >= nums2[i - 1]) { + nextDp[1] = max(nextDp[1], dp[2] + 1) + } + if (nums2[i] >= nums1[i - 1]) { + nextDp[2] = max(nextDp[2], dp[1] + 1) + } + if (nums2[i] >= nums2[i - 1]) { + nextDp[2] = max(nextDp[2], dp[2] + 1) + } + dp = nextDp + // console.log(dp, nextDp) + ans = max(ans, max(...dp)) + } + return ans +}; + diff --git a/2772-apply-operations-to-make-all-array-elements-equal-to-zero.js b/2772-apply-operations-to-make-all-array-elements-equal-to-zero.js new file mode 100644 index 00000000..bbc33d1e --- /dev/null +++ b/2772-apply-operations-to-make-all-array-elements-equal-to-zero.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {boolean} + */ +var checkArray = function(nums, k) { + let cur = 0 + let diff = Array(nums.length).fill(0) + const n = nums.length + for(let i = 0; i < n; i++) { + if (nums[i] != cur) { + diff[i] += nums[i] - cur + if( (i + k - 1) >= n ) return false + diff[i + k - 1] -= nums[i] - cur + } + if (nums[i] < cur) return false + cur += diff[i] + } + return true +}; diff --git a/2778-sum-of-squares-of-special-elements.js b/2778-sum-of-squares-of-special-elements.js new file mode 100644 index 00000000..621da5ef --- /dev/null +++ b/2778-sum-of-squares-of-special-elements.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var sumOfSquares = function(nums) { + const n = nums.length + let res = 0 + + for(let i = 1; i <= n; i++) { + if(n % i === 0) res += nums[i - 1] ** 2 + } + + return res +}; diff --git a/2779-maximum-beauty-of-an-array-after-applying-operation.js b/2779-maximum-beauty-of-an-array-after-applying-operation.js new file mode 100644 index 00000000..cd45bff2 --- /dev/null +++ b/2779-maximum-beauty-of-an-array-after-applying-operation.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var maximumBeauty = function(nums, k) { + nums.sort((a, b) => a - b) + let n = nums.length + let res = 0 + let l = 0, r = 0 + while( r < n) { + if (nums[l]+k >= nums[r]-k) { + if (r-l+1 > res) { + res = r - l + 1 + } + r++ + } else { + l++ + } + } + if (r-l > res) { + res = r - l + } + return res +}; diff --git a/2780-minimum-index-of-a-valid-split.js b/2780-minimum-index-of-a-valid-split.js new file mode 100644 index 00000000..99b54191 --- /dev/null +++ b/2780-minimum-index-of-a-valid-split.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minimumIndex = function(nums) { + let n = nums.length + if (n == 1) { + return -1 + } + let mp = {} + let mx = 0 + for (const num of nums) { + if(mp[num] == null) mp[num] = 0 + mp[num]++ + if (mp[num] > n/2) { + mx = num + } + } + let c = 0 + for (let i = 0; i < n-1; i++) { + let num = nums[i] + if (num == mx) { + c++ + } + if (c > (i+1)/2 && mp[mx]-c > (n-i-1)/2) { + return i + } + } + return -1 +}; diff --git a/2781-length-of-the-longest-valid-substring.js b/2781-length-of-the-longest-valid-substring.js new file mode 100644 index 00000000..d938a9be --- /dev/null +++ b/2781-length-of-the-longest-valid-substring.js @@ -0,0 +1,18 @@ +/** + * @param {string} word + * @param {string[]} forbidden + * @return {number} + */ +var longestValidSubstring = function(word, forbidden) { + let setF = new Set(forbidden) + let res = 0, left = 0 + for(let i = 0; i < word.length; i++) { + for(let j = Math.max(left, i - 10); j < i + 1; j++) { + if(setF.has(word.slice(j, i + 1))) { + left = j + 1 + } + } + res = Math.max(res, i - left + 1) + } + return res +}; diff --git a/2786-visit-array-positions-to-maximize-score.js b/2786-visit-array-positions-to-maximize-score.js new file mode 100644 index 00000000..33007b95 --- /dev/null +++ b/2786-visit-array-positions-to-maximize-score.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @param {number} x + * @return {number} + */ +const maxScore = function(nums, x) { + let even = nums[0] + (nums[0] % 2 ? -x : 0) + let odd = nums[0] + (nums[0] % 2 ? 0 : -x) + + const n = nums.length, { max } = Math + for(let i = 1; i < n; i++) { + const e = nums[i] + if(e % 2 === 1) { + odd = max(even - x, odd) + e + } else { + even = max(even, odd - x) + e + } + } + + return max(even, odd) +}; diff --git a/2787-ways-to-express-an-integer-as-sum-of-powers.js b/2787-ways-to-express-an-integer-as-sum-of-powers.js new file mode 100644 index 00000000..a6311cad --- /dev/null +++ b/2787-ways-to-express-an-integer-as-sum-of-powers.js @@ -0,0 +1,44 @@ +/** + * @param {number} n + * @param {number} x + * @return {number} + */ +const numberOfWays = function(n, x) { + const dp = Array(n + 1).fill(0) + dp[0] = 1 + const mod = 1e9 + 7 + for(let i = 1; i <= n; i++) { + const tmp = Math.pow(i, x) + for(let j = n; j >= tmp; j--) { + + dp[j] = (dp[j] + dp[j - tmp]) % mod + + } + } + + return dp[n] +}; + +// another + +/** + * @param {number} n + * @param {number} x + * @return {number} + */ +const numberOfWays = function(n, x) { + const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0)) + dp[0][0] = 1 + const mod = 1e9 + 7 + for(let i = 0; i <= n; i++) { + for(let j = 1; j <= n; j++) { + dp[i][j] = (dp[i][j] + dp[i][j - 1]) % mod + const tmp = Math.pow(j, x) + if(i >= tmp) { + dp[i][j] = (dp[i][j] + dp[i - tmp][j - 1]) % mod + } + } + } + + return dp[n][n] +}; diff --git a/279-perfect-squares.js b/279-perfect-squares.js index 23933ba9..6cdbbbdd 100644 --- a/279-perfect-squares.js +++ b/279-perfect-squares.js @@ -16,3 +16,65 @@ const numSquares = function(n) { } return dp[n] }; + +// another + +/** + * @param {number} n + * @return {number} + */ +const numSquares = function (n) { + if (n <= 0) return 0 + // cntPerfectSquares[i] = the least number of perfect square numbers + const cntPerfectSquares = [0] + // While cntPerfectSquares.length <= n, we need to incrementally + // calculate the next result until we get the result for n. + while (cntPerfectSquares.length <= n) { + const m = cntPerfectSquares.length + let cntSquares = Number.MAX_VALUE + for (let i = 1; i * i <= m; i++) { + cntSquares = Math.min(cntSquares, cntPerfectSquares[m - i * i] + 1) + } + cntPerfectSquares.push(cntSquares) + } + return cntPerfectSquares[n] +} + +// another + +/** + * @param {number} n + * @return {number} + */ +const numSquares = function (n) { + // Based on Lagrange's Four Square theorem, there + // are only 4 possible results: 1, 2, 3, 4. + // If n is a perfect square, return 1. + if (is_square(n)) { + return 1 + } + // The result is 4 if and only if n can be written in the + // form of 4^k*(8*m + 7). Please refer to + // Legendre's three-square theorem. + while ((n & 3) === 0) { + // n%4 == 0 + n >>= 2 + } + if ((n & 7) === 7) { + // n%8 == 7 + return 4 + } + // Check whether 2 is the result. + let sqrt_n = Math.sqrt(n) >> 0 + for (let i = 1; i <= sqrt_n; i++) { + if (is_square(n - i * i)) { + return 2 + } + } + return 3 + function is_square(n) { + const sqrt_n = Math.sqrt(n) >> 0 + return sqrt_n * sqrt_n == n + } +} + diff --git a/2791-count-paths-that-can-form-a-palindrome-in-a-tree.js b/2791-count-paths-that-can-form-a-palindrome-in-a-tree.js new file mode 100644 index 00000000..4cc7ad91 --- /dev/null +++ b/2791-count-paths-that-can-form-a-palindrome-in-a-tree.js @@ -0,0 +1,88 @@ +/** + * @param {number[]} parent + * @param {string} s + * @return {number} + */ +const countPalindromePaths = function (parent, s) { + const n = parent.length + const nxt = Array.from({ length: n }, () => Array()) + const cnt = {0:0} + for(let i = 1; i < n; i++) { + nxt[parent[i]].push([i, s[i]]) + } + let res = 0 + dfs(0, -1, 0) + return res + + function dfs(node, parent, state) { + if(cnt[state] != null) res += cnt[state] + for(let i = 0; i < 26; i++) { + const tmp = state ^ (1 << i) + if(cnt[tmp] != null) res += cnt[tmp] + } + if(cnt[state] == null) cnt[state] = 0 + cnt[state] += 1 + + for(const [next, ch] of (nxt[node] || [])) { + if(next === parent) continue + dfs(next, node, state ^ getMask(ch)) + } + + } + +} +function getMask(c) { + const a = 'a'.charCodeAt(0) + return 1 << (c.charCodeAt(0) - a) +} + + +// another + +/** + * @param {number[]} parent + * @param {string} s + * @return {number} + */ +const countPalindromePaths = function (parent, s) { + let n = parent.length + let dp = Array(n).fill(undefined) + dp[0] = 0 + + function getDp(x) { + if (dp[x] != undefined) return dp[x] + dp[x] = getDp(parent[x]) ^ getMask(s[x]) + return dp[x] + } + + for (let i = 1; i < n; i++) getDp(i) + dp.sort((a, b) => a - b) + let counter = {} + let res = 0 + + for (let i = 0; i <= n; i++) { + if (counter[dp[i]]) counter[dp[i]]++ + else { + counter[dp[i]] = 1 + + if (i) { + let temp = dp[i - 1] + let cntPrev = counter[temp] + let c = 0 + + while (temp) { + let b = temp & -temp + c += counter[dp[i - 1] ^ b] ?? 0 + temp ^= b + } + + res += c * cntPrev + (cntPrev * (cntPrev - 1)) / 2 + } + } + } + + return res +} +function getMask(c) { + return 1 << (c.charCodeAt() - 97) +} diff --git a/2798-number-of-employees-who-met-the-target.js b/2798-number-of-employees-who-met-the-target.js new file mode 100644 index 00000000..09b41092 --- /dev/null +++ b/2798-number-of-employees-who-met-the-target.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} hours + * @param {number} target + * @return {number} + */ +var numberOfEmployeesWhoMetTarget = function(hours, target) { + let res = 0 + for(const e of hours) { + if(e >= target) res++ + } + + return res +}; diff --git a/2799-count-complete-subarrays-in-an-array.js b/2799-count-complete-subarrays-in-an-array.js new file mode 100644 index 00000000..dd6d4307 --- /dev/null +++ b/2799-count-complete-subarrays-in-an-array.js @@ -0,0 +1,53 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const countCompleteSubarrays = function(nums) { + const set = new Set(nums) + const size = set.size + const hash = new Map() + + let res = 0, i = 0, j = 0 + const n = nums.length + + while(i < n) { + const e = nums[i] + hash.set(e, (hash.get(e) || 0) + 1) + while(j <= i && size === hash.size) { + const pre = nums[j] + hash.set(pre, hash.get(pre) - 1) + if(hash.get(pre) === 0) hash.delete(pre) + res += n - i + j++ + } + i++ + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const countCompleteSubarrays = function(nums) { + const set = new Set(nums) + const size = set.size + + let res = 0 + const n = nums.length + + for(let i = 0; i < n; i++) { + const s = new Set() + s.add(nums[i]) + for(let j = i; j < n; j++) { + s.add(nums[j]) + if(s.size === size) res++ + } + } + + return res + +}; diff --git a/28-implement-strStr().js b/28-implement-strStr().js index 6475ee3b..5bd5a760 100755 --- a/28-implement-strStr().js +++ b/28-implement-strStr().js @@ -1,3 +1,76 @@ +/** + * @param {string} haystack + * @param {string} needle + * @return {number} + */ +const strStr = function(haystack, needle) { + const m = haystack.length, n = needle.length + + const lps = process(needle) + for(let j = 0, i = 0; i < m; i++) { + while(j > 0 && haystack[i] !== needle[j]) { + j = lps[j - 1] + } + if(haystack[i] === needle[j]) { + j++ + if(j === n) { + return i - n + 1 + } + } + } + return -1 + + function process(s) { + const n = s.length + const lps = Array(n).fill(0) + for(let len = 0, i = 1; i < n; i++) { + while(len > 0 && s[i] !== s[len]) { + len = lps[len - 1] + } + if(s[i] === s[len]) { + len++ + lps[i] = len + } + } + + return lps + } +}; + +// another + +/** + * @param {string} haystack + * @param {string} needle + * @return {number} + */ +const strStr = function(a, b) { + if(b === '') return 0 + if(a.length < b.length) return -1 + if(a.length === b.length) return a === b ? 0 : -1 + const m = a.length, n = b.length + const fail = Array(n).fill(-1) + // DFA + for(let i = 1; i < n; i++) { + let j = fail[i - 1] + while(j !== -1 && b[j + 1] !== b[i]) { + j = fail[j] + } + if(b[j + 1] === b[i]) fail[i] = j + 1 + } + let pos = -1 + for(let i = 0; i < m; i++) { + while(pos !== -1 && a[i] !== b[pos + 1]) pos = fail[pos] + if(a[i] === b[pos + 1]) { + pos++ + if(pos === n - 1) return i - n + 1 + } + } + return -1 +}; + +// another + /** * @param {string} haystack * @param {string} needle diff --git a/280-wiggle-sort.js b/280-wiggle-sort.js new file mode 100644 index 00000000..754dc845 --- /dev/null +++ b/280-wiggle-sort.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +const wiggleSort = function(nums) { + for (let i = 1; i < nums.length; i++) { + let a = nums[i - 1] + if ((i % 2 === 1) === a > nums[i]) { + nums[i - 1] = nums[i] + nums[i] = a + } + } +} diff --git a/2800-shortest-string-that-contains-three-strings.js b/2800-shortest-string-that-contains-three-strings.js new file mode 100644 index 00000000..dd53a0b4 --- /dev/null +++ b/2800-shortest-string-that-contains-three-strings.js @@ -0,0 +1,23 @@ +const lexical_smallest_comp = (x, y) => x < y ? -1 : x > y ? 1 : 0; +const merge = (s, t) => { + if (s.indexOf(t) != -1) return s; + // concat based on suffix + for (let l = Math.min(s.length, t.length); l > 0; l--) { + if (s.slice(-l) == t.slice(0, l)) return s.slice(0, -l) + t; + } + return s + t; +}; +/** + * @param {string} a + * @param {string} b + * @param {string} c + * @return {string} + */ +const minimumString = (a, b, c) => { + let d = [merge(merge(a, b), c), merge(merge(a, c), b), merge(merge(b, a), c), merge(merge(b, c), a), merge(merge(c, a), b), merge(merge(c, b), a)]; + d.sort((x, y) => { + if (x.length != y.length) return x.length - y.length; + return lexical_smallest_comp(x, y); + }) + return d[0]; +}; diff --git a/2801-count-stepping-numbers-in-range.js b/2801-count-stepping-numbers-in-range.js new file mode 100644 index 00000000..17ea13df --- /dev/null +++ b/2801-count-stepping-numbers-in-range.js @@ -0,0 +1,173 @@ +/** + * @param {string} low + * @param {string} high + * @return {number} + */ +var countSteppingNumbers = function (low, high) { + const mod = 1000000007 + let init = () => new Array(101) + .fill(null) + .map(() => + new Array(2) + .fill(null) + .map(() => new Array(2).fill(null).map(() => new Array(11).fill(-1))), + ) +// console.log(dp) + const helper = (pos, tight, isZero, prevDigit, s) => { + if (pos === s.length) { + if (isZero) return 0 + return 1 + } + + if (dp[pos][tight][isZero][prevDigit + 1] !== -1) + return dp[pos][tight][isZero][prevDigit + 1] + + let res = 0 + let limit + + if (tight) limit = parseInt(s[pos]) + else limit = 9 + + for (let curDigit = 0; curDigit <= limit; curDigit++) { + let newTight = tight + if (tight && curDigit < limit) newTight = 0 + + let willBeZero = isZero + if (isZero && curDigit > 0) willBeZero = 0 + + if (isZero) { + res += helper(pos + 1, newTight, willBeZero, curDigit, s) + res %= mod + } else { + if (Math.abs(curDigit - prevDigit) === 1) { + res += helper(pos + 1, newTight, willBeZero, curDigit, s) + res %= mod + } + } + } + + dp[pos][tight][isZero][prevDigit + 1] = res + return res + } + let dp = init() + let l = helper(0, 1, 1, -1, low) + + dp = init() + let r = helper(0, 1, 1, -1, high) + + let res = r - l + res = (res + mod) % mod + + let add = true + for (let i = 1; i < low.length; i++) { + if (Math.abs(low[i] - low[i - 1]) !== 1) { + add = false + break + } + } + if (add) res++ + + res %= mod + return res +} + +// another + + +const minus_mod = (x, y, mod) => ((x - y) % mod + mod) % mod; +const mod = 1e9 + 7, ll = BigInt; +let memo; +const go = (s) => { + memo = new Map(); + return dfs(0, 0, true, false, s); +}; + +const dfs = (i, mask, isLimit, isNum, s) => { + let ke = i + " " + mask + " " + isLimit + " " + isNum; + if (memo.has(ke)) return memo.get(ke); + if (i == s.length) return isNum - '0'; + let res = 0; + if (!isNum) res = dfs(i + 1, mask, false, false, s); + let leading = isNum ? 0 : 1; + let up = isLimit ? s[i] - '0' : 9; + for (let digit = leading; digit <= up; digit++) { + if (!isNum || Math.abs(digit - mask) == 1) { + res += dfs(i + 1, digit, isLimit && digit == up, true, s); + } + } + res %= mod; + memo.set(ke, res); + return res; +}; +/** + * @param {string} low + * @param {string} high + * @return {number} + */ +const countSteppingNumbers = (low, high) => { + let x = go(high), y = go((ll(low) - 1n).toString()); + return minus_mod(x, y, mod); +}; + +// another + + +/** + * @param {string} low + * @param {string} high + * @return {number} + */ +const countSteppingNumbers = function(low, high) { + const mod = 1e9 + 7 + let res = 0 + res = (helper(high) - helper(low) + isSteppingNumber(low) + mod) % mod + + return res + + function helper(num) { + let res = 0 + const n = num.length + const memo = Array.from({ length: 2 }, () => Array.from({ length: 11 }, () => Array.from({ length: n + 1 }, () => -1))) + for (let len = 1; len < n; len++) { + for(let i = 1; i < 10; i++){ + res = (res + dfs(len - 1, i, false, num, memo)) % mod + } + } + const d = num[0] - '0' + for(let i = 1; i < d; i++){ + res = (res + dfs(n - 1, i, false, num, memo)) % mod + } + res = (res + dfs(n - 1, d, true, num, memo)) % mod + return res + } + function dfs(len, prev, isSame, num, memo) { + if(len === 0) return 1 + if(memo[+isSame][prev][len] !== -1) return memo[+isSame][prev][len] + let res = 0 + if(isSame){ + const d = num[num.length - len] - '0' + if(prev + 1 < d) res = (res + dfs(len - 1, prev + 1, false, num, memo)) % mod + else if(prev + 1 === d) res = (res + dfs(len - 1, prev + 1, true, num, memo)) % mod + if(prev - 1 >= 0 && prev - 1 < d) res = (res + dfs(len - 1, prev - 1, false, num, memo)) % mod + else if(prev - 1 === d) res = (res + dfs(len - 1, prev - 1, true, num, memo)) % mod + + + } else { + if(prev + 1 < 10) res = (res + dfs(len - 1, prev + 1, false, num, memo)) % mod + if(prev - 1 >= 0) res = (res + dfs(len - 1, prev - 1, false, num, memo)) % mod + } + + memo[+isSame][prev][len] = res + + return res + } + function isSteppingNumber(num){ + if(num.length === 1) return 1 + for(let i = 1; i < num.length; i++){ + if(Math.abs(num[i] - num[i - 1]) !== 1) return 0 + } + return 1 + } +}; + + diff --git a/2807-insert-greatest-common-divisors-in-linked-list.js b/2807-insert-greatest-common-divisors-in-linked-list.js new file mode 100644 index 00000000..9607c762 --- /dev/null +++ b/2807-insert-greatest-common-divisors-in-linked-list.js @@ -0,0 +1,32 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const insertGreatestCommonDivisors = function(head) { + const dummy = new ListNode() + + dummy.next = head + let cur = head + while(cur.next) { + const val = gcd(cur.val, cur.next.val) + const tmp = new ListNode(val) + const nxt = cur.next + cur.next = tmp + tmp.next = nxt + + cur = nxt + } + + return dummy.next + + function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) + } +}; diff --git a/2809-minimum-time-to-make-array-sum-at-most-x.js b/2809-minimum-time-to-make-array-sum-at-most-x.js new file mode 100644 index 00000000..f858ea98 --- /dev/null +++ b/2809-minimum-time-to-make-array-sum-at-most-x.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} x + * @return {number} + */ +const minimumTime = function (nums1, nums2, x) { + let n = nums1.length, + s1 = 0, + s2 = 0 + + let ids = Array(n) + for (let i = 0; i < n; i++) { + ids[i] = i + s1 += nums1[i] + s2 += nums2[i] + } + + ids.sort((i, j) => nums2[i] - nums2[j]) + + let f = new Array(n + 1).fill(0) + for (let i of ids) { + for (let j = n; j > 0; j--) { + f[j] = Math.max(f[j], f[j - 1] + nums1[i] + nums2[i] * j) + } + } + + for (let t = 0; t <= n; t++) { + if (s1 + s2 * t - f[t] <= x) { + return t + } + } + return -1 +} diff --git a/281-zigzag-iterator.js b/281-zigzag-iterator.js new file mode 100644 index 00000000..7d8ec1ce --- /dev/null +++ b/281-zigzag-iterator.js @@ -0,0 +1,142 @@ +/** + * @constructor + * @param {Integer[]} v1 + * @param {Integer[]} v1 + */ +const ZigzagIterator = function ZigzagIterator(v1, v2) { + this.collection = [] + if (v1 !== null && v1.length !== 0) { + this.collection.push(v1) + } + if (v2 !== null && v2.length !== 0) { + this.collection.push(v2) + } +} + +/** + * @this ZigzagIterator + * @returns {boolean} + */ +ZigzagIterator.prototype.hasNext = function hasNext() { + return this.collection.length > 0 +} + +/** + * @this ZigzagIterator + * @returns {integer} + */ +ZigzagIterator.prototype.next = function next() { + if (this.collection[0].length === 1) { + return this.collection.shift()[0] + } else { + let v = this.collection.shift() + this.collection.push(v) + return v.shift() + } +} + +/** + * Your ZigzagIterator will be called like this: + * var i = new ZigzagIterator(v1, v2), a = []; + * while (i.hasNext()) a.push(i.next()); + */ + +// another + +/** + * @constructor + * @param {Integer[]} v1 + * @param {Integer[]} v1 + */ +const ZigzagIterator = function ZigzagIterator(v1, v2) { + const A = [v1, v2] + this.A = A + this.n = A.length + this.m = Math.max(v1.length, v2.length) + this.j = 0 + this.i = 0 +} + +/** + * @this ZigzagIterator + * @returns {boolean} + */ +ZigzagIterator.prototype.hasNext = function hasNext() { + return this.j < this.m +} + +/** + * @this ZigzagIterator + * @returns {integer} + */ +ZigzagIterator.prototype.incrementPointers = function incrementPointers() { + this.i += 1 + if (this.i === this.n) { + this.j += 1 + this.i = 0 + } +} + +ZigzagIterator.prototype.next = function next() { + let next = undefined + while (next === undefined) { + next = this.A[this.i][this.j] + this.incrementPointers() + } + while (this.hasNext()) { + if (this.A[this.i][this.j] !== undefined) break + this.incrementPointers() + } + return next +} + +/** + * Your ZigzagIterator will be called like this: + * var i = new ZigzagIterator(v1, v2), a = []; + * while (i.hasNext()) a.push(i.next()); + */ + +// another + +/** + * @constructor + * @param {Integer[]} v1 + * @param {Integer[]} v1 + */ +const ZigzagIterator = function ZigzagIterator(v1, v2) { + this.queue = [] + if (v1.length > 0) { + const it = v1[Symbol.iterator]() + const res = it.next() + this.queue.push({ it, res }) + } + if (v2.length > 0) { + const it = v2[Symbol.iterator]() + const res = it.next() + this.queue.push({ it, res }) + } +} +/** + * @this ZigzagIterator + * @returns {boolean} + */ +ZigzagIterator.prototype.hasNext = function hasNext() { + return this.queue.length > 0 +} +/** + * @this ZigzagIterator + * @returns {integer} + */ +ZigzagIterator.prototype.next = function next() { + const { it, res } = this.queue.shift() + const { value } = res + const res1 = it.next() + if (!res1.done) this.queue.push({ it, res: res1 }) + return value +} +/** + * Your ZigzagIterator will be called like this: + * var i = new ZigzagIterator(v1, v2), a = []; + * while (i.hasNext()) a.push(i.next()); + */ + diff --git a/2810-faulty-keyboard.js b/2810-faulty-keyboard.js new file mode 100644 index 00000000..1eb78b4f --- /dev/null +++ b/2810-faulty-keyboard.js @@ -0,0 +1,16 @@ +/** + * @param {string} s + * @return {string} + */ +const finalString = function(s) { + const arr = [] + for(const ch of s) { + if(ch === 'i') { + arr.reverse() + } else { + arr.push(ch) + } + } + + return arr.join('') +}; diff --git a/2811-check-if-it-is-possible-to-split-array.js b/2811-check-if-it-is-possible-to-split-array.js new file mode 100644 index 00000000..bb135222 --- /dev/null +++ b/2811-check-if-it-is-possible-to-split-array.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @param {number} m + * @return {boolean} + */ +const canSplitArray = function(nums, m) { + const n = nums.length + if(n <= 2) return true + for(let i = 1; i < n; i++) { + if(nums[i] + nums[i - 1] >= m) return true + } + return false +}; diff --git a/2812-find-the-safest-path-in-a-grid.js b/2812-find-the-safest-path-in-a-grid.js new file mode 100644 index 00000000..73b62e49 --- /dev/null +++ b/2812-find-the-safest-path-in-a-grid.js @@ -0,0 +1,62 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const maximumSafenessFactor = function (grid) { + const n = grid.length; + const isInBound = (r, c) => r >= 0 && r < n && c >= 0 && c < n; + const dist = new Array(n).fill(0).map(() => new Array(n).fill(Infinity)); + const queue = []; + + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + if (grid[r][c] === 1) { + dist[r][c] = 0; + queue.push([r, c]); + } + } + } + + while (queue.length) { + const [r, c] = queue.shift(); + const neighbors = [ + [r + 1, c], + [r - 1, c], + [r, c + 1], + [r, c - 1], + ]; + + for (const [nr, nc] of neighbors) { + if (isInBound(nr, nc) && dist[nr][nc] === Infinity) { + dist[nr][nc] = dist[r][c] + 1; + queue.push([nr, nc]); + } + } + } + + const maxDistance = new Array(n).fill(0).map(() => new Array(n).fill(0)); + maxDistance[0][0] = dist[0][0]; + queue.push([0, 0]); + + while (queue.length) { + const [r, c] = queue.shift(); + const neighbors = [ + [r + 1, c], + [r - 1, c], + [r, c + 1], + [r, c - 1], + ]; + + for (const [nr, nc] of neighbors) { + if (isInBound(nr, nc)) { + const newDistance = Math.min(maxDistance[r][c], dist[nr][nc]); + if (newDistance > maxDistance[nr][nc]) { + maxDistance[nr][nc] = newDistance; + queue.push([nr, nc]); + } + } + } + } + + return maxDistance[n - 1][n - 1]; +} diff --git a/2813-maximum-elegance-of-a-k-length-subsequence.js b/2813-maximum-elegance-of-a-k-length-subsequence.js new file mode 100644 index 00000000..844e63f9 --- /dev/null +++ b/2813-maximum-elegance-of-a-k-length-subsequence.js @@ -0,0 +1,39 @@ +/** + * @param {number[][]} items + * @param {number} k + * @return {number} + */ +const findMaximumElegance = function (items, k) { + let v = items + let n = v.length + const { max } = Math + v.sort((a, b) => b[0] - a[0]) //sort according to profit + let ans = 0 + let m = {} + for (let i = 0; i < k; i++) { + ans += v[i][0] + if (m[v[i][1]] == null) m[v[i][1]] = 0 + m[v[i][1]]++ + } + let sz = Object.keys(m).length + ans += sz * sz + let res = ans + let j = k - 1 + for (let i = k; i < n; i++) { + if (m[v[i][1]] == 0 || m[v[i][1]] == null) { + //try to increase unique elements + while (j >= 0 && m[v[j][1]] < 2) j-- //finding smallest number in 0 to k-1 whose frequency is more than 1, and removing it to increasing uniquenes of the subsequence + if (j < 0) break //no number found that has frequency more than two + m[v[j][1]]-- + m[v[i][1]]++ + res -= v[j][0] + res += v[i][0] + res -= sz * sz + sz++ + res += sz * sz + j-- + ans = max(ans, res) //keep taking max + } + } + return max(ans, res) +} diff --git a/2815-max-pair-sum-in-an-array.js b/2815-max-pair-sum-in-an-array.js new file mode 100644 index 00000000..703a8456 --- /dev/null +++ b/2815-max-pair-sum-in-an-array.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maxSum = function(nums) { + let res = -1 + const n = nums.length + + for(let i = 0; i < n - 1; i++) { + const arr = `${nums[i]}`.split('') + arr.sort((a, b) => b - a) + for(let j = 1; j < n; j++) { + if(i === j) continue + const ar = `${nums[j]}`.split('') + ar.sort((a, b) => b - a) + if(arr[0] === ar[0]) { + res = Math.max(res, nums[i] + nums[j]) + } + } + } + + return res +}; diff --git a/2816-double-a-number-represented-as-a-linked-list.js b/2816-double-a-number-represented-as-a-linked-list.js new file mode 100644 index 00000000..62407097 --- /dev/null +++ b/2816-double-a-number-represented-as-a-linked-list.js @@ -0,0 +1,38 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +var doubleIt = function(head) { + const res = dfs(head) + if(res.val > 9) { + const dummy = new ListNode(1) + dummy.next = res + res.val = res.val % 10 + return dummy + } else return res + + function dfs(node) { + if(node == null) return + const nxt = dfs(node.next) + let val = node.val * 2 + if(nxt && nxt.val > 9) { + val++ + nxt.val = nxt.val % 10 + node.val = val + return node + } else { + node.val = val + return node + } + + } + + +}; diff --git a/2817-minimum-absolute-difference-between-elements-with-constraint.js b/2817-minimum-absolute-difference-between-elements-with-constraint.js new file mode 100644 index 00000000..68f63926 --- /dev/null +++ b/2817-minimum-absolute-difference-between-elements-with-constraint.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @param {number} x + * @return {number} + */ +var minAbsoluteDifference = function(nums, x) { + const {abs, min, max, floor} = Math + + let res = Infinity + let n = nums.length + for(let i = 0; i < n; i++) { + if( i + x <= n - 1) { + let j = n - 1 - i - x + // abs_var.push() + res = min(res, abs(nums[i] - nums[i + x])) + let g = 1 + while (j > 0) { + // abs_var.push() + res = min(res, abs(nums[i] - nums[i + x + g])) + g += 1 + j -= 1 + } + } + + } + return res +}; diff --git a/2818-apply-operations-to-maximize-score.js b/2818-apply-operations-to-maximize-score.js new file mode 100644 index 00000000..e48f7311 --- /dev/null +++ b/2818-apply-operations-to-maximize-score.js @@ -0,0 +1,105 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var maximumScore = function (nums, k) { + const n = nums.length + const factors = Array(n).fill(0) // To store prime factors count for each number + const count = Array(n).fill(0) // To store the count of reachable elements for each element + + // Calculate prime factors count for each number + for (let i = 0; i < n; i++) { + factors[i] = primeFactors(nums[i]) + } + + const stack = [-1] // Monotonic stack to keep track of elements in decreasing order of factors + let curr = 0 + + // Calculate the count of reachable elements for each element + for (let i = 0; i < n; i++) { + while ( + stack[stack.length - 1] !== -1 && + factors[stack[stack.length - 1]] < factors[i] + ) { + curr = stack.pop() + count[curr] = (curr - stack[stack.length - 1]) * (i - curr) + } + stack.push(i) + } + + // Process any remaining elements in the stack + while (stack[stack.length - 1] !== -1) { + curr = stack.pop() + count[curr] = (curr - stack[stack.length - 1]) * (n - curr) + } + + // Create an array of pairs containing elements and their corresponding reachable count + const pairs = Array(n) + for (let i = 0; i < n; i++) { + pairs[i] = [nums[i], count[i]] + } + + // Sort the pairs in descending order of elements + pairs.sort((a, b) => b[0] - a[0]) + + let res = BigInt(1) + const mod = BigInt(1e9 + 7) + + // Calculate the maximum score using modPow and available moves + for (let i = 0; i < pairs.length && k > 0; i++) { + const curr = Math.min(pairs[i][1], k) + res = (res * modPow(BigInt(pairs[i][0]), BigInt(curr), mod)) % mod + k -= curr + } + + return Number(res) // Convert the result to a regular number before returning +} + +/** + * Function to calculate modular exponentiation. + * @param {bigint} x - Base. + * @param {bigint} y - Exponent. + * @param {bigint} m - Modulus. + * @return {bigint} - Result of modular exponentiation. + */ +function modPow(x, y, m) { + if (y === 0n) { + return 1n + } + let p = modPow(x, y / 2n, m) % m + p = (p * p) % m + if (y % 2n === 0n) { + return p + } + return (p * x) % m +} + +/** + * Function to calculate the count of prime factors for a number. + * @param {number} num - Input number. + * @return {number} - Count of prime factors for the input number. + */ +function primeFactors(num) { + let count = 0 + let factor = 2 + const end = Math.sqrt(num) + + while (num > 1 && factor <= end) { + let inc = false + while (num % factor === 0) { + if (!inc) { + count++ + inc = true + } + num /= factor + } + factor++ + } + + if (num > 1) { + count++ + } + + return count +} diff --git a/282-expression-add-operators.js b/282-expression-add-operators.js new file mode 100644 index 00000000..e6c1cc2a --- /dev/null +++ b/282-expression-add-operators.js @@ -0,0 +1,27 @@ +/** + * @param {string} num + * @param {number} target + * @return {string[]} + */ +const addOperators = function(num, target) { + let res = []; + let n = num.length; + function recursive(k, str, add, mul, last) { + let sum = add + mul * last; + if (k === n) { + if (sum === target) { + res.push(str); + } + return; + } + let x = num[k] - "0"; + if (last !== 0) { + recursive(k + 1, str + num[k], add, mul, last * 10 + x); + } + recursive(k + 1, str + "*" + num[k], add, mul * last, x); + recursive(k + 1, str + "+" + num[k], sum, 1, x); + recursive(k + 1, str + "-" + num[k], sum, -1, x); + } + if (n) recursive(1, num[0], 0, 1, num[0] - "0"); + return res; +}; diff --git a/2826-sorting-three-groups.js b/2826-sorting-three-groups.js new file mode 100644 index 00000000..bab1b9b1 --- /dev/null +++ b/2826-sorting-three-groups.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumOperations = function(nums) { + const n = nums.length, { min } = Math + const dp = Array.from({ length: n + 1 }, () => Array(3 + 1).fill(0)) + + for(let i = 1; i <= n; i++) { + const e = nums[i - 1] + dp[i][1] = dp[i - 1][1] + (e === 1 ? 0 : 1) + dp[i][2] = min(dp[i - 1][1], dp[i - 1][2]) + (e === 2 ? 0 : 1) + dp[i][3] = min(dp[i - 1][1], dp[i - 1][2], dp[i - 1][3]) + (e === 3 ? 0 : 1) + } + return min(dp[n][1], dp[n][2], dp[n][3]) +}; diff --git a/2827-number-of-beautiful-integers-in-the-range.js b/2827-number-of-beautiful-integers-in-the-range.js new file mode 100644 index 00000000..1d2b4390 --- /dev/null +++ b/2827-number-of-beautiful-integers-in-the-range.js @@ -0,0 +1,54 @@ +/** + * @param {number} low + * @param {number} high + * @param {number} k + * @return {number} + */ +const numberOfBeautifulIntegers = function (low, high, k) { + const memo = new Map(); + + function dp(index, diff, isLimit, isZero, numStr, m) { + if (index === numStr.length) { + return Number(isZero) & (diff === 0) & (m === 0); + } + + const memoKey = `${index}-${diff}-${isLimit ? 1 : 0}-${isZero ? 1 : 0}-${numStr}-${m}`; + if (memo.has(memoKey)) { + return memo.get(memoKey); + } + + let res = 0; + if (!isZero) { + res = dp(index + 1, diff, false, false, numStr, m); + } + const bound = isLimit ? parseInt(numStr[index]) : 9; + + for (let d = 1 - Number(isZero); d <= bound; d++) { + if (d % 2 === 1) { + res += dp( + index + 1, + diff + 1, + isLimit && d === bound, + true, + numStr, + (m + d * Math.pow(10, numStr.length - index - 1)) % k + ); + } else { + res += dp( + index + 1, + diff - 1, + isLimit && d === bound, + true, + numStr, + (m + d * Math.pow(10, numStr.length - index - 1)) % k + ); + } + } + + memo.set(memoKey, res); + return res; + } + + return dp(0, 0, true, false, String(high), 0) - dp(0, 0, true, false, String(low - 1), 0); +} + diff --git a/2828-check-if-a-string-is-an-acronym-of-words.js b/2828-check-if-a-string-is-an-acronym-of-words.js new file mode 100644 index 00000000..5951071d --- /dev/null +++ b/2828-check-if-a-string-is-an-acronym-of-words.js @@ -0,0 +1,10 @@ +/** + * @param {string[]} words + * @param {string} s + * @return {boolean} + */ +const isAcronym = function(words, s) { + let str = '' + for(const e of words) str = str + e[0] + return s === str +}; diff --git a/2829-determine-the-minimum-sum-of-a-k-avoiding-array.js b/2829-determine-the-minimum-sum-of-a-k-avoiding-array.js new file mode 100644 index 00000000..8bf5b7c1 --- /dev/null +++ b/2829-determine-the-minimum-sum-of-a-k-avoiding-array.js @@ -0,0 +1,17 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const minimumSum = function(n, k) { + let res = 0 + const set = new Set() + for(let i = 1; set.size < n; i++) { + if(!set.has(k - i)) { + set.add(i) + res += i + } + } + + return res +}; diff --git a/2830-maximize-the-profit-as-the-salesman.js b/2830-maximize-the-profit-as-the-salesman.js new file mode 100644 index 00000000..d54b6eeb --- /dev/null +++ b/2830-maximize-the-profit-as-the-salesman.js @@ -0,0 +1,20 @@ +/** + * @param {number} n + * @param {number[][]} offers + * @return {number} + */ +const maximizeTheProfit = function(n, offers) { + const dp = Array(n + 1).fill(0); + const m = []; + for (const a of offers) { + if(m[a[1]] == null) m[a[1]] = [] + m[a[1]].push(a); + } + for (let e = 1; e <= n; e++) { + dp[e] = dp[e - 1]; + for (let a of (m[e - 1] || []) ) { + dp[e] = Math.max(dp[e], dp[a[0]] + a[2]); + } + } + return dp[n]; +}; diff --git a/2831-find-the-longest-equal-subarray.js b/2831-find-the-longest-equal-subarray.js new file mode 100644 index 00000000..db23ba03 --- /dev/null +++ b/2831-find-the-longest-equal-subarray.js @@ -0,0 +1,46 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const longestEqualSubarray = function(nums, k) { + let maxf = 0, i = 0, n = nums.length; + let count = {}; + for (let j = 0; j < n; j++) { + if(count[nums[j]] == null) count[nums[j]] = 0 + maxf = Math.max(maxf, ++count[nums[j]]); + if (j - i + 1 - maxf > k) { + if(count[nums[i]] == null) count[nums[i]] = 0 + --count[nums[i++]]; + } + + } + return maxf; +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const longestEqualSubarray = function(nums, k) { + const n = nums.length, cnt = {} + let i = 0, res = 0 + for(let j = 0; j < n; j++) { + const e = nums[j] + if(cnt[e] == null) cnt[e] = 0 + cnt[e]++ + res = Math.max(res, cnt[e]) + + if(j - i + 1 - res > k) { + const pre = nums[i] + if(cnt[pre] == null) cnt[pre] = 0 + cnt[pre]-- + i++ + } + } + + return res +}; diff --git a/2833-furthest-point-from-origin.js b/2833-furthest-point-from-origin.js new file mode 100644 index 00000000..b7a34e64 --- /dev/null +++ b/2833-furthest-point-from-origin.js @@ -0,0 +1,14 @@ +/** + * @param {string} moves + * @return {number} + */ +var furthestDistanceFromOrigin = function(moves) { + let u = 0 + let val = 0 + for(const e of moves) { + if(e === '_') u++ + else if(e === 'L') val-- + else if(e === 'R') val++ + } + return Math.abs(val) + u +}; diff --git a/2835-minimum-operations-to-form-subsequence-with-target-sum.js b/2835-minimum-operations-to-form-subsequence-with-target-sum.js new file mode 100644 index 00000000..399aefd2 --- /dev/null +++ b/2835-minimum-operations-to-form-subsequence-with-target-sum.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var minOperations = function(nums, target) { + const n = nums.length, arr = Array(31).fill(0); + let sum = 0; + + for(const x of nums) ++arr[Math.log2(x)], sum += x; + if(sum < target) return -1; + + let i=0, res = 0; + while(i < 31) { + if(1< { + let s = x.toString(2), + n = s.length + for (let j = 0; j < n; j++) { + if (n - j - 1 == i && s[j] == '1') return 1 + } + return 0 +} + +/** + * @param {number[]} receiver + * @param {number} k + * @return {number} + */ +var getMaxFunctionValue = function(receiver, k) { + const a = receiver + let n = a.length, + ia = [], + res = [], + iaP = [...a], + resP = [...a] + for (let i = 0; i < n; i++) { + ia.push(i) + res.push(i) + } + for (let i = 0; i < N; i++) { + if (checkIthBit64(k, i)) { + ;[res, ia] = update(res, resP, ia, iaP) + } + resP = updateResP(res, resP, iaP) + iaP = updateIaP(iaP) + } + return Math.max(...res) +}; + +const update = (cur, curP, ia, iaP) => { + let n = cur.length, + nextRes = [], + nextPos = [] + for (let i = 0; i < n; i++) { + nextRes.push(cur[i] + curP[ia[i]]) + nextPos.push(ia[iaP[i]]) + } + return [nextRes, nextPos] +} + +const updateResP = (cur, curP, iaP) => { + let n = cur.length, + next = [] + for (let i = 0; i < n; i++) next.push(curP[i] + curP[iaP[i]]) + return next +} + +const updateIaP = (iaP) => { + let n = iaP.length, + next = [] + for (let i = 0; i < n; i++) next.push(iaP[iaP[i]]) + return next +} diff --git a/2842-count-k-subsequences-of-a-string-with-maximum-beauty.js b/2842-count-k-subsequences-of-a-string-with-maximum-beauty.js new file mode 100644 index 00000000..06ec3d6f --- /dev/null +++ b/2842-count-k-subsequences-of-a-string-with-maximum-beauty.js @@ -0,0 +1,51 @@ +////////////////////////////// combination Template ////////////////////////////////// +const ll = BigInt, + mod = ll(1e9 + 7) +let N + +let fact, ifact, inv +const comb_init = () => { + ;(fact = Array(N)), (ifact = Array(N)), (inv = Array(N)) + fact[0] = ifact[0] = inv[1] = 1n + for (let i = 2; i < N; i++) + inv[i] = ((mod - mod / ll(i)) * inv[mod % ll(i)]) % mod + for (let i = 1; i < N; i++) { + fact[i] = (fact[i - 1] * ll(i)) % mod + ifact[i] = (ifact[i - 1] * inv[i]) % mod + } +} + +const comb = (n, k) => { + if (n < k || k < 0) return 0n + return (((fact[n] * ifact[k]) % mod) * ifact[n - k]) % mod +} +////////////////////////////////////////////////////////////////////// + +const ord = (c) => c.charCodeAt() + +const M = 1e9 + 7 +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const countKSubsequencesWithMaxBeauty = (s, k) => { + N = s.length + 1 + comb_init() + let f = Array(26).fill(0), + res = 1, + pick = 0 + for (const c of s) f[ord(c) - 97]++ + f = f.sort((x, y) => y - x).filter((x) => x > 0) + for (let i = 0; i < k; i++) { + if (f[i] >= f[k - 1]) { + // ways of first k-1 elements + res *= f[i] + res %= M + } + if (f[i] == f[k - 1]) pick++ // count last element needed + } + let lastPick = comb(f.filter((x) => x == f[k - 1]).length, pick) // ways of last element pick up + res = (ll(res) * lastPick) % mod + return res +} diff --git a/2845-count-of-interesting-subarrays.js b/2845-count-of-interesting-subarrays.js new file mode 100644 index 00000000..e1cac0b4 --- /dev/null +++ b/2845-count-of-interesting-subarrays.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums + * @param {number} modulo + * @param {number} k + * @return {number} + */ +const countInterestingSubarrays = function (nums, modulo, k) { + const n = nums.length + const map = new Map() + let res = 0 + map.set(0, 1) + for (let i = 0, cnt = 0; i < n; i++) { + const cur = nums[i] + if (cur % modulo === k) { + cnt++ + } + const key = cnt % modulo + /* + if(key >= k) res += map.get(key - k) || 0 + else res += map.get(modulo - (k - key)) || 0 + */ + res += map.get((modulo + key - k) % modulo) || 0 + + map.set(key, (map.get(key) || 0) + 1) + } + + return res +} diff --git a/2846-minimum-edge-weight-equilibrium-queries-in-a-tree.js b/2846-minimum-edge-weight-equilibrium-queries-in-a-tree.js new file mode 100644 index 00000000..113349f5 --- /dev/null +++ b/2846-minimum-edge-weight-equilibrium-queries-in-a-tree.js @@ -0,0 +1,120 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[][]} queries + * @return {number[]} + */ +const minOperationsQueries = function (n, edges, queries) { + let [directParents, counts, depths] = getParentsAndPrefixCounts(n, edges) + let lcaModule = new LCA(n, directParents, depths) + let ans = [] + for (let [a, b] of queries) { + let lca = lcaModule.getLCA(a, b) + let countsA = diffCounts(counts[a], counts[lca]), + countsB = diffCounts(counts[b], counts[lca]) + let totalCounts = addCounts(countsA, countsB) + let edgesInPath = depths[a] - depths[lca] + depths[b] - depths[lca] + let maxCount = 0 + for (let i = 1; i <= 26; i++) { + maxCount = Math.max(maxCount, totalCounts[i]) + } + ans.push(edgesInPath - maxCount) // turn all other non-majority weights into the weight with the most occurances + } + return ans +} + +function addCounts(countsA, countsB) { + let total = Array(27) + for (let i = 1; i <= 26; i++) { + total[i] = countsA[i] + countsB[i] + } + return total +} + +function diffCounts(countsA, countsLCA) { + let diff = Array(27) + for (let i = 1; i <= 26; i++) { + diff[i] = countsA[i] - countsLCA[i] + } + return diff +} + +function getParentsAndPrefixCounts(n, edges) { + let directParents = Array(n).fill(-1) + let graph = Array(n) + .fill(0) + .map(() => []) + let prefixCounts = Array(n) + for (let [u, v, w] of edges) { + graph[u].push([v, w]) + graph[v].push([u, w]) + } + let seen = Array(n).fill(false) + seen[0] = true + let queue = [[0, Array(27).fill(0), 0]] + let depths = Array(n) + while (queue.length) { + let [node, count, depth] = queue.shift() + prefixCounts[node] = count + depths[node] = depth + + for (let [nei, weight] of graph[node]) { + if (seen[nei]) continue + let newCount = [...count] + newCount[weight]++ + seen[nei] = true + queue.push([nei, newCount, depth + 1]) + directParents[nei] = node + } + } + return [directParents, prefixCounts, depths] +} + +class LCA { + constructor(n, directParents, depths) { + this.maxDepth = Math.ceil(Math.log2(n)) + this.p = Array(this.maxDepth + 1) + .fill(0) + .map(() => Array(n).fill(-1)) + this.depths = depths + + // precomputation for binary lifting + for (let node = 0; node < n; node++) { + this.p[0][node] = directParents[node] + } + for (let pow2 = 1; pow2 <= this.maxDepth; pow2++) { + for (let node = 0; node < n; node++) { + let halfParent = this.p[pow2 - 1][node] + this.p[pow2][node] = + halfParent === -1 ? -1 : this.p[pow2 - 1][halfParent] + } + } + } + getLCA(a, b) { + if (this.depths[a] > this.depths[b]) { + let temp = a + a = b + b = temp + } + + // bring both nodes up to the same depth + let depthDiff = this.depths[b] - this.depths[a] + for (let i = 0; i <= this.maxDepth; i++) { + if ((depthDiff >> i) & 1) { + b = this.p[i][b] // move b up to the 2^ith parent + } + } + if (a === b) return a + + // move both nodes up by 2^ith levels if the 2^ith parents are not equal + for (let i = this.maxDepth; i >= 0; i--) { + // this decrements so that we can jump the nodes up incrementally + if (this.p[i][a] !== this.p[i][b]) { + // if 2^ith parents of both nodes are not equal, we can safely both move up + a = this.p[i][a] + b = this.p[i][b] + } + } + return this.p[0][a] + } +} diff --git a/285-inorder-successor-in-bst.js b/285-inorder-successor-in-bst.js new file mode 100644 index 00000000..71cf8ef9 --- /dev/null +++ b/285-inorder-successor-in-bst.js @@ -0,0 +1,63 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @return {TreeNode} + */ +const inorderSuccessor = function(root, p) { + const res = { node: null } + dfs(root, [], res, p) + return res.node +}; + +function dfs(node, arr, res, target) { + if(node === null) return + dfs(node.left, arr, res, target) + if(arr.length && arr[arr.length - 1] === target) res.node = node + arr.push(node) + dfs(node.right, arr, res, target) +} + +// another + +const inorderSuccessor = function(root, p) { + let last = null + const chk = node => { + if(!node) return + const l = chk(node.left) + if(l !== undefined) return l + if(last === p) return node + last = node + return chk(node.right) + } + return chk(root) +}; + +// another + +const inorderSuccessor = function(root, p) { + while (root != null && root.val <= p.val) root = root.right + const left = root == null ? null : inorderSuccessor(root.left, p) + return left != null && left.val > p.val ? left : root +} + +// another + +const inorderSuccessor = function(root, p) { + let succ = null + while(root) { + if (p.val < root.val) { + succ = root + root = root.left + } else { + root = root.right + } + } + return succ +} diff --git a/2850-minimum-moves-to-spread-stones-over-grid.js b/2850-minimum-moves-to-spread-stones-over-grid.js new file mode 100644 index 00000000..8e6a6086 --- /dev/null +++ b/2850-minimum-moves-to-spread-stones-over-grid.js @@ -0,0 +1,39 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var minimumMoves = function (grid) { + let zeros = [] + let extras = [] + let ans = 0 + for (let r = 0; r < 3; ++r) { + for (let c = 0; c < 3; ++c) { + if (grid[r][c] > 1) { + extras.push([r, c, grid[r][c]]) + } else if (grid[r][c] == 0) { + zeros.push([r, c]) + } + } + } + function solve(index) { + if (index >= zeros.length) { + return 0 + } + let min = Number.MAX_SAFE_INTEGER + let [r, c] = zeros[index] + for (let j = 0; j < extras.length; ++j) { + if (extras[j][2] > 1) { + extras[j][2] -= 1 + min = Math.min( + min, + Math.abs(extras[j][0] - r) + + Math.abs(extras[j][1] - c) + + solve(index + 1), + ) + extras[j][2] += 1 + } + } + return min + } + return solve(0) +} diff --git a/2851-string-transformation.js b/2851-string-transformation.js new file mode 100644 index 00000000..84013a0f --- /dev/null +++ b/2851-string-transformation.js @@ -0,0 +1,270 @@ +/** + * @param {string} s + * @param {string} t + * @param {number} k + * @return {number} + */ +const numberOfWays = function (s, t, k) { + const n = s.length, + M = 1e9 + 7 + const pos = kmp(s + s.slice(0, n-1), t) + const fk = [0, 0] + calcFK() + + let res = 0 + for (let p of pos) { + if (p === 0) res = (res + fk[0]) % M + else res = (res + fk[1]) % M + } + return res + + function kmp(s, t) { + const m = s.length, + n = t.length + const pi = new Array(n).fill(0) + for (let i = 1; i < n; ++i) { + let j = pi[i - 1] + while (j > 0 && t.charAt(j) !== t.charAt(i)) j = pi[j - 1] + if (j === 0 && t.charAt(0) !== t.charAt(i)) pi[i] = 0 + else pi[i] = j + 1 + } + let j = 0 + const res = [] + for (let i = 0; i < m; ++i) { + while (j >= n || (j > 0 && s.charAt(i) !== t.charAt(j))) j = pi[j - 1] + if (s.charAt(i) === t.charAt(j)) j++ + if (j === n) res.push(i - n + 1) + } + return res + } + + function calcFK() { + fk[1] = + (((powWrap(n - 1, k, M) + BigInt(((k % 2) * 2 - 1)) + BigInt(M)) % BigInt(M)) * powWrap(n, M - 2, M)) % BigInt(M) + fk[0] = (fk[1] - BigInt(((k % 2) * 2 - 1)) + BigInt(M)) % BigInt(M) + // console.log(fk) + fk[1] = Number(fk[1]) + fk[0] = Number(fk[0]) + } + + function powWrap(a,b,M) { + a = BigInt(a) + b = BigInt(b) + M = BigInt(M) + return pow(a,b,M) + } + + function pow(a, b, M) { + if (b === 0n) return 1n + if ((b & 1n) === 0n) return pow((a * a) % M, b >> 1n, M) + return (a * pow((a * a) % M, b >> 1n, M)) % M + } +} + + +// another + + +class Modulo { + /** + * @param {number} modulo + */ + constructor(modulo) { + /** @type {number} @readonly */ + this.modulo = modulo; + + /** @private @type {undefined | number} */ + this._phi = undefined; + } + + /** + * @returns {number} + */ + getPhi() { + if (this._phi !== undefined) return this._phi; + + let result = this.modulo; + let temp = this.modulo; + for (let i = 2; i <= Math.sqrt(temp); i++) { + if (temp % i === 0) { + result /= i; + result *= i - 1; + } + while (temp % i === 0) temp /= i; + } + if (temp > 1) { + result /= temp; + result *= temp - 1; + } + + this._phi = result; + return result; + } + + /** + * @param {number} a + * @returns {number} + */ + getInverse(a) { + return this.pow(a, this.getPhi() - 1); + } + + /** + * @param {...number} numbers + */ + add(...numbers) { + let result = 0; + for (let number of numbers) { + result = (result + (number % this.modulo)) % this.modulo; + } + + if (result < 0) result += this.modulo; + return result; + } + + /** + * @private + * @param {number} a + * @param {number} b + * @returns {number} + */ + _quickMul(a, b) { + a = ((a % this.modulo) + this.modulo) % this.modulo; + b = ((b % this.modulo) + this.modulo) % this.modulo; + if (a === 0 || b === 0) return 0; + + let result = 0; + while (b) { + while (b % 2 === 0) { + a = (a * 2) % this.modulo; + b /= 2; + } + + if (b % 2 !== 0) { + result = (result + a) % this.modulo; + b--; + } + } + + return result; + } + + /** + * @param {...number} numbers + */ + mul(...numbers) { + let result = 1; + for (let number of numbers) { + if (number > 0 && number < 1) + number = this.getInverse(Math.round(1 / number)); + result = this._quickMul(result, number); + if (result === 0) return 0; + } + + if (result < 0) result += this.modulo; + return result; + } + + /** + * @param {number} a + * @param {number} b + * @returns {number} + */ + div(a, b) { + return this._quickMul(a, this.getInverse(b)); + } + + /** + * @param {number} a + * @param {number} b + * @returns {number} + */ + pow(a, b) { + a = ((a % this.modulo) + this.modulo) % this.modulo; + if (a === 0) return 0; + + let result = 1; + while (b) { + while (b % 2 === 0) { + a = this._quickMul(a, a); + b /= 2; + } + + if (b % 2 !== 0) { + result = this._quickMul(result, a); + b--; + } + } + + return result; + } +} + +const mod = new Modulo(1000000007); + +/** + * @param {string} s + * @param {string} t + * @param {number} k + * @return {number} + */ +var numberOfWays = function (s, t, k) { + s += s; + const BASE = 26; + + const basePows = [1]; + function getBasePow(n) { + while (n >= basePows.length) { + basePows.push(mod.mul(basePows[basePows.length - 1], BASE)); + } + return basePows[n]; + } + + /** @param {string} s */ + function calcHashWord(s, pre = 0) { + let result = pre; + for (let i = 0; i < s.length; i++) { + result = mod.add( + mod.mul(result, BASE), + mod.mul(1 + s.charCodeAt(i), s.charCodeAt(i)) + ); + } + return result; + } + + const prefixHash = []; + prefixHash[-1] = 0; + + for (let i = 0; i < s.length; i++) { + prefixHash.push(calcHashWord(s[i], prefixHash[prefixHash.length - 1])); + } + + function getHash(l, r) { + return mod.add( + prefixHash[r], + -mod.mul(prefixHash[l - 1], getBasePow(r - l + 1)) + ); + } + + const hashedT = calcHashWord(t, 0); + let cntOcc = 0; + let flagFirstMatch = 0; + if (getHash(0, t.length - 1) === hashedT) { + cntOcc++; + flagFirstMatch = 1; + } + + for (let i = 1; i < t.length; i++) { + if (getHash(i, i + t.length - 1) === hashedT) cntOcc++; + } + + if (k == 1) return cntOcc - flagFirstMatch; + let res = mod.mul(cntOcc, mod.pow(t.length - 1, k)); + res = mod.add( + res, + mod.mul(flagFirstMatch * t.length - cntOcc, k % 2 ? -1 : 1) + ); + res = mod.div(res, t.length); + + return res; +}; diff --git a/2856-minimum-array-length-after-pair-removals.js b/2856-minimum-array-length-after-pair-removals.js new file mode 100644 index 00000000..69e868e1 --- /dev/null +++ b/2856-minimum-array-length-after-pair-removals.js @@ -0,0 +1,41 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minLengthAfterRemovals = function(nums) { + const n = nums.length, rightStart = Math.floor((n + 1) / 2) + let i = 0, j = rightStart + let num = 0 + while(i < rightStart && j < n) { + if(nums[i] < nums[j]) { + num += 2 + i++ + j++ + } else j++ + } + + return n - num +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const minLengthAfterRemovals = function(nums) { + const map = new Map(), n = nums.length + for(const e of nums) { + if(!map.has(e)) map.set(e, 0) + map.set(e, map.get(e) + 1) + } + let maxFreq = 0 + for(const [k, v] of map) { + maxFreq = Math.max(maxFreq, v) + } + if(maxFreq <= n / 2) { + return n % 2 + } + + return 2 * maxFreq - n +}; diff --git a/2857-count-pairs-of-points-with-distance-k.js b/2857-count-pairs-of-points-with-distance-k.js new file mode 100644 index 00000000..e85d888c --- /dev/null +++ b/2857-count-pairs-of-points-with-distance-k.js @@ -0,0 +1,54 @@ +/** + * @param {number[][]} coordinates + * @param {number} k + * @return {number} + */ +var countPairs = function(coordinates, k) { + const map = new Map(); + const n = coordinates.length; + const MUL = 1e6 + let res = 0; + for(let i = 0; i < n; i++) { + const [x, y] = coordinates[i]; + for(let e = 0; e <= k; e++) { + const x2 = x ^ e; + const y2 = (k - e) ^ y; + const key = code(x2, y2); + res += map.get(key) || 0; + } + const key = code(x, y); + map.set(key, (map.get(key) || 0) + 1); + } + + return res + + function code(x, y) { + return x * MUL + y + } +}; + +// another + +/** + * @param {number[][]} coordinates + * @param {number} k + * @return {number} + */ +const countPairs = function(coordinates, k) { + const hash = new Map() + const n = coordinates.length + let res = 0 + for(let i = 0; i < n; i++) { + const [x, y] = coordinates[i] + for(let v = 0; v <= k; v++) { + const xx = v ^ x + const yy = (k - v) ^ y + const key = `${xx},${yy}` + res += hash.get(key) || 0 + } + const kk = `${x},${y}` + hash.set(kk, (hash.get(kk) || 0) + 1) + } + + return res +}; diff --git a/2858-minimum-edge-reversals-so-every-node-is-reachable.js b/2858-minimum-edge-reversals-so-every-node-is-reachable.js new file mode 100644 index 00000000..839d6212 --- /dev/null +++ b/2858-minimum-edge-reversals-so-every-node-is-reachable.js @@ -0,0 +1,71 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ +const minEdgeReversals = function (n, edges) { + let edgesMap = {} + for (let i = 0; i < edges.length; i++) { + let a = edges[i][0] + let b = edges[i][1] + if (edgesMap[a] === undefined) { + edgesMap[a] = [] + } + //its a forward edge + edgesMap[a].push([b, 'f']) + if (edgesMap[b] === undefined) { + edgesMap[b] = [] + } + //its a revers edge + edgesMap[b].push([a, 'r']) + } + + //We can cosnider any node as root node, Here I choose node 0 + let res = bfs(0) + let ans = [] + ans[0] = res[0] + let dist = res[1] + for (let i = 1; i < n; i++) { + //Ans for rest of the node will be, distance from node to root + answer of root + ans[i] = dist[i][0] - dist[i][1] + ans[0] + } + + return ans + function bfs(root) { + let distance = [], + visited = [], + totalReversal = 0 + let queue = [] + queue.push([root, 0, 0]) + distance[root] = [0, 0] + visited[root] = true + while (queue.length > 0) { + let nextLevelQueue = [] + for (let i = 0; i < queue.length; i++) { + let node = queue[i][0] + let weightF = queue[i][1] + let weightR = queue[i][2] + for (let j = 0; j < edgesMap[node].length; j++) { + let neighbour = edgesMap[node][j][0] + if (visited[neighbour] !== undefined) { + continue + } + let type = edgesMap[node][j][1] + let f = weightF, + r = weightR + if (type === 'r') { + totalReversal += 1 + r++ + } else { + f++ + } + visited[neighbour] = true + distance[neighbour] = [f, r] + nextLevelQueue.push([neighbour, f, r]) + } + } + queue = nextLevelQueue + } + return [totalReversal, distance] + } +} diff --git a/286-walls-and-gates.js b/286-walls-and-gates.js new file mode 100644 index 00000000..f0a47019 --- /dev/null +++ b/286-walls-and-gates.js @@ -0,0 +1,98 @@ +/** + +You are given a m x n 2D grid initialized with these three possible values. + +-1 - A wall or an obstacle. +0 - A gate. +INF - Infinity means an empty room. We use the value 231 - 1 = 2147483647 +to represent INF as you may assume that the distance to a gate +is less than 2147483647. + +Fill each empty room with the distance to its nearest gate. +If it is impossible to reach a gate, it should be filled with INF. + +Example: + +Given the 2D grid: + +INF -1 0 INF +INF INF INF -1 +INF -1 INF -1 + 0 -1 INF INF +After running your function, the 2D grid should be: + + 3 -1 0 1 + 2 2 1 -1 + 1 -1 2 -1 + 0 -1 3 4 + +*/ + +/** + * @param {number[][]} rooms + * @return {void} Do not return anything, modify rooms in-place instead. + */ +const wallsAndGates = function(rooms) { + const dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]] + const rows = rooms.length + const cols = rows === 0 ? 0 : rooms[0].length + const q = [] + const INF = 2147483647 + for(let i = 0; i < rows; i++) { + for(let j = 0; j < cols; j++) { + if(rooms[i][j] === 0) q.push([i, j]) + } + } + while(q.length) { + const el = q.shift() + for(let d of dirs) { + const r = el[0] + d[0] + const c = el[1] + d[1] + if(r < 0 || c < 0 || r >= rows || c >= cols || rooms[r][c] !== INF) continue + rooms[r][c] = rooms[el[0]][el[1]] + 1 + q.push([r, c]) + } + } +}; + +// another + +/** + * @param {number[][]} rooms + * @return {void} Do not return anything, modify rooms in-place instead. + */ +const wallsAndGates = function(rooms) { + const dirs = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1] + ]; + const rows = rooms.length; + const cols = rows === 0 ? 0 : rooms[0].length; + const q = []; + const INF = 2147483647; + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (rooms[i][j] === 0) dfs(dirs, rooms, i, j, rows, cols, 0); + } + } +}; + +function dfs(dirs, rooms, i, j, rows, cols, dis) { + if ( + i < 0 || + j < 0 || + i >= rows || + j >= cols || + rooms[i][j] === -1 || + rooms[i][j] < dis + ) { + return; + } + rooms[i][j] = dis; + for (let dir of dirs) { + dfs(dirs, rooms, i + dir[0], j + dir[1], rows, cols, dis + 1); + } +} + diff --git a/2860-happy-students.js b/2860-happy-students.js new file mode 100644 index 00000000..0ab1d182 --- /dev/null +++ b/2860-happy-students.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const countWays = function(nums) { + const n = nums.length + nums.sort((a, b) => a - b) + let res = 0, num = 0 + if(nums[0] !== 0) res = 1 + for(let i = 0; i < n; i++) { + num++ + if(num > nums[i]) { + if(i + 1 < n && num < nums[i + 1]) res++ + else if(i + 1 === n) res++ + } + } + return res +}; diff --git a/2861-maximum-number-of-alloys.js b/2861-maximum-number-of-alloys.js new file mode 100644 index 00000000..41c009ed --- /dev/null +++ b/2861-maximum-number-of-alloys.js @@ -0,0 +1,41 @@ +/** + * @param {number} n + * @param {number} k + * @param {number} budget + * @param {number[][]} composition + * @param {number[]} stock + * @param {number[]} cost + * @return {number} + */ +const maxNumberOfAlloys = function(n, k, budget, composition, stock, cost) { + let low = 0, + high = 1e9 + let res = 0 + + while (low < high) { + let mid = high - Math.floor((high - low) / 2) + if (isPossible(n, k, budget, composition, stock, cost, mid)) { + low = mid + } else { + high = mid - 1 + } + } + + return low +}; + +function isPossible(n, k, budget, composition, stock, costs, fixed_alloy) { + for (let i = 0; i < k; i++) { + let calBudget = 0 + for (let j = 0; j < n; j++) { + let required = 1 * composition[i][j] * fixed_alloy + required -= stock[j] + if (required > 0) { + calBudget += 1 * required * costs[j] + } + } + if (calBudget <= 1 * budget) return true + } + + return false +} diff --git a/2862-maximum-element-sum-of-a-complete-subset-of-indices.js b/2862-maximum-element-sum-of-a-complete-subset-of-indices.js new file mode 100644 index 00000000..3489dde0 --- /dev/null +++ b/2862-maximum-element-sum-of-a-complete-subset-of-indices.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maximumSum = function(nums) { + const n = nums.length; + + // Find squares + let sq = [1]; + while(sq.at(-1) < n) sq.push((sq.length+1) ** 2); + + let res = 0; + for(let i=1; i<=n; ++i) { + let cur = 0; + for(const s of sq) { // s*i will give {i*1, i*4, i*9, ...} + const idx = s*i; + if(idx>n) break; + cur += nums[idx-1]; + } + res = Math.max(res, cur); + } + + return res; +}; diff --git a/2866-beautiful-towers-ii.js b/2866-beautiful-towers-ii.js new file mode 100644 index 00000000..8cbf4e55 --- /dev/null +++ b/2866-beautiful-towers-ii.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} maxHeights + * @return {number} + */ +const maximumSumOfHeights = function (maxHeights) { + let n = maxHeights.length + + let left = Array(n).fill(0) + let stack = [] + stack.push(-1) + let res = 0, + cur = 0 + for (let i = 0; i < n; i++) { + while (stack.length > 1 && maxHeights[stack.at(-1)] > maxHeights[i]) { + let j = stack.pop() + cur -= (j - stack.at(-1)) * maxHeights[j] + } + cur += 1 * (i - stack.at(-1)) * maxHeights[i] + stack.push(i) + left[i] = cur + } + + stack = [] + stack.push(n) + cur = 0 + for (let i = n - 1; i >= 0; i--) { + while (stack.length > 1 && maxHeights[stack.at(-1)] > maxHeights[i]) { + let j = stack.pop() + cur -= 1 * -(j - stack.at(-1)) * maxHeights[j] + } + cur += 1 * -(i - stack.at(-1)) * maxHeights[i] + stack.push(i) + res = Math.max(res, left[i] + cur - maxHeights[i]) + } + + return res +} diff --git a/2867-count-valid-paths-in-a-tree.js b/2867-count-valid-paths-in-a-tree.js new file mode 100644 index 00000000..519dd339 --- /dev/null +++ b/2867-count-valid-paths-in-a-tree.js @@ -0,0 +1,97 @@ +let eratosthenesSieve; + +/** + * @param {number} n + */ +function initEratosthenesSieve(n) { + eratosthenesSieve = Array(n + 1).fill(1); + eratosthenesSieve[0] = 0; + eratosthenesSieve[1] = 0; + + for (let i = 2; i <= n; i++) { + if (eratosthenesSieve[i]) { + for (let j = 2 * i; j <= n; j += i) { + eratosthenesSieve[j] = 0; + } + } + } +} +initEratosthenesSieve(100000); + +/** + * @typedef {{ parent: number, children: number[], p0: number, p1: number, res }} TNode + */ + +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +var countPaths = function(n, edges) { + /** @type {TNode[]} */ + let nodes = [undefined]; + + for (let i = 1; i <= n; i++) nodes.push({ + parent: 0, + children: [], + p0: 0, + p1: 0, + }); + + for (let [u,v] of edges) { + nodes[u].children.push(v); + nodes[v].children.push(u); + } + + function buildRoot(x, parent) { + const node = nodes[x]; + node.parent = parent; + + for (let c of node.children) { + if (c !== parent) buildRoot(c, x) + } + } + + buildRoot(1); + let res = 0; + + function dp(x) { + const isPrime = eratosthenesSieve[x]; + const node = nodes[x]; + let exc = 0; + let cp0 = 0; + let cp1 = 0; + + for (let c of node.children) { + if (c !== node.parent) { + dp(c); + let nodeC = nodes[c]; + cp0 += nodeC.p0; + cp1 += nodeC.p1; + + if (isPrime) { + exc += nodeC.p0 * (nodeC.p0 - 1) / 2 - nodeC.p0; + } + else { + exc += nodeC.p0 * nodeC.p1; + } + } + } + + if (isPrime) { + node.p0 = 0; + node.p1 = cp0 + 1; + res += cp0 * (cp0 - 1) / 2 - exc; + } + else { + node.p0 = cp0 + 1; + node.p1 = cp1; + res += (cp0 + 1) * cp1 - exc + } + } + + dp(1); + + return res; +}; + diff --git a/287-find-the-duplicate-number.js b/287-find-the-duplicate-number.js index 10bf088e..d0a9bb2d 100755 --- a/287-find-the-duplicate-number.js +++ b/287-find-the-duplicate-number.js @@ -1,3 +1,33 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const findDuplicate = function(nums) { + const n = nums.length; + let ans = 0; + let bit_max = 31; + while (((n - 1) >> bit_max) == 0) { + bit_max -= 1; + } + for (let bit = 0; bit <= bit_max; ++bit) { + let x = 0, y = 0; + for (let i = 0; i < n; ++i) { + if ((nums[i] & (1 << bit)) != 0) { + x += 1; + } + if (i >= 1 && ((i & (1 << bit)) != 0)) { + y += 1; + } + } + if (x > y) { + ans |= 1 << bit; + } + } + return ans; +}; + +// another + /** * @param {number[]} nums * @return {number} @@ -59,3 +89,195 @@ const findDuplicate = function(nums) { } } }; + + +/** + +# File: FindDuplicate.py +# Author: Keith Schwarz (htiek@cs.stanford.edu) +# +# An algorithm for solving the following (classic) hard interview problem: +# +# "You are given an array of integers of length n, where each element ranges +# from 0 to n - 2, inclusive. Prove that at least one duplicate element must +# exist, and give an O(n)-time, O(1)-space algorithm for finding some +# duplicated element. You must not modify the array elements during this +# process." +# +# This problem (reportedly) took CS legend Don Knuth twenty-four hours to solve +# and I have only met one person (Keith Amling) who could solve it in less time +# than this. +# +# The first part of this problem - proving that at least one duplicate element +# must exist - is a straightforward application of the pigeonhole principle. +# If the values range from 0 to n - 2, inclusive, then there are only n - 1 +# different values. If we have an array of n elements, one must necessarily be +# duplicated. +# +# The second part of this problem - finding the duplicated element subject to +# the given constraints - is much harder. To solve this, we're going to need a +# series of nonobvious insights that transform the problem into an instance of +# something entirely different. +# +# The main trick we need to use to solve this problem is to notice that because +# we have an array of n elements ranging from 0 to n - 2, we can think of the +# array as defining a function f from the set {0, 1, ..., n - 1} onto itself. +# This function is defined by f(i) = A[i]. Given this setup, a duplicated +# value corresponds to a pair of indices i != j such that f(i) = f(j). Our +# challenge, therefore, is to find this pair (i, j). Once we have it, we can +# easily find the duplicated value by just picking f(i) = A[i]. +# +# But how are we to find this repeated value? It turns out that this is a +# well-studied problem in computer science called cycle detection. The general +# form of the problem is as follows. We are given a function f. Define the +# sequence x_i as +# +# x_0 = k (for some k) +# x_1 = f(x_0) +# x_2 = f(f(x_0)) +# ... +# x_{n+1} = f(x_n) +# +# Assuming that f maps from a domain into itself, this function will have one +# of three forms. First, if the domain is infinite, then the sequence could be +# infinitely long and nonrepeating. For example, the function f(n) = n + 1 on +# the integers has this property - no number is ever duplicated. Second, the +# sequence could be a closed loop, which means that there is some i so that +# x_0 = x_i. In this case, the sequence cycles through some fixed set of +# values indefinitely. Finally, the sequence could be "rho-shaped." In this +# case, the sequence looks something like this: +# +# x_0 -> x_1 -> ... x_k -> x_{k+1} ... -> x_{k+j} +# ^ | +# | | +# +-----------------------+ +# +# That is, the sequence begins with a chain of elements that enters a cycle, +# then cycles around indefinitely. We'll denote the first element of the cycle +# that is reached in the sequence the "entry" of the cycle. +# +# For our particular problem of finding a duplicated element in the array, +# consider the sequence formed by starting at position n - 1 and then +# repeatedly applying f. That is, we start at the last position in the array, +# then go to the indicated index, repeating this process. My claim is that +# this sequence is rho-shaped. To see this, note that it must contains a cycle +# because the array is finite and after visiting n elements, we necessarily +# must visit some element twice. This is true no matter where we start off in +# the array. Moreover, note that since the array elements range from 0 to +# n - 2 inclusive, there is no array index that contains n - 1 as a value. +# Consequently, when we leave index n - 1 after applying the function f one +# time, we can never get back there. This means that n - 1 can't be part of a +# cycle, but if we follow indices starting there we must eventually hit some +# other node twice. The concatenation of the chain starting at n - 1 with the +# cycle it hits must be rho-shaped. +# +# Moreover, think about the node we encounter that starts at the entry of the +# cycle. Since this node is at the entry of the cycle, there must be two +# inputs to the function f that both result in that index being generated. For +# this to be possible, it must be that there are indices i != j with +# f(i) = f(j), meaning that A[i] = A[j]. Thus the index of the entry of the +# cycle must be one of the values that is duplicated in the array. +# +# There is a famous algorithm due to Robert Floyd that, given a rho-shaped +# sequence, finds the entry point of the cycle in linear time and using only +# constant space. This algorithm is often referred to as the "tortoise and +# hare" algorithm, for reasons that will become clearer shortly. +# +# The idea behind the algorithm is to define two quantities. First, let c be +# the length of the chain that enters the cycle, and let l be the length of the +# cycle. Next, let l' be the smallest multiple of l that's larger than c. +# I claim that for any rho-shaped sequence l' defined above, that +# +# x_{l'} = x_{2l'} +# +# The proof is actually straightforward and very illustrative - it's one of my +# favorite proofs in computer science. The idea is that since l' is at least +# c, it must be contained in the cycle. Moreover, since l' is a multiple of +# the length of the loop, we can write it as ml for some constant m. If we +# start at position x_{l'}, which is inside the loop, then take l' more steps +# forward to get to x_{2l'}, then we will just walk around the loop m times, +# ending up right back where we started. +# +# One key trick of Floyd's algorithm is that even if we don't explicitly know l +# or c, we can still find the value l' in O(l') time. The idea is as follows. +# We begin by keeping track of two values "slow" and "fast," both starting at +# x_0. We then iteratively compute +# +# slow = f(slow) +# fast = f(f(fast)) +# +# We repeat this process until we find that slow and fast are equal to one +# another. When this happens, we know that slow = x_j for some j, and +# fast = x_{2j} for that same j. Since x_j = x_{2j}, we know that j must be at +# least c, since it has to be contained in the cycle. Moreover, we know that j +# must be a multiple of l, since the fact that x_j = x_{2j} means that taking j +# steps while in the cycle ends up producing the same result. Finally, j must +# be the smallest multiple of l greater than c, since if there were a smaller +# multiple of l greater than c then we would have reached that multiple before +# we reached j. Consequently, we must have that j = l', meaning that we can +# find l' without knowing anything about the length or shape of the cycle! +# +# To complete the construction, we need to show how to use our information +# about l' to find the entry to the cycle (which is at position x_c). To do +# this, we start off one final variable, which we call "finder," at x_0. We +# then iteratively repeat the following: +# +# finder = f(finder) +# slow = f(slow) +# +# until finder = slow. We claim that (1) the two will eventually hit each +# other, and (2) they will hit each other at the entry to the cycle. To see +# this, we remark that since slow is at position x_{l'}, if we take c steps +# forward, then we have that slow will be at position x_{l' + c}. Since l' is +# a multiple of the loop length, this is equivalent to taking c steps forward, +# then walking around the loop some number of times back to where you started. +# In other words, x_{l' + c} = x_c. Moreover, consider the position of the +# finder variable after c steps. It starts at x_0, so after c steps it will be +# at position x_c. This proves both (1) and (2), since we've shown that the +# two must eventually hit each other, and when they do they hit at position x_c +# at the entry to the cycle. +# +# The beauty of this algorithm is that it uses only O(1) external memory to +# keep track of two different pointers - the slow pointer, and then the fast +# pointer (for the first half) and the finder pointer (for the second half). +# But on top of that, it runs in O(n) time. To see this, note that the time +# required for the slow pointer to hit the fast pointer is O(l'). Since l' is +# the smallest multiple of l greater than c, we have two cases to consider. +# First, if l > c, then this is l. Otherwise, if l < c, then we have that +# there must be some multiple of l between c and 2c. To see this, note that +# in the range c and 2c there are c different values, and since l < c at least +# one of them must be equal to 0 mod l. Finally, the time required to find the +# start of the cycle from this point is O(c). This gives a total runtime of at +# most O(c + max{l, 2c}). All of these values are at most n, so this algorithm +# runs in time O(n). + +def findArrayDuplicate(array): + assert len(array) > 0 + + # The "tortoise and hare" step. We start at the end of the array and try + # to find an intersection point in the cycle. + slow = len(array) - 1 + fast = len(array) - 1 + + # Keep advancing 'slow' by one step and 'fast' by two steps until they + # meet inside the loop. + while True: + slow = array[slow] + fast = array[array[fast]] + + if slow == fast: + break + + # Start up another pointer from the end of the array and march it forward + # until it hits the pointer inside the array. + finder = len(array) - 1 + while True: + slow = array[slow] + finder = array[finder] + + # If the two hit, the intersection index is the duplicate element. + if slow == finder: + return slow + + +*/ diff --git a/2871-split-array-into-maximum-number-of-subarrays.js b/2871-split-array-into-maximum-number-of-subarrays.js new file mode 100644 index 00000000..a71c473c --- /dev/null +++ b/2871-split-array-into-maximum-number-of-subarrays.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maxSubarrays = function(nums) { + let n = nums.length; + let s = nums[0]; + for (let i = 1; i < n; i++) s &= nums[i]; + if (s > 0) return 1; + + let res = 0; + let l = 0; + let cs = nums[l]; + for (let r = 0; r < n; r++) { + cs &= nums[r]; + if (cs == 0) { + res++; + l = r + 1; + cs = nums[l]; + } + } + + return res; +}; diff --git a/2873-maximum-value-of-an-ordered-triplet-i.js b/2873-maximum-value-of-an-ordered-triplet-i.js new file mode 100644 index 00000000..06fc592a --- /dev/null +++ b/2873-maximum-value-of-an-ordered-triplet-i.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maximumTripletValue = function(nums) { + const n = nums.length + let res = 0 + for(let i = 0; i < n - 2; i++) { + for(let j = i + 1; j < n - 1; j++) { + for(let k = j + 1; k < n ; k++) { + if(nums[i] < 0 && nums[j] < 0 && nums[k] < 0) continue + res = Math.max(res, (nums[i] - nums[j]) * nums[k]) + } + } + } + return res +}; diff --git a/2874-maximum-value-of-an-ordered-triplet-ii.js b/2874-maximum-value-of-an-ordered-triplet-ii.js new file mode 100644 index 00000000..2b996426 --- /dev/null +++ b/2874-maximum-value-of-an-ordered-triplet-ii.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maximumTripletValue = function(nums) { + const n = nums.length, {max} = Math + const left = Array(n).fill(0), right = Array(n).fill(0) + for(let i = 0, ma = 0; i < n; i++) { + ma = max(ma, nums[i]) + left[i] = ma + } + for(let i = n - 1, ma = 0; i >= 0; i--) { + ma = max(ma, nums[i]) + right[i] = ma + } + let res = 0 + + for(let i = 1; i < n - 1; i++) { + res = max(res, (left[i - 1] - nums[i]) * right[i + 1] ) + } + + return res +}; diff --git a/2875-minimum-size-subarray-in-infinite-array.js b/2875-minimum-size-subarray-in-infinite-array.js new file mode 100644 index 00000000..9746278e --- /dev/null +++ b/2875-minimum-size-subarray-in-infinite-array.js @@ -0,0 +1,54 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const minSizeSubarray = function (nums, target) { + const sum = nums.reduce((ac, e) => ac + e, 0) + const remain = target % sum + if(remain === 0) return target / sum * nums.length + const arr = [...nums, ...nums] + const map = new Map() + const n = arr.length + let r = Infinity + for(let i = 0, cur = 0; i < n; i++) { + const e = arr[i] + cur += e + // const tmp = cur % target + if(map.has(cur - remain)) r = Math.min(r, i - map.get(cur-remain)) + map.set(cur, i) + } + if(r === Infinity) return -1 + return r + Math.floor(target / sum) * nums.length +} + +// another + + +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var minSizeSubarray = function(nums, target) { + let sum = 0, su = 0; + for (const a of nums) sum += a; + let n = nums.length, k = Math.floor(target / sum), res = n; + target %= sum; + if (target === 0) { + return k * n; + } + + let dp = new Map(); + dp.set(0, -1); + + for (let i = 0; i < 2 * n; ++i) { + su += nums[i % n]; + if (dp.has(su - target)) { + res = Math.min(res, i - dp.get(su - target)); + } + dp.set(su, i); + } + + return res < n ? res + k * n : -1; +}; diff --git a/2876-count-visited-nodes-in-a-directed-graph.js b/2876-count-visited-nodes-in-a-directed-graph.js new file mode 100644 index 00000000..1fc4fc24 --- /dev/null +++ b/2876-count-visited-nodes-in-a-directed-graph.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} edges + * @return {number[]} + */ +const countVisitedNodes = function(edges) { + const n = edges.length, res = Array(n).fill(0) + for(let i = 0; i < n; i++) { + const visited = new Set() + let j = i, q = [] + while(res[j] === 0 && !visited.has(j)) { + q.push(j) + visited.add(j) + j = edges[j] + } + + if(visited.has(j)) { + const k = q.length - q.indexOf(j) + for(let ii = 0; ii < k; ii++) { + res[q.pop()] = k + } + } + + while(q.length) { + const ii = q.pop() + res[ii] = res[edges[ii]] + 1 + } + + } + + return res +}; diff --git a/288-unique-word-abbreviation.js b/288-unique-word-abbreviation.js new file mode 100644 index 00000000..4afe5e29 --- /dev/null +++ b/288-unique-word-abbreviation.js @@ -0,0 +1,40 @@ +/** + * @param {string[]} dictionary + */ +const ValidWordAbbr = function(dictionary) { + this.map = new Map() + for (let i = 0; i < dictionary.length; i++) { + let w = dictionary[i] + if (w.length < 3) this.map.set(w, true) + else { + let key = this.toAbbr(w) + let val = this.map.has(key) ? false : w + this.map.set(key, val) + } + } +} +/** + * @param {string} word + * @return {boolean} + */ +ValidWordAbbr.prototype.isUnique = function(word) { + let len = word.length + if (len < 3) return true + let key = this.toAbbr(word) + if (this.map.has(key)) { + let val = this.map.get(key) + if (val === false) return false + return word === val + } + return true +} +ValidWordAbbr.prototype.toAbbr = word => { + let len = word.length + if (len < 3) return word + return word[0] + (len - 2) + word[len - 1] +} +/** + * Your ValidWordAbbr object will be instantiated and called as such: + * var obj = new ValidWordAbbr(dictionary) + * var param_1 = obj.isUnique(word) + */ diff --git a/289-game-of-life.js b/289-game-of-life.js new file mode 100644 index 00000000..1af3d028 --- /dev/null +++ b/289-game-of-life.js @@ -0,0 +1,56 @@ +/** + * @param {number[][]} board + * @return {void} Do not return anything, modify board in-place instead. + */ +const gameOfLife = function(board) { + const DIRECTIONS = [ + [1, 0], + [1, 1], + [0, 1], + [-1, 1], + [-1, 0], + [-1, -1], + [0, -1], + [1, -1] + ]; + + const isValid = function(x, y) { + if (x >= 0 && y >= 0 && x < board.length && y < board[0].length) + return true; + else return false; + }; + + const getAliveNeighbors = function(x, y) { + let aliveNeighs = 0; + for (let dir of DIRECTIONS) { + let newX = x + dir[0]; + let newY = y + dir[1]; + if (!isValid(newX, newY)) continue; + if (board[newX][newY] === 1 || board[newX][newY] === -1) { + aliveNeighs++; + } + } + + return aliveNeighs; + }; + + for (let row = 0; row < board.length; row++) { + for (let col = 0; col < board[0].length; col++) { + let aliveNeighbors = getAliveNeighbors(row, col); + if (board[row][col] === 0) { + if (aliveNeighbors === 3) board[row][col] = 2; + else board[row][col] = 0; + } else { + if (aliveNeighbors === 2 || aliveNeighbors === 3) board[row][col] = 1; + else board[row][col] = -1; + } + } + } + + for (let row = 0; row < board.length; row++) { + for (let col = 0; col < board[0].length; col++) { + if (board[row][col] > 0) board[row][col] = 1; + else board[row][col] = 0; + } + } +}; diff --git a/2894-divisible-and-non-divisible-sums-difference.js b/2894-divisible-and-non-divisible-sums-difference.js new file mode 100644 index 00000000..d7a5db30 --- /dev/null +++ b/2894-divisible-and-non-divisible-sums-difference.js @@ -0,0 +1,13 @@ +/** + * @param {number} n + * @param {number} m + * @return {number} + */ +const differenceOfSums = function(n, m) { + let num1 = 0, num2 = 0 + for(let i = 1; i <= n; i++) { + if(i % m !== 0) num1 += i + if(i % m === 0) num2 += i + } + return num1 - num2 +}; diff --git a/2895-minimum-processing-time.js b/2895-minimum-processing-time.js new file mode 100644 index 00000000..02747490 --- /dev/null +++ b/2895-minimum-processing-time.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} processorTime + * @param {number[]} tasks + * @return {number} + */ +const minProcessingTime = function (processorTime, tasks) { + const n = processorTime.length + processorTime.sort((a, b) => a - b) + tasks.sort((a, b) => b - a) + let res = 0 + for(let i = 0, j = 0; i < n; i++, j += 4) { + res = Math.max(res, processorTime[i] + tasks[j]) + } + return res +} diff --git a/2896-apply-operations-to-make-two-strings-equal.js b/2896-apply-operations-to-make-two-strings-equal.js new file mode 100644 index 00000000..2f43e165 --- /dev/null +++ b/2896-apply-operations-to-make-two-strings-equal.js @@ -0,0 +1,114 @@ +/** + * @param {string} s1 + * @param {string} s2 + * @param {number} x + * @return {number} + */ +const minOperations = function (s1, s2, x) { + const n = s1.length, arr = [] + for(let i = 0; i < n; i++) { + if(s1[i] !== s2[i]) arr.push(i) + } + const len = arr.length + if(len % 2) return -1 + const cache = new Map() + return dfs(len - 1) + + function dfs(i) { + if(i < 0) return 0 + if(i === 0) return x / 2 + if(cache.has(i)) return cache.get(i) + const res = Math.min(dfs(i - 2) + arr[i] - arr[i - 1], dfs(i - 1) + x/2) + cache.set(i, res) + return res + } +} + +// another + + +/** + * @param {string} s1 + * @param {string} s2 + * @param {number} x + * @return {number} + */ +var minOperations = function(s1, s2, x) { + const n = s1.length; + const idxs = []; + for (let i = 0; i < n; i++) { + if (s1[i] !== s2[i]) { + idxs.push(i); + } + } + const k = idxs.length; + if (k % 2) { + return -1; + } + const dp = new Array(k + 1).fill(Infinity); + dp[0] = 0; + for (let i = 0; i < k; i++) { + /* + # 这里没有删除指的是没有用第二种操作 + # 如果目前考虑的元素个数为奇数,如果最后一个位置没有被删除,则前面位置都被删除了,那么当前的成本是 dp[i] + */ + if (i % 2 === 0) { + dp[i + 1] = dp[i]; + } else { + /* + # 如果目前考虑的元素个数为偶数,如果最后一个位置没有被删除,则需要与前面的某项进行配对删除(第一种操作), + # 那么当前的成本是 dp[i] + x,即前面有位置没被删除的成本 + 这次删除的成本,因为要删去最后两项 + */ + dp[i + 1] = dp[i] + x; + } + /* + # 考虑使用第二种操作 + */ + if (i) { + dp[i + 1] = Math.min(dp[i + 1], dp[i - 1] + idxs[i] - idxs[i - 1]); + } + } + return dp[k]; +}; + +// another + +/** + * @param {string} s1 + * @param {string} s2 + * @param {number} x + * @return {number} + */ +const minOperations = function(s1, s2, x) { + const diffs = []; + for (let i = 0; i < s1.length; i++) { + if (s1[i] !== s2[i]) { + diffs.push(i); + } + } + + if (diffs.length % 2 === 1) { + return -1; + } + + const cache = new Map(); + function bestCostUpTo(i) { + if (i === 0) { + return x / 2; + } + if (i === -1) { + return 0; + } + if (cache.has(i)) { + return cache.get(i); + } + const cost = Math.min( + bestCostUpTo(i - 1) + x / 2, + bestCostUpTo(i - 2) + diffs[i] - diffs[i - 1] + ); + cache.set(i, cost); + return cost; + } + + return Math.floor(bestCostUpTo(diffs.length - 1)); +}; diff --git a/2897-apply-operations-on-array-to-maximize-sum-of-squares.js b/2897-apply-operations-on-array-to-maximize-sum-of-squares.js new file mode 100644 index 00000000..64c54537 --- /dev/null +++ b/2897-apply-operations-on-array-to-maximize-sum-of-squares.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxSum = function(nums, k) { + const n = nums.length, mod = BigInt(1e9 + 7) + let res = 0n + const stk = Array(n).fill(0), idx = Array(32).fill(0) + for(const e of nums) { + for(let i = 0; i < 32; i++) { + if((e >> i) & 1) { + stk[idx[i]] += (1 << i) + idx[i]++ + } + } + } + + for(let i = 0; i < k; i++) { + res += BigInt(stk[i]) * BigInt(stk[i]) + res %= mod + } + + return Number(res) +}; diff --git a/2900-longest-unequal-adjacent-groups-subsequence-i.js b/2900-longest-unequal-adjacent-groups-subsequence-i.js new file mode 100644 index 00000000..ba50d1fb --- /dev/null +++ b/2900-longest-unequal-adjacent-groups-subsequence-i.js @@ -0,0 +1,15 @@ +/** + * @param {number} n + * @param {string[]} words + * @param {number[]} groups + * @return {string[]} + */ +const getWordsInLongestSubsequence = function (n, words, groups) { + let res = [] + res.push(words[0]) + + for(let i = 1; i < n; i++) { + if(groups[i] !== groups[i - 1]) res.push(words[i]) + } + return res +} diff --git a/2901-longest-unequal-adjacent-groups-subsequence-ii.js b/2901-longest-unequal-adjacent-groups-subsequence-ii.js new file mode 100644 index 00000000..00f99e6d --- /dev/null +++ b/2901-longest-unequal-adjacent-groups-subsequence-ii.js @@ -0,0 +1,48 @@ +/** + * @param {number} n + * @param {string[]} words + * @param {number[]} groups + * @return {string[]} + */ +const getWordsInLongestSubsequence = function(n, words, groups) { + let res = [] + let len = new Array(1001).fill(1) + let next = new Array(1001).fill(-1) + let startNodeWithMaxLen = -1 + let maxLen = 0 + for (let i = n - 1; i >= 0; i--) { + for (let t = i + 1; t < n; t++) { + if (len[i] < len[t] + 1 && check(words, groups, i, t)) { + len[i] = len[t] + 1 + next[i] = t + } + } + if (maxLen < len[i]) { + maxLen = len[i] + startNodeWithMaxLen = i + } + } + let p = startNodeWithMaxLen + while (p !== -1) { + res.push(words[p]) + p = next[p] + } + return res + + function check(words, groups, i, lastInd) { + if ( + groups[i] === groups[lastInd] || + words[i].length !== words[lastInd].length + ) { + return false + } + let diff = 0 + for (let j = 0; j < words[i].length; j++) { + if (words[i][j] !== words[lastInd][j]) { + diff++ + } + } + return diff === 1 + } + +}; diff --git a/2902-count-of-sub-multisets-with-bounded-sum.js b/2902-count-of-sub-multisets-with-bounded-sum.js new file mode 100644 index 00000000..7fbd2d1b --- /dev/null +++ b/2902-count-of-sub-multisets-with-bounded-sum.js @@ -0,0 +1,39 @@ +/** + * @param {number[]} nums + * @param {number} l + * @param {number} r + * @return {number} + */ +var countSubMultisets = function (nums, l, r) { + const a = nums + const counter = (a_or_s) => { + let m = new Map() + for (const x of a_or_s) m.set(x, m.get(x) + 1 || 1) + return m + } + + const mod = 1e9 + 7 + let f = Array(r + 1).fill(0), + m = counter(a), + res = 0 + f[0] = 1 + for (const [x, occ] of m) { + if (x == 0) { + f = f.map((e) => e * (occ + 1)) + } else { + for (let i = x; i <= r; i++) { + f[i] += f[i - x] + f[i] %= mod + } + for (let i = r; i >= (occ + 1) * x; i--) { + f[i] -= f[i - (occ + 1) * x] + f[i] %= mod + } + } + } + for (let i = l; i <= r; i++) { + res += f[i] + res %= mod + } + return (res + mod) % mod +} diff --git a/2903-find-indices-with-index-and-value-difference-i.js b/2903-find-indices-with-index-and-value-difference-i.js new file mode 100644 index 00000000..46a565c9 --- /dev/null +++ b/2903-find-indices-with-index-and-value-difference-i.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @param {number} indexDifference + * @param {number} valueDifference + * @return {number[]} + */ +var findIndices = function(nums, indexDifference, valueDifference) { + let res = [-1, -1] + const {abs} = Math, n = nums.length + for(let i = 0; i < n; i++) { + for(let j = i; j < n; j++) { + if(abs(i - j) >= indexDifference && abs(nums[i] - nums[j]) >= valueDifference) { + res = [i, j] + } + } + } + + + return res +}; diff --git a/2904-shortest-and-lexicographically-smallest-beautiful-string.js b/2904-shortest-and-lexicographically-smallest-beautiful-string.js new file mode 100644 index 00000000..b138eec2 --- /dev/null +++ b/2904-shortest-and-lexicographically-smallest-beautiful-string.js @@ -0,0 +1,43 @@ +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const shortestBeautifulSubstring = function (s, k) { + let n = s.length; + let left = 0; + let right = 0; + let count = 0; + let min_length = Infinity; + let res = ""; + while (right < n) { + count = updateCount(s[right], count); + while (count === k) { + [min_length, res] = updateRes(s, left, right, min_length, res); + count = updateCount(s[left], count, false); + left++; + } + right++; + } + return res; + + + function updateCount(c, count, increment = true) { + if (c === '1') { + return increment ? count + 1 : count - 1; + } + return count; + } + + function updateRes(s, left, right, min_length, res) { + if (right - left + 1 < min_length) { + min_length = right - left + 1; + res = s.substring(left, left + min_length); + } else if (right - left + 1 === min_length) { + // res = Math.min(res, s.substring(left, left + min_length)); + if(s.substring(left, left + min_length) < res) res = s.substring(left, left + min_length) + } + return [min_length, res]; + } + +} diff --git a/2905-find-indices-with-index-and-value-difference-ii.js b/2905-find-indices-with-index-and-value-difference-ii.js new file mode 100644 index 00000000..a8d47bb8 --- /dev/null +++ b/2905-find-indices-with-index-and-value-difference-ii.js @@ -0,0 +1,156 @@ +/** + * @param {number[]} nums + * @param {number} indexDifference + * @param {number} valueDifference + * @return {number[]} + */ +class SegmentTree { + constructor(start = 0, end = 0, value = null, lazy = null, merge) { + this.start = start + this.end = end + this.value = value + this.lazy = lazy + this.merge = merge + this.left = null + this.right = null + } + + get mid() { + return this.start + Math.floor((this.end - this.start) / 2) + } + + build(arr) { + return this.buildHelper(0, arr.length - 1, arr) + } + + buildHelper(left, right, arr) { + if (left > right) return null + const root = new SegmentTree(left, right, arr[left], null, this.merge) + if (left === right) return root + const mid = Math.floor((left + right) / 2) + root.left = this.buildHelper(left, mid, arr) + root.right = this.buildHelper(mid + 1, right, arr) + root.value = this.safeMerge(root.left?.value, root.right?.value) + return root + } + + build(left, right, defaultValue) { + if (left > right) return null + return new SegmentTree(left, right, defaultValue, null, this.merge) + } + + update(root, l, r, v) { + if (l <= root.start && r >= root.end) { + root.value = v + root.lazy = this.safeMerge(root.lazy, v) + return + } + if (root.left === null || root.right === null) { + const mid = root.mid + if (root.left === null) + root.left = this.build(root.start, mid, root.value) + if (root.right === null) + root.right = this.build(mid + 1, root.end, root.value) + } + this.pushDown(root) + const mid = root.mid + if (l <= mid) { + this.update(root.left, l, r, v) + } + if (r > mid) { + this.update(root.right, l, r, v) + } + root.value = this.merge(root.left.value, root.right.value) + } + + pushDown(root) { + if (root.lazy === null) return + root.left.lazy = this.safeMerge(root.left.lazy, root.lazy) + root.right.lazy = this.safeMerge(root.right.lazy, root.lazy) + root.left.value = this.safeMerge(root.left.value, root.lazy) + root.right.value = this.safeMerge(root.right.value, root.lazy) + root.lazy = null + } + + update(root, index, value) { + if (root.start === index && root.end === index) { + root.value = value + return + } + if (root.left === null || root.right === null) { + const mid = root.mid + if (root.left === null) + root.left = this.build(root.start, mid, root.value) + if (root.right === null) + root.right = this.build(mid + 1, root.end, root.value) + } + const mid = root.mid + if (index <= mid) { + this.update(root.left, index, value) + root.value = this.safeMerge(root.left.value, root.right.value) + } else { + this.update(root.right, index, value) + root.value = this.safeMerge(root.left.value, root.right.value) + } + } + + query(root, left, right) { + if (left <= root.start && right >= root.end) { + return root.value + } + if (root.left === null || root.right === null) { + const mid = root.mid + if (root.left === null) + root.left = this.build(root.start, mid, root.value) + if (root.right === null) + root.right = this.build(mid + 1, root.end, root.value) + } + this.pushDown(root) + const mid = root.mid + let ans = null + if (mid >= left) { + ans = this.safeMerge(ans, this.query(root.left, left, right)) + } + if (mid + 1 <= right) { + ans = this.safeMerge(ans, this.query(root.right, left, right)) + } + return ans + } + + safeMerge(a, b) { + if (a === null) return b + if (b === null) return a + return this.merge(a, b) + } + + lazyMerge(a, b) { + return b + } +} + +function findIndices(nums, indexDifference, valueDifference) { + const root = new SegmentTree(0, 100005, [0, 0], null, (a, b) => + a[0] >= b[0] ? a : b, + ) + for (let i = 0; i < nums.length; i++) { + root.update(root, i, [nums[i], i]) + } + + for (let i = 0; i < nums.length; i++) { + const left = i - indexDifference + if (left >= 0) { + const max = root.query(root, 0, left) + if (max[0] - nums[i] >= valueDifference) { + return [max[1], i] + } + } + const right = i + indexDifference + if (right < nums.length) { + const max = root.query(root, right, nums.length - 1) + if (max[0] - nums[i] >= valueDifference) { + return [i, max[1]] + } + } + } + return [-1, -1] +} diff --git a/2906-construct-product-matrix.js b/2906-construct-product-matrix.js new file mode 100644 index 00000000..5396d36c --- /dev/null +++ b/2906-construct-product-matrix.js @@ -0,0 +1,68 @@ +/** + * @param {number[][]} grid + * @return {number[][]} + */ +var constructProductMatrix = function(grid) { + const mod = 12345; + const n = grid.length; + const m = grid[0].length; + + const row = new Array(n).fill(1); + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + row[i] = (row[i] * grid[i][j]) % mod; + } + } + + const rowLeft = new Array(n).fill(1); + const rowRight = new Array(n).fill(1); + for (let i = 0; i < n; i++) { + rowLeft[i] = (i === 0) ? row[i] : rowLeft[i - 1] * row[i]; + rowLeft[i] = rowLeft[i] % mod; + } + for (let i = n - 1; i >= 0; i--) { + rowRight[i] = (i === n - 1) ? row[i] : rowRight[i + 1] * row[i]; + rowRight[i] = rowRight[i] % mod; + } + + const colLeft = new Array(n); + const colRight = new Array(n); + for (let i = 0; i < n; i++) { + colLeft[i] = new Array(m); + colRight[i] = new Array(m); + for (let j = 0; j < m; j++) { + colLeft[i][j] = (j === 0) ? grid[i][j] : colLeft[i][j - 1] * grid[i][j]; + colLeft[i][j] = colLeft[i][j] % mod; + } + for (let j = m - 1; j >= 0; j--) { + colRight[i][j] = (j === m - 1) ? grid[i][j] : colRight[i][j + 1] * grid[i][j]; + colRight[i][j] = colRight[i][j] % mod; + } + } + + const ans = new Array(n); + for (let i = 0; i < n; i++) { + ans[i] = new Array(m); + for (let j = 0; j < m; j++) { + let tmp = 1; + if (i - 1 >= 0) { + tmp *= rowLeft[i - 1]; + tmp %= mod; + } + if (i + 1 < n) { + tmp *= rowRight[i + 1]; + tmp %= mod; + } + if (j - 1 >= 0) { + tmp *= colLeft[i][j - 1]; + tmp %= mod; + } + if (j + 1 < m) { + tmp *= colRight[i][j + 1]; + tmp %= mod; + } + ans[i][j] = tmp; + } + } + return ans; +}; diff --git a/2908-minimum-sum-of-mountain-triplets-i.js b/2908-minimum-sum-of-mountain-triplets-i.js new file mode 100644 index 00000000..d5fc9135 --- /dev/null +++ b/2908-minimum-sum-of-mountain-triplets-i.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumSum = function(nums) { + let pre = [],pmin = [], suf = [], smin = [] + let i = 0 + const n = nums.length + for(let i = 0; i < n; i++) { + const cur = nums[i] + while(pre.length && cur <= nums[pre.at(-1)]) { + pre.pop() + } + if(pre.length) pmin[i] = nums[pre[0]] + pre.push(i) + } + for(let i = n - 1; i >= 0; i--) { + const cur = nums[i] + while(suf.length && cur <= nums[suf.at(-1)]) { + suf.pop() + } + if(suf.length) smin[i] = nums[suf[0]] + suf.push(i) + } + let res = Infinity + + for(let i = 1; i < n - 1;i++) { + if(pmin[i] != null && smin[i] != null) { + res = Math.min(res, nums[i] + pmin[i] + smin[i]) + } + } + + return res === Infinity ? -1 : res +}; diff --git a/2909-minimum-sum-of-mountain-triplets-ii.js b/2909-minimum-sum-of-mountain-triplets-ii.js new file mode 100644 index 00000000..d5fc9135 --- /dev/null +++ b/2909-minimum-sum-of-mountain-triplets-ii.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minimumSum = function(nums) { + let pre = [],pmin = [], suf = [], smin = [] + let i = 0 + const n = nums.length + for(let i = 0; i < n; i++) { + const cur = nums[i] + while(pre.length && cur <= nums[pre.at(-1)]) { + pre.pop() + } + if(pre.length) pmin[i] = nums[pre[0]] + pre.push(i) + } + for(let i = n - 1; i >= 0; i--) { + const cur = nums[i] + while(suf.length && cur <= nums[suf.at(-1)]) { + suf.pop() + } + if(suf.length) smin[i] = nums[suf[0]] + suf.push(i) + } + let res = Infinity + + for(let i = 1; i < n - 1;i++) { + if(pmin[i] != null && smin[i] != null) { + res = Math.min(res, nums[i] + pmin[i] + smin[i]) + } + } + + return res === Infinity ? -1 : res +}; diff --git a/291-word-pattern-ii.js b/291-word-pattern-ii.js new file mode 100644 index 00000000..91f77ac2 --- /dev/null +++ b/291-word-pattern-ii.js @@ -0,0 +1,68 @@ +/** + * @param {string} pattern + * @param {string} str + * @return {boolean} + */ +const wordPatternMatch = function(pattern, str) { + const map = new Map() + const set = new Set() + return isMatch(str, 0, pattern, 0, map, set) +}; +function isMatch(str, i, pat, j, map, set) { + if(i === str.length && j === pat.length) return true + if(i === str.length || j === pat.length) return false + let c = pat.charAt(j) + if(map.has(c)) { + let s = map.get(c) + if(!str.startsWith(s, i)) return false + return isMatch(str, i + s.length, pat, j + 1, map, set) + } + for(let k = i; k < str.length; k++) { + let p = str.slice(i, k + 1) + if(set.has(p)) continue + map.set(c, p) + set.add(p) + if(isMatch(str, k + 1, pat, j + 1, map, set)) return true + map.delete(c) + set.delete(p) + } + return false +} + +// another + +/** + * @param {string} pattern + * @param {string} s + * @return {boolean} + */ +const wordPatternMatch = function(pattern, s) { + const obj = { res: false } + const hash = {} + helper(pattern, s, 0, 0, hash, obj) + return obj.res +}; + +function helper(p, s, i, j, hash, obj) { + if(obj.res) return + if(i === p.length && j === s.length) { + obj.res = true + return + } + if(i >= p.length || j >= s.length) return + for(let m = j; m < s.length && obj.res === false; m++) { + const tmp = s.slice(j, m + 1) + if(hash[p[i]]) { + if(tmp === hash[p[i]]) { + helper(p, s, i + 1, m + 1, hash, obj) + } + } else { + const set = new Set(Object.values(hash)) + if (!set.has(tmp)) { + hash[p[i]] = tmp + helper(p, s, i + 1, m + 1, hash, obj) + delete hash[p[i]] + } + } + } +} diff --git a/2910-minimum-number-of-groups-to-create-a-valid-assignment.js b/2910-minimum-number-of-groups-to-create-a-valid-assignment.js new file mode 100644 index 00000000..37496cc8 --- /dev/null +++ b/2910-minimum-number-of-groups-to-create-a-valid-assignment.js @@ -0,0 +1,61 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minGroupsForValidAssignment = function(nums) { + let mp = new Map(); + for (let i = 0; i < nums.length; i++) { + if (mp.has(nums[i])) { + mp.set(nums[i], mp.get(nums[i]) + 1); + } else { + mp.set(nums[i], 1); + } + } + + let maxi = 0; + let n = nums.length; + + let u = new Map(); + for (let i of nums) { + if (u.has(i)) { + u.set(i, u.get(i) + 1); + } else { + u.set(i, 1); + } + maxi = Math.max(maxi, u.get(i)); + } + + for (let i = maxi; i >= 1; i--) { + if (posi(i, u)) { + let res = 0; + for (let [curr, c] of u) { + let left = c % i; + res += Math.floor(c / i); + if (left > 0) { + res++; + } + } + return res; + } + } + return -1; + } + + function posi(x, u) { + for (let [curr, cnt] of u) { + let left = cnt % x; + let tt = Math.floor(cnt / x); + + if (left < x - 1) { + let req = (x - 1) - left; + if (tt >= req) { + left = x - 1; + } + } + + if (left > 0 && left < x - 1) { + return false; + } + } + return true; + } diff --git a/2911-minimum-changes-to-make-k-semi-palindromes.js b/2911-minimum-changes-to-make-k-semi-palindromes.js new file mode 100644 index 00000000..7e758952 --- /dev/null +++ b/2911-minimum-changes-to-make-k-semi-palindromes.js @@ -0,0 +1,62 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +var minimumChanges = function(s, k) { + const ins = new Solution() + return ins.minimumChanges(s,k) +}; + +class Solution { + constructor() { + this.fac = new Array(210).fill(0).map(() => []); // A vector of vectors to store factors of string lengths. + } + + num(st) { + const n = st.length; + let ans = 1e9; + for (const it of this.fac[st.length]) { + const nu = Math.floor(n / it); + let cur = 0; + for (let i = 0; i < Math.floor(nu / 2); i++) { + const i2 = nu - i - 1; + for (let j = 0; j < it; j++) { + if (st[i * it + j] !== st[i2 * it + j]) { + cur++; + } + } + } + ans = Math.min(ans, cur); + } + return ans; + } + + minimumChanges(st, k) { + const n = st.length; + + for (let i = 2; i <= n; i++) { + this.fac[i] = []; + for (let j = 1; j < i; j++) { + if (i % j === 0) { + this.fac[i].push(j); + } + } + } + + const dp = new Array(n + 1).fill(0).map(() => new Array(k + 1).fill(1e9)); + dp[0][0] = 0; + + for (let i = 0; i < n; i++) { + for (let j = 0; j <= i; j++) { + const cur = st.slice(j, i + 1); + const add = this.num(cur); + for (let l = 0; l < k; l++) { + dp[i + 1][l + 1] = Math.min(dp[i + 1][l + 1], dp[j][l] + add); + } + } + } + + return dp[n][k]; + } +} diff --git a/2916-subarrays-distinct-element-sum-of-squares-ii.js b/2916-subarrays-distinct-element-sum-of-squares-ii.js new file mode 100644 index 00000000..041d74da --- /dev/null +++ b/2916-subarrays-distinct-element-sum-of-squares-ii.js @@ -0,0 +1,67 @@ +const MOD = 1e9 + 7; +/** + * @param {number[]} nums + * @return {number} + */ +const sumCounts = function(nums) { + let n = nums.length; + const last_pos = Array(100001).fill(-1); + + const tree = new SegmentTree(n); + let res = 0; + + for (let j = 0; j < n; j ++) { + let st = last_pos[nums[j]] + 1, ed = j; + tree.AddOne(st, ed); + + res = (res + tree.sqr[0]) % MOD; + + last_pos[nums[j]] = j; + } + return res; +}; + + +class SegmentTree { + constructor (n) { + this.n = n + this.lzy = Array(4*n).fill(0); + this.sum = Array(4*n).fill(0); + this.sqr = Array(4*n).fill(0); + } + + update_lzy( l, r, i) { + const {lzy, sum, sqr} = this + + if (l != r) { + lzy[i*2+1] += lzy[i]; + lzy[i*2+2] += lzy[i]; + } + let gap = r-l+1; + let new_sum = sum[i] + lzy[i]*gap; + let new_sqr = sqr[i] + lzy[i]*sum[i]*2 + lzy[i]*lzy[i]*gap; + + sum[i] = new_sum % MOD; + sqr[i] = new_sqr % MOD; + lzy[i] = 0; + } + + AddOne ( x, y, l = 0, r = -1, i = 0) { + const {lzy, sum, sqr, n} = this + if (r == -1) r += n; + this.update_lzy(l, r, i); + + if (r < x || l > y) return; + if (l >= x && r <= y) { + lzy[i] = 1; + return this.update_lzy(l, r, i); + } + + let m = (l+r) >> 1; + this.AddOne (x, y, l, m, i*2+1); + this.AddOne (x, y, m+1, r, i*2+2); + + sum[i] = (sum[i*2+1] + sum[i*2+2]) % MOD; + sqr[i] = (sqr[i*2+1] + sqr[i*2+2]) % MOD; + } +}; diff --git a/2919-minimum-increment-operations-to-make-array-beautiful.js b/2919-minimum-increment-operations-to-make-array-beautiful.js new file mode 100644 index 00000000..b0d83880 --- /dev/null +++ b/2919-minimum-increment-operations-to-make-array-beautiful.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minIncrementOperations = function(nums, k) { + const dp = new Array(nums.length).fill(-1) + + const traverse = (index) => { + if (index >= nums.length - 2) return 0 + + if (dp[index] !== -1) return dp[index] + + let res = Infinity; + for (let i = index; i <= index + 2; i++) { + const val = Math.max(k - nums[i], 0) + const next = traverse(i + 1) + res = Math.min(val + next, res) + } + + dp[index] = res + return res + } + + + return traverse(0) +}; diff --git a/292-nim-game.js b/292-nim-game.js new file mode 100644 index 00000000..04d31e55 --- /dev/null +++ b/292-nim-game.js @@ -0,0 +1,7 @@ +/** + * @param {number} n + * @return {boolean} + */ +const canWinNim = function(n) { + return n % 4 !== 0 ; +}; diff --git a/2920-maximum-points-after-collecting-coins-from-all-nodes.js b/2920-maximum-points-after-collecting-coins-from-all-nodes.js new file mode 100644 index 00000000..02020d94 --- /dev/null +++ b/2920-maximum-points-after-collecting-coins-from-all-nodes.js @@ -0,0 +1,47 @@ +/** + * @param {number[][]} edges + * @param {number[]} coins + * @param {number} k + * @return {number} + */ +const maximumPoints = function (edges, coins, k) { + const n = coins.length + const g = Array(n) + .fill() + .map(() => []) + for (const edge of edges) { + const [u, v] = edge + g[u].push(v) + g[v].push(u) + } + const dp = Array(n) + .fill() + .map(() => Array(15).fill(-1)) + const dfs = (node, parent, reduce) => { + if (dp[node][reduce] !== -1) { + return dp[node][reduce] + } + if (reduce >= 14) { + return (dp[node][reduce] = 0) + } + let currCoins = coins[node] + for (let j = 0; j < reduce; j++) { + currCoins = Math.floor(currCoins / 2) + } + let way1 = currCoins - k + let way2 = Math.floor(currCoins / 2) + for (const child of g[node]) { + if (child !== parent) { + dfs(child, node, reduce + 1) + dfs(child, node, reduce) + way1 += dp[child][reduce] + way2 += dp[child][reduce + 1] + } + } + dp[node][reduce] = Math.max(way1, way2) + return dp[node][reduce] + } + dfs(0, -1, 0) + + return dp[0][0] +} diff --git a/2925-maximum-score-after-applying-operations-on-a-tree.js b/2925-maximum-score-after-applying-operations-on-a-tree.js new file mode 100644 index 00000000..6bcc7db3 --- /dev/null +++ b/2925-maximum-score-after-applying-operations-on-a-tree.js @@ -0,0 +1,51 @@ +/** + * @param {number[][]} edges + * @param {number[]} values + * @return {number} + */ +var maximumScoreAfterOperations = function(edges, values) { + const n = values.length; + const g = new Array(n).fill(null).map(() => []); + for (const edge of edges) { + const [u, v] = edge; + g[u].push(v); + g[v].push(u); + } + + const subtree = new Array(n); + for (let i = 0; i < n; i++) { + subtree[i] = values[i]; + } + + const pre = (node, parent) => { + for (const child of g[node]) { + if (child !== parent) { + pre(child, node); + subtree[node] += subtree[child]; + } + } + }; + + pre(0, -1); + + const dp = new Array(n).fill(-1); + + const dfs = (node, parent) => { + dp[node] = subtree[node] - values[node]; + let sum = 0; + let cnt = 0; + for (const child of g[node]) { + if (child !== parent) { + dfs(child, node); + cnt++; + sum += dp[child]; + } + } + if (cnt > 0) { + dp[node] = Math.max(dp[node], values[node] + sum); + } + }; + + dfs(0, -1); + return dp[0]; +}; diff --git a/2926-maximum-balanced-subsequence-sum.js b/2926-maximum-balanced-subsequence-sum.js new file mode 100644 index 00000000..ec53d630 --- /dev/null +++ b/2926-maximum-balanced-subsequence-sum.js @@ -0,0 +1,141 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxBalancedSubsequenceSum = (nums) => { + const stack = [[-Infinity, 0]] + for (let i = 0; i < nums.length; i++) { + if (nums[i] > 0) { + const key = nums[i] - i + + let left = 0, + right = stack.length - 1 + while (left < right) { + const mid = left + Math.floor((right - left) / 2) + if (stack[mid][0] <= key) { + left = mid + 1 + } else { + right = mid + } + } + if (stack[left][0] <= key) left++ + const sum = nums[i] + Math.max(0, stack[left - 1][1]) + if (left === stack.length) { + stack.push([key, sum]) + } else { + stack.splice(left, 0, [key, sum]) + } + let k = left + 1 + while (k < stack.length && sum >= stack[k][1]) { + stack.splice(k, 1) + } + } + } + + if (stack.length > 1) { + return stack[stack.length - 1][1] + } + + return Math.max(...nums) +} + +// another + +////////////////////// Template ///////////////////////////////// +function Bisect() { + return { insort_right, insort_left, bisect_left, bisect_right } + function insort_right(a, x, lo = 0, hi = null) { + lo = bisect_right(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_right(a, x, lo = 0, hi = null) { + // > upper_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + a[mid] > x ? (hi = mid) : (lo = mid + 1) + } + return lo + } + function insort_left(a, x, lo = 0, hi = null) { + lo = bisect_left(a, x, lo, hi) + a.splice(lo, 0, x) + } + function bisect_left(a, x, lo = 0, hi = null) { + // >= lower_bound + if (lo < 0) throw new Error('lo must be non-negative') + if (hi == null) hi = a.length + while (lo < hi) { + let mid = parseInt((lo + hi) / 2) + a[mid] < x ? (lo = mid + 1) : (hi = mid) + } + return lo + } +} + +function SegmentTreeRMQArray(A) { + // max + let n = A.length, + h = Math.ceil(Math.log2(n)), + len = 2 * 2 ** h, + a = Array(len).fill(Number.MIN_SAFE_INTEGER) + h = 2 ** h + initializeFromArray() + return { update, maxx, tree } + function initializeFromArray() { + for (let i = 0; i < n; i++) a[h + i] = A[i] + for (let i = h - 1; i >= 1; i--) pushup(i) + } + function update(pos, v) { + a[h + pos] = v + for (let i = parent(h + pos); i >= 1; i = parent(i)) pushup(i) + } + function pushup(i) { + a[i] = Math.max(a[left(i)], a[right(i)]) + } + function maxx(l, r) { + // [l, r) + let max = Number.MIN_SAFE_INTEGER + if (l >= r) return max + l += h + r += h + for (; l < r; l = parent(l), r = parent(r)) { + if (l & 1) max = Math.max(max, a[l++]) + if (r & 1) max = Math.max(max, a[--r]) + } + return max + } + function parent(i) { + return i >> 1 + } + function left(i) { + return 2 * i + } + function right(i) { + return 2 * i + 1 + } + function tree() { + return a + } +} +///////////////////////////////////////////////////////////// +/** + * @param {number[]} nums + * @return {number} + */ +const maxBalancedSubsequenceSum = (a) => { + let vals = a.map((x, i) => x - i).sort((x, y) => x - y) + vals = [...new Set(vals)] + let n = a.length, + st = new SegmentTreeRMQArray(Array(n + 1).fill(Number.MIN_SAFE_INTEGER)), + bi = new Bisect() + for (let i = 0; i < n; i++) { + let v = a[i] - i, + idx = bi.bisect_left(vals, v) + let max = st.maxx(0, idx + 1) // query [0, idx] + if (max < 0) max = 0 + st.update(idx, a[i] + max) // each time accumulate previous [0, idx] max, and update new max sum + } + return st.maxx(0, n + 1) // query [0, n] +} diff --git a/293-flip-game.js b/293-flip-game.js new file mode 100644 index 00000000..b37ca28b --- /dev/null +++ b/293-flip-game.js @@ -0,0 +1,10 @@ +/** + * @param {string} s + * @return {string[]} + */ +const generatePossibleNextMoves = function(s) { + const list = [] + for (let i = -1; (i = s.indexOf('++', i + 1)) >= 0; ) + list.push(s.slice(0, i) + '--' + s.slice(i + 2)) + return list +} diff --git a/2930-number-of-strings-which-can-be-rearranged-to-contain-substring.js b/2930-number-of-strings-which-can-be-rearranged-to-contain-substring.js new file mode 100644 index 00000000..d9dac832 --- /dev/null +++ b/2930-number-of-strings-which-can-be-rearranged-to-contain-substring.js @@ -0,0 +1,31 @@ +/** + * @param {number} n + * @return {number} + */ +const stringCount = function(n) { + const LEET = parseInt('1111', 2), + L = parseInt('1000', 2), + FE = parseInt('0100', 2), + SE = parseInt('0010', 2), + T = parseInt('0001', 2), + MOD = 1e9 + 7 + const dp = Array.from({ length: n }, () => Array(16).fill(-1)) + return helper(0, 0) + + function helper(i, mask) { + if(i === n) { + return mask === LEET ? 1 : 0 + } + if(dp[i][mask] !== -1) return dp[i][mask] + + let res = (helper(i + 1, mask | L) + helper(i + 1, mask | T)) % MOD + if(mask & FE) { + res = (res + helper(i + 1, mask | SE)) % MOD + } else { + res = (res + helper(i + 1, mask | FE)) % MOD + } + res = (res + 23 * helper(i + 1, mask)) % MOD + dp[i][mask] = res + return dp[i][mask] + } +}; diff --git a/2932-maximum-strong-pair-xor-i.js b/2932-maximum-strong-pair-xor-i.js new file mode 100644 index 00000000..41a92ef3 --- /dev/null +++ b/2932-maximum-strong-pair-xor-i.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maximumStrongPairXor = function(nums) { + const n = nums.length + let res = -Infinity + for(let i = 0; i < n; i++) { + const x = nums[i] + for(let j = i; j < n; j++) { + const y = nums[j] + if(Math.abs(x - y) <= Math.min(x, y) && (x ^ y) > res) { + res = x ^ y + } + } + } + return res +}; diff --git a/2933-high-access-employees.js b/2933-high-access-employees.js new file mode 100644 index 00000000..4660b7f4 --- /dev/null +++ b/2933-high-access-employees.js @@ -0,0 +1,23 @@ +/** + * @param {string[][]} access_times + * @return {string[]} + */ +var findHighAccessEmployees = function(access_times) { + const map = new Map(); + access_times.sort((a, b) => a[1] - b[1]).forEach((item) => { + const key = item[0]; + const value = parseInt(item[1]); + map.set(key, map.get(key) || []); + map.get(key).push(value); + }); + const ans = []; + map.forEach((value, key) => { + for (let i = 2; i < value.length; i++) { + if (value[i] - value[i - 2] < 100) { + ans.push(key); + break; + } + } + }); + return ans; +}; diff --git a/2934-minimum-operations-to-maximize-last-elements-in-arrays.js b/2934-minimum-operations-to-maximize-last-elements-in-arrays.js new file mode 100644 index 00000000..6ee08455 --- /dev/null +++ b/2934-minimum-operations-to-maximize-last-elements-in-arrays.js @@ -0,0 +1,40 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +var minOperations = function (nums1, nums2) { + const n = nums1.length + let a = nums1[n - 1] + let b = nums2[n - 1] + + let tmp0 = 0 + for (let i = 0; i < n - 1; i++) { + const x = nums1[i] + const y = nums2[i] + + if (Math.min(x, y) > Math.min(a, b)) return -1 + if (Math.max(x, y) > Math.max(a, b)) return -1 + + if (y <= a && x <= b && (x > a || y > b)) { + tmp0++ + } + } + + a = nums2[n - 1] + b = nums1[n - 1] + let tmp1 = 0 + for (let i = 0; i < n - 1; i++) { + const x = nums1[i] + const y = nums2[i] + + if (Math.min(x, y) > Math.min(a, b)) return -1 + if (Math.max(x, y) > Math.max(a, b)) return -1 + + if (y <= a && x <= b && (x > a || y > b)) { + tmp1++ + } + } + + return Math.min(tmp0, tmp1 + 1) +} diff --git a/2935-maximum-strong-pair-xor-ii.js b/2935-maximum-strong-pair-xor-ii.js new file mode 100644 index 00000000..6246500b --- /dev/null +++ b/2935-maximum-strong-pair-xor-ii.js @@ -0,0 +1,119 @@ +class Node { + constructor() { + this.links = [null, null] + this.frequency = 0 + } + + containsKey(bit) { + return this.links[bit] !== null + } + + get(bit) { + return this.links[bit] + } + + put(bit, node) { + this.links[bit] = node + } +} + +class Trie { + constructor() { + this.root = new Node() + } + + insert(num) { + let node = this.root + for (let i = 31; i >= 0; i--) { + const bit = (num >> i) & 1 + if (!node.containsKey(bit)) { + node.put(bit, new Node()) + } + node = node.get(bit) + node.frequency++ + } + } + + getMax(num) { + let node = this.root + let res = 0 + for (let i = 31; i >= 0; i--) { + const bit = (num >> i) & 1 + if (node.containsKey(1 - bit) && node.get(1 - bit).frequency > 0) { + res = res | (1 << i) + node = node.get(1 - bit) + } else { + if (node.containsKey(bit) && node.get(bit).frequency > 0) { + node = node.get(bit) + } else { + return 0 + } + } + } + return res + } + + deleteKey(num) { + let node = this.root + for (let i = 31; i >= 0; i--) { + const bit = (num >> i) & 1 + if (node.containsKey(bit)) { + node = node.get(bit) + node.frequency-- + } else { + break + } + } + } +} +/** + * @param {number[]} nums + * @return {number} + */ +function maximumStrongPairXor(nums) { + const n = nums.length + nums.sort((a, b) => a - b) + let maxi = 0 + let j = 0 + const t = new Trie() + t.insert(nums[0]) + for (let i = 1; i < n; i++) { + while (j < i && nums[i] - nums[j] > Math.min(nums[i], nums[j])) { + t.deleteKey(nums[j]) + j++ + } + maxi = Math.max(maxi, t.getMax(nums[i])) + t.insert(nums[i]) + } + return maxi +} + +// another + + +const maximumStrongPairXor= (nums) => { + const A = nums + let res = 0; + for (let i = 20; i >= 0; --i) { + res <<= 1; + let pref = new Map(); + let pref2 = new Map(); + for (let a of A) { + let p = a >> i; + if (!pref.has(p)) { + pref.set(p, a); + pref2.set(p, a); + } + pref.set(p, Math.min(pref.get(p), a)); + pref2.set(p, Math.max(pref2.get(p), a)); + } + for (let [x, val] of pref) { + let y = res ^ 1 ^ x; + if (x >= y && pref.has(y) && pref.get(x) <= pref2.get(y) * 2) { + res |= 1; + break; + } + } + } + return res; +} diff --git a/2937-make-three-strings-equal.js b/2937-make-three-strings-equal.js new file mode 100644 index 00000000..47bdc08e --- /dev/null +++ b/2937-make-three-strings-equal.js @@ -0,0 +1,26 @@ +/** + * @param {string} s1 + * @param {string} s2 + * @param {string} s3 + * @return {number} + */ +var findMinimumOperations = function(s1, s2, s3) { + let a = s1.length + let b = s2.length + let c = s3.length + + let min = Math.min(a, Math.min(b, c)) + let i = 0 + for (; i < min; i++) { + let c1 = s1.charAt(i) + let c2 = s2.charAt(i) + let c3 = s3.charAt(i) + if (c1 !== c2 || c2 !== c3) { + break + } + } + if (i === 0) return -1 + let ans = 0 + ans = a - i + b - i + c - i + return ans +}; diff --git a/2938-separate-black-and-white-balls.js b/2938-separate-black-and-white-balls.js new file mode 100644 index 00000000..1e12ea4b --- /dev/null +++ b/2938-separate-black-and-white-balls.js @@ -0,0 +1,18 @@ +/** + * @param {string} s + * @return {number} + */ +var minimumSteps = function(s) { + let n = s.length + let left = n - 1 + let right = n - 1 + let cnt = 0 + while (left >= 0) { + if (s.charAt(left) === '1') { + cnt += right - left + right-- + } + left-- + } + return cnt +}; diff --git a/2939-maximum-xor-product.js b/2939-maximum-xor-product.js new file mode 100644 index 00000000..ec022b12 --- /dev/null +++ b/2939-maximum-xor-product.js @@ -0,0 +1,36 @@ +/** + * @param {number} a + * @param {number} b + * @param {number} n + * @return {number} + */ +var maximumXorProduct = function(a, b, n) { + let ans = 0n; + let big = 0n; + let found = false; + a = BigInt(a) + b = BigInt(b) + + for (let i = 50; i >= 0; i--) { + let curr = BigInt(1) << BigInt(i); + + if (((a & curr) == 0n) && ((b & curr) == 0n)) { + if (i < n) ans += curr; + } else if (((a & curr)) && ((b & curr) == 0n)) { + if (big == 0) big = -1; + else if (big == -1 && i < n) ans += curr; + } else if (((a & curr) == 0n) && ((b & curr))) { + if (big == 0) big = 1; + else if (big == 1 && i < n) ans += curr; + } + } + + let mod = BigInt(1000000007); + a ^= ans; + b ^= ans; + a %= mod; + b %= mod; + ans = (a * b) % mod; + + return Number(ans); +}; diff --git a/294-flip-game-ii.js b/294-flip-game-ii.js new file mode 100644 index 00000000..3a4a183b --- /dev/null +++ b/294-flip-game-ii.js @@ -0,0 +1,22 @@ +/** + * @param {string} s + * @return {boolean} + */ +const canWin = function(s) { + const ss = s.split('') + const len = s.length + return chk() + function chk() { + for (let i = 0; i <= len - 2; i++) { + if (ss[i] === '+' && ss[i + 1] === '+') { + ss[i] = '-' + ss[i + 1] = '-' + const wins = !chk() + ss[i] = '+' + ss[i + 1] = '+' + if (wins) return true + } + } + return false + } +} diff --git a/2940-find-building-where-alice-and-bob-can-meet.js b/2940-find-building-where-alice-and-bob-can-meet.js new file mode 100644 index 00000000..d32ecd9f --- /dev/null +++ b/2940-find-building-where-alice-and-bob-can-meet.js @@ -0,0 +1,160 @@ +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} +/** + * @param {number[]} heights + * @param {number[][]} queries + * @return {number[]} + */ +const leftmostBuildingQueries = function(heights, queries) { + const n = queries.length, m = heights.length + const res = Array(n).fill(-1) + const pq = new PQ((a,b) => a[0] < b[0]) + const que = Array.from({ length: m }, () => Array()) + for(let i = 0; i < n; i++) { + let [a, b] = queries[i]; + if(a < b && heights[a] < heights[b]) { + res[i] = b + } else if(a > b && heights[a] > heights[b]) { + res[i] = a + } else if(a === b) { + res[i] = a + } else { + que[Math.max(a, b)].push([Math.max(heights[a], heights[b]), i]) + } + } + + for(let i = 0; i < m; i++) { + while(!pq.isEmpty() && pq.peek()[0] < heights[i]) { + const e = pq.pop() + res[e[1]] = i + } + + for(const e of que[i]) { + pq.push(e) + } + } + + return res +}; + +// another + + +/** + * @param {number[]} heights + * @param {number[][]} queries + * @return {number[]} + */ +var leftmostBuildingQueries = function (heights, queries) { + const st = [] + const [hs, qs] = [heights, queries] + let n = qs.length; + let ans = new Array(n).fill(-1); + let es = new Array(hs.length).fill().map(() => []); + for (let i = 0; i < n; i++) { + let x = qs[i][0]; + let y = qs[i][1]; + if (x > y) { + [x, y] = [y, x]; + } + if (hs[y] > hs[x] || x === y) { + ans[i] = y; + } else { + es[y].push([hs[x], i]); + } + } + for (let i = hs.length - 1; i >= 0; i--) { + let n1 = st.length; + for (let [x, y] of es[i]) { + let p = search(x); + if (p < n1 && p >= 0) { + ans[y] = st[p][1]; + } + } + while (st.length > 0 && st[st.length - 1][0] <= hs[i]) { + st.pop(); + } + st.push([hs[i], i]); + } + return ans; + function search(x) { + let l = 0; + let r = st.length - 1; + let ans = -1; + while (l <= r) { + let m = Math.floor((l + r) / 2); + if (st[m][0] > x) { + ans = Math.max(ans, m); + l = m + 1; + } else { + r = m - 1; + } + } + return ans; + } +} diff --git a/2945-find-maximum-non-decreasing-array-length.js b/2945-find-maximum-non-decreasing-array-length.js new file mode 100644 index 00000000..1d94bfdb --- /dev/null +++ b/2945-find-maximum-non-decreasing-array-length.js @@ -0,0 +1,53 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const findMaximumLength = function(nums) { + const n = nums.length + const stk = [0] + const preSum = Array(n + 1).fill(0) + const maxLen = Array(n + 1).fill(0) + const last = Array(n + 1).fill(0) + for(let i = 1; i <= n; i++) { + preSum[i] = preSum[i - 1] + nums[i - 1] + } + // console.log(preSum) + let stkPtr = 0 + last[0] = nums[0] + for(let i = 1; i <= n; i++) { + while(stkPtr < stk.length - 1 && preSum[stk[stkPtr + 1]] + last[stk[stkPtr + 1]] <= preSum[i]) stkPtr++ + const idx = stk[stkPtr] + maxLen[i] = maxLen[idx] + 1 + last[i] = preSum[i] - preSum[idx] + while(stk.length && preSum[stk.at(-1)] + last[stk.at(-1)] >= preSum[i] + last[i]) stk.pop() + stk.push(i) + } + // console.log(maxLen) + return maxLen[n] +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const findMaximumLength = function(nums) { + let res = 0 + const n = nums.length + const stk = [[0,0,0]] + let pre = 0 + for(let i = 0, j = 0; i < n; i++) { + pre += nums[i] + j = Math.min(j, stk.length - 1) + while(j + 1 < stk.length && pre >= stk[j + 1][0]) j++ + const [val, preVal, preDp] = stk[j] + const curDp = preDp + 1 + res = curDp + const last = pre - preVal + while(stk.length && stk.at(-1)[0] >= last + pre) stk.pop() + stk.push([last + pre, pre, curDp]) + } + + return res +}; diff --git a/2946-matrix-similarity-after-cyclic-shifts.js b/2946-matrix-similarity-after-cyclic-shifts.js new file mode 100644 index 00000000..e1c852ee --- /dev/null +++ b/2946-matrix-similarity-after-cyclic-shifts.js @@ -0,0 +1,42 @@ +/** + * @param {number[][]} mat + * @param {number} k + * @return {boolean} + */ +var areSimilar = function(mat, k) { + const m = mat.length, n = mat[0].length + const clone = Array.from({ length: m }, () => Array(n).fill(null)) + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + clone[i][j] = mat[i][j] + } + } + for(let i = 0; i < m; i++) { + const odd = i % 2 === 1 + if(odd) { + sr(clone, i) + } else { + sl(clone, i) + } + } + // console.log(clone) + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(mat[i][j] !== clone[i][j]) return false + } + } + + + return true + + function sr(mat, i) { + const row = mat[i] + const idx = k % n + mat[i] = row.slice(n - idx).concat(row.slice(0, n - idx)) + } + function sl(mat, i) { + const row = mat[i] + const idx = k % n + mat[i] = row.slice(idx, n).concat(row.slice(0, idx)) + } +}; diff --git a/2947-count-beautiful-substrings-i.js b/2947-count-beautiful-substrings-i.js new file mode 100644 index 00000000..d16869a5 --- /dev/null +++ b/2947-count-beautiful-substrings-i.js @@ -0,0 +1,27 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +var beautifulSubstrings = function(s, k) { + let counter=0; + for(let i=0;i v < 0).length; + } + function equiv(x, y) { // isConnected + return find(x) == find(y); + } + function par() { + return parent; + } + function grp() { + let groups = []; + for (let i = 0; i < n; i++) groups.push([]); + for (let i = 0; i < n; i++) groups[find(i)].push(i); // sorted and unique + return groups; + } +} +//////////////////////////////////////////////////////////////// +/** + * @param {number[]} nums + * @param {number} limit + * @return {number[]} + */ +var lexicographicallySmallestArray = function(nums, limit) { + let d = nums.map((x, i) => [x, i]).sort((x, y) => x[0] - y[0] || x[1] - y[1]), pairs = []; + for (let i = 1; i < nums.length; i++) { + if (d[i][0] - d[i - 1][0] <= limit) pairs.push([d[i - 1][1], d[i][1]]); + } + return LexicalSmallestArrayWithSwaps(nums, pairs) +}; + + +// reference: https://leetcode.com/problems/smallest-string-with-swaps/ +function LexicalSmallestArrayWithSwaps (a, pairs) { + let n = a.length, ds = new DJSet(n), res = Array(n).fill(0); + for (const [x, y] of pairs) ds.union(x, y); + let groups = ds.grp().filter(e => e.length); + for (const group of groups) { + let ga = []; + for (let i of group) ga.push(a[i]); + ga.sort((x, y) => x - y); + for (let i = 0; i < group.length; i++) res[group[i]] = ga[i]; + } + return res; +}; + diff --git a/2949-count-beautiful-substrings-ii.js b/2949-count-beautiful-substrings-ii.js new file mode 100644 index 00000000..a9497f70 --- /dev/null +++ b/2949-count-beautiful-substrings-ii.js @@ -0,0 +1,73 @@ +const set = new Set(['a', 'e', 'i', 'o', 'u']); +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +var beautifulSubstrings = function(s, k) { + const primes = Eratosthenes(k); + let m = 1; + + for (const p of primes) { + let count = 0; + while (k % p === 0) { + count++; + k /= p; + } + if (count !== 0 && count % 2 === 1) { + m *= Math.pow(p, (count + 1) / 2); + } else if (count !== 0 && count % 2 === 0) { + m *= Math.pow(p, count / 2); + } + } + m *= 2; + + const n = s.length; + s = '#' + s; // Prepend a character to ensure 1-based indexing + let ret = 0; + + const map = new Map(); + map.set(0, new Map()); + map.get(0).set(0, 1); + + let count = 0; + + for (let i = 1; i <= n; i++) { + if (set.has(s[i])) { + count++; + } else { + count--; + } + + if (map.has(count) && map.get(count).has(i % m)) { + ret += map.get(count).get(i % m); + } + + if (!map.has(count)) { + map.set(count, new Map()); + } + map.get(count).set(i % m, (map.get(count).get(i % m) || 0) + 1); + } + + return ret; +}; + +function Eratosthenes(n) { + const q = Array(n + 1).fill(0); + const primes = []; + + for (let i = 2; i <= Math.sqrt(n); i++) { + if (q[i] === 1) continue; + for (let j = i * 2; j <= n; j += i) { + q[j] = 1; + } + } + + for (let i = 2; i <= n; i++) { + if (q[i] === 0) { + primes.push(i); + } + } + + return primes; +} diff --git a/295-find-median-from-data-stream.js b/295-find-median-from-data-stream.js index 86c11b55..99487161 100644 --- a/295-find-median-from-data-stream.js +++ b/295-find-median-from-data-stream.js @@ -38,3 +38,107 @@ MedianFinder.prototype.findMedian = function() { * obj.addNum(num) * var param_2 = obj.findMedian() */ + +// another + +/** + * initialize your data structure here. + */ +const MedianFinder = function() { + this.minPQ = new PriorityQueue() + this.maxPQ = new PriorityQueue((a, b) => a < b) +}; + +/** + * @param {number} num + * @return {void} + */ +MedianFinder.prototype.addNum = function(num) { + this.minPQ.push(num) + this.maxPQ.push(this.minPQ.pop()) + if(this.minPQ.size() < this.maxPQ.size()) { + this.minPQ.push(this.maxPQ.pop()) + } +}; + +/** + * @return {number} + */ +MedianFinder.prototype.findMedian = function() { + if(this.minPQ.size() > this.maxPQ.size()) return this.minPQ.peek() + else return (this.minPQ.peek() + this.maxPQ.peek()) / 2 +}; + +/** + * Your MedianFinder object will be instantiated and called as such: + * var obj = new MedianFinder() + * obj.addNum(num) + * var param_2 = obj.findMedian() + */ +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/2951-find-the-peaks.js b/2951-find-the-peaks.js new file mode 100644 index 00000000..e564e870 --- /dev/null +++ b/2951-find-the-peaks.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} mountain + * @return {number[]} + */ +var findPeaks = function(mountain) { + const res = [] + const n = mountain.length + for(let i = 1; i < n - 1; i++) { + if(mountain[i] > mountain[i - 1] && mountain[i] > mountain[i + 1]) res.push(i) + } + + return res +}; diff --git a/2952-minimum-number-of-coins-to-be-added.js b/2952-minimum-number-of-coins-to-be-added.js new file mode 100644 index 00000000..a2d2e7d5 --- /dev/null +++ b/2952-minimum-number-of-coins-to-be-added.js @@ -0,0 +1,81 @@ +/** + * @param {number[]} coins + * @param {number} target + * @return {number} + */ +const minimumAddedCoins = function(coins, target) { + coins.sort((a,b) => a - b) + const n = coins.length + let sum = 1, i = 0, res = 0 + while(true) { + const e = coins[i] + if(sum > target) break + if(e <= sum) { + sum += e + i++ + } else { + sum *= 2 + res++ + } + } + return res +}; + +// another + +/** + * @param {number[]} coins + * @param {number} target + * @return {number} + */ +var minimumAddedCoins = function (coins, target) { + coins.sort((a, b) => a - b) + let current_max = 0; + let additions = 0; + let index = 0; + + while (current_max < target) { + if (index < coins.length && coins[index] <= current_max + 1) { + current_max += coins[index]; + index++; + } else { + current_max += current_max + 1; + additions++; + } + } + + return additions; +} + + +// another + +/** + * @param {number[]} coins + * @param {number} target + * @return {number} + */ +var minimumAddedCoins = function (coins, target) { + coins.sort((a, b) => a - b) + let currin = 1 + let res = 0 + + for (let coin of coins) { + while (coin > currin) { + res += 1 + currin *= 2 + } + currin += coin + + if (currin > target) { + break + } + } + + while (currin <= target) { + res += 1 + currin *= 2 + } + + return res +} diff --git a/2953-count-complete-substrings.js b/2953-count-complete-substrings.js new file mode 100644 index 00000000..fedf13a6 --- /dev/null +++ b/2953-count-complete-substrings.js @@ -0,0 +1,139 @@ +/** + * @param {string} word + * @param {number} k + * @return {number} + */ +const countCompleteSubstrings = function(word, k) { + const arr = [], { abs } = Math + const n = word.length + const code = ch => ch.charCodeAt(0) + let i = 0 + if(n === 1) arr.push(word) + for(let j = 1; j < n; j++) { + const pre = j - 1 + if(abs(word[j].charCodeAt(0) - word[pre].charCodeAt(0)) > 2) { + arr.push(word.slice(i, j)) + i = j + } + if(j === n - 1) { + arr.push(word.slice(i)) + } + } + // console.log(arr) + let res = 0 + for(const str of arr) { + if(str === '') continue + res += helper(str) + } + + return res + + + function helper(str) { + let res = 0 + const n = str.length, a = code('a') + + for(let i = 1; i <= 26; i++) { + const len = i * k + const arr = Array(26).fill(0) + let pre = 0 + for(let j = 0; j < len && j < n; j++) { + const idx = code(str[j]) - a + arr[idx]++ + } + if(valid(arr, i)) res++ + + for(let j = len; j < n; j++) { + const idx = code(str[j]) - a + arr[idx]++ + const preIdx = code(str[pre]) - a + arr[preIdx]-- + if(valid(arr, i)) res++ + pre++ + } + } + + return res + } + + function valid(arr, num) { + let cnt = 0 + for(const e of arr) { + if(e === 0) continue + if(e !== k) return false + else cnt++ + } + + if(cnt !== num) return false + return true + } +}; + +// another + + +/** + * @param {string} word + * @param {number} k + * @return {number} + */ +var countCompleteSubstrings = function (word, k) { + let w = word + function calc(s) { + let res = 0; + let v = s.length; + for (let i = 1; i < 27; i++) { + if (i * k > v) break; + let l = i * k; + let len = i * k + let cnt = {}; + for (let j = 0; j < l; j++) { + if (cnt[s[j]] == null) { + cnt[s[j]] = 0; + } + cnt[s[j]]++ + } + let freq = {}; + for (let key in cnt) { + if (freq[cnt[key]] == null) { + freq[cnt[key]] = 0; + } + freq[cnt[key]]++; + } + // console.log(freq) + + if (freq[k] === i) res++; + for (let idx = 0; idx < v - len; idx++) { + if (cnt[s[idx]] == null) cnt[s[idx]] = 0 + if (freq[cnt[s[idx]]] == null) freq[cnt[s[idx]]] = 0 + freq[cnt[s[idx]]]--; + cnt[s[idx]]--; + if (freq[cnt[s[idx]]] == null) freq[cnt[s[idx]]] = 0 + freq[cnt[s[idx]]]++; + + if (cnt[s[idx + len]] == null) cnt[s[idx + len]] = 0 + if (freq[cnt[s[idx + len]]] == null) freq[cnt[s[idx + len]]] = 0 + freq[cnt[s[idx + len]]]--; + cnt[s[idx + len]]++; + if (freq[cnt[s[idx + len]]] == null) freq[cnt[s[idx + len]]] = 0 + freq[cnt[s[idx + len]]]++; + if (freq[k] === i) res++; + } + // console.log(res, freq, cnt) + } + return res; + } + + let idx = 0; + let ans = 0; + let n = w.length; + for (let i = 1; i < n; i++) { + if (Math.abs(w.charCodeAt(i) - w.charCodeAt(i - 1)) > 2) { + ans += calc(w.slice(idx, i)); + idx = i; + } + } + // console.log(ans, idx) + ans += calc(w.slice(idx)); + return ans; +}; diff --git a/2954-count-the-number-of-infection-sequences.js b/2954-count-the-number-of-infection-sequences.js new file mode 100644 index 00000000..86db31f4 --- /dev/null +++ b/2954-count-the-number-of-infection-sequences.js @@ -0,0 +1,228 @@ +const MOD = 1e9 + 7; +const MX = 100000; +const big = BigInt + +const FAC = new Array(MX).fill(0); +const INV_FAC = new Array(MX).fill(0); + +FAC[0] = 1; +for (let i = 1; i < MX; i++) { + FAC[i] = mul(FAC[i - 1], i) % MOD; +} + +INV_FAC[MX - 1] = pow(FAC[MX - 1], MOD - 2); +for (let i = MX - 1; i > 0; i--) { + INV_FAC[i - 1] = mul(INV_FAC[i], i) % MOD; +} + +function comb(n, k) { + return mul(mul(FAC[n], INV_FAC[k]), INV_FAC[n - k]) % MOD; +} +/** + * @param {number} n + * @param {number[]} sick + * @return {number} + */ +var numberOfSequence = function(n, sick) { + const a = sick + const m = a.length; + let total = n - m; + let ans = mul(comb(total, a[0]), comb(total - a[0], n - a[m - 1] - 1)); + total -= a[0] + n - a[m - 1] - 1; + let e = 0; + for (let i = 1; i < m; i++) { + const k = a[i] - a[i - 1] - 1; + if (k > 0) { + e += k - 1; + ans = mul(ans, comb(total, k)); + total -= k; + } + } + return mul(ans, pow(2, e)); +}; + +function pow(x, n) { + + const mod = big(MOD) + let res = 1n; + x = big(x) + while (n > 0) { + if (n % 2 === 1) { + res = (res * x) % mod; + } + x = (x * x) % mod; + n = Math.floor(n / 2); + } + return Number(res); +} + +function mul(a, b) { + return Number(big(a) * big(b) % big(MOD)) +} + +// another + + +//#region Modulo +class Modulo { + /** + * @param {number} modulo + */ + constructor(modulo) { + /** @type {number} @readonly */ + this.modulo = modulo; + } + + /** + * @param {...number} numbers + */ + add(...numbers) { + let result = 0; + for (let number of numbers) { + result = (result + (number % this.modulo)) % this.modulo; + } + + if (result < 0) result += this.modulo; + return result; + } + + /** + * @private + * @param {number} a + * @param {number} b + * @returns {number} + */ + _quickMul(a, b) { + a = ((a % this.modulo) + this.modulo) % this.modulo; + b = ((b % this.modulo) + this.modulo) % this.modulo; + if (a === 0 || b === 0) return 0; + if (Math.log2(a) + Math.log2(b) < 50) return (a * b) % this.modulo; + + let result = 0; + while (b) { + while (b % 2 === 0) { + a = (a * 2) % this.modulo; + b /= 2; + } + + if (b % 2 !== 0) { + result = (result + a) % this.modulo; + b--; + } + } + + return result; + } + + /** + * @param {...number} numbers + */ + mul(...numbers) { + let result = 1; + for (let number of numbers) { + result = this._quickMul(result, number); + if (result === 0) return 0; + } + + if (result < 0) result += this.modulo; + return result; + } + + /** + * @param {number} a + * @param {number} b + * @returns {number} + */ + pow(a, b) { + a = ((a % this.modulo) + this.modulo) % this.modulo; + if (a === 0) return 0; + + let result = 1; + while (b) { + while (b % 2 === 0) { + a = this._quickMul(a, a); + b /= 2; + } + + if (b % 2 !== 0) { + result = this._quickMul(result, a); + b--; + } + } + + return result; + } +} +//#endregion + +//#region Division +/** @private @type {undefined | number} */ +Modulo.prototype._phi = undefined; + +/** + * @returns {number} + */ +Modulo.prototype.getPhi = function () { + if (this._phi !== undefined) return this._phi; + + let result = this.modulo; + let temp = this.modulo; + for (let i = 2; i <= Math.sqrt(temp); i++) { + if (temp % i === 0) { + result /= i; + result *= i - 1; + } + while (temp % i === 0) temp /= i; + } + if (temp > 1) { + result /= temp; + result *= temp - 1; + } + + this._phi = result; + return result; +}; + +/** + * @param {number} a + * @returns {number} + */ +Modulo.prototype.getInverse = function (a) { + return this.pow(a, this.getPhi() - 1); +}; + +/** + * @param {number} a + * @param {number} b + * @returns {number} + */ +Modulo.prototype.div = function (a, b) { + return this._quickMul(a, this.getInverse(b)); +}; +//#endregion + +let mod = new Modulo(1000000007); + +let FACTS = new Uint32Array(100001); +FACTS[0] = 1; +for (let i = 1; i <= 1e5; ++i) FACTS[i] = mod.mul(FACTS[i - 1], i); + +/** + * @param {number} n + * @param {number[]} sick + * @return {number} + */ +var numberOfSequence = function (n, sick) { + let m = sick.length; + let e = FACTS[n - m]; + let d = mod.mul(FACTS[sick[0]], FACTS[n - 1 - sick[m - 1]]); + + for (let i = 1; i < m; ++i) { + let dis = sick[i] - sick[i - 1] - 1; + if (dis <= 1) continue; + e = mod.mul(e, mod.pow(2, dis - 1)); + d = mod.mul(d, FACTS[dis]); + } + + return mod.div(e, d); +}; diff --git a/2957-remove-adjacent-almost-equal-characters.js b/2957-remove-adjacent-almost-equal-characters.js new file mode 100644 index 00000000..f3d6b9b6 --- /dev/null +++ b/2957-remove-adjacent-almost-equal-characters.js @@ -0,0 +1,19 @@ +/** + * @param {string} word + * @return {number} + */ +var removeAlmostEqualCharacters = function(word) { + const n = word.length, { abs } = Math + + let res = 0 + for(let i = 1; i < n;) { + const delta = abs(word.charCodeAt(i) - word.charCodeAt(i - 1)) + if(delta <= 1) { + res++ + i += 2 + } else i++ + + } + + return res +}; diff --git a/2958-length-of-longest-subarray-with-at-most-k-frequency.js b/2958-length-of-longest-subarray-with-at-most-k-frequency.js new file mode 100644 index 00000000..a4688f63 --- /dev/null +++ b/2958-length-of-longest-subarray-with-at-most-k-frequency.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxSubarrayLength = function(nums, k) { + const n = nums.length, cnt = {}, {max} = Math + let i = 0, res = 0 + for(let j = 0; j < n; j++) { + const e = nums[j] + if(cnt[e] == null) cnt[e] = 0 + cnt[e]++ + while(cnt[e] > k) { + const tmp = nums[i] + cnt[tmp]-- + i++ + } + res = Math.max(res, j - i + 1) + } + + return res +}; diff --git a/2959-number-of-possible-sets-of-closing-branches.js b/2959-number-of-possible-sets-of-closing-branches.js new file mode 100644 index 00000000..2c497516 --- /dev/null +++ b/2959-number-of-possible-sets-of-closing-branches.js @@ -0,0 +1,40 @@ +/** + * @param {number} n + * @param {number} maxDistance + * @param {number[][]} roads + * @return {number} + */ +const numberOfSets = function(n, maxDistance, roads) { + let res = 0 + const {min} = Math + for(let i = 0, limit = 1< Array(n).fill(1e9)) + for(const [u,v,w] of roads) { + if( (1 & (i >> u)) && (1 & (i >> v))) { + mat[u][v] = mat[v][u] = min(w, mat[u][v]) + } + } + for(let x = 0; x < n; x++) mat[x][x] = 0 + + for(let k = 0; k < n; k++) { + for(let x = 0; x < n; x++) { + for(let y = 0; y < n; y++) { + mat[x][y] = min(mat[x][y], mat[x][k] + mat[k][y]) + } + } + } + + let tmp = true + for(let x = 0; x < n; x++) { + for(let y = 0; y < n; y++) { + if( (1 & (i >> x)) && (1 & (i >> y))) { + tmp &= mat[x][y] <= maxDistance + } + } + } + + res += tmp ? 1 : 0 + } + + return res +}; diff --git a/296-best-meeting-point.js b/296-best-meeting-point.js new file mode 100644 index 00000000..deceaa09 --- /dev/null +++ b/296-best-meeting-point.js @@ -0,0 +1,97 @@ +/** + +A group of two or more people wants to meet and minimize the total travel distance. +You are given a 2D grid of values 0 or 1, where each 1 marks the home of someone in the group. +The distance is calculated using Manhattan Distance, +where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|. + +Example: + +Input: + +1 - 0 - 0 - 0 - 1 +| | | | | +0 - 0 - 0 - 0 - 0 +| | | | | +0 - 0 - 1 - 0 - 0 + +Output: 6 + +Explanation: Given three people living at (0,0), (0,4), and (2,2): + The point (0,2) is an ideal meeting point, as the total travel distance + of 2+2+2=6 is minimal. So return 6. + +*/ + +/** + * @param {number[][]} grid + * @return {number} + */ +const minTotalDistance = function(grid) { + const m = grid.length + if(!m) return 0 + const n = grid[0].length + const I = [] + const J = [] + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] === 1) I.push(i) + } + } + for(let j = 0; j < n; j++) { + for(let i = 0; i < m; i++) { + if(grid[i][j] === 1) J.push(j) + } + } + return min(I) + min(J) +}; + +function min(arr) { + let i = 0, j = arr.length - 1, sum = 0 + while(i < j) { + sum += arr[j--] - arr[i++] + } + return sum +} + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const minTotalDistance = function (grid) { + const homeArr = [] + const horiArr = [], vertArr = [] + const m = grid.length, + n = grid[0].length + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] === 1) { + homeArr.push([i, j]) + vertArr.push(i) + horiArr.push(j) + } + } + } + + vertArr.sort((a, b) => a - b) + horiArr.sort((a, b) => a - b) + + let y = vertArr[~~(vertArr.length/2)] + let x = horiArr[~~(horiArr.length/2)] + + const center = [y, x] + + let res = 0 + for(const point of homeArr) { + res += dis(center, point) + } + + return res + + function dis(a, b) { + return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]) + } + +} diff --git a/2960-count-tested-devices-after-test-operations.js b/2960-count-tested-devices-after-test-operations.js new file mode 100644 index 00000000..014419e9 --- /dev/null +++ b/2960-count-tested-devices-after-test-operations.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} batteryPercentages + * @return {number} + */ +var countTestedDevices = function(batteryPercentages) { + const arr = batteryPercentages + const n = arr.length + let cnt = 0 + for(let i = 0; i < n; i++) { + const e = Math.max(0, arr[i] - cnt) + if(e > 0) { + cnt++ + } + } + return cnt +}; diff --git a/2961-double-modular-exponentiation.js b/2961-double-modular-exponentiation.js new file mode 100644 index 00000000..a6643495 --- /dev/null +++ b/2961-double-modular-exponentiation.js @@ -0,0 +1,36 @@ +/** + * @param {number[][]} variables + * @param {number} target + * @return {number[]} + */ +var getGoodIndices = function (variables, target) { + const res = [] + let index = 0 + for (let v of variables) { + let a = v[0] + let b = v[1] + let c = v[2] + let m = v[3] + let x = pw(a, b, 10) + let y = pw(x, c, m) + // console.log(y) + if (y === BigInt(target)) { + res.push(index) + } + index++ + } + return res + + function pw(a, b, m) { + let res = 1n + a = BigInt(a) + while (b) { + if (b & 1) { + res = (1n * res * a) % BigInt(m) + } + a = (1n * a * a) % BigInt(m) + b >>= 1 + } + return res + } +} diff --git a/2962-count-subarrays-where-max-element-appears-at-least-k-times.js b/2962-count-subarrays-where-max-element-appears-at-least-k-times.js new file mode 100644 index 00000000..9b4d793f --- /dev/null +++ b/2962-count-subarrays-where-max-element-appears-at-least-k-times.js @@ -0,0 +1,91 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countSubarrays = function (nums, k) { + const n = nums.length + const t = Math.max(...nums) + let i = 0, + num = 0, res = 0 + for (let j = 0; j < n; j++) { + const e = nums[j] + if (e === t) { + num++ + while(num >= k) { + if(nums[i] === t) num-- + i++ + res += n - j + } + } + } + + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const countSubarrays = function (nums, k) { + const n = nums.length + const t = Math.max(...nums) + const cnt = {0: -1} + let i = 0, num = 0 + for(let j = 0; j < n; j++) { + const e = nums[j] + if(e === t) { + num++ + cnt[num] = j + } + } + + let res = 0 + // console.log(cnt) + for(let i = k; i <= num; i++) { + const preLen = cnt[i - k + 1] - cnt[i - k] + const sufLen = n - cnt[i] + res += preLen * sufLen + } + + + return res + } + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var countSubarrays = function (nums, k) { + const n = nums.length + const mx = Math.max(...nums) + const prefix = new Array(n + 2).fill(0) + for (let i = 1; i <= n; i++) { + prefix[i] = prefix[i - 1] + (nums[i - 1] === mx ? 1 : 0) + } + let res = 0 + for (let i = 0; i < n; i++) { + let l = i + let r = n + while (r - l > 1) { + let mid = Math.floor((l + r) / 2) + if (prefix[mid + 1] - prefix[i] < k) { + l = mid + } else { + r = mid + } + } + res += n - i + if (l === i && k === 1 && nums[i] === mx) { + continue + } + res -= l - i + 1 + } + return res +} diff --git a/2963-count-the-number-of-good-partitions.js b/2963-count-the-number-of-good-partitions.js new file mode 100644 index 00000000..4e94ff51 --- /dev/null +++ b/2963-count-the-number-of-good-partitions.js @@ -0,0 +1,74 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const numberOfGoodPartitions = function(nums) { + const n = nums.length, mod = 1e9 + 7, lastIdxHash = {} + let res = 1 + for (let i = 0; i < n; i++) lastIdxHash[nums[i]] = i + let j = 0 + for(let i = 0; i < n; i++) { + if(i > j) res = (res * 2) % mod + j = Math.max(j, lastIdxHash[nums[i]]) + } + + + return res +}; + +// another + +class Interval { + constructor(left, right) { + this.left = left + this.right = right + } +} +/** + * @param {number[]} nums + * @return {number} + */ +var numberOfGoodPartitions = function (nums) { + const mod = BigInt(1000000007) + const mapFst = new Map() + const mapLst = new Map() + + for (let i = 0; i < nums.length; i++) { + const item = nums[i] + if (mapFst.has(item)) { + mapLst.set(item, i) + } else { + mapFst.set(item, i) + } + } + + const l = [] + for (const key of mapLst.keys()) { + l.push(new Interval(mapFst.get(key), mapLst.get(key))) + } + l.sort((a, b) => a.left - b.left) + + const st = [] + for (let i = 0; i < l.length; i++) { + const cur = l[i] + if (st.length === 0) { + st.push(cur) + } else { + const pre = st.pop() + if (cur.left < pre.right) { + st.push(new Interval(pre.left, Math.max(pre.right, cur.right))) + } else { + st.push(pre) + st.push(cur) + } + } + } + + let n = nums.length - 1 + while (st.length > 0) { + const item = st.pop() + n -= item.right - item.left + } + + return BigInt(2) ** BigInt(n) % mod +} diff --git a/2965-find-missing-and-repeated-values.js b/2965-find-missing-and-repeated-values.js new file mode 100644 index 00000000..11c0b988 --- /dev/null +++ b/2965-find-missing-and-repeated-values.js @@ -0,0 +1,20 @@ +/** + * @param {number[][]} grid + * @return {number[]} + */ +var findMissingAndRepeatedValues = function(grid) { + const hash = {}, res = [] + const m = grid.length, n = grid[0].length + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + const e = grid[i][j] + if(hash[e] == null) hash[e] = 0 + hash[e]++ + if(hash[e] === 2) res[0] = e + } + } + for(let i = 1; i <= n * n; i++) { + if(hash[i] == null) res[1] = i + } + return res +}; diff --git a/2966-divide-array-into-arrays-with-max-difference.js b/2966-divide-array-into-arrays-with-max-difference.js new file mode 100644 index 00000000..a6bf20b2 --- /dev/null +++ b/2966-divide-array-into-arrays-with-max-difference.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number[][]} + */ +const divideArray = function(nums, k) { + nums.sort((a, b) => a - b) + const res = [], n = nums.length + for(let i = 2; i < n; i += 3) { + if(nums[i] - nums[i - 2] > k) { + return res + } + } + for(let i = 0; i < n;) { + const tmp = [] + let num = 3 + while(num) { + tmp.push(nums[i]) + i++ + num-- + } + res.push(tmp) + } + return res +}; diff --git a/2967-minimum-cost-to-make-array-equalindromic.js b/2967-minimum-cost-to-make-array-equalindromic.js new file mode 100644 index 00000000..4a4ca258 --- /dev/null +++ b/2967-minimum-cost-to-make-array-equalindromic.js @@ -0,0 +1,95 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minimumCost = function (nums) { + nums.sort((a, b) => a - b) + const n = nums.length + const median = nums[Math.floor(n / 2)] + + // Helper function to find the next palindromic number greater than or equal to x + const getNextPalindromic = (x) => { + while (true) { + const strX = String(x) + const revStrX = strX.split('').reverse().join('') + if (strX === revStrX) return x + x++ + } + } + + // Helper function to find the previous palindromic number smaller than or equal to x + const getPrevPalindromic = (x) => { + while (true) { + const strX = String(x) + const revStrX = strX.split('').reverse().join('') + if (strX === revStrX) return x + x-- + } + } + + const candidate1 = getNextPalindromic(median) + const candidate2 = getPrevPalindromic(median) + + let cost1 = 0 + let cost2 = 0 + + // Calculate the cost for candidate1 + for (const num of nums) { + cost1 += Math.abs(num - candidate1) + } + + // Calculate the cost for candidate2 + for (const num of nums) { + cost2 += Math.abs(num - candidate2) + } + + // Return the minimum cost between candidate1 and candidate2 + return Math.min(cost1, cost2) +} + +// another + + + +/** + * @param {number[]} nums + * @return {number} + */ +var minimumCost = function (nums) { + nums.sort((a, b) => a - b) + let costs = [] + let numbersPalindromic = getPalindromic(nums[Math.floor(nums.length / 2)]) + for (let i = 0; i < numbersPalindromic.length; i++) { + costs.push(caculateCost(nums, numbersPalindromic[i])) + } + return Math.min(...costs) +} + +function getPalindromic(number) { + let numbers = [] + let nextNumber = number + let prevNumber = number + while (numbers.length <= 2) { + if (reverseString(nextNumber.toString()) === nextNumber.toString()) { + numbers.push(nextNumber) + } + if (reverseString(prevNumber.toString()) === prevNumber.toString()) { + numbers.push(prevNumber) + } + nextNumber++ + prevNumber-- + } + return numbers +} + +function caculateCost(nums, palindromic) { + let cost = 0 + for (let i = 0; i < nums.length; i++) { + cost += Math.abs(nums[i] - palindromic) + } + return cost +} + +function reverseString(str) { + return str.split('').reverse().join('') +} diff --git a/2968-apply-operations-to-maximize-frequency-score.js b/2968-apply-operations-to-maximize-frequency-score.js new file mode 100644 index 00000000..a1f407e6 --- /dev/null +++ b/2968-apply-operations-to-maximize-frequency-score.js @@ -0,0 +1,43 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var maxFrequencyScore = function (nums, k) { + nums.sort((a, b) => a - b) + + const n = nums.length + const prefixSum = new Array(n + 1).fill(0) + + for (let i = 0; i < n; ++i) { + prefixSum[i + 1] = prefixSum[i] + nums[i] + } + + let start = 0 + let end = 1 + let maxScore = 1 + + while (end < n) { + ++end + const mid = Math.floor((start + end) / 2) + const target = nums[mid] + let cost = + target * (mid - start) - + (prefixSum[mid] - prefixSum[start]) + + (prefixSum[end] - prefixSum[mid] - target * (end - mid)) + + while (start < end && cost > k) { + ++start + const mid = Math.floor((start + end) / 2) + const target = nums[mid] + cost = + target * (mid - start) - + (prefixSum[mid] - prefixSum[start]) + + (prefixSum[end] - prefixSum[mid] - target * (end - mid)) + } + + maxScore = Math.max(maxScore, end - start) + } + + return maxScore +} diff --git a/2972-count-the-number-of-incremovable-subarrays-ii.js b/2972-count-the-number-of-incremovable-subarrays-ii.js new file mode 100644 index 00000000..e21dcf60 --- /dev/null +++ b/2972-count-the-number-of-incremovable-subarrays-ii.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var incremovableSubarrayCount = function(nums) { + let n = nums.length; + let l = 0; + while (nums[l + 1] > nums[l]) ++l; + if (l + 1 == n) return (n * (n + 1)) / 2; + + let res = l + 2; + let r = n; + do { + --r; + while (l >= 0 && nums[l] >= nums[r]) --l; + res += l + 2 + } + while (nums[r] > nums[r-1]) + + return res; +}; diff --git a/2973-find-number-of-coins-to-place-in-tree-nodes.js b/2973-find-number-of-coins-to-place-in-tree-nodes.js new file mode 100644 index 00000000..a9a5f44e --- /dev/null +++ b/2973-find-number-of-coins-to-place-in-tree-nodes.js @@ -0,0 +1,133 @@ +/** + * @param {number[][]} edges + * @param {number[]} cost + * @return {number[]} + */ +var placedCoins = function (edges, cost) { + let tree = buildRootedTree(buildGraph(cost.length, edges), 0) + let res = Array(cost.length).fill() + + function solve(root) { + let node = tree[root] + let c = cost[root] + + if (c > 0) node.max1 = c + else node.min1 = c + + for (let child of node.aNodes) { + solve(child) + let childNode = tree[child] + opt(node, childNode.max1) + opt(node, childNode.max2) + opt(node, childNode.max3) + opt(node, childNode.min1) + opt(node, childNode.min2) + opt(node, childNode.min3) + } + + let cnt = + !!node.min1 + + !!node.min2 + + !!node.min3 + + !!node.max1 + + !!node.max2 + + !!node.max3 + if (cnt < 3) { + res[root] = 1 + return + } + + res[root] = 0 + let v = node.max1 * node.max2 * node.max3 + if (v > res[root]) res[root] = v + v = node.max1 * node.min1 * node.min2 + if (v > res[root]) res[root] = v + } + + solve(0) + return res +} + +/** + * @typedef {{ aNodes: number[] }} TGraphNode + * @param {number} n + * @param {[number,number,number?][]} edges + * @return {TGraphNode[]} + */ +function buildGraph(n, edges) { + /** @type {TGraphNode[]} */ + let nodes = [] + for (let i = 0; i < n; i++) nodes.push({ aNodes: [] }) + + let m = edges.length + for (let i = 0; i < m; i++) { + let [u, v] = edges[i] + nodes[u].aNodes.push(v) + nodes[v].aNodes.push(u) + } + + return nodes +} + +/** + * @typedef {{ parent: number, min1, min2, min3, max1, max2, max3 }} TTreeNode + * @param {(TGraphNode & TTreeNode)[]} graph + * @param {number} root + * @param {number?} parent + * @return {(TGraphNode & TTreeNode)[]} + */ +function buildRootedTree(graph, root, parent) { + let node = graph[root] + node.parent = parent + + let m = node.aNodes.length + let parentIndex = undefined + for (let i = 0; i < m; i++) { + if (node.aNodes[i] == parent) parentIndex = i + else buildRootedTree(graph, node.aNodes[i], root) + } + + if (parentIndex != undefined) { + node.aNodes[parentIndex] = node.aNodes[m - 1] + node.aNodes.pop() + } + + node.max1 = 0 + node.max2 = 0 + node.max3 = 0 + node.min1 = 0 + node.min2 = 0 + node.min3 = 0 + return graph +} + +/** + * @param {TTreeNode} node + * @param {number} cost + */ +function opt(node, cost) { + if (!cost) return + if (cost > 0) { + if (cost >= node.max1) { + node.max3 = node.max2 + node.max2 = node.max1 + node.max1 = cost + } else if (cost >= node.max2) { + node.max3 = node.max2 + node.max2 = cost + } else if (cost > node.max3) { + node.max3 = cost + } + } else { + if (cost <= node.min1) { + node.min3 = node.min2 + node.min2 = node.min1 + node.min1 = cost + } else if (cost <= node.min2) { + node.min3 = node.min2 + node.min2 = cost + } else if (cost < node.min3) { + node.min3 = cost + } + } +} diff --git a/2974-minimum-number-game.js b/2974-minimum-number-game.js new file mode 100644 index 00000000..81bfdcfb --- /dev/null +++ b/2974-minimum-number-game.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var numberGame = function(nums) { + nums.sort((a, b) => a - b) + const res = [] + for(let i = 0; i < nums.length - 1; i+=2) { + const a = nums[i], b = nums[i + 1] + res.push(b, a) + } + return res +}; diff --git a/2975-maximum-square-area-by-removing-fences-from-a-field.js b/2975-maximum-square-area-by-removing-fences-from-a-field.js new file mode 100644 index 00000000..8cca4a09 --- /dev/null +++ b/2975-maximum-square-area-by-removing-fences-from-a-field.js @@ -0,0 +1,40 @@ +/** + * @param {number} m + * @param {number} n + * @param {number[]} hFences + * @param {number[]} vFences + * @return {number} + */ +const maximizeSquareArea = function (m, n, hFences, vFences) { + hFences.sort((a, b) => a - b) + vFences.sort((a, b) => a - b) + const hSet = new Set(), + vSet = new Set() + + const mod = 10 ** 9 + 7 + + hFences.unshift(1) + hFences.push(m) + vFences.unshift(1) + vFences.push(n) + for (let i = 0; i < vFences.length; i++) { + for (let j = i + 1; j < vFences.length; j++) { + vSet.add(vFences[j] - vFences[i]) + } + } + for (let i = 0; i < hFences.length; i++) { + for (let j = i + 1; j < hFences.length; j++) { + hSet.add(hFences[j] - hFences[i]) + } + } + + let max = -1 + for (const v of vSet) { + if (hSet.has(v)) { + max = Math.max(max, v) + } + } + if (max === -1) return -1 + + return Number((BigInt(max) * BigInt(max)) % BigInt(mod)) +} diff --git a/2976-minimum-cost-to-convert-string-i.js b/2976-minimum-cost-to-convert-string-i.js new file mode 100644 index 00000000..bccec13d --- /dev/null +++ b/2976-minimum-cost-to-convert-string-i.js @@ -0,0 +1,39 @@ +/** + * @param {string} source + * @param {string} target + * @param {character[]} original + * @param {character[]} changed + * @param {number[]} cost + * @return {number} + */ +var minimumCost = function(source, target, original, changed, cost) { + const mat = Array.from({ length: 26 }, () => Array(26).fill(Number.MAX_SAFE_INTEGER)) + const a = 'a'.charCodeAt(0) + const len = cost.length + for(let i = 0; i < len; i++) { + const u = original[i].charCodeAt(0) - a + const v = changed[i].charCodeAt(0) - a + const w = cost[i] + mat[u][v] = Math.min(w, mat[u][v]) + } + for(let i = 0; i < 26; i++) mat[i][i] = 0 + + for(let k = 0; k < 26; k++) { + for(let i = 0; i < 26; i++) { + for(let j = 0; j < 26; j++) { + mat[i][j] = Math.min(mat[i][j], mat[i][k] + mat[k][j]) + } + } + } + + let res = 0 + const n = source.length + for(let i = 0; i < n; i++) { + const u = source[i].charCodeAt(0) - a + const v = target[i].charCodeAt(0) - a + if(mat[u][v] === Number.MAX_SAFE_INTEGER) return -1 + res += mat[u][v] + } + + return res +}; diff --git a/2977-minimum-cost-to-convert-string-ii.js b/2977-minimum-cost-to-convert-string-ii.js new file mode 100644 index 00000000..0d152f85 --- /dev/null +++ b/2977-minimum-cost-to-convert-string-ii.js @@ -0,0 +1,140 @@ +/** + * @param {string} source + * @param {string} target + * @param {string[]} original + * @param {string[]} changed + * @param {number[]} cost + * @return {number} + */ +var minimumCost = function (source, target, original, changed, cost) { + const index = {} + const set = new Set() + for(const e of original) set.add(e) + for(const e of changed) set.add(e) + let idx = 0 + for(const e of set) { + index[e] = idx + idx++ + } + + const n = set.size + const dis = Array.from({ length: n }, () => Array(n).fill(Infinity)) + for(let i = 0; i < original.length; i++) { + const s = index[original[i]], e = index[changed[i]] + dis[s][e] = Math.min(dis[s][e], cost[i]) + } + for(let k = 0; k < n; k++) { + for(let i = 0; i < n; i++) { + if(dis[i][k] === Infinity) continue + for(let j = 0; j < n; j++) { + if(dis[k][j] === Infinity) continue + dis[i][j] = Math.min(dis[i][j], dis[i][k] + dis[k][j]) + } + } + } + const lenSet = new Set() + for(const e of original) lenSet.add(e.length) + const len = source.length + const dp = Array(len + 1).fill(Infinity) + dp[0] = 0 + for(let i = 0; i < len; i++) { + if(dp[i] === Infinity) continue + if(source[i] === target[i]) { + dp[i + 1] = Math.min(dp[i + 1], dp[i]) + } + for(const le of lenSet) { + if(i + le > len) continue + const sub = source.slice(i, i + le) + const subT = target.slice(i, i + le) + const sIdx = index.hasOwnProperty(sub) ? index[sub] : -1 + const tIdx = index.hasOwnProperty(subT) ? index[subT] : -1 + if(sIdx >= 0 && tIdx >= 0 && dis[sIdx][tIdx] !== Infinity) { + dp[i + le] = Math.min(dp[i + le], dp[i] + dis[sIdx][tIdx]) + } + } + } + // console.log(dis,dp) + return dp.at(-1) === Infinity ? -1 : dp.at(-1) +} + +// another + + +/** + * @param {string} source + * @param {string} target + * @param {string[]} original + * @param {string[]} changed + * @param {number[]} cost + * @return {number} + */ +var minimumCost = function (source, target, original, changed, cost) { + const index = {} + original.forEach((o) => { + if (!(o in index)) { + index[o] = Object.keys(index).length + } + }) + changed.forEach((c) => { + if (!(c in index)) { + index[c] = Object.keys(index).length + } + }) + + const n = Object.keys(index).length + const dis = new Array(n) + .fill(null) + .map(() => new Array(n).fill(Number.POSITIVE_INFINITY)) + + for (let i = 0; i < cost.length; ++i) { + dis[index[original[i]]][index[changed[i]]] = Math.min( + dis[index[original[i]]][index[changed[i]]], + cost[i], + ) + } + + for (let k = 0; k < n; ++k) { + for (let i = 0; i < n; ++i) { + if (dis[i][k] < Number.POSITIVE_INFINITY) { + for (let j = 0; j < n; ++j) { + if (dis[k][j] < Number.POSITIVE_INFINITY) { + dis[i][j] = Math.min(dis[i][j], dis[i][k] + dis[k][j]) + } + } + } + } + } + + const substrLengths = new Set(original.map((o) => o.length)) + + const dp = new Array(target.length + 1).fill(Number.POSITIVE_INFINITY) + dp[0] = 0 + + for (let i = 0; i < target.length; ++i) { + if (dp[i] === Number.POSITIVE_INFINITY) { + continue + } + + if (target[i] === source[i]) { + dp[i + 1] = Math.min(dp[i + 1], dp[i]) + } + + for (const t of substrLengths) { + if (i + t >= dp.length) { + continue + } + + const subSource = source.substring(i, i + t) + const subTarget = target.substring(i, i + t) + + const c1 = subSource in index ? index[subSource] : -1 + const c2 = subTarget in index ? index[subTarget] : -1 + + if (c1 >= 0 && c2 >= 0 && dis[c1][c2] < Number.POSITIVE_INFINITY) { + dp[i + t] = Math.min(dp[i + t], dp[i] + dis[c1][c2]) + } + } + } + + return dp[dp.length - 1] !== Number.POSITIVE_INFINITY ? dp[dp.length - 1] : -1 +} diff --git a/298-binary-tree-longest-consecutive-sequence.js b/298-binary-tree-longest-consecutive-sequence.js new file mode 100644 index 00000000..c9c981a3 --- /dev/null +++ b/298-binary-tree-longest-consecutive-sequence.js @@ -0,0 +1,71 @@ +/** + +Given a binary tree, find the length of the longest consecutive sequence path. + +The path refers to any sequence of nodes from some starting node to any node +in the tree along the parent-child connections. +The longest consecutive path need to be from parent to child (cannot be the reverse). + +Example 1: + +Input: + + 1 + \ + 3 + / \ + 2 4 + \ + 5 + +Output: 3 + +Explanation: Longest consecutive sequence path is 3-4-5, so return 3. + +Example 2: + +Input: + + 2 + \ + 3 + / + 2 + / + 1 + +Output: 2 + +Explanation: Longest consecutive sequence path is 2-3, not 3-2-1, so return 2. + +*/ + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const longestConsecutive = function(root) { + const res = { max: 0 } + dfs(root, null, 0, res) + return res.max +}; + +function dfs(node, p, cur, res) { + if(node === null) { + return + } + let s = 0 + if(p === null) s = 1 + else if(node.val - p.val === 1) s = cur + 1 + else s = 1 + if(s > res.max) res.max = s + dfs(node.left, node, s, res) + dfs(node.right, node, s, res) +} diff --git a/2983-palindrome-rearrangement-queries.js b/2983-palindrome-rearrangement-queries.js new file mode 100644 index 00000000..291d8bfe --- /dev/null +++ b/2983-palindrome-rearrangement-queries.js @@ -0,0 +1,70 @@ +function canMakePalindromeQueries(s, queries) { + const n = s.length + // Prefix sum (difference) + const psd = [0] + for (let i = 0, j = n - 1; i < j; i++, j--) { + psd.push(psd[psd.length - 1] + (s[i] !== s[j] ? 1 : 0)) + } + // Prefix sum (count) + const cnt = new Array(26).fill(0) + const psc = [cnt.slice()] + for (const c of s) { + cnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++ + psc.push([...cnt]) + } + const ans = [] + for (const q of queries) { + const a1 = q[0], + b1 = q[1] + 1, + a2 = n - q[0], + b2 = n - 1 - q[1] + const c1 = q[2], + d1 = q[3] + 1, + c2 = n - q[2], + d2 = n - 1 - q[3] + // No difference allowed outside the query ranges + if ( + (min(a1, d2) && psd[min(a1, d2)]) || + (n / 2 > max(b1, c2) && psd[Math.floor(n / 2)] - psd[max(b1, c2)]) || + (d2 > b1 && psd[d2] - psd[b1]) || + (a1 > c2 && psd[a1] - psd[c2]) + ) { + ans.push(false) + } else { + // Intersection of query ranges in the lower half must equate to that in the upper half + const ix1 = psc[d1].map((val, i) => val - (psc[c1][i] || 0)) + const ix2 = psc[b1].map((val, i) => val - (psc[a1][i] || 0)) + if (a1 > d2) { + ix1.forEach( + (val, i) => (ix1[i] -= psc[Math.min(a1, c2)][i] - (psc[d2][i] || 0)), + ) + } + if (c2 > b1) { + ix1.forEach( + (val, i) => (ix1[i] -= psc[c2][i] - (psc[Math.max(b1, d2)][i] || 0)), + ) + } + if (c1 > b2) { + ix2.forEach( + (val, i) => (ix2[i] -= psc[Math.min(c1, a2)][i] - (psc[b2][i] || 0)), + ) + } + if (a2 > d1) { + ix2.forEach( + (val, i) => (ix2[i] -= psc[a2][i] - (psc[Math.max(d1, b2)][i] || 0)), + ) + } + ans.push(ix1.every((val, i) => val >= 0 && val === ix2[i])) + } + } + return ans +} + +// Helper functions +function min(a, b) { + return a < b ? a : b +} + +function max(a, b) { + return a > b ? a : b +} diff --git a/299-bulls-and-cows.js b/299-bulls-and-cows.js new file mode 100644 index 00000000..dd67443e --- /dev/null +++ b/299-bulls-and-cows.js @@ -0,0 +1,54 @@ +/** + * @param {string} secret + * @param {string} guess + * @return {string} + */ +const getHint = function(secret, guess) { + let x = 0, y = 0 + const arr = Array(10).fill(0) + for(let i = 0; i < guess.length; i++) { + const ch = guess[i], e = secret[i] + if(secret[i] === ch) { + x++ + } else { + if(arr[+ch] < 0) y++ + if(arr[+e] > 0) y++ + arr[+ch]++ + arr[+e]-- + } + } + + return `${x}A${y}B` +}; + +// another + +/** + * @param {string} secret + * @param {string} guess + * @return {string} + */ +const getHint = function(secret, guess) { + let bulls = 0 + let cows = 0 + const h = {} + for(let i = 0, len = secret.length; i < len; i++) { + if(secret[i] === guess[i]) { + bulls++ + } else { + if(!h.hasOwnProperty(secret[i])) h[secret[i]] = 0 + h[secret[i]]++ + } + } + + for(let i = 0, len = secret.length; i < len; i++) { + if(secret[i] !== guess[i]) { + if(h.hasOwnProperty(guess[i]) && h[guess[i]] > 0) { + cows++ + h[guess[i]]-- + } + } + } + + return `${bulls}A${cows}B` +}; diff --git a/2999-count-the-number-of-powerful-integers.js b/2999-count-the-number-of-powerful-integers.js new file mode 100644 index 00000000..1a2b8079 --- /dev/null +++ b/2999-count-the-number-of-powerful-integers.js @@ -0,0 +1,54 @@ +/** + * @param {number} num + * @param {number} limit + * @param {string} s + */ +function adjust(num, limit, s) { + let sn = parseInt(s); + let sufMod = 10 ** s.length; + + let suf = num % sufMod; + num = Math.floor(num / sufMod); + if (suf < sn) --num; + + if (num <= 0) return num + 1; + + let sNum = num.toString(); + let res = sNum.charCodeAt(0) - 48; + let tight = 1; + if (res > limit) { + return (limit + 1) ** sNum.length; + } + + for (let i = 1; i < sNum.length; ++i) { + res *= (limit + 1); + + if (tight) { + let c = sNum.charCodeAt(i) - 48; + if (c > limit) { + tight = 0; + res += limit + 1; + } + else { + res += c; + } + } + } + + return res + tight; +} +/** + * @param {number} start + * @param {number} finish + * @param {number} limit + * @param {string} s + * @return {number} + */ +var numberOfPowerfulInt = function (start, finish, limit, s) { + --start; + + let ss = adjust(start, limit, s); + let ff = adjust(finish, limit, s); + + return ff - ss; +}; diff --git a/3-longest-substring-without-repeating-characters.js b/3-longest-substring-without-repeating-characters.js index 1bd9a89c..773dc4ff 100755 --- a/3-longest-substring-without-repeating-characters.js +++ b/3-longest-substring-without-repeating-characters.js @@ -1,3 +1,75 @@ +/** + * @param {string} s + * @return {number} + */ +const lengthOfLongestSubstring = function(s) { + const n = s.length, hash = {} + let res = 0 + let i = -1 + for(j = 0;j < n; j++) { + const e = s[j] + if(hash[e] != null) i = Math.max(i, hash[e]) + hash[e] = j + res = Math.max(res, j - i) + } + + return res +}; + + +// another + +/** + * @param {string} s + * @return {number} + */ +const lengthOfLongestSubstring = function(s) { + if(s.length < 2) return s.length + const hash = {} + let max = 0 + for(let i = 0, j = -1, len = s.length; i < len; i++) { + const cur = s[i] + if(hash[cur] != null) j = Math.max(j, hash[cur]) + + hash[cur] = i + max = Math.max(max, i - j) + } + + return max +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const lengthOfLongestSubstring = function(s) { + const n = s.length, hash = {} + let res = 0 + let l = 0, r = 0 + while(r < n) { + const ch = s[r] + if(hash[ch] == null) hash[ch] = 0 + hash[ch]++ + while(hash[s[l]] > 1) { + hash[s[l]]-- + l++ + } + while(l <= r && Object.keys(hash).length !== r - l + 1) { + hash[s[l]]-- + if(hash[s[l]] === 0) delete hash[s[l]] + l++ + } + res = Math.max(res, r - l + 1) + r++ + } + + return res +}; + +// another + /** * @param {string} s * @return {number} diff --git a/300-longest-increasing-subsequence.js b/300-longest-increasing-subsequence.js index fa2d287b..3d79c6ec 100644 --- a/300-longest-increasing-subsequence.js +++ b/300-longest-increasing-subsequence.js @@ -1,3 +1,27 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const lengthOfLIS = function(nums) { + const stack = [] + for(let e of nums) { + if(stack.length === 0 || e > stack[stack.length - 1]) { + stack.push(e) + continue + } + let l = 0, r = stack.length - 1, mid + while(l < r) { + const mid = l + ((r - l) >> 1) + if(e > stack[mid]) l = mid + 1 + else r = mid + } + stack[l] = e + } + return stack.length +}; + +// another + /** * @param {number[]} nums * @return {number} @@ -22,3 +46,56 @@ const lengthOfLIS = function(nums) { return maxans }; +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const lengthOfLIS = function(nums) { + const n = nums.length + const tails = [] + let res = 0 + for(let e of nums) { + let i = 0, j = res + while(i !== j) { + const mid = i + ((j - i) >> 1) + if(tails[mid] < e) i = mid + 1 + else j = mid + } + tails[i] = e + if(i === res) res++ + } + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const lengthOfLIS = function(nums) { + const n = nums.length, stack = [] + let res = 0 + stack.push(nums[0]) + for(let i = 1; i < n; i++) { + const cur = nums[i] + if(cur > stack[stack.length - 1]) { + stack.push(cur) + } else { + let l = 0, r = stack.length - 1 + while(l < r) { + let mid = ~~((l + r) / 2) + if(stack[mid] < cur) { + l = mid + 1 + } else { + r = mid + } + } + stack[l] = cur + } + } + + return stack.length +}; diff --git a/3007-maximum-number-that-sum-of-the-prices-is-less-than-or-equal-to-k.js b/3007-maximum-number-that-sum-of-the-prices-is-less-than-or-equal-to-k.js new file mode 100644 index 00000000..11d26787 --- /dev/null +++ b/3007-maximum-number-that-sum-of-the-prices-is-less-than-or-equal-to-k.js @@ -0,0 +1,35 @@ +/** + * @param {number} k + * @param {number} x + * @return {number} + */ +var findMaximumNumber = function(k, x) { + let l = 0n; + let r = 10n ** 20n; + + while (l + 1n < r) { + let m = (l + r) >> 1n; + + if (F(Number(m + 1n)) <= k) l = m; + else r = m; + } + + return Number(l); + + function F(m) { + let count = 0; + + for (let i = 1; i < 80; i++) { + let bit = (i * x) - 1; + let S = 1n << BigInt(bit); + let B = BigInt(m) / S; + + count += Number(S) * Math.floor(Number(B) / 2); + if ((Number(B) & 1) === 1) { + count += Number(BigInt(m) % S); + } + } + + return count; + } +}; diff --git a/3008-find-beautiful-indices-in-the-given-array-ii.js b/3008-find-beautiful-indices-in-the-given-array-ii.js new file mode 100644 index 00000000..905ac00b --- /dev/null +++ b/3008-find-beautiful-indices-in-the-given-array-ii.js @@ -0,0 +1,122 @@ +/** + * @param {string} s + * @param {string} a + * @param {string} b + * @param {number} k + * @return {number[]} + */ +var beautifulIndices = function (s, a, b, k) { + const is = kmp(s, a) + if (is.length === 0) return [] + + const js = kmp(s, b) + if (js.length === 0) return [] + + const res = [] + let p = 0 + let q = 0 + + while (p < is.length && q < js.length) { + const distance = Math.abs(is[p] - js[q]) + + if (distance <= k) { + res.push(is[p]) + p++ + } else if (is[p] < js[q]) { + p++ + } else { + q++ + } + } + + return res +} + +function kmp(str1, str2) { + const pattern = buildPattern(str2) + + const res = [] + let i = 0 + let j = 0 + + while (i < str1.length) { + if (str1[i] === str2[j]) { + i++ + j++ + if (j === str2.length) { + res.push(i - str2.length) + j = pattern[j - 1] + } + } else if (j > 0) { + j = pattern[j - 1] + } else { + i++ + } + } + + return res +} + +function buildPattern(str) { + const pattern = new Array(str.length).fill(0) + let i = 1 + let j = 0 + + while (i < str.length) { + if (str[i] === str[j]) { + j++ + pattern[i] = j + i++ + } else if (j > 0) { + j = pattern[j - 1] + } else { + i++ + } + } + + return pattern +} + + +// another + +/** + * @param {string} s + * @param {string} a + * @param {string} b + * @param {number} k + * @return {number[]} + */ +var beautifulIndices = function (s, a, b, k) { + let res = [] + let v1 = [] + let v2 = [] + getPatternMatchingIndex(s, a, v1) + getPatternMatchingIndex(s, b, v2) + for (let i = 0, j = 0; i < v1.length; i++) { + while (j < v2.length && v1[i] > v2[j] && Math.abs(v1[i] - v2[j]) > k) { + j++ + } + if (j < v2.length && Math.abs(v1[i] - v2[j]) <= k) { + res.push(v1[i]) + } + } + return res +} + +function getPatternMatchingIndex(s, a, v) { + let t = a + '@' + s + let lps = [0] + for (let i = 1; i < t.length; i++) { + let ind = lps[i - 1] + while (ind > 0 && t[ind] !== t[i]) { + ind = lps[ind - 1] + } + lps.push(t[ind] === t[i] ? ind + 1 : 0) + } + for (let i = 0; i < lps.length; i++) { + if (lps[i] === a.length) { + v.push(i - 2 * a.length) + } + } +} diff --git a/301-remove-invalid-parentheses.js b/301-remove-invalid-parentheses.js index c587e840..9cb8bdde 100644 --- a/301-remove-invalid-parentheses.js +++ b/301-remove-invalid-parentheses.js @@ -1,3 +1,37 @@ +/** + * @param {string} s + * @return {string[]} + */ +const removeInvalidParentheses = function(s) { + const res = [] + helper(s, 0, 0, ['(', ')']) + return res + + function helper(str, lastI, lastJ, pair) { + let openNum = 0, closeNum = 0 + for(let i = lastI; i < str.length; i++) { + if(str[i] === pair[0]) openNum++ + if(str[i] === pair[1]) closeNum++ + if(closeNum > openNum) { + for(let j = lastJ; j <= i; j++) { + if(str[j] === pair[1] && (j === lastJ || str[j - 1] !== pair[1])) { + helper(str.slice(0, j) + str.slice(j + 1), i, j, pair) + } + } + return + } + } + let rev = str.split('').reverse().join('') + if(pair[0] === '(') { + helper(rev, 0, 0, [')', '(']) + } else { + res.push(rev) + } + } +}; + +// another + /** * @param {string} s * @return {string[]} diff --git a/3013-divide-an-array-into-subarrays-with-minimum-cost-ii.js b/3013-divide-an-array-into-subarrays-with-minimum-cost-ii.js new file mode 100644 index 00000000..8c181741 --- /dev/null +++ b/3013-divide-an-array-into-subarrays-with-minimum-cost-ii.js @@ -0,0 +1,734 @@ +/** + * @param {number[]} nums + * @param {number} k + * @param {number} dist + * @return {number} + */ +var minimumCost = function (nums, k, dist) { + // store k-1 smallest elements + const maxHeap = new PriorityQueue({ compare: (a, b) => b - a }) + // store dist - k + 1 biggest elements + const minHeap = new PriorityQueue({ compare: (a, b) => a - b }) + const maxDiscard = {} + const minDiscard = {} + let sum = nums[0] + let start = 1 + let end = start + while (end - start < k - 1) { + maxHeap.enqueue(nums[end]) + sum += nums[end] + end++ + } + // now there are k-1 elemetns in the Max heap + while (end - start <= dist) { + maxHeap.enqueue(nums[end]) + sum += nums[end] + let dequeued = maxHeap.dequeue() + sum -= dequeued + minHeap.enqueue(dequeued) + end++ + } + + let minSum = sum + while (end < nums.length) { + if (k - 2 === dist) { + sum += nums[end++] + sum -= nums[start++] + } else { + discardMin() + + if (nums[start] < minHeap.front()) { + maxDiscard[nums[start]] = 1 + (maxDiscard[nums[start]] ?? 0) + sum -= nums[start] + + sum += minHeap.front() + maxHeap.enqueue(minHeap.dequeue()) + } else minDiscard[nums[start]] = 1 + (minDiscard[nums[start]] ?? 0) + + maxHeap.enqueue(nums[end]) + sum += nums[end] + + discardMax() + sum -= maxHeap.front() + minHeap.enqueue(maxHeap.dequeue()) + + end++ + start++ + } + minSum = Math.min(minSum, sum) + } + + function discardMax() { + if (maxHeap.isEmpty()) return + + while (maxDiscard[maxHeap.front()]) { + maxDiscard[maxHeap.front()]-- + maxHeap.dequeue() + } + } + function discardMin() { + if (minHeap.isEmpty()) return + + while (minDiscard[minHeap.front()]) { + minDiscard[minHeap.front()]-- + minHeap.dequeue() + } + } + + return minSum +} + +// another + + +//#region AVL Tree +/** + * @typedef {"keep-all" | "override" | "ignore"} DuplicateMode + */ +/** + * @template TItem + * @typedef {(a: TItem, b: TItem) => number} Comparer + */ +/** + * @template TItem + * @typedef {Object} AvlConfigs + * @property {Comparer} comparer + * @property {DuplicateMode} duplicateMode Defines the behavior to add a node when the result of comparer is 0. + * @property {AvlNodesPool} nodesPool Keeping node instances to avoid creating too many AVL Nodes. + */ + +/** + * @template TItem + */ +class AvlNode { + /** @type {AvlNode | undefined} */ + left; + /** @type {AvlNode | undefined} */ + right; + + /** @type {TItem} */ + value; + + /** @type {number} */ + height; + /** @type {number} */ + size; + + /** + * @param {TItem} value + */ + constructor(value) { + this.value = value; + this.height = 1; + this.size = 1; + } + + getBalanceFactor() { + return (this.left?.height ?? 0) - (this.right?.height ?? 0); + } + + recalculateHeight() { + this.height = 1 + Math.max(this.left?.height ?? 0, this.right?.height ?? 0); + } + + recalculateSize() { + this.size = 1 + (this.left?.size ?? 0) + (this.right?.size ?? 0); + } + + dispose() { + delete this.left; + delete this.right; + delete this.height; + delete this.value; + delete this.height; + delete this.size; + } +} + +/** + * @template TItem + */ +class AvlTree { + //#region Constructor + /** + * @param {AvlConfigs} configs + */ + constructor(configs) { + /** @private */ + this._comparer = configs.comparer; + /** @private */ + this._duplicationMode = configs.duplicateMode ?? "keep-all"; + /** @private */ + this._nodesPool = configs.nodesPool; + + /** @private @type {AvlNode | undefined} */ + this._root = undefined; + } + + get size() { + return this._root?.size ?? 0; + } + + /** + * @private + * @param {number} order + * @returns {number} + */ + _adjustOrder(order) { + return ((order % this.size) + this.size) % this.size; + } + + /** + * @private + * @param {AvlNode} parent + * @param {number} parentOrder + */ + _calculateLeftNodeOrder(parent, parentOrder) { + return parentOrder - 1 - (parent?.left?.right?.size ?? 0); + } + + /** + * @private + * @param {AvlNode} parent + * @param {number} parentOrder + */ + _calculateRightNodeOrder(parent, parentOrder) { + return parentOrder + 1 + (parent?.right?.left?.size ?? 0); + } + //#endregion + + //#region Balancing + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _rotateLeft(node) { + let newTop = node.right; + node.right = newTop.left; + newTop.left = node; + + node.recalculateHeight(); + newTop.recalculateHeight(); + node.recalculateSize(); + newTop.recalculateSize(); + return newTop; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _rotateRight(node) { + let newTop = node.left; + node.left = newTop.right; + newTop.right = node; + + node.recalculateHeight(); + newTop.recalculateHeight(); + node.recalculateSize(); + newTop.recalculateSize(); + return newTop; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _rotateDoubleLeft(node) { + let newRight = node.right; + let newTop = newRight.left; + node.right = newTop.left; + newRight.left = newTop.right; + newTop.left = node; + newTop.right = newRight; + + node.recalculateHeight(); + newRight.recalculateHeight(); + newTop.recalculateHeight(); + node.recalculateSize(); + newRight.recalculateSize(); + newTop.recalculateSize(); + return newTop; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _rotateDoubleRight(node) { + let newLeft = node.left; + let newTop = newLeft.right; + node.left = newTop.right; + newLeft.right = newTop.left; + newTop.right = node; + newTop.left = newLeft; + + node.recalculateHeight(); + newLeft.recalculateHeight(); + newTop.recalculateHeight(); + node.recalculateSize(); + newLeft.recalculateSize(); + newTop.recalculateSize(); + return newTop; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _balance(node) { + let bf = node.getBalanceFactor(); + if (bf < -1) { + bf = node.right.getBalanceFactor(); + if (bf < 0) return this._rotateLeft(node); + else return this._rotateDoubleLeft(node); + } else if (bf > 1) { + bf = node.left.getBalanceFactor(); + if (bf > 0) return this._rotateRight(node); + else return this._rotateDoubleRight(node); + } + + return node; + } + //#endregion + + //#region Add + /** + * @private + * @param {TItem} item + * @returns {AvlNode} + */ + _createNode(item) { + if (this._nodesPool) return this._nodesPool.provide(item); + return new AvlNode(item); + } + + /** + * @private + * @param {TItem} item + * @param {AvlNode | undefined} node + * @returns {AvlNode} + */ + _addFromNode(item, node) { + if (!node) return this._createNode(item); + const cmp = this._comparer(item, node.value); + const isToLeftNode = cmp < 0; + + if (cmp == 0) { + switch (this._duplicationMode) { + case "keep-all": + break; + case "override": { + node.value = item; + return node; + } + case "ignore": { + return node; + } + } + } + + if (isToLeftNode) node.left = this._addFromNode(item, node.left); + else node.right = this._addFromNode(item, node.right); + node.recalculateHeight(); + node.recalculateSize(); + return this._balance(node); + } + + /** + * @param {...TItem} items + */ + add(...items) { + for (let i = 0; i < items.length; i++) { + this._root = this._addFromNode(items[i], this._root); + } + } + //#endregion + + //#region Retrieve + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _findLeftMostFromNode(node) { + let res = node; + while (res?.left) res = res.left; + return res; + } + + findLeftMostItem() { + return this._findLeftMostFromNode(this._root)?.value; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _findRightMostFromNode(node) { + let res = node; + while (res?.right) res = res.right; + return res; + } + + findRightMostItem() { + return this._findRightMostFromNode(this._root)?.value; + } + + /** + * @private + * @param {number} order + * @returns {AvlNode} + */ + _getNodeAt(order) { + if (!this.size) return undefined; + + order = this._adjustOrder(order); + let res = this._root; + let leftSize = res; + + while (true) { + leftSize = res.left?.size ?? 0; + if (order === leftSize) return res; + if (order < leftSize) { + res = res.left; + } else { + res = res.right; + order -= leftSize + 1; + } + } + } + + /** + * @param {number} order + * @returns {TItem} + */ + getItemAt(order) { + return this._getNodeAt(order)?.value; + } + + /** + * @param {TItem} item + * @param {number} start + * @returns {number} + */ + findFirstOrder(item, start = 0) { + if (!this.size) return -1; + start = this._adjustOrder(start); + + let node = this._root; + let order = node.left?.size ?? 0; + let res = -1; + + while (node) { + if (order < start) { + order = this._calculateRightNodeOrder(node, order); + node = node.right; + } else { + let cmp = this._comparer(item, node.value); + if (cmp === 0) res = order; + if (cmp <= 0) { + order = this._calculateLeftNodeOrder(node, order); + node = node?.left; + } else { + order = this._calculateRightNodeOrder(node, order); + node = node.right; + } + } + } + + return res; + } + + /** + * @param {TItem} item + * @param {number} end + * @returns {number} + */ + findLastOrder(item, end = -1) { + if (!this.size) return -1; + end = this._adjustOrder(end); + + let node = this._root; + let order = node.left?.size ?? 0; + let res = -1; + + while (node) { + if (order > end) { + order = this._calculateLeftNodeOrder(node, order); + node = node.left; + } else { + let cmp = this._comparer(item, node.value); + if (cmp === 0) res = order; + if (cmp < 0) { + order = this._calculateLeftNodeOrder(node, order); + node = node?.left; + } else { + order = this._calculateRightNodeOrder(node, order); + node = node.right; + } + } + } + + return res; + } + + /** + * @param {TItem} item + * @returns {number} + */ + count(item) { + let first = this.findFirstOrder(item); + if (first === -1) return 0; + let last = this.findLastOrder(item); + return last - first + 1; + } + + /** + * Find the right-est value that can be added to the the left of item + * @param {TItem} item + * @returns {TItem | undefined} + */ + findLeftBound(item) { + let node = this._root; + let res = undefined; + + while (node) { + let cmp = this._comparer(item, node.value); + if (cmp < 0) node = node.left; + else { + res = node.value; + node = node.right; + } + } + + return res; + } + + /** + * Find the left-est value that can be added to the the right of item + * @param {TItem} item + * @returns {TItem | undefined} + */ + findRightBound(item) { + let node = this._root; + let res = undefined; + + while (node) { + let cmp = this._comparer(item, node.value); + if (cmp > 0) node = node.right; + else { + res = node.value; + node = node.left; + } + } + + return res; + } + + /** + * @private + * @param {(item: TItem, order: number) => any} fn + * @param {AvlNode} node + * @param {number} startOrder + */ + _forLeftToRightNode(fn, node, startOrder) { + if (!node) return; + this._forLeftToRightNode(fn, node.left, startOrder); + fn(node.value, startOrder + (node.left?.size ?? 0)); + this._forLeftToRightNode( + fn, + node.right, + startOrder + (node.left?.size ?? 0) + 1 + ); + } + /** + * @param {(item: TItem, order: number) => any} fn + */ + forLeftToRight(fn) { + this._forLeftToRightNode(fn, this._root, 0); + } + + /** + * @private + * @param {(item: TItem, order: number) => any} fn + * @param {AvlNode} node + * @param {number} startOrder + */ + _forRightToLeftNode(fn, node, startOrder) { + if (!node) return; + this._forRightToLeftNode(fn, node.right, startOrder); + fn(node.value, startOrder - (node.right?.size ?? 0)); + this._forRightToLeftNode( + fn, + node.left, + startOrder - (node.right?.size ?? 0) - 1 + ); + } + + /** + * @param {(item: TItem, order: number) => any} fn + */ + forRightToLeft(fn) { + this._forRightToLeftNode(fn, this._root, this.size - 1); + } + //#endregion + + //#region Remove + /** + * @private + * @param {AvlNode} node + */ + _destroyNode(node) { + if (this._nodesPool) this._nodesPool.return(node); + else node.dispose(); + } + + /** + * @private + * @param {TItem} item + * @param {AvlNode | undefined} node + * @returns {AvlNode} + */ + _removeFromNode(item, node) { + if (!node) return node; + + const cmp = this._comparer(item, node.value); + if (cmp < 0) node.left = this._removeFromNode(item, node.left); + else if (cmp > 0) node.right = this._removeFromNode(item, node.right); + else { + if (!node.left) { + let child = node.right; + this._destroyNode(node); + return child; + } + if (!node.right) { + let child = node.left; + this._destroyNode(node); + return child; + } + + let leftMostOfRight = this._findLeftMostFromNode(node.right); + node.value = leftMostOfRight.value; + node.right = this._removeFromNode(leftMostOfRight.value, node.right); + } + node.recalculateHeight(); + node.recalculateSize(); + return this._balance(node); + } + + /** + * @param {...TItem} items + */ + remove(...items) { + for (let i = 0; i < items.length; i++) { + this._root = this._removeFromNode(items[i], this._root); + } + } + + /** + * @param {AvlNode} node + */ + _clearFromNode(node) { + if (!node) return; + if (node.left) this._clearFromNode(node.left); + if (node.right) this._clearFromNode(node.right); + this._destroyNode(node); + } + + clear() { + if (!this._root) return; + this._clearFromNode(this._root); + delete this._root; + } + //#endregion +} +//#endregion + +//#region AVL Nodes Pool +class AvlNodesPool { + /** + * @private + * @type {AvlNode[]} + */ + _nodes = []; + /** + * @private + * @type {number} + */ + _top = 0; + + provide(value) { + if (this._top) { + let result = this._nodes[--this._top]; + result.value = value; + result.left = null; + result.right = null; + result.size = 1; + result.height = 1; + return result; + } + return new AvlNode(value); + } + + /** + * @param {AvlNode} node + */ + return(node) { + if (this._top === this._nodes.length) this._nodes.push(node); + else this._nodes[this._top] = node; + this._top++; + } +} +//#endregion + +let avl = new AvlTree({ + comparer: (a, b) => a - b, + duplicateMode: "keep-all", + nodesPool: new AvlNodesPool(), +}); + +/** + * @param {number[]} nums + * @param {number} k + * @param {number} dist + * @return {number} + */ +var minimumCost = function (nums, k, dist) { + let n = nums.length; + avl.clear(); + + let sum = 0; + for (let i = 1; i < k; ++i) { + sum += nums[i]; + avl.add(nums[i]); + } + let res = sum; + + for (let i = k; i < n; ++i) { + avl.add(nums[i]); + let p = avl.findLastOrder(nums[i]); + if (p < k - 1) { + sum += nums[i]; + sum -= avl.getItemAt(k - 1); + } + if (i - dist > 1) { + p = avl.findLastOrder(nums[i - dist - 1]); + avl.remove(nums[i - dist - 1]); + if (p < k - 1) { + sum -= nums[i - dist - 1]; + sum += avl.getItemAt(k - 2); + } + } + + res = Math.min(res, sum); + } + + return res + nums[0]; +}; diff --git a/3017-count-the-number-of-houses-at-a-certain-distance-ii.js b/3017-count-the-number-of-houses-at-a-certain-distance-ii.js new file mode 100644 index 00000000..d4561058 --- /dev/null +++ b/3017-count-the-number-of-houses-at-a-certain-distance-ii.js @@ -0,0 +1,26 @@ +/** + * @param {number} n + * @param {number} x + * @param {number} y + * @return {number[]} + */ +var countOfPairs = function (n, x, y) { + if (x > y) { + ;[x, y] = [y, x] + } + const res = new Array(n).fill(0) + for (let i = 1; i <= n; ++i) { + res[0] += 2 // go left and right + res[Math.min(i - 1, Math.abs(i - y) + x)]-- // reach 1 then stop + res[Math.min(n - i, Math.abs(i - x) + 1 + n - y)]-- // reach n then stop + res[Math.min(Math.abs(i - x), Math.abs(y - i) + 1)]++ // reach x then split + res[Math.min(Math.abs(i - x) + 1, Math.abs(y - i))]++ // reach y then split + let r = Math.max(x - i, 0) + Math.max(i - y, 0) + res[r + Math.floor((y - x) / 2)]-- // i -> x -> y <- x + res[r + Math.floor((y - x + 1) / 2)]-- // i -> y -> x <- y + } + for (let i = 1; i < n; ++i) { + res[i] += res[i - 1] + } + return res +} diff --git a/3019-number-of-changing-keys.js b/3019-number-of-changing-keys.js new file mode 100644 index 00000000..0d18c3a5 --- /dev/null +++ b/3019-number-of-changing-keys.js @@ -0,0 +1,12 @@ +/** + * @param {string} s + * @return {number} + */ +var countKeyChanges = function(s) { + const ss = s.toLowerCase() + let res = 0 + for(let i = 1;i < ss.length; i++) { + if(ss[i] !== ss[i - 1]) res++ + } + return res +}; diff --git a/302-smallest-rectangle-enclosing-black-pixels.js b/302-smallest-rectangle-enclosing-black-pixels.js new file mode 100644 index 00000000..7c085de5 --- /dev/null +++ b/302-smallest-rectangle-enclosing-black-pixels.js @@ -0,0 +1,74 @@ +/** + * @param {character[][]} image + * @param {number} x + * @param {number} y + * @return {number} + */ +const minArea = function(image, x, y) { + const m = image.length, + n = image[0].length; + const left = searchColumns(0, y, 0, m, true); + const right = searchColumns(y + 1, n, 0, m, false); + const top = searchRows(0, x, left, right, true); + const bottom = searchRows(x + 1, m, left, right, false); + return (right - left) * (bottom - top); + function searchColumns(i, j, top, bottom, opt) { + while (i != j) { + let k = top, + mid = ((i + j) >> 1); + while (k < bottom && image[k][mid] === "0") ++k; + if (k < bottom === opt) j = mid; + else i = mid + 1; + } + return i; + } + function searchRows(i, j, left, right, opt) { + while (i != j) { + let k = left, + mid = ((i + j) >> 1); + while (k < right && image[mid][k] === "0") ++k; + if (k < right === opt) j = mid; + else i = mid + 1; + } + return i; + } +}; + +// another + +/** + * @param {character[][]} image + * @param {number} x + * @param {number} y + * @return {number} + */ +const minArea = function(image, x, y) { + let top = x, + bottom = x + let left = y, + right = y + function dfs(x, y) { + if ( + x < 0 || + y < 0 || + x >= image.length || + y >= image[0].length || + image[x][y] === '0' + ) + return + image[x][y] = '0' + top = Math.min(top, x) + bottom = Math.max(bottom, x) + left = Math.min(left, y) + right = Math.max(right, y) + dfs(x + 1, y) + dfs(x - 1, y) + dfs(x, y - 1) + dfs(x, y + 1) + } + + if (image.length === 0 || image[0].length === 0) return 0 + dfs(x, y) + return (right - left + 1) * (bottom - top + 1) +} + diff --git a/3020-find-the-maximum-number-of-elements-in-subset.js b/3020-find-the-maximum-number-of-elements-in-subset.js new file mode 100644 index 00000000..d2d6f16f --- /dev/null +++ b/3020-find-the-maximum-number-of-elements-in-subset.js @@ -0,0 +1,62 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maximumLength = function (nums) { + const um = new Map() + + for (const val of nums) { + if (um.has(val)) { + um.set(val, um.get(val) + 1) + } else { + um.set(val, 1) + } + } + + if (um.size === 1) { + return 1 + } + + let cnt = 0 + let res = 1 + + for (const [key, value] of um) { + // .5 = 1/2 which is square root + let fnd = Math.pow(key, 0.5) + cnt = 1 + + // yha condition greate than equal 2 isiliye rkha + // to avoid the infinite loop as use calculator + // and find root(2)->root(root(2))...so on + // it will never end + while (fnd >= 2) { + if (um.has(fnd)) { + if (um.get(fnd) >= 2) { + cnt += 2 + } else { + break + } + fnd = Math.pow(fnd, 0.5) + } else { + break + } + } + + res = Math.max(res, cnt) + cnt = 0 + } + + let maxi = 0 + if (um.has(1)) { + maxi = um.get(1) + } + + if (maxi > ans) { + if (maxi & 1) { + return maxi + } + return maxi - 1 + } + + return res +} diff --git a/3021-alice-and-bob-playing-flower-game.js b/3021-alice-and-bob-playing-flower-game.js new file mode 100644 index 00000000..b201a348 --- /dev/null +++ b/3021-alice-and-bob-playing-flower-game.js @@ -0,0 +1,22 @@ +/** + * @param {number} n + * @param {number} m + * @return {number} + */ +var flowerGame = function(n, m) { + let res = 0 + let oddNum = 0, evenNum = 0 + let oddNum1 = 0, evenNum1 = 0 + for(let i = 1; i <= n; i++) { + if(i % 2 === 1) oddNum++ + else evenNum++ + } + for(let i = 1; i <= m; i++) { + if(i % 2 === 1) oddNum1++ + else evenNum1++ + } + res += oddNum * evenNum1 + res += evenNum * oddNum1 + + return res +}; diff --git a/3022-minimize-or-of-remaining-elements-using-operations.js b/3022-minimize-or-of-remaining-elements-using-operations.js new file mode 100644 index 00000000..d72db393 --- /dev/null +++ b/3022-minimize-or-of-remaining-elements-using-operations.js @@ -0,0 +1,70 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minOrAfterOperations = function(nums, k) { + let n = nums.length; //length of the array + let res = 0; //this will contain the 'or' of all final elements of array + + //Iterating from MSB to LSB + for (let j = 30; j >= 0; j--) + { + let cnt = 0; //count of elements which have 0 at jth bit + + //we will do & of all elements and store it here in 'cur' variable + let cur = (1 << 30) - 1; //this is basically all last 30 bits set to 1 + + let target = res | ((1 << j) - 1); //jth bit is set 0 here, and bits from 0 to (j-1)th index are set to 1 + + for (let x of nums) + { + cur &= x; + if ((cur | target) == target) + { + cnt++; + cur = (1 << 30) - 1; + } + } + + //we have to keep the jth bit if (n-cnt) is greater than k otherwise we can remove jth bit in less than or equal to k operations + if (n - cnt > k) + { + res |= (1 << j); + } + } + return res; +}; + + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minOrAfterOperations = function(nums, k) { + const n = nums.length; + let ans = 0; + + for (let j = 30; j >= 0; j--) { + let cnt = 0; + let cur = (1 << 30) - 1; + let target = ans | ((1 << j) - 1); + + for (let i = 0; i < n; i++) { + cur &= nums[i]; + if ((cur | target) === target) { + cnt++; + cur = (1 << 30) - 1; + } + } + + if (n - cnt > k) { + ans |= (1 << j); + } + } + + return ans; +}; diff --git a/3027-find-the-number-of-ways-to-place-people-ii.js b/3027-find-the-number-of-ways-to-place-people-ii.js new file mode 100644 index 00000000..088053d5 --- /dev/null +++ b/3027-find-the-number-of-ways-to-place-people-ii.js @@ -0,0 +1,25 @@ +/** + * @param {number[][]} points + * @return {number} + */ +var numberOfPairs = function(points) { + points.sort((a, b) => { + if (a[0] === b[0]) return b[1] - a[1]; + return a[0] - b[0]; + }); + + let solution = 0; + for (let i = 0; i < points.length; i++) { + let c = points[i]; + let currentMax = -Infinity; + for (let j = i + 1; j < points.length; j++) { + let t = points[j]; + if (c[1] < t[1]) continue; + if (currentMax >= t[1]) continue; + currentMax = Math.max(currentMax, t[1]); + solution++; + } + } + + return solution; +}; diff --git a/3031-minimum-time-to-revert-word-to-initial-state-ii.js b/3031-minimum-time-to-revert-word-to-initial-state-ii.js new file mode 100644 index 00000000..6906f960 --- /dev/null +++ b/3031-minimum-time-to-revert-word-to-initial-state-ii.js @@ -0,0 +1,20 @@ +/** + * @param {string} word + * @param {number} k + * @return {number} + */ +var minimumTimeToInitialState = function(word, k) { + const n = word.length; + let v = 0; + let dp = new Array(n).fill(0); + for (let i = 1; i < n; i++) { + while (v > 0 && word.charAt(i) != word.charAt(v)) { + v = dp[v - 1]; + } + v = dp[i] = v + (word.charAt(i) == word.charAt(v) ? 1 : 0); + } + while (v > 0 && (n - v) % k > 0) { + v = dp[v - 1]; + } + return Math.ceil((n - v) / k); +}; diff --git a/304-range-sum-query-2d-immutable.js b/304-range-sum-query-2d-immutable.js index 9613134f..8333a777 100644 --- a/304-range-sum-query-2d-immutable.js +++ b/304-range-sum-query-2d-immutable.js @@ -40,3 +40,37 @@ NumMatrix.prototype.sumRegion = function(row1, col1, row2, col2) { * var obj = Object.create(NumMatrix).createNew(matrix) * var param_1 = obj.sumRegion(row1,col1,row2,col2) */ + +// another + +/** + * @param {number[][]} matrix + */ +const NumMatrix = function(matrix) { + const m = matrix.length, n = matrix[0].length + const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)) + 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] - dp[i - 1][j - 1] + matrix[i - 1][j - 1] + } + } + this.dp = dp +}; + +/** + * @param {number} row1 + * @param {number} col1 + * @param {number} row2 + * @param {number} col2 + * @return {number} + */ +NumMatrix.prototype.sumRegion = function(row1, col1, row2, col2) { + const dp = this.dp + return dp[row2 + 1][col2 + 1] - dp[row2 + 1][col1] - dp[row1][col2 + 1] + dp[row1][col1] +}; + +/** + * Your NumMatrix object will be instantiated and called as such: + * var obj = new NumMatrix(matrix) + * var param_1 = obj.sumRegion(row1,col1,row2,col2) + */ diff --git a/3041-maximize-consecutive-elements-in-an-array-after-modification.js b/3041-maximize-consecutive-elements-in-an-array-after-modification.js new file mode 100644 index 00000000..f18f6a25 --- /dev/null +++ b/3041-maximize-consecutive-elements-in-an-array-after-modification.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maxSelectedElements = function (nums) { + let dp = new Uint32Array(1e6 + 2) + let n = nums.length + nums.sort((a, b) => a - b) + + dp.fill(0, 0, nums[n - 1] + 1) + let res = 1 + for (let i = 0; i < n; ++i) { + let x = nums[i] + dp[x + 1] = dp[x] + 1 + dp[x] = dp[x - 1] + 1 + res = Math.max(res, dp[x], dp[x + 1]) + } + + return res +} diff --git a/3042-count-prefix-and-suffix-pairs-i.js b/3042-count-prefix-and-suffix-pairs-i.js new file mode 100644 index 00000000..576bdace --- /dev/null +++ b/3042-count-prefix-and-suffix-pairs-i.js @@ -0,0 +1,23 @@ +/** + * @param {string[]} words + * @return {number} + */ +var countPrefixSuffixPairs = function (words) { + let count = 0 + for (let i = 0; i < words.length; i++) { + for (let j = i + 1; j < words.length; j++) { + let str1 = words[i] + let str2 = words[j] + if (isPrefixAndSuffix(str1, str2)) { + count++ + } + } + } + return count + function isPrefixAndSuffix(s1, s2) { + if (s2.startsWith(s1) && s2.endsWith(s1)) { + return true + } + return false + } +} diff --git a/3043-find-the-length-of-the-longest-common-prefix.js b/3043-find-the-length-of-the-longest-common-prefix.js new file mode 100644 index 00000000..266ae19a --- /dev/null +++ b/3043-find-the-length-of-the-longest-common-prefix.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number} + */ +var longestCommonPrefix = function (arr1, arr2) { + let f = new Set() + for (let i of arr1) { + for (; i > 0; i = Math.floor(i / 10)) { + f.add(i) + } + } + let res = 0 + for (let i of arr2) { + for (; i > 0; i = Math.floor(i / 10)) { + if (f.has(i)) { + res = Math.max(res, i.toString().length) + break + } + } + } + return res +} diff --git a/3044-most-frequent-prime.js b/3044-most-frequent-prime.js new file mode 100644 index 00000000..8b7fde30 --- /dev/null +++ b/3044-most-frequent-prime.js @@ -0,0 +1,61 @@ +/** + * @param {number[][]} mat + * @return {number} + */ +var mostFrequentPrime = function (mat) { + const DIRS = [ + [1, 1], + [1, -1], + [-1, 1], + [-1, -1], + [1, 0], + [0, 1], + [-1, 0], + [0, -1], + ] + + const m = mat.length + const n = mat[0].length + const f = new Map() + + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + for (const d of DIRS) { + let t = 0 + for ( + let k = i, l = j; + k >= 0 && k < m && l >= 0 && l < n; + k += d[0], l += d[1] + ) { + t = t * 10 + mat[k][l] + f.set(t, (f.get(t) || 0) + 1) + } + } + } + } + + let res = -1 + let maxF = 0 + + for (const [val, freq] of f.entries()) { + if (val <= 10) continue + if (freq >= maxF && isPrime(val)) { + if (freq === maxF) { + res = Math.max(res, val) + } else { + res = val + } + maxF = freq + } + } + + return res +} +function isPrime(N) { + if (N < 2) return false + const R = Math.sqrt(N) + for (let d = 2; d <= R; ++d) { + if (N % d === 0) return false + } + return true +} diff --git a/3045-count-prefix-and-suffix-pairs-ii.js b/3045-count-prefix-and-suffix-pairs-ii.js new file mode 100644 index 00000000..ace89667 --- /dev/null +++ b/3045-count-prefix-and-suffix-pairs-ii.js @@ -0,0 +1,59 @@ +class Trie { + constructor() { + this.word = null + this.children = new Array(27) + this.cnt = 0 + } +} +/** + * @param {string[]} words + * @return {number} + */ +var countPrefixSuffixPairs = function (words) { + const M = 31 + let rt1 = new Trie() + let rt2 = new Trie() + let res = 0 + + for (let w of words) { + res += addAndCount(w) + } + + return res + + function addAndCount(w) { + let res = 0 + let pre = rt1 + let suf = rt2 + let n = w.length + + for (let i = 0; i < n; i++) { + let a = w.charAt(i) + let b = w.charAt(n - 1 - i) + + if (!pre.children[a.charCodeAt() & M]) { + pre.children[a.charCodeAt() & M] = new Trie() + } + if (!suf.children[b.charCodeAt() & M]) { + suf.children[b.charCodeAt() & M] = new Trie() + } + + pre = pre.children[a.charCodeAt() & M] + suf = suf.children[b.charCodeAt() & M] + + if (pre.word && suf.word === pre.word) { + res += pre.cnt + } + } + + if (!pre.word) { + pre.word = w + suf.word = w + } + + pre.cnt++ + suf.cnt++ + + return res + } +} diff --git a/3048-earliest-second-to-mark-indices-i.js b/3048-earliest-second-to-mark-indices-i.js new file mode 100644 index 00000000..1b9a33f0 --- /dev/null +++ b/3048-earliest-second-to-mark-indices-i.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums + * @param {number[]} changeIndices + * @return {number} + */ +var earliestSecondToMarkIndices = function(nums, changeIndices) { + let isPossible = function (mid) { + let last = new Uint16Array(nums.length); + for (let i = 0; i <= mid; ++i) last[changeIndices[i]] = i; + + let count = 0, marked = 0; + for (let i = 0; i <= mid; ++i) { + if (last[changeIndices[i]] === i) { + count -= nums[changeIndices[i]]; + if (count < 0) return false; + ++marked; + } else { + ++count; + } + } + return marked === nums.length; + }; + + changeIndices = changeIndices.map((x) => x - 1); + let l = 0, r = changeIndices.length - 1; + while (l < r) { + let mid = (l + r) >> 1; + isPossible(mid) ? r = mid : l = mid + 1; + } + return isPossible(l) ? l + 1 : -1; +}; diff --git a/3049-earliest-second-to-mark-indices-ii.js b/3049-earliest-second-to-mark-indices-ii.js new file mode 100644 index 00000000..cd88f7d4 --- /dev/null +++ b/3049-earliest-second-to-mark-indices-ii.js @@ -0,0 +1,93 @@ +function heapfy_up(heap, current) { + if (current == 1) return + let parent = current >> 1 + if (heap[current] < heap[parent]) { + ;[heap[parent], heap[current]] = [heap[current], heap[parent]] + heapfy_up(heap, parent) + } +} + +function heapfy_down(heap, current) { + let left = current << 1 + let right = (current << 1) + 1 + let min = current + if (left < heap.length && heap[left] < heap[min]) min = left + if (right < heap.length && heap[right] < heap[min]) min = right + if (min != current) { + ;[heap[min], heap[current]] = [heap[current], heap[min]] + heapfy_down(heap, min) + } +} + +function heap_pop(heap) { + ;[heap[1], heap[heap.length - 1]] = [heap[heap.length - 1], heap[1]] + heap.pop() + heapfy_down(heap, 1) +} + +function heap_push(heap, num) { + heap.push(num) + heapfy_up(heap, heap.length - 1) +} + +/** + * @param {number[]} nums + * @param {number[]} changeIndices + * @return {number} + */ +var earliestSecondToMarkIndices = function (nums, changeIndices) { + const search = function (ceil) { + let heap = [0] + let set = new Set() + let is_first = new Array(ceil).fill(false) + for (let i = 0; i <= ceil - 1; i++) { + if (set.has(changeIndices[i])) continue + else { + set.add(changeIndices[i]) + is_first[i] = true + } + } + + for (let i = ceil - 1; i >= 0; i--) { + let max_size = (ceil - i + 1) >> 1 + if (nums[changeIndices[i] - 1] == 0) continue + if (is_first[i] == false) continue + if (heap.length - 1 < max_size) { + heap_push(heap, nums[changeIndices[i] - 1]) + continue + } else { + if (heap[1] < nums[changeIndices[i] - 1]) { + heap_pop(heap) + heap_push(heap, nums[changeIndices[i] - 1]) + continue + } + } + } + + let days_on_hand = ceil + 1 - heap.length + 1 + let days_need = nums.length + for (let num of nums) days_need += num + for (let i = 1; i <= heap.length - 1; i++) { + days_need -= heap[i] + } + + if (days_need > days_on_hand) return -1 + else return 1 + } + + let r = changeIndices.length - 1 + let l = nums.length - 1 + if (search(r) == -1) return -1 + + while (l < r) { + let mid = (l + r) >> 1 + let res = search(mid) + if (res == -1) { + l = mid + 1 + } else { + r = mid + } + } + + return l + 1 +} diff --git a/305-number-of-islands-ii.js b/305-number-of-islands-ii.js new file mode 100644 index 00000000..2002e476 --- /dev/null +++ b/305-number-of-islands-ii.js @@ -0,0 +1,91 @@ +/** + +A 2d grid map of m rows and n columns is initially filled with water. +We may perform an addLand operation which turns the water at position (row, col) into a land. +Given a list of positions to operate, count the number of islands after each addLand operation. +An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. +You may assume all four edges of the grid are all surrounded by water. + +Example: + +Input: m = 3, n = 3, positions = [[0,0], [0,1], [1,2], [2,1]] +Output: [1,1,2,3] +Explanation: + +Initially, the 2d grid grid is filled with water. (Assume 0 represents water and 1 represents land). + +0 0 0 +0 0 0 +0 0 0 +Operation #1: addLand(0, 0) turns the water at grid[0][0] into a land. + +1 0 0 +0 0 0 Number of islands = 1 +0 0 0 +Operation #2: addLand(0, 1) turns the water at grid[0][1] into a land. + +1 1 0 +0 0 0 Number of islands = 1 +0 0 0 +Operation #3: addLand(1, 2) turns the water at grid[1][2] into a land. + +1 1 0 +0 0 1 Number of islands = 2 +0 0 0 +Operation #4: addLand(2, 1) turns the water at grid[2][1] into a land. + +1 1 0 +0 0 1 Number of islands = 3 +0 1 0 + +*/ + +/** + * @param {number} m + * @param {number} n + * @param {number[][]} positions + * @return {number[]} + */ +const numIslands2 = function(m, n, positions) { + const result = [] + if (m <= 0 || n <= 0) return result + const dirs = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0] + ] + let count = 0 + const roots = new Array(m * n).fill(-1) + for (let p of positions) { + let root = n * p[0] + p[1] + if (roots[root] !== -1) { + result.push(count) + continue + } + roots[root] = root + count++ + for (let dir of dirs) { + const x = p[0] + dir[0] + const y = p[1] + dir[1] + const nb = n * x + y + if (x < 0 || x >= m || y < 0 || y >= n || roots[nb] === -1) continue + const rootNb = findIsland(roots, nb) + if (root !== rootNb) { + roots[root] = rootNb + root = rootNb + count-- + } + } + result.push(count) + } + return result +} + +function findIsland(roots, id) { + while (id !== roots[id]) { + roots[id] = roots[roots[id]] + id = roots[id] + } + return id +} diff --git a/306-additive-number.js b/306-additive-number.js new file mode 100644 index 00000000..29879f49 --- /dev/null +++ b/306-additive-number.js @@ -0,0 +1,54 @@ +/** + +Additive number is a string whose digits can form additive sequence. +A valid additive sequence should contain at least three numbers. +Except for the first two numbers, each subsequent number in the sequence must be the sum of the preceding two. +Given a string containing only digits '0'-'9', write a function to determine if it's an additive number. +Note: Numbers in the additive sequence cannot have leading zeros, so sequence 1, 2, 03 or 1, 02, 3 is invalid. + +Example 1: + +Input: "112358" +Output: true +Explanation: The digits can form an additive sequence: 1, 1, 2, 3, 5, 8. + 1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8 + +Example 2: + +Input: "199100199" +Output: true +Explanation: The additive sequence is: 1, 99, 100, 199. + 1 + 99 = 100, 99 + 100 = 199 + +Constraints: + +num consists only of digits '0'-'9'. +1 <= num.length <= 35 + +*/ + +/** + * @param {string} num + * @return {boolean} + */ +const isAdditiveNumber = function(num) { + const n = num.length + for (let i = 1; i <= (n / 2) >> 0; ++i) { + if (num.charAt(0) === '0' && i > 1) return false + const x1 = +num.slice(0, i) + for (let j = 1; Math.max(j, i) <= n - i - j; ++j) { + if (num.charAt(i) == '0' && j > 1) break + const x2 = +num.slice(i, i + j) + if (isValid(x1, x2, j + i, num)) return true + } + } + return false +} + +function isValid(x1, x2, start, num) { + if (start === num.length) return true + x2 = x2 + x1 + x1 = x2 - x1 + const sum = x2 + '' + return num.startsWith(sum, start) && isValid(x1, x2, start + sum.length, num) +} diff --git a/3069-distribute-elements-into-two-arrays-i.js b/3069-distribute-elements-into-two-arrays-i.js new file mode 100644 index 00000000..966a77aa --- /dev/null +++ b/3069-distribute-elements-into-two-arrays-i.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var resultArray = function(nums) { + const n = nums.length + const a1 = [], a2 = [] + a1.push(nums[0]) + a2.push(nums[1]) + for(let i = 2; i < n; i++) { + const e = nums[i] + const l1 = a1[a1.length - 1], l2 = a2[a2.length - 1] + if(l1 > l2) { + a1.push(e) + } else { + a2.push(e) + } + } + + return a1.concat(a2) +}; diff --git a/307-range-sum-query-mutable.js b/307-range-sum-query-mutable.js index 8c64848f..faff27c5 100644 --- a/307-range-sum-query-mutable.js +++ b/307-range-sum-query-mutable.js @@ -1,3 +1,68 @@ +const lowBit = (x) => x & -x +class FenwickTree { + constructor(n) { + if (n < 1) return + this.sum = Array(n + 1).fill(0) + } + update(i, delta) { + if (i < 1) return + while (i < this.sum.length) { + this.sum[i] += delta + i += lowBit(i) + } + } + query(i) { + if (i < 1) return 0 + let sum = 0 + while (i > 0) { + sum += this.sum[i] + i -= lowBit(i) + } + return sum + } +} + +/** + * @param {number[]} nums + */ +var NumArray = function(nums) { + this.nums = nums + const n = nums.length + this.bit = new FenwickTree(n) + for(let i = 1; i <= n; i++) { + this.bit.update(i, nums[i - 1]) + } +}; + +/** + * @param {number} index + * @param {number} val + * @return {void} + */ +NumArray.prototype.update = function(index, val) { + const delta = val - this.nums[index] + this.nums[index] = val + this.bit.update(index + 1, delta) +}; + +/** + * @param {number} left + * @param {number} right + * @return {number} + */ +NumArray.prototype.sumRange = function(left, right) { + return this.bit.query(right + 1) - this.bit.query(left) +}; + +/** + * Your NumArray object will be instantiated and called as such: + * var obj = new NumArray(nums) + * obj.update(index,val) + * var param_2 = obj.sumRange(left,right) + */ + +// another + /** * @param {number[]} nums */ diff --git a/3070-count-submatrices-with-top-left-element-and-sum-less-than-k.js b/3070-count-submatrices-with-top-left-element-and-sum-less-than-k.js new file mode 100644 index 00000000..f451b12f --- /dev/null +++ b/3070-count-submatrices-with-top-left-element-and-sum-less-than-k.js @@ -0,0 +1,26 @@ +/** + * @param {number[][]} grid + * @param {number} k + * @return {number} + */ +var countSubmatrices = function (grid, k) { + const n = grid.length + const m = grid[0].length + const acc = new Array(m + 1).fill(0) + + let res = 0 + for (let i = 0; i < n; i++) { + const tmp = new Array(m + 1).fill(0) + for (let j = 0; j < m; j++) { + tmp[j + 1] = tmp[j] + grid[i][j] + } + + for (let j = 0; j < m; j++) { + acc[j + 1] += tmp[j + 1] + if (acc[j + 1] <= k) { + res += 1 + } + } + } + return res +} diff --git a/3071-minimum-operations-to-write-the-letter-y-on-a-grid.js b/3071-minimum-operations-to-write-the-letter-y-on-a-grid.js new file mode 100644 index 00000000..3caf484f --- /dev/null +++ b/3071-minimum-operations-to-write-the-letter-y-on-a-grid.js @@ -0,0 +1,44 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var minimumOperationsToWriteY = function (grid) { + const mapY = new Map() + const mapNotY = new Map() + const n = grid.length + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + let inY = false + if (i <= n / 2) { + if (i === j || i + j === n - 1) { + inY = true + } + } else { + if (j === Math.floor(n / 2)) { + inY = true + } + } + + const item = grid[i][j] + if (inY) { + mapY.set(item, (mapY.get(item) || 0) + 1) + } else { + mapNotY.set(item, (mapNotY.get(item) || 0) + 1) + } + } + } + const countY = n + Math.floor(n / 2) + const countNotY = n * n - countY + let res = Infinity + for (let a = 0; a <= 2; a++) { + for (let b = 0; b <= 2; b++) { + if (a === b) continue + const tmp1 = mapY.get(a) || 0 + const tmp2 = mapNotY.get(b) || 0 + + const tmp = countY - tmp1 + (countNotY - tmp2) + res = Math.min(res, tmp) + } + } + return res +} diff --git a/3072-distribute-elements-into-two-arrays-ii.js b/3072-distribute-elements-into-two-arrays-ii.js new file mode 100644 index 00000000..96356a43 --- /dev/null +++ b/3072-distribute-elements-into-two-arrays-ii.js @@ -0,0 +1,750 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const resultArray = function(nums) { + const n = nums.length + const a1 = [nums[0]], a2 = [nums[1]], a1s = [nums[0]], a2s = [nums[1]] + for(let i = 2; i < n; i++) { + const e = nums[i] + const [gc1, s1] = bs(a1s, e) + const [gc2, s2] = bs(a2s, e) + if(gc1 > gc2) { + a1.push(e) + a1s.splice(s1, 0, e) + } else if(gc1 < gc2) { + a2.push(e) + a2s.splice(s2, 0, e) + } else if(a1.length > a2.length) { + a2.push(e) + a2s.splice(s2, 0, e) + } else { + a1.push(e) + a1s.splice(s1, 0, e) + } + } + + return [...a1, ...a2] + + function bs(arr, val) { + const n = arr.length + let l = 0, r = n - 1 + while(l < r) { + const mid = Math.floor((l + r) / 2) + if(arr[mid] > val) r = mid + else l = mid + 1 + } + if(arr[l] <= val) l++ + return [n - l, l] + } +}; + +// another + +const binarySearch = function (arr, val) { + let start = 0, + end = arr.length - 1 + while (start < end) { + const mid = Math.floor((start + end) / 2) + if (arr[mid] > val) { + end = mid + } else { + start = mid + 1 + } + } + if (arr[start] <= val) { + start++; + } + return [arr.length - start, start] +} + +/** + * @param {number[]} nums + * @return {number[]} + */ +const resultArray = function(nums) { + const arr1 = [nums[0]], + arr2 = [nums[1]] + let sortedArr1 = [nums[0]], + sortedArr2 = [nums[1]] + for (let i = 2; i < nums.length; i++) { + const n = nums[i], + [gc1, s1] = binarySearch(sortedArr1, n), + [gc2, s2] = binarySearch(sortedArr2, n) + if (gc1 > gc2) { + arr1.push(n) + sortedArr1.splice(s1, 0, n) + } else if (gc2 > gc1) { + arr2.push(n) + sortedArr2.splice(s2, 0, n) + } else if (arr2.length < arr1.length){ + arr2.push(n) + sortedArr2.splice(s2, 0, n) + } else { + arr1.push(n) + sortedArr1.splice(s1, 0, n) + } + } + return [...arr1, ...arr2] +}; + +// another + + +//#region AVL Tree +/** + * @typedef {"keep-all" | "override" | "ignore"} DuplicateMode + */ +/** + * @template TItem + * @typedef {(a: TItem, b: TItem) => number} Comparer + */ +/** + * @template TItem + * @typedef {Object} AvlConfigs + * @property {Comparer} comparer + * @property {DuplicateMode} duplicateMode Defines the behavior to add a node when the result of comparer is 0. + * @property {AvlNodesPool} nodesPool Keeping node instances to avoid creating too many AVL Nodes. + */ + +/** + * @template TItem + */ +class AvlNode { + /** @type {AvlNode | undefined} */ + left; + /** @type {AvlNode | undefined} */ + right; + + /** @type {TItem} */ + value; + + /** @type {number} */ + height; + /** @type {number} */ + size; + + /** + * @param {TItem} value + */ + constructor(value) { + this.value = value; + this.height = 1; + this.size = 1; + } + + getBalanceFactor() { + return (this.left?.height ?? 0) - (this.right?.height ?? 0); + } + + recalculateHeight() { + this.height = 1 + Math.max(this.left?.height ?? 0, this.right?.height ?? 0); + } + + recalculateSize() { + this.size = 1 + (this.left?.size ?? 0) + (this.right?.size ?? 0); + } + + dispose() { + delete this.left; + delete this.right; + delete this.height; + delete this.value; + delete this.height; + delete this.size; + } +} + +/** + * @template TItem + */ +class AvlTree { + //#region Constructor + /** + * @param {AvlConfigs} configs + */ + constructor(configs) { + /** @private */ + this._comparer = configs.comparer; + /** @private */ + this._duplicationMode = configs.duplicateMode ?? "keep-all"; + /** @private */ + this._nodesPool = configs.nodesPool; + + /** @private @type {AvlNode | undefined} */ + this._root = undefined; + } + + get size() { + return this._root?.size ?? 0; + } + + /** + * @private + * @param {number} order + * @returns {number} + */ + _adjustOrder(order) { + return ((order % this.size) + this.size) % this.size; + } + + /** + * @private + * @param {AvlNode} parent + * @param {number} parentOrder + */ + _calculateLeftNodeOrder(parent, parentOrder) { + return parentOrder - 1 - (parent?.left?.right?.size ?? 0); + } + + /** + * @private + * @param {AvlNode} parent + * @param {number} parentOrder + */ + _calculateRightNodeOrder(parent, parentOrder) { + return parentOrder + 1 + (parent?.right?.left?.size ?? 0); + } + //#endregion + + //#region Balancing + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _rotateLeft(node) { + let newTop = node.right; + node.right = newTop.left; + newTop.left = node; + + node.recalculateHeight(); + newTop.recalculateHeight(); + node.recalculateSize(); + newTop.recalculateSize(); + return newTop; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _rotateRight(node) { + let newTop = node.left; + node.left = newTop.right; + newTop.right = node; + + node.recalculateHeight(); + newTop.recalculateHeight(); + node.recalculateSize(); + newTop.recalculateSize(); + return newTop; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _rotateDoubleLeft(node) { + let newRight = node.right; + let newTop = newRight.left; + node.right = newTop.left; + newRight.left = newTop.right; + newTop.left = node; + newTop.right = newRight; + + node.recalculateHeight(); + newRight.recalculateHeight(); + newTop.recalculateHeight(); + node.recalculateSize(); + newRight.recalculateSize(); + newTop.recalculateSize(); + return newTop; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _rotateDoubleRight(node) { + let newLeft = node.left; + let newTop = newLeft.right; + node.left = newTop.right; + newLeft.right = newTop.left; + newTop.right = node; + newTop.left = newLeft; + + node.recalculateHeight(); + newLeft.recalculateHeight(); + newTop.recalculateHeight(); + node.recalculateSize(); + newLeft.recalculateSize(); + newTop.recalculateSize(); + return newTop; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _balance(node) { + let bf = node.getBalanceFactor(); + if (bf < -1) { + bf = node.right.getBalanceFactor(); + if (bf < 0) return this._rotateLeft(node); + else return this._rotateDoubleLeft(node); + } else if (bf > 1) { + bf = node.left.getBalanceFactor(); + if (bf > 0) return this._rotateRight(node); + else return this._rotateDoubleRight(node); + } + + return node; + } + //#endregion + + //#region Add + /** + * @private + * @param {TItem} item + * @returns {AvlNode} + */ + _createNode(item) { + if (this._nodesPool) return this._nodesPool.provide(item); + return new AvlNode(item); + } + + /** + * @private + * @param {TItem} item + * @param {AvlNode | undefined} node + * @returns {AvlNode} + */ + _addFromNode(item, node) { + if (!node) return this._createNode(item); + const cmp = this._comparer(item, node.value); + const isToLeftNode = cmp < 0; + + if (cmp == 0) { + switch (this._duplicationMode) { + case "keep-all": + break; + case "override": { + node.value = item; + return node; + } + case "ignore": { + return node; + } + } + } + + if (isToLeftNode) node.left = this._addFromNode(item, node.left); + else node.right = this._addFromNode(item, node.right); + node.recalculateHeight(); + node.recalculateSize(); + return this._balance(node); + } + + /** + * @param {TItem} item + */ + add(item) { + this._root = this._addFromNode(item, this._root); + } + //#endregion + + //#region Retrieve + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _findLeftMostFromNode(node) { + let res = node; + while (res?.left) res = res.left; + return res; + } + + findLeftMostItem() { + return this._findLeftMostFromNode(this._root)?.value; + } + + /** + * @private + * @param {AvlNode} node + * @returns {AvlNode} + */ + _findRightMostFromNode(node) { + let res = node; + while (res?.right) res = res.right; + return res; + } + + findRightMostItem() { + return this._findRightMostFromNode(this._root)?.value; + } + + /** + * @private + * @param {number} order + * @returns {AvlNode} + */ + _getNodeAt(order) { + if (!this.size) return undefined; + + order = this._adjustOrder(order); + let res = this._root; + let leftSize = res; + + while (true) { + leftSize = res.left?.size ?? 0; + if (order === leftSize) return res; + if (order < leftSize) { + res = res.left; + } else { + res = res.right; + order -= leftSize + 1; + } + } + } + + /** + * @param {number} order + * @returns {TItem} + */ + getItemAt(order) { + return this._getNodeAt(order)?.value; + } + + /** + * @param {TItem} item + * @param {number} start + * @returns {number} + */ + findFirstOrder(item, start = 0) { + if (!this.size) return -1; + start = this._adjustOrder(start); + + let node = this._root; + let order = node.left?.size ?? 0; + let res = -1; + + while (node) { + if (order < start) { + order = this._calculateRightNodeOrder(node, order); + node = node.right; + } else { + let cmp = this._comparer(item, node.value); + if (cmp === 0) res = order; + if (cmp <= 0) { + order = this._calculateLeftNodeOrder(node, order); + node = node?.left; + } else { + order = this._calculateRightNodeOrder(node, order); + node = node.right; + } + } + } + + return res; + } + + /** + * @param {TItem} item + * @param {number} end + * @returns {number} + */ + findLastOrder(item, end = -1) { + if (!this.size) return -1; + end = this._adjustOrder(end); + + let node = this._root; + let order = node.left?.size ?? 0; + let res = -1; + + while (node) { + if (order > end) { + order = this._calculateLeftNodeOrder(node, order); + node = node.left; + } else { + let cmp = this._comparer(item, node.value); + if (cmp === 0) res = order; + if (cmp < 0) { + order = this._calculateLeftNodeOrder(node, order); + node = node?.left; + } else { + order = this._calculateRightNodeOrder(node, order); + node = node.right; + } + } + } + + return res; + } + + /** + * @param {TItem} item + * @returns {number} + */ + count(item) { + let first = this.findFirstOrder(item); + if (first === -1) return 0; + let last = this.findLastOrder(item); + return last - first + 1; + } + + /** + * Find the right-est value that can be added to the the left of item + * @param {TItem} item + * @returns {TItem | undefined} + */ + findLeftBound(item) { + let node = this._root; + let res = undefined; + + while (node) { + let cmp = this._comparer(item, node.value); + if (cmp < 0) node = node.left; + else { + res = node.value; + node = node.right; + } + } + + return res; + } + + /** + * Find the left-est value that can be added to the the right of item + * @param {TItem} item + * @returns {TItem | undefined} + */ + findRightBound(item) { + let node = this._root; + let res = undefined; + + while (node) { + let cmp = this._comparer(item, node.value); + if (cmp > 0) node = node.right; + else { + res = node.value; + node = node.left; + } + } + + return res; + } + + /** + * @private + * @param {(item: TItem, order: number) => any} fn + * @param {AvlNode} node + * @param {number} startOrder + */ + _forLeftToRightNode(fn, node, startOrder) { + if (!node) return; + this._forLeftToRightNode(fn, node.left, startOrder); + fn(node.value, startOrder + (node.left?.size ?? 0)); + this._forLeftToRightNode( + fn, + node.right, + startOrder + (node.left?.size ?? 0) + 1 + ); + } + /** + * @param {(item: TItem, order: number) => any} fn + */ + forLeftToRight(fn) { + this._forLeftToRightNode(fn, this._root, 0); + } + + /** + * @private + * @param {(item: TItem, order: number) => any} fn + * @param {AvlNode} node + * @param {number} startOrder + */ + _forRightToLeftNode(fn, node, startOrder) { + if (!node) return; + this._forRightToLeftNode(fn, node.right, startOrder); + fn(node.value, startOrder - (node.right?.size ?? 0)); + this._forRightToLeftNode( + fn, + node.left, + startOrder - (node.right?.size ?? 0) - 1 + ); + } + + /** + * @param {(item: TItem, order: number) => any} fn + */ + forRightToLeft(fn) { + this._forRightToLeftNode(fn, this._root, this.size - 1); + } + //#endregion + + //#region Remove + /** + * @private + * @param {AvlNode} node + */ + _destroyNode(node) { + if (this._nodesPool) this._nodesPool.return(node); + else node.dispose(); + } + + /** + * @private + * @param {TItem} item + * @param {AvlNode | undefined} node + * @returns {AvlNode} + */ + _removeFromNode(item, node) { + if (!node) return node; + + const cmp = this._comparer(item, node.value); + if (cmp < 0) node.left = this._removeFromNode(item, node.left); + else if (cmp > 0) node.right = this._removeFromNode(item, node.right); + else { + if (!node.left) { + let child = node.right; + this._destroyNode(node); + return child; + } + if (!node.right) { + let child = node.left; + this._destroyNode(node); + return child; + } + + let leftMostOfRight = this._findLeftMostFromNode(node.right); + node.value = leftMostOfRight.value; + node.right = this._removeFromNode(leftMostOfRight.value, node.right); + } + node.recalculateHeight(); + node.recalculateSize(); + return this._balance(node); + } + + /** + * @param {TItem} item + */ + remove(item) { + this._root = this._removeFromNode(item, this._root); + } + + /** + * @param {AvlNode} node + */ + _clearFromNode(node) { + if (!node) return; + if (node.left) this._clearFromNode(node.left); + if (node.right) this._clearFromNode(node.right); + this._destroyNode(node); + } + + clear() { + if (!this._root) return; + this._clearFromNode(this._root); + delete this._root; + } + //#endregion +} +//#endregion + +//#region AVL Nodes Pool +class AvlNodesPool { + /** + * @private + * @type {AvlNode[]} + */ + _nodes = []; + /** + * @private + * @type {number} + */ + _top = 0; + + provide(value) { + if (this._top) { + let result = this._nodes[--this._top]; + result.value = value; + result.left = null; + result.right = null; + result.size = 1; + result.height = 1; + return result; + } + return new AvlNode(value); + } + + /** + * @param {AvlNode} node + */ + return(node) { + if (this._top === this._nodes.length) this._nodes.push(node); + else this._nodes[this._top] = node; + this._top++; + } +} +//#endregion + +let pool = new AvlNodesPool(); +let avl1 = new AvlTree({ + comparer: (a, b) => b - a, + duplicateMode: "keep-all", + nodesPool: pool, +}); +let avl2 = new AvlTree({ + comparer: (a, b) => b - a, + duplicateMode: "keep-all", + nodesPool: pool, +}); +let addTo1 = new Uint8Array(1e5); + +/** + * @param {number[]} nums + * @return {number[]} + */ +var resultArray = function (nums) { + let n = nums.length; + avl1.clear(); + avl2.clear(); + + addTo1[0] = 1; + avl1.add(nums[0]); + addTo1[1] = 0; + avl2.add(nums[1]); + + for (let i = 2; i < n; ++i) { + let b1 = avl1.findLeftBound(nums[i] + 1); + b1 = b1 == null ? 0 : avl1.findLastOrder(b1) + 1; + let b2 = avl2.findLeftBound(nums[i] + 1); + b2 = b2 == null ? 0 : avl2.findLastOrder(b2) + 1; + + addTo1[i] = b1 > b2 || (b1 == b2 && avl1.size <= avl2.size); + if (addTo1[i]) { + avl1.add(nums[i]); + } else { + avl2.add(nums[i]); + } + } + + let res = new Uint32Array(n); + let l = 0; + let r = avl1.size; + for (let i = 0; i < n; ++i) { + if (addTo1[i]) { + res[l++] = nums[i]; + } else { + res[r++] = nums[i]; + } + } + + return res; +}; diff --git a/3074-apple-redistribution-into-boxes.js b/3074-apple-redistribution-into-boxes.js new file mode 100644 index 00000000..37b7dc67 --- /dev/null +++ b/3074-apple-redistribution-into-boxes.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} apple + * @param {number[]} capacity + * @return {number} + */ +var minimumBoxes = function(apple, capacity) { + const sum = apple.reduce((ac, e) => ac+ e, 0) + capacity.sort((a, b) => b - a) + let res = 0 + let remain = sum, i = 0 + while(remain > 0) { + res++ + remain -= capacity[i] + i++ + } + + return res +}; diff --git a/3075-maximize-happiness-of-selected-children.js b/3075-maximize-happiness-of-selected-children.js new file mode 100644 index 00000000..2b02155d --- /dev/null +++ b/3075-maximize-happiness-of-selected-children.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} happiness + * @param {number} k + * @return {number} + */ +var maximumHappinessSum = function(happiness, k) { +happiness.sort((a, b) => b - a) +let ans = 0 +for (let i = 0; i < k; i++) { + ans += Math.max(happiness[i] - i, 0) +} +return ans +}; diff --git a/3076-shortest-uncommon-substring-in-an-array.js b/3076-shortest-uncommon-substring-in-an-array.js new file mode 100644 index 00000000..5f202f58 --- /dev/null +++ b/3076-shortest-uncommon-substring-in-an-array.js @@ -0,0 +1,163 @@ +/** + * @param {string[]} arr + * @return {string[]} + */ +const shortestSubstrings = function (arr) { + const root = new Node() + const res = [] + for (const s of arr) { + for (let i = 0; i < s.length; ++i) { + add(root, s, i) + } + } + for (const s of arr) { + const tmpRoot = new Node() + let resStr = s + s + for (let i = 0; i < s.length; ++i) { + add(tmpRoot, s, i) + } + + for (let i = 0; i < s.length; ++i) { + const t = check(root, tmpRoot, s, i) + if ( + t.length < resStr.length || + (t.length === resStr.length && t < resStr) + ) { + resStr = t + } + } + res.push(resStr.length <= s.length ? resStr : "") + } + + return res + function add(node, str, start) { + let ptr = node + for (let i = start; i < str.length; ++i) { + const c = str.charCodeAt(i) - "a".charCodeAt(0) + if (ptr.child[c] === null) ptr.child[c] = new Node() + ptr = ptr.child[c] + ptr.count++ + } + } + function check(root, node, str, start) { + let ptr1 = root + let ptr2 = node + let res = "" + for (let i = start; i < str.length; ++i) { + const chIdx = str.charCodeAt(i) - "a".charCodeAt(0) + res += str[i] + ptr1 = ptr1.child[chIdx] + ptr2 = ptr2.child[chIdx] + if (ptr1.count === ptr2.count) return res + } + return str + str + } +} +class Node { + constructor() { + this.child = new Array(26).fill(null) + this.count = 0 + } +} + +// another + +/** + * @param {string[]} arr + * @return {string[]} + */ +const shortestSubstrings = function (arr) { + const ans = [] + const head = new Node() + for (const s of arr) { + for (let i = 0; i < s.length; ++i) add(head, s, i) + } + for (const s of arr) { + let res = s + s + for (let i = 0; i < s.length; ++i) remove(head, s, i) + for (let i = 0; i < s.length; ++i) { + const t = check(head, s, i) + if (t.length < res.length || (t.length === res.length && t < res)) res = t + } + ans.push(res.length <= s.length ? res : "") + // add back the current string to the trie + for (let i = 0; i < s.length; ++i) add(head, s, i) + } + return ans + + function add(head, s, ind) { + let ptr = head + for (let i = ind; i < s.length; ++i) { + const c = s.charCodeAt(i) - "a".charCodeAt(0) + if (ptr.child[c] === null) ptr.child[c] = new Node() + ptr = ptr.child[c] + ptr.count++ + } + } + + function remove(head, s, ind) { + let ptr = head + for (let i = ind; i < s.length; ++i) { + ptr = ptr.child[s.charCodeAt(i) - "a".charCodeAt(0)] + ptr.count-- + } + } + + function check(head, s, ind) { + let ptr = head + let ans = "" + for (let i = ind; i < s.length; ++i) { + const c = s.charCodeAt(i) - "a".charCodeAt(0) + if (ptr.child[c] === null) return ans + ans += s[i] + ptr = ptr.child[c] + if (ptr.count < 1) return ans + } + return s + s + } +} + +class Node { + constructor() { + this.child = new Array(26).fill(null) + this.count = 0 + } +} + +// another + + +/** + * @param {string[]} arr + * @return {string[]} + */ +var shortestSubstrings = function(arr) { +function* gen(s) { + const s_len = s.length + for (let i = 0; i < s_len; i++) { + for (let j = i; j < s_len; j++) { + yield s.slice(i, j + 1) + } + } +} + +const ans = [] +const n = arr.length +for (let i = 0; i < n; i++) { + const cur_s = arr[i] + let cur_ans = null + for (const s of gen(cur_s)) { + if (arr.filter((_, j) => j !== i).every((str) => !str.includes(s))) { + if (cur_ans === null) { + cur_ans = s + } else if (s.length < cur_ans.length) { + cur_ans = s + } else if (s.length === cur_ans.length && s < cur_ans) { + cur_ans = s + } + } + } + ans.push(cur_ans || '') +} +return ans +}; diff --git a/3077-maximum-strength-of-k-disjoint-subarrays.js b/3077-maximum-strength-of-k-disjoint-subarrays.js new file mode 100644 index 00000000..b37816ec --- /dev/null +++ b/3077-maximum-strength-of-k-disjoint-subarrays.js @@ -0,0 +1,94 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumStrength = function(nums, k) { + const n = nums.length; + let dp = new Array(n + 1).fill(0); + + for (let i = 0; i < k; i++) { + let m = k - i; + m = (i % 2 === 0) ? m : -m; + const nextdp = new Array(n + 1).fill(-Infinity); + for (let j = 1; j <= n; j++) { + nextdp[j] = Math.max(nextdp[j-1], dp[j-1]) + nums[j-1] * m; + } + dp = nextdp; + for (let j = 1; j <= n; j++) { + dp[j] = Math.max(dp[j-1], dp[j]); + } + } + return dp[n]; +}; + + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumStrength = function(nums, k) { + let dp = new Array(k + 1).fill(0).map(() => new Array(nums.length + 1).fill(0)); + + for (let i = 1; i <= k; i++) { + let maxSum = Number.MIN_SAFE_INTEGER / 2; + let curr = Number.MIN_SAFE_INTEGER / 2; + let multiplier = (i % 2 === 1) ? (k + 1 - i) : (i - 1 - k); + + for (let j = i - 1; j < nums.length; j++) { + curr = Math.max(curr + nums[j] * multiplier, dp[i - 1][j] + nums[j] * multiplier); + maxSum = Math.max(maxSum, curr); + dp[i][j + 1] = maxSum; + } + } + + return dp[k][nums.length]; +}; + + + +// another + +let pre = Array(10001).fill(0); +let cur = Array(10001).fill(0); +let ps = Array(10001).fill(0); + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var maximumStrength = function (nums, k) { + let n = nums.length; + + ps[0] = 0; + for (let i = 0; i < n; ++i) { + ps[i + 1] = ps[i] + nums[i]; + } + + ++n; + cur.fill(0, 0, n); + + for (let i = 1; i <= k; ++i) { + let tem = pre; + pre = cur; + cur = tem; + + let t = 1 + k - i; + if (!(i & 1)) t = -t; + + let m = pre[i - 1] - ps[i - 1] * t; + cur[i] = ps[i] * t + m; + m = Math.max(m, pre[i] - ps[i] * t); + + for (let j = i + 1; j < n; ++j) { + cur[j] = Math.max(cur[j - 1], ps[j] * t + m); + m = Math.max(m, pre[j] - ps[j] * t); + } + } + + return cur[n - 1]; +}; diff --git a/308-range-sum-query-2d-mutable.js b/308-range-sum-query-2d-mutable.js new file mode 100644 index 00000000..183b4e31 --- /dev/null +++ b/308-range-sum-query-2d-mutable.js @@ -0,0 +1,68 @@ +/** + * @param {number[][]} matrix + */ +const NumMatrix = function(matrix) { + this.matrix = matrix + if (matrix.length === 0) { + this.sums = [] + } else { + this.sums = new Array(matrix.length + 1) + .fill() + .map(() => new Array(matrix[0].length + 1).fill(0)) + } + this.insert = (i, j, diff) => { + for (let n = i; n < this.sums.length; n += n & -n) { + for (let m = j; m < this.sums[n].length; m += m & -m) { + this.sums[n][m] += diff + } + } + } + this.search = (i, j) => { + let sum = 0 + for (let n = i; n > 0; n -= n & -n) { + for (let m = j; m > 0; m -= m & -m) { + sum += this.sums[n][m] + } + } + return sum + } + for (let n = 0; n < matrix.length; n++) { + for (let m = 0; m < matrix[n].length; m++) { + this.insert(n + 1, m + 1, matrix[n][m]) + } + } +} + +/** + * @param {number} row + * @param {number} col + * @param {number} val + * @return {void} + */ +NumMatrix.prototype.update = function(row, col, val) { + this.insert(row + 1, col + 1, val - this.matrix[row][col]) + this.matrix[row][col] = val +} + +/** + * @param {number} row1 + * @param {number} col1 + * @param {number} row2 + * @param {number} col2 + * @return {number} + */ +NumMatrix.prototype.sumRegion = function(row1, col1, row2, col2) { + return ( + this.search(row2 + 1, col2 + 1) - + this.search(row1, col2 + 1) - + this.search(row2 + 1, col1) + + this.search(row1, col1) + ) +} + +/** + * Your NumMatrix object will be instantiated and called as such: + * var obj = new NumMatrix(matrix) + * obj.update(row,col,val) + * var param_2 = obj.sumRegion(row1,col1,row2,col2) + */ diff --git a/3082-find-the-sum-of-the-power-of-all-subsequences.js b/3082-find-the-sum-of-the-power-of-all-subsequences.js new file mode 100644 index 00000000..9944513e --- /dev/null +++ b/3082-find-the-sum-of-the-power-of-all-subsequences.js @@ -0,0 +1,43 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const sumOfPower = function(nums, k) { + const n = nums.length, mod = 1e9 + 7; + const dp = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0)) + dp[0][0] = 1 + let res = 0, pow = 1 + for(const e of nums) { + for(let j = k; j >= e; j--) { + for(let i = n; i > 0; i--) { + dp[i][j] = (dp[i][j] + dp[i - 1][j - e]) % mod + } + } + } + for(let i = n; i > 0; i--) { + res = (res + (dp[i][k] * pow) % mod) % mod + pow *= 2 + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const sumOfPower = function(nums, k) { + const n = nums.length, mod = 1e9 + 7; + const dp = Array(k + 1).fill(0) + dp[0] = 1; + for (const a of nums) { + for (let v = k; v >= 0; v--) { + dp[v] = (dp[v] * 2 % mod + (v >= a ? dp[v - a] : 0)) % mod + } + } + return dp[k]; +}; diff --git a/3083-existence-of-a-substring-in-a-string-and-its-reverse.js b/3083-existence-of-a-substring-in-a-string-and-its-reverse.js new file mode 100644 index 00000000..51754026 --- /dev/null +++ b/3083-existence-of-a-substring-in-a-string-and-its-reverse.js @@ -0,0 +1,19 @@ +/** + * @param {string} s + * @return {boolean} + */ +var isSubstringPresent = function(s) { + let res = false + const n = s.length + for(let i = 0; i < n - 1; i++) { + const e = s[i] + s[i + 1] + for(let j = n - 1; j > 0; j--) { + if(s[j] === s[i] && s[j - 1] === s[i + 1]) { + res = true + return res + } + } + } + + return res +}; diff --git a/3084-count-substrings-starting-and-ending-with-given-character.js b/3084-count-substrings-starting-and-ending-with-given-character.js new file mode 100644 index 00000000..a3a501d1 --- /dev/null +++ b/3084-count-substrings-starting-and-ending-with-given-character.js @@ -0,0 +1,22 @@ +/** + * @param {string} s + * @param {character} c + * @return {number} + */ +const countSubstrings = function(s, c) { + const n = s.length + const arr = [] + for(let i = 0; i < n; i++) { + if(s[i] === c) { + arr.push(i) + } + } + let len = arr.length + let res = 0 + while(len) { + res += len + len-- + } + + return res +}; diff --git a/3085-minimum-deletions-to-make-string-k-special.js b/3085-minimum-deletions-to-make-string-k-special.js new file mode 100644 index 00000000..560f121a --- /dev/null +++ b/3085-minimum-deletions-to-make-string-k-special.js @@ -0,0 +1,34 @@ +/** + * @param {string} word + * @param {number} k + * @return {number} + */ +var minimumDeletions = function(word, k) { + let freq = new Array(26).fill(0); + let deleted = 0; + let ans = word.length; + + for (let i = 0; i < word.length; i++) { + freq[word.charCodeAt(i) - 'a'.charCodeAt(0)]++; + } + + freq.sort((a, b) => a - b); + + for (let i = 0; i < freq.length; i++) { + let res = deleted; + let minFreq = freq[i]; + + for (let j = freq.length - 1; j > i; j--) { + if (freq[j] - minFreq <= k) { + break; + } + + res += freq[j] - minFreq - k; + } + + ans = Math.min(ans, res); + deleted += freq[i]; + } + + return ans; +}; diff --git a/3086-minimum-moves-to-pick-k-ones.js b/3086-minimum-moves-to-pick-k-ones.js new file mode 100644 index 00000000..22705b40 --- /dev/null +++ b/3086-minimum-moves-to-pick-k-ones.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} nums + * @param {number} k + * @param {number} maxChanges + * @return {number} + */ +var minimumMoves = function(nums, k, maxChanges) { + let A = [0]; + for (let i = 0; i < nums.length; i++) { + if (nums[i] > 0) { + A.push(A[A.length - 1] + i); + } + } + + let n = A.length - 1; + let m = Math.max(0, k - maxChanges); + let res = Number.MAX_VALUE; + + for (let l = m; l <= Math.min(n, Math.min(m + 3, k)); l++) { + for (let i = 0; i <= n - l; i++) { + let mid1 = i + Math.floor(l / 2); + let mid2 = i + l - Math.floor(l / 2); + let cur = A[i + l] - A[mid2] - (A[mid1] - A[i]); + res = Math.min(res, cur + (k - l) * 2); + } + } + + return res; +}; diff --git a/309-best-time-to-buy-and-sell-stock-with-cooldown.js b/309-best-time-to-buy-and-sell-stock-with-cooldown.js index a401175f..0bc3138d 100755 --- a/309-best-time-to-buy-and-sell-stock-with-cooldown.js +++ b/309-best-time-to-buy-and-sell-stock-with-cooldown.js @@ -9,14 +9,14 @@ const maxProfit = function(prices) { const length = prices.length; // buy[i]: max profit if the first "i" days end with a "buy" day - let buy = Array(length + 1).fill(0); // new int[length + 1]; + const buy = Array(length + 1).fill(0); // buy[i]: max profit if the first "i" days end with a "sell" day - let sell = Array(length + 1).fill(0); // new int[length + 1]; + const sell = Array(length + 1).fill(0); buy[1] = -prices[0]; for (let i = 2; i <= length; i++) { - let price = prices[i - 1]; + const price = prices[i - 1]; buy[i] = Math.max(buy[i - 1], sell[i - 2] - price); sell[i] = Math.max(sell[i - 1], buy[i - 1] + price); } diff --git a/3093-longest-common-suffix-queries.js b/3093-longest-common-suffix-queries.js new file mode 100644 index 00000000..1866b181 --- /dev/null +++ b/3093-longest-common-suffix-queries.js @@ -0,0 +1,54 @@ +/** + * @param {string[]} wordsContainer + * @param {string[]} wordsQuery + * @return {number[]} + */ +const stringIndices = function (wordsContainer, wordsQuery) { + const root = new TrieNode() + const arr = [] + for (let i = 0; i < wordsContainer.length; i++) { + arr.push({ word: wordsContainer[i], index: i }) + } + arr.sort((a, b) => { + if (a.word.length !== b.word.length) return a.word.length - b.word.length + else return a.index - b.index + }) + for (let i = arr.length - 1; i >= 0; i--) { + let node = root + const s = arr[i].word + for (let j = s.length - 1; j >= 0; j--) { + const charIndex = s[j].charCodeAt(0) - 'a'.charCodeAt(0) + if (node.next[charIndex] === null) { + node.next[charIndex] = new TrieNode() + } + node = node.next[charIndex] + node.idx = arr[i].index + } + } + root.idx = arr[0].index + const res = [] + for (const query of wordsQuery) { + let node = root + let ans = -1 + for (let i = query.length - 1; i >= 0; i--) { + const charIndex = query[i].charCodeAt(0) - 'a'.charCodeAt(0) + if (node.next[charIndex] !== null) { + node = node.next[charIndex] + } else { + break + } + } + + ans = node.idx + + res.push(ans) + } + return res +} + +class TrieNode { + constructor() { + this.next = new Array(26).fill(null) + this.idx = -1 + } +} diff --git a/3097-shortest-subarray-with-or-at-least-k-ii.js b/3097-shortest-subarray-with-or-at-least-k-ii.js new file mode 100644 index 00000000..c5c4f5fc --- /dev/null +++ b/3097-shortest-subarray-with-or-at-least-k-ii.js @@ -0,0 +1,74 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minimumSubarrayLength = function (nums, k) { + const a = nums + let n = a.length, + st = new SegmentTreeRORQ(a), + res = Number.MAX_SAFE_INTEGER + for (let i = 0; i < n; i++) { + let L = i, + R = n - 1, + len = Number.MAX_SAFE_INTEGER + while (L <= R) { + const mid = L + Math.floor((R - L) / 2) + let v = st.query(i, mid + 1) + if (v >= k) { + len = mid - i + 1 + R = mid - 1 + } else { + L = mid + 1 + } + } + res = Math.min(res, len) + } + return res === Number.MAX_SAFE_INTEGER ? -1 : res +} + +/////////////////////////// Template /////////////////////////// +function SegmentTreeRORQ(A) { + let n = A.length, + h = Math.ceil(Math.log2(n)), + len = 2 * 2 ** h, + a = Array(len).fill(0) + initializeFromArray() + return { update, query, tree } + function initializeFromArray() { + for (let i = 0; i < n; i++) a[n + i] = A[i] + for (let i = n - 1; i >= 1; i--) pushup(i) + } + function update(pos, v) { + a[n + pos] = v + for (let i = parent(n + pos); i >= 1; i = parent(i)) pushup(i) + } + function pushup(i) { + a[i] = a[left(i)] | a[right(i)] + } + function query(l, r) { + // [L, R) + let or = 0 + if (l >= r) return 0 + l += n + r += n + for (; l < r; l = parent(l), r = parent(r)) { + if (l & 1) or |= a[l++] + if (r & 1) or |= a[--r] + } + return or + } + function parent(i) { + return i >> 1 + } + function left(i) { + return 2 * i + } + function right(i) { + return 2 * i + 1 + } + function tree() { + return a + } +} +//////////////////////////////////////////////////////////////// diff --git a/3098-find-the-sum-of-subsequence-powers.js b/3098-find-the-sum-of-subsequence-powers.js new file mode 100644 index 00000000..4b9902f7 --- /dev/null +++ b/3098-find-the-sum-of-subsequence-powers.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var sumOfPowers = function (nums, k) { + const mod = 1e9 + 7 + + let n, res, a, memo + a = nums + a.sort((x, y) => x - y) + n = a.length + memo = new Map() + const dfs = (i, k, pre, mi) => { + if (k == 0) return mi + if (n - i - 1 < k) return 0 + let ke = i + ' ' + k + ' ' + pre + ' ' + mi + if (memo.has(ke)) return memo.get(ke) + res = dfs(i + 1, k - 1, a[i + 1], Math.min(mi, a[i + 1] - pre)) + res += dfs(i + 1, k, pre, mi) + memo.set(ke, res) + return res % mod + } + res = dfs(-1, k, -Infinity, Infinity) + return res +} diff --git a/31-next-permutation.js b/31-next-permutation.js index 3df5d135..28de12d6 100644 --- a/31-next-permutation.js +++ b/31-next-permutation.js @@ -1,3 +1,46 @@ +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +const nextPermutation = function(nums) { + const n = nums.length + let k = null + for(let i = n - 2; i >= 0; i--) { + if(nums[i] < nums[i + 1]) { + k = i + break + } + } + if(k == null) { + reverse(nums, 0, n - 1) + } else { + let end + for(let i = n - 1; i >= 0; i--) { + if(nums[i] > nums[k]) { + end = i + break + } + } + swap(nums, k, end) + reverse(nums, k + 1, n - 1) + } + + function reverse(arr, start, end) { + while(start < end) { + swap(arr, start, end) + start++ + end-- + } + } + + function swap(arr, i, j) { + ;[arr[i], arr[j]] = [arr[j], arr[i]]; + } +}; + +// another + + /** * @param {number[]} nums * @return {void} Do not return anything, modify nums in-place instead. @@ -32,3 +75,42 @@ function swap(arr, i, j) { arr[j] ^= arr[i]; arr[i] ^= arr[j]; } + +// another + +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +const nextPermutation = function(nums) { + const n = nums.length + let start, end + for(let i = n - 2; i >= 0; i--) { + if(nums[i] < nums[i + 1]) { + start = i + break + } + } + if(start == null) { + reverse(nums, 0, n - 1) + } else { + for(let i = n - 1; i >= 0; i--) { + if(nums[i] > nums[start]) { + end = i + break + } + } + swap(nums, start, end) + reverse(nums, start + 1, n - 1) + } +}; +function reverse(arr, start, end) { + while(start < end) { + swap(arr, start++, end--) + } +} +function swap(arr, i, j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp +} diff --git a/310-minimum-height-trees.js b/310-minimum-height-trees.js index 98e754ee..9bdaed7f 100644 --- a/310-minimum-height-trees.js +++ b/310-minimum-height-trees.js @@ -1,3 +1,130 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ +var findMinHeightTrees = function(n, edges) { + if(n === 1) return [0] + if(n === 2) return [0, 1] + const g = {} + const degree = new Array(n).fill(0) + for(const [u, v] of edges) { + degree[u]++ + degree[v]++ + if(g[u] == null) g[u] = [] + if(g[v] == null) g[v] = [] + g[u].push(v) + g[v].push(u) + } + let q = [] + for(let i = 0; i < n; i++) { + if(degree[i] === 1) q.push(i) + } + let cnt = 0 + while(q.length) { + const size = q.length + const tmp = [] + for(let i = 0; i < size; i++) { + const node = q[i] + cnt++ + for(const nxt of (g[node] || [])) { + degree[nxt]-- + if(degree[nxt] === 1) { + tmp.push(nxt) + } + } + } + + q = tmp + if(n - cnt <= 2) break + } + + const res = [] + while(q.length) { + res.push(q.pop()) + } + return res +}; + +// another + +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ +const findMinHeightTrees = function (n, edges) { + const graph = {} + + for(const [u, v] of edges) { + if(graph[u] == null) graph[u] = new Set() + if(graph[v] == null) graph[v] = new Set() + graph[u].add(v) + graph[v].add(u) + } + + let q = [] + for(let i = 0; i < n; i++) { + if(graph[i].size === 1) q.push(i) + } + + while(n > 2) { + const size = q.length, nxt = [] + n -= size + for(let i = 0; i < size; i++) { + const cur = q[i] + for(const e of (graph[cur] || [])) { + graph[e].delete(cur) + if(graph[e].size === 1) nxt.push(e) + } + } + + q = nxt + } + + return q +} + +// another + +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ + const findMinHeightTrees = function(n, edges) { + if(n === 1) return [0] + const res = [], graph = {} + for(const [u, v] of edges) { + if(graph[u] == null) graph[u] = new Set() + if(graph[v] == null) graph[v] = new Set() + graph[u].add(v) + graph[v].add(u) + } + + let leaves = [] + Object.keys(graph).forEach(k => { + if(graph[k].size === 1) leaves.push(+k) + }) + while(n > 2) { + const newLeaves = [] + const size = leaves.length + for (let i = 0; i < size; i++) { + const cur = leaves.pop() + for (const next of graph[cur]) { + graph[next].delete(cur) + if(graph[next].size === 1) newLeaves.push(next) + } + } + n -= size + leaves = newLeaves + } + + return leaves +}; + +// another + /** * @param {number} n * @param {number[][]} edges diff --git a/3105-longest-strictly-increasing-or-strictly-decreasing-subarray.js b/3105-longest-strictly-increasing-or-strictly-decreasing-subarray.js new file mode 100644 index 00000000..0be0a8fc --- /dev/null +++ b/3105-longest-strictly-increasing-or-strictly-decreasing-subarray.js @@ -0,0 +1,36 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var longestMonotonicSubarray = function(nums) { + const n = nums.length + return Math.max(inc(), desc()) + + function inc() { + let res = 1, cur = 1 + for(let i = 1; i < n; i++) { + if(nums[i] > nums[i - 1]) { + cur++ + res = Math.max(res, cur) + } else { + cur = 1 + } + } + + return res + } + + function desc() { + let res = 1, cur = 1 + for(let i = 1; i < n; i++) { + if(nums[i] < nums[i - 1]) { + cur++ + res = Math.max(res, cur) + } else { + cur = 1 + } + } + + return res + } +}; diff --git a/3106-lexicographically-smallest-string-after-operations-with-constraint.js b/3106-lexicographically-smallest-string-after-operations-with-constraint.js new file mode 100644 index 00000000..c2e9da1b --- /dev/null +++ b/3106-lexicographically-smallest-string-after-operations-with-constraint.js @@ -0,0 +1,37 @@ +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const getSmallestString = function(s, k) { + const n = s.length + s = s + s + const a = 'a'.charCodeAt(0) + let res = '', idx = 0 + for(let j = 0; j < n; j++) { + for(let i = 0; i < 26; i++) { + const len = chk(a + i, j) + if(len === 0) { + res += s[j] + break + } else if(len && len <= k) { + k -= len + res += String.fromCharCode(a + i) + break + } + } + } + + + return res + + function chk(code, targetIdx) { + const targetCode = s[targetIdx].charCodeAt(0) + if(targetCode > code) { + return Math.min(targetCode - code, code + 26 - targetCode) + } else { + return Math.min(code - targetCode, targetCode + 26 - code) + } + + } +}; diff --git a/3107-minimum-operations-to-make-median-of-array-equal-to-k.js b/3107-minimum-operations-to-make-median-of-array-equal-to-k.js new file mode 100644 index 00000000..af16bb11 --- /dev/null +++ b/3107-minimum-operations-to-make-median-of-array-equal-to-k.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minOperationsToMakeMedianK = function(nums, k) { + nums.sort((a, b) => a - b) + + let n = nums.length + let medIdx = Math.floor(n / 2) + let res = 0 + + for(let i = 0; i < n; i++) { + if(nums[i] < k && medIdx <= i) { + res = res + (k - nums[i]) + } + else if(nums[i] > k && medIdx >= i) { + res = res + (nums[i] - k) + } + } + + return res +}; + diff --git a/3108-minimum-cost-walk-in-weighted-graph.js b/3108-minimum-cost-walk-in-weighted-graph.js new file mode 100644 index 00000000..d538c09b --- /dev/null +++ b/3108-minimum-cost-walk-in-weighted-graph.js @@ -0,0 +1,94 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[][]} query + * @return {number[]} + */ +var minimumCost = function (n, edges, query) { + const map = new Map() + const ufs = new UFS(n) + + for (let i = 0; i < edges.length; i++) { + const [a, b, e] = edges[i] + ufs.union(a, b) + } + + for (let i = 0; i < edges.length; i++) { + const [a, b, e] = edges[i] + const rootA = ufs.find(a) + const rootB = ufs.find(b) + + const root = ufs.find(a) + let tmp = e + if (map.has(rootA)) { + tmp = e & map.get(rootA) + } + if (map.has(rootB)) { + tmp = e & map.get(rootB) + } + map.set(root, tmp) + } + + const ans = [] + for (let i = 0; i < query.length; i++) { + const [s, t] = query[i] + const rootA = ufs.find(s) + const rootB = ufs.find(t) + + if (rootA !== rootB) { + ans.push(-1) + } else if (s === t) { + ans.push(0) + } else { + ans.push(map.get(rootA)) + } + } + + return ans +} + +class UFS { + constructor(n) { + this.parent = new Array(n).fill(0).map((_, i) => i) + this.rank = new Array(n).fill(0) + this.size = n + this.sz = new Array(n).fill(1) + } + + find(x) { + if (x !== this.parent[x]) { + this.parent[x] = this.find(this.parent[x]) + } + return this.parent[x] + } + + union(x, y) { + const px = this.find(x) + const py = this.find(y) + + if (px === py) { + return false + } + + if (this.rank[px] > this.rank[py]) { + this.parent[py] = px + this.sz[px] += this.sz[py] + } else if (this.rank[px] < this.rank[py]) { + this.parent[px] = py + this.sz[py] += this.sz[px] + } else { + this.parent[px] = py + this.sz[py] += this.sz[px] + this.rank[px]++ + } + + this.size-- + return true + } + + reset() { + this.parent = new Array(n).fill(0).map((_, i) => i) + this.rank = new Array(n).fill(0) + this.size = n + } +} diff --git a/311-sparse-matrix-multiplication.js b/311-sparse-matrix-multiplication.js new file mode 100644 index 00000000..9a1c3b7f --- /dev/null +++ b/311-sparse-matrix-multiplication.js @@ -0,0 +1,49 @@ +/** + +Given two sparse matrices A and B, return the result of AB. +You may assume that A's column number is equal to B's row number. + +Example: + +Input: + +A = [ + [ 1, 0, 0], + [-1, 0, 3] +] + +B = [ + [ 7, 0, 0 ], + [ 0, 0, 0 ], + [ 0, 0, 1 ] +] + +Output: + + | 1 0 0 | | 7 0 0 | | 7 0 0 | +AB = | -1 0 3 | x | 0 0 0 | = | -7 0 3 | + | 0 0 1 | + +*/ + +/** + * @param {number[][]} A + * @param {number[][]} B + * @return {number[][]} + */ +const multiply = function(A, B) { + const aLen = A.length, bLen = B.length + if(aLen === 0 || bLen === 0) return [] + const aCol = A[0].length, bCol = B[0].length + const res = Array.from({ length: aLen }, () => new Array(bCol).fill(0)) + for(let i = 0; i < aLen; i++) { + for(let j = 0; j < bCol; j++) { + let tmp = 0 + for(let k = 0; k < bLen; k++) { + tmp += A[i][k] * B[k][j] + } + res[i][j] = tmp + } + } + return res +}; diff --git a/3112-minimum-time-to-visit-disappearing-nodes.js b/3112-minimum-time-to-visit-disappearing-nodes.js new file mode 100644 index 00000000..ec24d5cc --- /dev/null +++ b/3112-minimum-time-to-visit-disappearing-nodes.js @@ -0,0 +1,155 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} disappear + * @return {number[]} + */ +const minimumTime = function(n, edges, disappear) { + const g = Array.from({ length: n }, () => []) + for (const [u, v, w] of edges) { + g[u].push([v, w]) + g[v].push([u, w]) + } + const pq = new PQ((a, b) => a[1] < b[1]) + pq.push([0, 0]) + const res = Array(n).fill(-1) + while(!pq.isEmpty()) { + const [u, t] = pq.pop() + if (res[u] !== -1) continue + res[u] = t + for(const [v, w] of g[u]) { + if (res[v] === -1 && t + w < disappear[v]) { + pq.push([v, t + w]) + } + } + } + + return res +}; + +// another + + +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} disappear + * @return {number[]} + */ +var minimumTime = function(n, edges, disappear) { + const graph = {}; + for (let i = 0; i < n; i++) { + graph[i] = []; + } + for (const [u, v, length] of edges) { + graph[u].push({ node: v, length }); + graph[v].push({ node: u, length }); + } + + const answer = new Array(n).fill(-1); + const pq = new MinHeap(); + const visited = new Set(); + + pq.insert(0, 0); + + while (!pq.isEmpty()) { + const [node, distance] = pq.removeMin(); + + if (visited.has(node)) continue; + visited.add(node); + + answer[node] = distance; + + for (const { node: adjNode, length } of graph[node]) { + if (disappear[adjNode] > distance + length && !visited.has(adjNode)) { + pq.insert(adjNode, distance + length); + } + } + } + + return answer; +}; + +// Basic MinHeap implementation +class MinHeap { + constructor() { + this.heap = []; + } + + insert(node, distance) { + this.heap.push([node, distance]); + this.heapifyUp(); + } + + removeMin() { + [this.heap[0], this.heap[this.heap.length - 1]] = [this.heap[this.heap.length - 1], this.heap[0]]; + const min = this.heap.pop(); + this.heapifyDown(); + return min; + } + + heapifyUp() { + let index = this.heap.length - 1; + while (this.hasParent(index) && this.parent(index)[1] > this.heap[index][1]) { + [this.heap[this.parentIndex(index)], this.heap[index]] = [this.heap[index], this.heap[this.parentIndex(index)]]; + index = this.parentIndex(index); + } + } + + heapifyDown() { + let index = 0; + while (this.hasLeftChild(index)) { + let smallerChildIndex = this.leftChildIndex(index); + if (this.hasRightChild(index) && this.rightChild(index)[1] < this.leftChild(index)[1]) { + smallerChildIndex = this.rightChildIndex(index); + } + + if (this.heap[index][1] < this.heap[smallerChildIndex][1]) { + break; + } else { + [this.heap[index], this.heap[smallerChildIndex]] = [this.heap[smallerChildIndex], this.heap[index]]; + } + index = smallerChildIndex; + } + } + + isEmpty() { + return this.heap.length === 0; + } + + parentIndex(index) { + return Math.floor((index - 1) / 2); + } + + leftChildIndex(index) { + return 2 * index + 1; + } + + rightChildIndex(index) { + return 2 * index + 2; + } + + hasParent(index) { + return this.parentIndex(index) >= 0; + } + + hasLeftChild(index) { + return this.leftChildIndex(index) < this.heap.length; + } + + hasRightChild(index) { + return this.rightChildIndex(index) < this.heap.length; + } + + parent(index) { + return this.heap[this.parentIndex(index)]; + } + + leftChild(index) { + return this.heap[this.leftChildIndex(index)]; + } + + rightChild(index) { + return this.heap[this.rightChildIndex(index)]; + } +} diff --git a/3114-latest-time-you-can-obtain-after-replacing-characters.js b/3114-latest-time-you-can-obtain-after-replacing-characters.js new file mode 100644 index 00000000..df8e8040 --- /dev/null +++ b/3114-latest-time-you-can-obtain-after-replacing-characters.js @@ -0,0 +1,25 @@ +/** + * @param {string} s + * @return {string} + */ +var findLatestTime = function (s) { + let l = s.split('') + + if (l[0] === '?') { + l[0] = l[1] === '?' || parseInt(l[1]) <= 1 ? '1' : '0' + } + + if (l[1] === '?') { + l[1] = l[0] === '1' ? '1' : '9' + } + + if (l[3] === '?') { + l[3] = '5' + } + + if (l[4] === '?') { + l[4] = '9' + } + + return l.join('') +} diff --git a/3115-maximum-prime-difference.js b/3115-maximum-prime-difference.js new file mode 100644 index 00000000..9dfe499c --- /dev/null +++ b/3115-maximum-prime-difference.js @@ -0,0 +1,32 @@ +const isPrime = num => { + for(let i = 2, s = Math.sqrt(num); i <= s; i++) { + if(num % i === 0) return false; + } + return num > 1; +} +/** + * @param {number[]} nums + * @return {number} + */ +var maximumPrimeDifference = function(nums) { + let fi = -1, li = nums.length + const n = nums.length + for(let i = 0; i < n; i++) { + const e = nums[i] + if(isPrime(e)) { + fi = i + break + } + } + for(let i = n - 1; i >= 0; i--) { + const e = nums[i] + if(isPrime(e)) { + li = i + break + } + } + + if(fi === -1) return 0 + + return li - fi +}; diff --git a/3116-kth-smallest-amount-with-single-denomination-combination.js b/3116-kth-smallest-amount-with-single-denomination-combination.js new file mode 100644 index 00000000..b7c432bf --- /dev/null +++ b/3116-kth-smallest-amount-with-single-denomination-combination.js @@ -0,0 +1,143 @@ +/** + * @param {number[]} coins + * @param {number} k + * @return {number} + */ +var findKthSmallest = function (coins, k) { + const n = coins.length; + const dic = new Map(); + for (let i = 1; i <= n; i++) { + const combinations = getCombinations(coins, i); + for (const comb of combinations) { + const lcm = getLCM(comb); + if (!dic.has(i)) { + dic.set(i, []); + } + dic.get(i).push(lcm); + } + } + + function count(dic, target) { + let ans = 0; + for (let i = 1; i <= n; i++) { + const lcms = dic.get(i); + for (const lcm of lcms) { + ans += Math.floor(target / lcm) * Math.pow(-1, i + 1); + } + } + return ans; + } + + let start = Math.min(...coins); + let end = Math.min(...coins) * k; + while (start + 1 < end) { + const mid = Math.floor((start + end) / 2); + if (count(dic, mid) >= k) { + end = mid; + } else { + start = mid; + } + } + if (count(dic, start) >= k) { + return start; + } else { + return end; + } + + function getCombinations(arr, k) { + const combinations = []; + const helper = (start, current) => { + if (current.length === k) { + combinations.push([...current]); + return; + } + for (let i = start; i < arr.length; i++) { + current.push(arr[i]); + helper(i + 1, current); + current.pop(); + } + }; + helper(0, []); + return combinations; + } + + function getLCM(arr) { + const gcd = (a, b) => { + if (b === 0) { + return a; + } + return gcd(b, a % b); + }; + let lcm = arr[0]; + for (let i = 1; i < arr.length; i++) { + const g = gcd(lcm, arr[i]); + lcm = (lcm * arr[i]) / g; + } + return lcm; + } +} + + +// another + + + +function calcLcm(a, b) { + let p = a * b + + let t = 0 + while (b) { + t = b + b = a % b + a = t + } + + return p / a +} + +/** + * @param {number[]} coins + * @param {number} k + * @return {number} + */ +var findKthSmallest = function (coins, k) { + let n = coins.length + + let cnt = 0 + let lcm = 1 + let sgn = -1 + let cur = 0 + let res = 0 + + let l = 1 + let r = 50000000000 + + while (l <= r) { + cur = Math.floor((l + r) / 2) + cnt = 0 + bt(0) + + if (cnt >= k) { + res = cur + r = cur - 1 + } else { + l = cur + 1 + } + } + + return res + + function bt(i) { + let bak = lcm + lcm = calcLcm(lcm, coins[i]) + sgn = -sgn + cnt += sgn * Math.floor(cur / lcm) + + ++i + if (i < n) bt(i) + + lcm = bak + sgn = -sgn + if (i < n) bt(i) + } +} diff --git a/3117-minimum-sum-of-values-by-dividing-array.js b/3117-minimum-sum-of-values-by-dividing-array.js new file mode 100644 index 00000000..7c6eb968 --- /dev/null +++ b/3117-minimum-sum-of-values-by-dividing-array.js @@ -0,0 +1,243 @@ +//#region Circular Queue +/** + * @template TItem + */ +class CircularQueue { + /** + * @param {number} capacity + */ + constructor(capacity) { + /** + * @private + * @type {number} + */ + this._capacity = capacity + /** + * @private + * @type {number} + */ + this._size = 0 + /** + * @private + * @type {number} + */ + this._bottom = 0 + + /** + * @private + * @type {number} + */ + this._maxSize = 0 + + /** + * @private + * @type {TItem[]} + */ + this._data = Array(capacity).fill(undefined) + } + + /** + * @private + * @param {number} index + * @returns {number} + */ + _getCircularIndex(index) { + const result = index % this._capacity + if (result < 0) result += this._capacity + return result + } + + get capacity() { + return this._capacity + } + + get size() { + return this._size + } + + get nextItem() { + return this._size ? this._data[this._bottom] : undefined + } + + get lastItem() { + return this._size + ? this._data[this._getCircularIndex(this._bottom + this._size - 1)] + : undefined + } + + fromFirst(index) { + return index < this._size + ? this._data[this._getCircularIndex(this._bottom + index)] + : undefined + } + + fromLast(index) { + return index < this._size + ? this._data[ + this._getCircularIndex(this._bottom + this._size - 1 - index) + ] + : undefined + } + + /** + * @param {...TItem} items + */ + enqueue(...items) { + if (this._size + items.length > this._capacity) + throw new Error('Queue capacity exceeded.') + + let queueIndex = (this._bottom + this._size) % this._capacity + this._size += items.length + this._maxSize = Math.max(this._size, this._maxSize) + for (let i = 0; i < items.length; ++i) { + this._data[queueIndex] = items[i] + queueIndex = (queueIndex + 1) % this._capacity + } + } + + /** + * @returns {TItem | undefined} + */ + dequeue() { + if (!this._size) return undefined + + const result = this._data[this._bottom] + this._bottom = (this._bottom + 1) % this._capacity + --this._size + + return result + } + + /** + * @returns {TItem | undefined} + */ + popLast() { + if (!this._size) return undefined + + --this._size + const result = this._data[(this._bottom + this._size) % this._capacity] + + return result + } + + clear() { + this._size = 0 + } + + get maxSize() { + return this._maxSize + } + + asArray() { + let res = [] + for (let i = 0; i < this._size; ++i) { + res.push(this.fromFirst(i)) + } + + return res + } +} +//#endregion + +let oo = 1048575 +let dp = new Uint32Array(10001) +let dq = new CircularQueue(10001) + +//#region Segment tree +let st = new Uint32Array(40004) + +function buildST(nums, root, l, r) { + if (l == r) { + st[root] = nums[l] + return + } + + let m = (l + r) >> 1 + let c = root * 2 + 1 + buildST(nums, c, l, m) + buildST(nums, c + 1, m + 1, r) + + st[root] = st[c] & st[c + 1] +} + +function queryST(ql, qr, root, l, r) { + if (qr < l || ql > r) return oo + if (ql <= l && r <= qr) return st[root] + + let m = (l + r) >> 1 + let c = root * 2 + 1 + let x = queryST(ql, qr, c, l, m) + let y = queryST(ql, qr, c + 1, m + 1, r) + + return x & y +} +//#endregion + + +/** + * @param {number[]} nums + * @param {number[]} andValues + * @return {number} + */ +var minimumValueSum = function (nums, andValues) { + let n = nums.length + let m = andValues.length + buildST(nums, 0, 0, n - 1) + + dp.fill(oo, 0, n) + let a = nums[0] + let t = andValues[0] + for (let i = 0; i < n; ++i) { + a &= nums[i] + + if (a == t) { + dp[i] = nums[i] + } + } + + for (let j = 1; j < m; ++j) { + dq.clear() + t = andValues[j] + let ll = n + let rr = n - 1 + + for (let i = n - 1; i >= 0; --i) { + if (rr > i) { + rr = i + } + + a = queryST(rr, i, 0, 0, n - 1) + while (rr > 1 && a > t && (a & nums[rr - 1]) >= t) { + a &= nums[--rr] + } + + if (a != t || !rr) { + dp[i] = oo + continue + } + + if (ll > rr) { + ll = rr + dq.clear() + dq.enqueue(ll - 1) + } + + while (ll > 1 && (a & nums[ll - 1]) == a) { + --ll + + while (dq.size && dp[ll - 1] <= dp[dq.fromLast(0)]) { + dq.popLast() + } + dq.enqueue(ll - 1) + } + + while (dq.size && dq.fromFirst(0) >= rr) { + dq.dequeue() + } + + dp[i] = Math.min(dp[dq.fromFirst(0)] + nums[i], oo) + } + } + + return dp[n - 1] >= oo ? -1 : dp[n - 1] +} diff --git a/312-burst-balloons.js b/312-burst-balloons.js index 1509854d..a6cb9fa8 100644 --- a/312-burst-balloons.js +++ b/312-burst-balloons.js @@ -1,3 +1,28 @@ +function maxCoins(arr) { + const len = arr.length + const nums = Array(len + 2).fill(0); + let n = 1; + for (const x of arr) if (x > 0) nums[n++] = x; + nums[0] = nums[n++] = 1; + + const dp = Array.from({ length: n }, () => Array(n).fill(0)); + for (let k = 2; k < n; k++) { + for (let left = 0; left < n - k; left++) { + let right = left + k; + for (let i = left + 1; i < right; i++) { + dp[left][right] = Math.max( + dp[left][right], + nums[left] * nums[i] * nums[right] + dp[left][i] + dp[i][right], + ); + } + } + } + + return dp[0][n - 1]; +} + +// another + /** * @param {number[]} nums * @return {number} diff --git a/3122-minimum-number-of-operations-to-satisfy-conditions.js b/3122-minimum-number-of-operations-to-satisfy-conditions.js new file mode 100644 index 00000000..0d99473c --- /dev/null +++ b/3122-minimum-number-of-operations-to-satisfy-conditions.js @@ -0,0 +1,33 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const minimumOperations = function(grid) { + const m = grid.length, n = grid[0].length + const dp = Array.from({ length: n }, () => Array(10).fill(Infinity)) + for(let i = 0; i < n; i++) { + for(let v = 0; v < 10; v++) { + let cost = 0 + + for(let j = 0; j < m; j++) { + if(grid[j][i] !== v) cost++ + } + + if(i == 0) dp[i][v] = cost + else { + for(let p = 0; p < 10; p++) { + if(p === v) continue + dp[i][v] = Math.min(dp[i][v], dp[i - 1][p] + cost) + } + } + } + } + + let res = Infinity + + for(let v = 0; v < 10; v++) { + res = Math.min(res, dp[n - 1][v]) + } + + return res +}; diff --git a/3123-find-edges-in-shortest-paths.js b/3123-find-edges-in-shortest-paths.js new file mode 100644 index 00000000..3694b4ad --- /dev/null +++ b/3123-find-edges-in-shortest-paths.js @@ -0,0 +1,198 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {boolean[]} + */ +const findAnswer = function (n, edges) { + const m = edges.length + const res = Array(m).fill(false) + const MAX = Number.MAX_SAFE_INTEGER + const g = Array(n) + .fill(null) + .map(() => []) + for (const [u, v, w] of edges) { + g[u].push([v, w]) + g[v].push([u, w]) + } + const dist = Array(n).fill(MAX) + dist[0] = 0 + const pq = new PQ((a, b) => a[1] < b[1]) + pq.push([0, 0]) + while (!pq.isEmpty()) { + const [u, d] = pq.pop() + if (d > dist[u]) continue + for (const [v, w] of g[u]) { + if (dist[v] > d + w) { + dist[v] = d + w + pq.push([v, dist[v]]) + } + } + } + const dist1 = Array(n).fill(MAX) + dist1[n - 1] = 0 + pq.push([n - 1, 0]) + while (!pq.isEmpty()) { + const [u, d] = pq.pop() + if (d > dist1[u]) continue + for (const [v, w] of g[u]) { + if (dist1[v] > d + w) { + dist1[v] = d + w + pq.push([v, dist1[v]]) + } + } + } + for (let i = 0; i < m; i++) { + const [u, v, w] = edges[i] + if ( + dist[u] + dist1[v] + w === dist[n - 1] || + dist[v] + dist1[u] + w === dist[n - 1] + ) { + res[i] = true + } + } + + return res +} + +// another + + +/** + * @param {number} n + * @param {number[][]} edges + * @return {boolean[]} + */ +var findAnswer = function (n, edges) { + let graph = {} + let edgeMapWithIndex = {} + + for (let i = 0; i < n; i++) { + graph[i] = [] + } + + for (let i = 0; i < edges.length; i++) { + let [node1, node2, cost] = edges[i] + graph[node1].push([node2, cost]) + graph[node2].push([node1, cost]) + edgeMapWithIndex[String(node1) + '.' + String(node2)] = i + edgeMapWithIndex[String(node2) + '.' + String(node1)] = i + } + + let distance = new Array(n).fill(Infinity) + distance[0] = 0 + + let pq = new PQ((a, b) => a[1] < b[1]) + + // node,cost + pq.push([0, 0, [0]]) + + let shortestPath = null + let visited = new Array(edges.length).fill(false) + + while (!pq.isEmpty()) { + let [node, currentCost, path] = pq.pop() + + if (node === n - 1) { + if (shortestPath === null) { + shortestPath = currentCost + } else if (shortestPath !== currentCost) { + continue + } + + for (let i = 0; i < path.length - 1; i++) { + let key1 = String(path[i]) + '.' + String(path[i + 1]) + let key2 = String(path[i + 1]) + '.' + String(path[i]) + + if (edgeMapWithIndex[key1] !== undefined) { + visited[edgeMapWithIndex[key1]] = true + } else if (edgeMapWithIndex[key2] !== undefined) { + visited[edgeMapWithIndex[key2]] = true + } + } + continue + } + + if (shortestPath !== null && currentCost >= shortestPath) { + continue + } + + let neighbours = graph[node] + + for (let [neighbour, cost] of neighbours) { + if (currentCost + cost <= distance[neighbour]) { + distance[neighbour] = currentCost + cost + pq.push([neighbour, distance[neighbour], [...path, neighbour]]) + } + } + } + + return visited +} + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/313-super-ugly-number.js b/313-super-ugly-number.js new file mode 100644 index 00000000..598944b8 --- /dev/null +++ b/313-super-ugly-number.js @@ -0,0 +1,114 @@ +/** + * @param {number} n + * @param {number[]} primes + * @return {number} + */ +const nthSuperUglyNumber = function(n, primes) { + if (n === 1) return 1 + const indexes = new Array(primes.length).fill(0) + const arr = [1] + for (let i = 1; i <= n - 1; i++) { + arr[i] = +Infinity + for (let j = 0; j < primes.length; j++) { + arr[i] = Math.min(arr[i], arr[indexes[j]] * primes[j]) + } + for (let j = 0; j < primes.length; j++) { + if (arr[i] === arr[indexes[j]] * primes[j]) { + indexes[j]++ + } + } + } + return arr[n - 1] +} + +// another + +/** + * @param {number} n + * @param {number[]} primes + * @return {number} + */ +const nthSuperUglyNumber = function(n, primes) { + const ugly = Array(n).fill(0) + const pq = new PriorityQueue((a, b) => a[0] < b[0]) + + for(let i = 0; i < primes.length; i++) pq.push([primes[i], 1, primes[i]]) + ugly[0] = 1 + for(let i = 1; i < n; i++) { + ugly[i] = pq.peek()[0] + while(pq.peek()[0] === ugly[i]) { + const next = pq.pop() + pq.push([next[2] * ugly[next[1]], next[1] + 1, next[2]]) + } + } + + return ugly[n - 1] +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/3130-find-all-possible-stable-binary-arrays-ii.js b/3130-find-all-possible-stable-binary-arrays-ii.js new file mode 100644 index 00000000..8518dd04 --- /dev/null +++ b/3130-find-all-possible-stable-binary-arrays-ii.js @@ -0,0 +1,42 @@ +let MOD = 1000000007; + +function createDpArray() { + return Array.from({ length: 1001 }, () => new Uint32Array(1001)); +} + +let dp0 = createDpArray(); +let dp1 = createDpArray(); + +/** + * @param {number} zero + * @param {number} one + * @param {number} limit + * @return {number} + */ +var numberOfStableArrays = function (zero, one, limit) { + ++limit; + + for (let i = 0; i <= zero; ++i) { + for (let j = 0; j <= one; ++j) { + if (!i && !j) continue; + if (!i) { + dp1[i][j] = j < limit; + dp0[i][j] = 0; + continue; + } + if (!j) { + dp0[i][j] = i < limit; + dp1[i][j] = 0; + continue; + } + + dp1[i][j] = (dp0[i][j - 1] + dp1[i][j - 1]) % MOD; + if (j >= limit) dp1[i][j] = (dp1[i][j] - dp0[i][j - limit] + MOD) % MOD; + + dp0[i][j] = (dp0[i - 1][j] + dp1[i - 1][j]) % MOD; + if (i >= limit) dp0[i][j] = (dp0[i][j] - dp1[i - limit][j] + MOD) % MOD; + } + } + + return (dp0[zero][one] + dp1[zero][one]) % MOD; +}; diff --git a/3131-find-the-integer-added-to-array-i.js b/3131-find-the-integer-added-to-array-i.js new file mode 100644 index 00000000..59378cf0 --- /dev/null +++ b/3131-find-the-integer-added-to-array-i.js @@ -0,0 +1,10 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +var addedInteger = function(nums1, nums2) { + nums1.sort((a,b) => a - b) + nums2.sort((a,b) => a - b) + return nums2[0] - nums1[0] +}; diff --git a/3132-find-the-integer-added-to-array-ii.js b/3132-find-the-integer-added-to-array-ii.js new file mode 100644 index 00000000..aae98108 --- /dev/null +++ b/3132-find-the-integer-added-to-array-ii.js @@ -0,0 +1,45 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +var minimumAddedInteger = function (nums1, nums2) { + nums1.sort((a, b) => a - b) + nums2.sort((a, b) => a - b) + let min = Number.MAX_SAFE_INTEGER + for (let i = 0; i < nums1.length - 1; i++) { + for (let j = i + 1; j < nums1.length; j++) { + const [flag, value] = judgeEqual(nums1, nums2, i, j) + if (flag && min > value) { + min = value + } + } + } + return min +} + +function judgeEqual(nums1, nums2, i, j) { + let m = 0 + let n = 0 + let flag = false + let value = 0 + while (m < nums1.length) { + if (m === i || m === j) { + m++ + continue + } + if (!flag) { + value = nums2[n] - nums1[m] + m++ + n++ + flag = true + continue + } + if (nums2[n] - nums1[m] !== value) { + return [false, 0] + } + m++ + n++ + } + return [true, value] +} diff --git a/3133-minimum-array-end.js b/3133-minimum-array-end.js new file mode 100644 index 00000000..037aa7b4 --- /dev/null +++ b/3133-minimum-array-end.js @@ -0,0 +1,39 @@ +/** + * @param {number} n + * @param {number} x + * @return {number} + */ +var minEnd = function (n, x) { + let str = x.toString(2).padStart(50, '0') + + let map = new Map() + let c = 1 + for (let i = str.length - 1; i >= 0; i--) { + if (str[i] === '0') { + map.set(c, i) + c *= 2 + } + } + + let sb = str.split('') + let cur = n + ;[...map.keys()] + .sort((a, b) => b - a) + .forEach((key) => { + if (cur > key) { + cur -= key + sb[map.get(key)] = '1' + } + }) + + let ans = 0 + let step = 1 + for (let i = sb.length - 1; i >= 0; i--) { + if (sb[i] === '1') { + ans += step + } + step *= 2 + } + + return ans +} diff --git a/3134-find-the-median-of-the-uniqueness-array.js b/3134-find-the-median-of-the-uniqueness-array.js new file mode 100644 index 00000000..0bdfa43b --- /dev/null +++ b/3134-find-the-median-of-the-uniqueness-array.js @@ -0,0 +1,110 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const medianOfUniquenessArray = function(nums) { + const n = nums.length; + const {floor} = Math; + const total = (n * (n + 1)) / 2; + const half = floor((total + 1) / 2); + let l = 1, r = n + while(l < r) { + const mid = l + floor((r - l) / 2); + if (atMostK(nums, mid) >= half) { + r = mid; + } else { + l = mid + 1; + } + } + return l + + function atMostK(nums, k) { + const hash = new Map(), n = nums.length; + let res = 0 + let i = 0, j = 0 + while(j < n) { + const e = nums[j] + if(!hash.has(e)) hash.set(e, 0) + hash.set(e, hash.get(e) + 1) + while(i < j && hash.size > k) { + + hash.set(nums[i], hash.get(nums[i]) - 1) + if(hash.get(nums[i]) === 0) { + hash.delete(nums[i]) + } + i++ + } + res += j - i + 1 + + j++ + } + + return res + } +}; + + +// another + + +/** + * @param {number[]} nums + * @return {number} + */ +var medianOfUniquenessArray = function (nums) { + let low = 1 + let high = nums.length + let n = nums.length + + while (low < high) { + let mid = low + Math.floor((high - low) / 2) + if (countDistinct(nums, mid) >= Math.floor(((n * (n + 1)) / 2 + 1) / 2)) { + high = mid + } else { + low = mid + 1 + } + } + + if ( + countDistinct(nums, low - 1) === Math.floor(((n * (n + 1)) / 2 + 1) / 2) + ) { + return low - 1 + } + return low +} + +function countDistinct(nums, k) { + let occurrences = new Map() + let left = 0 + let count = 0 + let result = 0 + + for (let right = 0; right < nums.length; right++) { + occurrences.set(nums[right], (occurrences.get(nums[right]) || 0) + 1) + if (occurrences.get(nums[right]) === 1) { + count++ + } + while (count > k) { + occurrences.set(nums[left], occurrences.get(nums[left]) - 1) + if (occurrences.get(nums[left]) === 0) { + count-- + } + left++ + } + result += right - left + 1 + } + return result +} + +function force(nums) { + let l = [] + for (let i = 0; i < nums.length; i++) { + let set = new Set() + for (let j = i; j < nums.length; j++) { + set.add(nums[j]) + l.push(set.size) + } + } + l.sort((a, b) => a - b) + return l[Math.floor(l.length / 2)] +} diff --git a/3136-valid-word.js b/3136-valid-word.js new file mode 100644 index 00000000..a5f51edb --- /dev/null +++ b/3136-valid-word.js @@ -0,0 +1,27 @@ +/** + * @param {string} word + * @return {boolean} + */ +var isValid = function (word) { + const set = new Set(['a', 'e', 'i', 'o', 'u']) + let ans = true + ans = ans && word.length >= 3 + ans = + ans && + [...word].every( + (char) => + (char >= '0' && char <= '9') || + (char >= 'a' && char <= 'z') || + (char >= 'A' && char <= 'Z'), + ) + ans = ans && [...word].some((char) => set.has(char.toLowerCase())) + ans = + ans && + [...word].some( + (char) => + char.toLowerCase() >= 'a' && + char.toLowerCase() <= 'z' && + !set.has(char.toLowerCase()), + ) + return ans +} diff --git a/3137-minimum-number-of-operations-to-make-word-k-periodic.js b/3137-minimum-number-of-operations-to-make-word-k-periodic.js new file mode 100644 index 00000000..2180881a --- /dev/null +++ b/3137-minimum-number-of-operations-to-make-word-k-periodic.js @@ -0,0 +1,16 @@ +/** + * @param {string} word + * @param {number} k + * @return {number} + */ +var minimumOperationsToMakeKPeriodic = function (word, k) { + const n = Math.floor(word.length / k) + const map = new Map() + + for (let i = 0; i < word.length; i += k) { + const sub = word.substring(i, i + k) + map.set(sub, (map.get(sub) || 0) + 1) + } + + return n - Math.max(...map.values()) +} diff --git a/3138-minimum-length-of-anagram-concatenation.js b/3138-minimum-length-of-anagram-concatenation.js new file mode 100644 index 00000000..823168ce --- /dev/null +++ b/3138-minimum-length-of-anagram-concatenation.js @@ -0,0 +1,31 @@ +/** + * @param {string} s + * @return {number} + */ +var minAnagramLength = function (s) { + const n = s.length + + function checkI(k) { + const set = new Set() + for (let i = 0; i < n; i += k) { + const sub = s + .substring(i, i + k) + .split('') + .sort() + .join('') + set.add(sub) + if (set.size > 1) return false + } + return true + } + + for (let i = 1; i <= n; i++) { + if (n % i === 0) { + if (checkI(i)) { + return i + } + } + } + + return s.length +} diff --git a/3139-minimum-cost-to-equalize-array.js b/3139-minimum-cost-to-equalize-array.js new file mode 100644 index 00000000..d7a2e76d --- /dev/null +++ b/3139-minimum-cost-to-equalize-array.js @@ -0,0 +1,54 @@ +/** + * @param {number[]} nums + * @param {number} cost1 + * @param {number} cost2 + * @return {number} + */ +var minCostToEqualizeArray = function (nums, cost1, cost2) { + const big = BigInt + const mod = big(1e9 + 7) + const max = Math.max(...nums) + + cost1 = big(cost1) + cost2 = big(cost2) + + const l = [] + let sum = 0n + for (let i = 0; i < nums.length; i++) { + const diff = big(max - nums[i]) + sum += diff + l.push(diff) + } + l.sort((a ,b) => { + if(a > b) { + return -1; + } else if (a < b){ + return 1; + } else { + return 0; + } + }); + + if (cost1 * 2n <= cost2) { + return Number((sum * cost1) % mod) + } + + let ans = big(1e30) + for (let add = 0; add <= max; add++) { + let tmp = 0n + if (l[0] <= sum / 2n) { + tmp += (sum / 2n) * cost2 + tmp += (sum % 2n) * cost1 + if(tmp < ans) ans = tmp + } else { + tmp += (sum - l[0]) * cost2 + tmp += (l[0] - (sum - l[0])) * cost1 + if(tmp < ans) ans = tmp + } + + l[0]++ + sum += big(nums.length) + } + + return ans % mod +} diff --git a/314-binary-tree-vertical-order-traversal.js b/314-binary-tree-vertical-order-traversal.js new file mode 100644 index 00000000..46123f5d --- /dev/null +++ b/314-binary-tree-vertical-order-traversal.js @@ -0,0 +1,144 @@ +/** + +Given a binary tree, return the vertical order traversal of its +nodes' values. (ie, from top to bottom, column by column). + +If two nodes are in the same row and column, the order +should be from left to right. + +Examples 1: + +Input: [3,9,20,null,null,15,7] + + 3 + /\ + / \ + 9 20 + /\ + / \ + 15 7 + +Output: + +[ + [9], + [3,15], + [20], + [7] +] + +Examples 2: + +Input: [3,9,8,4,0,1,7] + + 3 + /\ + / \ + 9 8 + /\ /\ + / \/ \ + 4 01 7 + +Output: + +[ + [4], + [9], + [3,0,1], + [8], + [7] +] + +Examples 3: + +Input: [3,9,8,4,0,1,7,null,null,null,2,5] (0's right child is 2 and 1's left child is 5) + + 3 + /\ + / \ + 9 8 + /\ /\ + / \/ \ + 4 01 7 + /\ + / \ + 5 2 + +Output: + +[ + [4], + [9,5], + [3,0,1], + [8,2], + [7] +] + +*/ + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[][]} + */ +const verticalOrder = function(root) { + const res = [] + if(root == null) return res + const map = new Map() + const q = [] + const cols = [] + q.push(root) + cols.push(0) + let min = 0 + let max = 0 + while(q.length) { + const node = q.shift() + const col = cols.shift() + if(!map.has(col)) { + map.set(col, []) + } + map.get(col).push(node.val) + if(node.left !== null) { + q.push(node.left) + cols.push(col - 1) + min = Math.min(min, col - 1) + } + if(node.right !== null) { + q.push(node.right) + cols.push(col + 1) + max = Math.max(max, col + 1) + } + } + for(let i = min; i <= max; i++) { + res.push(map.get(i)) + } + return res +}; + +// another + +const verticalOrder = function(root) { + if (!root) return [] + let result = [] + function recurse(root, col, row) { + if (!root) return + recurse(root.left, col - 1, row + 1) + recurse(root.right, col + 1, row + 1) + result[col] = result[col] || [] + result[col][row] = result[col][row] || [] + result[col][row].push(root.val) + } + + recurse(root, 100, 0) + return result + .filter(x => x) + .map(row => row.reduce((acc, val) => acc.concat(val), [])) +} + + diff --git a/3144-minimum-substring-partition-of-equal-character-frequency.js b/3144-minimum-substring-partition-of-equal-character-frequency.js new file mode 100644 index 00000000..e543b411 --- /dev/null +++ b/3144-minimum-substring-partition-of-equal-character-frequency.js @@ -0,0 +1,40 @@ +/** + * @param {string} s + * @return {number} + */ +var minimumSubstringsInPartition = function (s) { + const n = s.length; + const dp = new Array(n + 1).fill(); + dp[0] = 0; + const chars = new Array(26).fill(); + + for (let i = 0; i < n; i++) { + dp[i + 1] = 1 + dp[i]; + chars.forEach((_, idx) => (chars[idx] = undefined)); + const idxOne = s.charCodeAt(i) - 97; + chars[idxOne] = 1; + + for (let j = i - 1; j >= 0; j--) { + const idxTwo = s.charCodeAt(j) - 97; + chars[idxTwo] = (chars[idxTwo] || 0) + 1; + if (isOk(chars)) { + dp[i + 1] = Math.min(dp[j] + 1, dp[i + 1]); + } + } + } + + return dp[n]; +}; + +function isOk(chars) { + let freq = undefined; + for (let i = 0; i < chars.length; i++) { + if (chars[i] === undefined) continue; + if (freq === undefined) { + freq = chars[i]; + } else if (chars[i] !== freq) { + return false; + } + } + return true; +} diff --git a/3146-permutation-difference-between-two-strings.js b/3146-permutation-difference-between-two-strings.js new file mode 100644 index 00000000..a0191c21 --- /dev/null +++ b/3146-permutation-difference-between-two-strings.js @@ -0,0 +1,17 @@ +/** + * @param {string} s + * @param {string} t + * @return {number} + */ +var findPermutationDifference = function(s, t) { + let mp1 = {} ,mp2 = {} + for (let i = 0; i < s.length; i++) { + mp1[s[i]] = i + mp2[t[i]] = i + } + let res = 0 + for (let i = 0; i < s.length; i++) { + res += Math.abs(mp1[s[i]] - mp2[s[i]]) + } + return res +}; diff --git a/3147-taking-maximum-energy-from-the-mystic-dungeon.js b/3147-taking-maximum-energy-from-the-mystic-dungeon.js new file mode 100644 index 00000000..2c4b1f17 --- /dev/null +++ b/3147-taking-maximum-energy-from-the-mystic-dungeon.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} energy + * @param {number} k + * @return {number} + */ +var maximumEnergy = function (energy, k) { + const n = energy.length + const sum = new Array(n).fill(0) + const arr = new Array(k).fill(0) + + let max = -Infinity + + for (let i = 0; i < n; i++) { + arr[i % k] += energy[i] + } + + for (let i = 0; i < k; i++) { + sum[i] = arr[i] + max = Math.max(sum[i], max) + } + + for (let i = k; i < n; i++) { + sum[i] = sum[i - k] - energy[i - k] + max = Math.max(sum[i], max) + } + + return max +} diff --git a/3148-maximum-difference-score-in-a-grid.js b/3148-maximum-difference-score-in-a-grid.js new file mode 100644 index 00000000..ece4039f --- /dev/null +++ b/3148-maximum-difference-score-in-a-grid.js @@ -0,0 +1,41 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var maxScore = function (grid) { + const rows = grid.length + const cols = grid[0].length + const dp = new Array(rows) + .fill() + .map(() => new Array(cols).fill(-Infinity)) + + dp[rows - 1][cols - 1] = grid[rows - 1][cols - 1] + + let res = -Infinity + + for (let i = rows - 1; i >= 0; i--) { + for (let j = cols - 1; j >= 0; j--) { + if (i < rows - 1) { + dp[i][j] = Math.max(dp[i][j], dp[i + 1][j]) + } + + if (j < cols - 1) { + dp[i][j] = Math.max(dp[i][j], dp[i][j + 1]) + } + + dp[i][j] = Math.max(dp[i][j], grid[i][j]) + } + } + + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (i < rows - 1) { + res = Math.max(res, dp[i + 1][j] - grid[i][j]) + } + if (j < cols - 1) { + res = Math.max(res, dp[i][j + 1] - grid[i][j]) + } + } + } + return res +} diff --git a/3149-find-the-minimum-cost-array-permutation.js b/3149-find-the-minimum-cost-array-permutation.js new file mode 100644 index 00000000..f9c6e032 --- /dev/null +++ b/3149-find-the-minimum-cost-array-permutation.js @@ -0,0 +1,49 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var findPermutation = function (nums) { + const n = nums.length + const memo = new Array(n).fill(0) + let min = Infinity + let res = null + + recursive([], 0) + + return res + + function recursive (oneCase, acc) { + if (acc > min) return + + let flag = 0 + + for (let i = 0; i < n; i += 1) { + if (!memo[i]) { + flag = 1 + memo[i] = 1 + oneCase.push(i) + recursive( + oneCase, + oneCase.length >= 2 + ? acc + + Math.abs( + oneCase[oneCase.length - 2] - + nums[oneCase[oneCase.length - 1]], + ) + : acc, + ) + memo[i] = 0 + oneCase.pop() + } + } + + if (!flag) { + acc += Math.abs(oneCase[oneCase.length - 1] - nums[oneCase[0]]) + + if (acc < min) { + res = [...oneCase] + min = acc + } + } + } +} diff --git a/315-count-of-smaller-numbers-after-self.js b/315-count-of-smaller-numbers-after-self.js index 16df5aa7..8bda9213 100644 --- a/315-count-of-smaller-numbers-after-self.js +++ b/315-count-of-smaller-numbers-after-self.js @@ -78,3 +78,60 @@ function insert(num, node, ans, i, preSum) { } return node } + +// another + +/** + * @param {number[]} nums + * @return {number[]} + */ +const countSmaller = function(nums) { + + const arr = [] + const n = nums.length + for(let i = 0; i < n; i++) { + arr.push([nums[i], i]) + } + + const res = Array(n).fill(0) + cntSmaller(arr, 0, n - 1, res) + + return res + + function cntSmaller(arr, l, r, res) { + if(l >= r) return + + const mid = ~~((l + r) / 2) + cntSmaller(arr, l, mid, res) + cntSmaller(arr, mid + 1, r, res) + let leftPos = l, rightPos = mid + 1, cnt = 0 + const merged = [] + while(leftPos < mid + 1 && rightPos <= r) { + if(arr[leftPos][0] > arr[rightPos][0]) { + cnt++ + merged.push(arr[rightPos]) + rightPos++ + } else { + res[arr[leftPos][1]] += cnt + merged.push(arr[leftPos]) + leftPos++ + } + } + + while(leftPos < mid + 1) { + res[arr[leftPos][1]] += cnt + merged.push(arr[leftPos]) + leftPos++ + } + + while(rightPos <= r) { + merged.push(arr[rightPos]) + rightPos++ + } + + for(let i = l; i <= r; i++) { + arr[i] = merged[i - l] + } + + } +}; diff --git a/3151-special-array-i.js b/3151-special-array-i.js new file mode 100644 index 00000000..005d43aa --- /dev/null +++ b/3151-special-array-i.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +var isArraySpecial = function (nums) { + for (let i = 0; i < nums.length - 1; i++) { + if (nums[i] % 2 == nums[i + 1] % 2) { + return false + } + } + return true +} diff --git a/3152-special-array-ii.js b/3152-special-array-ii.js new file mode 100644 index 00000000..82743e5e --- /dev/null +++ b/3152-special-array-ii.js @@ -0,0 +1,40 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {boolean[]} + */ +var isArraySpecial = function (nums, queries) { + let n = nums.length + let sameParity = new Array(n - 1).fill(false) + + + for (let i = 0; i < n - 1; ++i) { + if (nums[i] % 2 === nums[i + 1] % 2) { + sameParity[i] = true + } + } + + + let prefixSameParity = new Array(n).fill(0) + for (let i = 1; i < n; ++i) { + prefixSameParity[i] = prefixSameParity[i - 1] + (sameParity[i - 1] ? 1 : 0) + } + + let res = [] + for (const query of queries) { + let start = query[0] + let end = query[1] + if (start === end) { + // A single element subarray is always special + res.push(true) + } else { + if (prefixSameParity[end] - prefixSameParity[start] > 0) { + res.push(false) + } else { + res.push(true) + } + } + } + + return res +} diff --git a/3153-sum-of-digit-differences-of-all-pairs.js b/3153-sum-of-digit-differences-of-all-pairs.js new file mode 100644 index 00000000..03abf0ca --- /dev/null +++ b/3153-sum-of-digit-differences-of-all-pairs.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var sumDigitDifferences = function (nums) { + const numDigits = nums[0].toString().length + const n = nums.length + let totalDiff = 0 + + for (let pos = 0; pos < numDigits; ++pos) { + const digitCount = new Array(10).fill(0) + for (const num of nums) { + const digit = parseInt(num.toString()[pos]) + digitCount[digit]++ + } + for (let digit = 0; digit < 10; ++digit) { + const pairsCount = digitCount[digit] * (n - digitCount[digit]) + totalDiff += pairsCount + } + } + + return Math.floor(totalDiff / 2) +} diff --git a/3154-find-number-of-ways-to-reach-the-k-th-stair.js b/3154-find-number-of-ways-to-reach-the-k-th-stair.js new file mode 100644 index 00000000..feefb525 --- /dev/null +++ b/3154-find-number-of-ways-to-reach-the-k-th-stair.js @@ -0,0 +1,30 @@ +/** + * @param {number} k + * @return {number} + */ +var waysToReachStair = function (k) { + const memo = new Map() + + return dfs(1, 0, true) + + function dfs(cur, jump, minus) { + const key = `${cur}-${jump}-${minus}` + if (memo.has(key)) return memo.get(key) + + let ret = 0 + if (cur - 2 > k) { + memo.set(key, ret) + return ret + } + if (cur === k) { + ret += 1 + } + if (cur > 0 && minus) { + ret += dfs(cur - 1, jump, false) + } + ret += dfs(cur + 2 ** jump, jump + 1, true) + + memo.set(key, ret) + return ret + } +} diff --git a/316-remove-duplicate-letters.js b/316-remove-duplicate-letters.js new file mode 100644 index 00000000..a64a93b2 --- /dev/null +++ b/316-remove-duplicate-letters.js @@ -0,0 +1,78 @@ +/** + * @param {string} s + * @return {string} + */ +const removeDuplicateLetters = function(s) { + const last = {} + for (let i = 0; i < s.length; i++) last[s.charAt(i)] = i + const added = {} + const stack = [] + for (let i = 0; i < s.length; i++) { + const char = s.charAt(i) + if (added[char]) continue + while (stack.length && char < stack[0] && last[stack[0]] > i) { + added[stack[0]] = false + stack.shift() + } + stack.unshift(char) + added[char] = true + } + return stack.reverse().join('') +} + +// another + + +/** + * @param {string} s + * @return {string} + */ +const removeDuplicateLetters = function(s) { + const m = new Array(26) + const a = 'a'.charCodeAt(0) + for (let i = 0; i < s.length; i++) { + const k = s.charCodeAt(i) - a + m[k] = m[k] ? m[k] + 1 : 1 + } + const aChNo = [] + const visited = {} + for (let i = 0; i < s.length; i++) { + const k = s.charCodeAt(i) - a + m[k]-- + if (visited[k]) continue + while (aChNo.length > 0) { + const last = aChNo[aChNo.length - 1] - a + if (last > k && m[last] > 0) { + visited[last] = 0 + aChNo.pop() + } else break + } + visited[k] = 1 + aChNo.push(k + a) + } + return String.fromCharCode(...aChNo) +} + +// another + +/** + * @param {string} s + * @return {string} + */ +const removeDuplicateLetters = function(s) { + const last = {} + for (let i = 0; i < s.length; i++) last[s.charAt(i)] = i + const added = {} + const stack = [] + for (let i = 0; i < s.length; i++) { + const char = s.charAt(i) + if (added[char]) continue + while (stack.length && char < stack[stack.length - 1] && last[stack[stack.length - 1]] > i) { + added[stack[stack.length - 1]] = false + stack.pop() + } + stack.push(char) + added[char] = true + } + return stack.join('') +} diff --git a/3161-block-placement-queries.js b/3161-block-placement-queries.js new file mode 100644 index 00000000..e33d5d7c --- /dev/null +++ b/3161-block-placement-queries.js @@ -0,0 +1,89 @@ +/** + * @param {number[][]} queries + * @return {boolean[]} + */ +var getResults = function(queries) { + const max = queries.reduce((max, [_, x, sz = 0]) => Math.max(max, x, sz), 0) + 1; + const segmentTree = new SegmentTree(max) + const results = []; + for (const [type, x, sz = 0] of queries) { + if (type === 1) { + segmentTree.add(x); + } else { + results.push(segmentTree.query(x)[2] >= sz) + } + } + return results; +}; + +class SegmentTree { + n = 0 + minBlock = [] + maxBlock = [] + max = [] + + constructor(n) { + this.n = n + this.minBlock = new Array(2 * 2 ** Math.ceil(Math.log2(n))).fill(0); + this.maxBlock = new Array(2 * 2 ** Math.ceil(Math.log2(n))).fill(0); + this.max = new Array(2 * 2 ** Math.ceil(Math.log2(n))).fill(1); + this.populate() + } + + populate(idx = 0, l = 0, r = this.n - 1) { + if (l === r) return; + const mid = l + r >> 1; + this.populate(idx * 2 + 1, l, mid); + this.populate(idx * 2 + 2, mid + 1, r); + this.max[idx] = r - l + 1; + } + + update(idx, l, r) { + const left = idx * 2 + 1; + const leftSplit = this.maxBlock[left] > 0; + const right = idx * 2 + 2; + const rightSplit = this.minBlock[right] > 0; + + if (leftSplit && rightSplit) { + this.minBlock[idx] = this.minBlock[left]; + this.maxBlock[idx] = this.maxBlock[right]; + this.max[idx] = Math.max(this.max[left], this.max[right], this.minBlock[right] - this.maxBlock[left]); + } else if (leftSplit) { + this.minBlock[idx] = this.minBlock[left]; + this.maxBlock[idx] = this.maxBlock[left]; + this.max[idx] = r - this.maxBlock[left] + 1; + } else if (rightSplit) { + this.minBlock[idx] = this.minBlock[right]; + this.maxBlock[idx] = this.maxBlock[right]; + this.max[idx] = this.minBlock[right] - l; + } + } + + + add(x, idx = 0, l = 0, r = this.n - 1) { + if (l === r) { + this.minBlock[idx] = x; + this.maxBlock[idx] = x; + return; + } + const mid = l + r >> 1; + if (x <= mid + 1) this.add(x, idx * 2 + 1, l, mid); + else this.add(x, idx * 2 + 2, mid + 1, r); + this.update(idx, l, r) + } + + query(x, idx = 0, l = 0, r = this.n - 1) { + if (x <= l) return [0, 0, 0]; + if (x > r) return [this.minBlock[idx], this.maxBlock[idx], this.max[idx]]; + const mid = l + r >> 1; + if (x <= mid + 1) return this.query(x, idx * 2 + 1, l, mid); + const [lMinBlock, lMaxBlock, lMax] = this.query(x, idx * 2 + 1, l, mid); + const [rMinBlock, rMaxBlock, rMax] = this.query(x, idx * 2 + 2, mid + 1, r); + const leftEnd = lMaxBlock || l; + return [ + lMinBlock || rMinBlock, + rMaxBlock || lMaxBlock, + Math.max(lMax, rMax, (rMinBlock ? Math.min(rMinBlock, x) : x) - leftEnd) + ] + } +} diff --git a/3162-find-the-number-of-good-pairs-i.js b/3162-find-the-number-of-good-pairs-i.js new file mode 100644 index 00000000..9741659c --- /dev/null +++ b/3162-find-the-number-of-good-pairs-i.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ +var numberOfPairs = function (nums1, nums2, k) { + let res = 0 + for (let i = 0; i < nums1.length; i++) { + for (let j = 0; j < nums2.length; j++) { + if (nums1[i] % (nums2[j] * k) === 0) { + res++ + } + } + } + return res +} diff --git a/3163-string-compression-iii.js b/3163-string-compression-iii.js new file mode 100644 index 00000000..0b170072 --- /dev/null +++ b/3163-string-compression-iii.js @@ -0,0 +1,28 @@ +/** + * @param {string} word + * @return {string} + */ +var compressedString = function(word) { + let res = '' + let c = word[0] + let cnt = 0 + for (let i = 0; i < word.length; i++) { + if (c === word[i]) { + cnt++ + if (cnt === 9) { + res += `${cnt}${c}` + cnt = 0 + } + } else { + if (cnt !== 0) { + res += `${cnt}${c}` + } + c = word[i] + cnt = 1 + } + } + if (cnt !== 0) { + res += `${cnt}${c}` + } + return res +}; diff --git a/3164-find-the-number-of-good-pairs-ii.js b/3164-find-the-number-of-good-pairs-ii.js new file mode 100644 index 00000000..0ac0139c --- /dev/null +++ b/3164-find-the-number-of-good-pairs-ii.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ +var numberOfPairs = function(nums1, nums2, k) { + const freqMap = new Map() + for (const num of nums2) { + freqMap.set(num, (freqMap.get(num) || 0) + 1) + } + + let res = 0 + + for (const num1 of nums1) { + let factor = 1 + while (factor * factor <= num1) { + if (num1 % factor === 0) { + if (factor % k === 0 && freqMap.has(factor / k)) { + res += freqMap.get(factor / k) + } + if (factor !== num1 / factor) { + if ((num1 / factor) % k === 0 && freqMap.has(num1 / factor / k)) { + res += freqMap.get(num1 / factor / k) + } + } + } + factor++ + } + } + + return res +}; diff --git a/3165-maximum-sum-of-subsequence-with-non-adjacent-elements.js b/3165-maximum-sum-of-subsequence-with-non-adjacent-elements.js new file mode 100644 index 00000000..64433f77 --- /dev/null +++ b/3165-maximum-sum-of-subsequence-with-non-adjacent-elements.js @@ -0,0 +1,181 @@ +const M = 1e9 + 7 +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number} + */ +var maximumSumSubsequence = function (nums, queries) { + const n = nums.length + const root = new SegTreeNode(0, n - 1, nums) + let res = 0 + for (const q of queries) { + root.updateRange(q[0], q[1]) + res += Math.max(root.info00, root.info01, root.info10, root.info11) + res %= M + } + return res +} + +class SegTreeNode { + constructor(a, b, vals) { + this.left = null + this.right = null + this.start = a + this.end = b + if (a === b) { + this.info11 = vals[a] + this.info01 = -1e18 + this.info10 = -1e18 + this.info00 = 0 + return + } + const mid = Math.floor((a + b) / 2) + this.left = new SegTreeNode(a, mid, vals) + this.right = new SegTreeNode(mid + 1, b, vals) + this.info11 = Math.max( + this.left.info10 + this.right.info01, + this.left.info11 + this.right.info01, + this.left.info10 + this.right.info11, + ) + this.info00 = Math.max( + this.left.info00 + this.right.info00, + this.left.info01 + this.right.info00, + this.left.info00 + this.right.info10, + ) + this.info10 = Math.max( + this.left.info10 + this.right.info00, + this.left.info10 + this.right.info10, + this.left.info11 + this.right.info00, + ) + this.info01 = Math.max( + this.left.info00 + this.right.info01, + this.left.info01 + this.right.info01, + this.left.info00 + this.right.info11, + ) + } + + updateRange(a, val) { + if (a < this.start || a > this.end) { + return + } + if (this.start === this.end) { + this.info00 = 0 + this.info11 = val + return + } + this.left.updateRange(a, val) + this.right.updateRange(a, val) + this.info11 = Math.max( + this.left.info10 + this.right.info01, + this.left.info11 + this.right.info01, + this.left.info10 + this.right.info11, + ) + this.info00 = Math.max( + this.left.info00 + this.right.info00, + this.left.info01 + this.right.info00, + this.left.info00 + this.right.info10, + ) + this.info10 = Math.max( + this.left.info10 + this.right.info00, + this.left.info10 + this.right.info10, + this.left.info11 + this.right.info00, + ) + this.info01 = Math.max( + this.left.info00 + this.right.info01, + this.left.info01 + this.right.info01, + this.left.info00 + this.right.info11, + ) + } +} + +// another + + +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number} + */ +var maximumSumSubsequence = function (nums, queries) { + const ninf = -Infinity + const mod = 1e9 + 7 + const n = nums.length + let tree = new Tree(n) + + for (let i = 0; i < n; ++i) { + tree.modify(1, 0, tree.nn, i, nums[i]) + } + for (let i = n; i < tree.nn; ++i) { + tree.modify(1, 0, tree.nn, i, 0) + } + + let res = 0 + + for (let q of queries) { + let pos = q[0] + let x = q[1] + tree.modify(1, 0, tree.nn, pos, x) + res += mod + (tree.query() % mod) // [0, 2*mod) + } + + res %= mod + return res +} + +class Tree { + constructor(n) { + this.nn = n + this.space = new Array(4 * n + 1).fill(null).map(() => ({ + mx: [ + [0, -0x1ffffffffffff], + [-0x1ffffffffffff, 0], + ], + })) + for (;;) { + let low_bit = this.nn & -this.nn + if (low_bit == this.nn) { + break + } + this.nn += low_bit + } + } + + modify(index, sl, sr, q, qv) { + let v = this.space[index] + if (sl + 1 == sr) { + v.mx = [ + [0, -0x1ffffffffffff], + [-0x1ffffffffffff, qv], + ] + return + } + let m = (sl + sr) >> 1 + if (q < m) { + this.modify(index * 2, sl, m, q, qv) + } else { + this.modify(index * 2 + 1, m, sr, q, qv) + } + let l = this.space[index * 2] + let r = this.space[index * 2 + 1] + for (let lb of [0, 1]) { + for (let rb of [0, 1]) { + let ans = -0x1ffffffffffff + ans = Math.max(ans, l.mx[lb][1] + r.mx[0][rb]) + ans = Math.max(ans, l.mx[lb][0] + r.mx[1][rb]) + ans = Math.max(ans, l.mx[lb][0] + r.mx[0][rb]) + v.mx[lb][rb] = ans + } + } + } + + query() { + let v = this.space[1] + let ans = -0x1ffffffffffff + for (let i = 0; i < 2; i++) { + for (let j = 0; j < 2; j++) { + ans = Math.max(ans, v.mx[i][j]) + } + } + return ans + } +} diff --git a/3168-minimum-number-of-chairs-in-a-waiting-room.js b/3168-minimum-number-of-chairs-in-a-waiting-room.js new file mode 100644 index 00000000..8fa89084 --- /dev/null +++ b/3168-minimum-number-of-chairs-in-a-waiting-room.js @@ -0,0 +1,19 @@ +/** + * @param {string} s + * @return {number} + */ +var minimumChairs = function(s) { + let currentChairs = 0 + let maxChairsNeeded = 0 + + for (let event of s) { + if (event === 'E') { + currentChairs++ + maxChairsNeeded = Math.max(maxChairsNeeded, currentChairs) + } else if (event === 'L') { + currentChairs-- + } + } + + return maxChairsNeeded +}; diff --git a/3169-count-days-without-meetings.js b/3169-count-days-without-meetings.js new file mode 100644 index 00000000..17da932d --- /dev/null +++ b/3169-count-days-without-meetings.js @@ -0,0 +1,27 @@ +/** + * @param {number} days + * @param {number[][]} meetings + * @return {number} + */ +var countDays = function (days, meetings) { + let uniqueMeetings = Array.from(new Set(meetings.map(JSON.stringify))).map( + JSON.parse, + ) + uniqueMeetings.sort((a, b) => a[0] - b[0]) + let mergedMeetings = [uniqueMeetings[0]] + for (let i = 1; i < uniqueMeetings.length; i++) { + if (uniqueMeetings[i][0] <= mergedMeetings[mergedMeetings.length - 1][1]) { + mergedMeetings[mergedMeetings.length - 1][1] = Math.max( + mergedMeetings[mergedMeetings.length - 1][1], + uniqueMeetings[i][1], + ) + } else { + mergedMeetings.push(uniqueMeetings[i]) + } + } + let totalWork = mergedMeetings.reduce( + (acc, meeting) => acc + (meeting[1] - meeting[0] + 1), + 0, + ) + return days - totalWork +} diff --git a/317-shortest-distance-from-all-buildings.js b/317-shortest-distance-from-all-buildings.js new file mode 100644 index 00000000..1c670748 --- /dev/null +++ b/317-shortest-distance-from-all-buildings.js @@ -0,0 +1,59 @@ +const DIRECTIONS = [ + [0, 1], + [1, 0], + [0, -1], + [-1, 0] +] + +function distanceFromBuilding(grid, r, c, distance, start) { + const rows = grid.length + const cols = grid[0].length + const queue = [[r, c, 1]] + let qIndex = 0 + let minDistance = Infinity + while (qIndex < queue.length) { + const [r0, c0, d] = queue[qIndex] + for (const [dr, dc] of DIRECTIONS) { + const r1 = r0 + dr + const c1 = c0 + dc + if ( + 0 <= r1 && + r1 < rows && + 0 <= c1 && + c1 < cols && + grid[r1][c1] === start + ) { + distance[r1][c1] += d + minDistance = Math.min(minDistance, distance[r1][c1]) + grid[r1][c1] -= 1 + queue.push([r1, c1, d + 1]) + } + } + qIndex += 1 + } + return minDistance +} + +/** + * @param {number[][]} grid + * @return {number} + */ +const shortestDistance = function(grid) { + const rows = grid.length + const cols = grid[0].length + const distance = new Array(rows).fill(null).map(() => new Array(cols).fill(0)) + let start = 0 + let minDistance = 0 + for (let r = 0; r < rows; r += 1) { + for (let c = 0; c < cols; c += 1) { + if (grid[r][c] === 1) { + minDistance = distanceFromBuilding(grid, r, c, distance, start) + if (minDistance === Infinity) { + return -1 + } + start -= 1 + } + } + } + return minDistance +} diff --git a/3170-lexicographically-minimum-string-after-removing-stars.js b/3170-lexicographically-minimum-string-after-removing-stars.js new file mode 100644 index 00000000..e0bb7c0e --- /dev/null +++ b/3170-lexicographically-minimum-string-after-removing-stars.js @@ -0,0 +1,36 @@ +/** + * @param {string} s + * @return {string} + */ +var clearStars = function (s) { + let starPos = [] + for (let i = 0; i < s.length; i++) { + if (s[i] === '*') { + starPos.push(i) + } + } + let toDel = new Set(starPos) + if (starPos.length === 0) { + return s + } + let chsPos = Array.from({ length: 26 }, () => []) + for (let i = 0; i < s.length; i++) { + if (s[i] === '*') { + for (let j = 0; j < 26; j++) { + if (chsPos[j].length > 0) { + toDel.add(chsPos[j].pop()) + break + } + } + } else { + chsPos[s.charCodeAt(i) - 'a'.charCodeAt(0)].push(i) + } + } + let t = '' + for (let i = 0; i < s.length; i++) { + if (!toDel.has(i)) { + t += s[i] + } + } + return t +} diff --git a/3171-find-subarray-with-bitwise-or-closest-to-k.js b/3171-find-subarray-with-bitwise-or-closest-to-k.js new file mode 100644 index 00000000..2aba1d29 --- /dev/null +++ b/3171-find-subarray-with-bitwise-or-closest-to-k.js @@ -0,0 +1,33 @@ + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minimumDifference = function(nums, k) { + const bits = new Array(32).fill(0); + let res = Number.MAX_SAFE_INTEGER, n = nums.length; + let left = 0, right = 0; + while (right < n) { + let curr = update(nums[right], 1); + res = Math.min(res, Math.abs(curr - k)); + while (left < right && curr > k) { + curr = update(nums[left++], -1); + res = Math.min(res, Math.abs(curr - k)); + } + right++; + } + return res; + function update(num, val) { + let res = 0; + for (let i = 0; i < 32; i++) { + if ((num >> i) & 1) { + bits[i] += val; + } + if (bits[i]) res |= 1 << i; + } + return res; + } +}; + + diff --git a/3176-find-the-maximum-length-of-a-good-subsequence-i.js b/3176-find-the-maximum-length-of-a-good-subsequence-i.js new file mode 100644 index 00000000..f8f16f5a --- /dev/null +++ b/3176-find-the-maximum-length-of-a-good-subsequence-i.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumLength = function (nums, k) { + const n = nums.length + const res = Array(k + 1).fill(0) + const dp = Array.from({ length: k + 1 }, () => new Map()) + for (const a of nums) { + for (let i = k; i >= 0; i--) { + const v = dp[i].get(a) || 0 + dp[i].set(a, Math.max(v + 1, i > 0 ? res[i - 1] + 1 : 0)) + res[i] = Math.max(res[i], dp[i].get(a)) + } + } + + return res[k] +} diff --git a/3177-find-the-maximum-length-of-a-good-subsequence-ii.js b/3177-find-the-maximum-length-of-a-good-subsequence-ii.js new file mode 100644 index 00000000..d5739f7b --- /dev/null +++ b/3177-find-the-maximum-length-of-a-good-subsequence-ii.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumLength = function(nums, k) { + const n = nums.length; + const res = Array(k + 1).fill(0); + const dp = Array.from({ length: k + 1 }, () => new Map()); + for (const a of nums) { + for (let i = k; i >= 0; i--) { + const v = dp[i].get(a) || 0; + const vv = Math.max(v + 1, i > 0 ? res[i - 1] + 1 : 0) + dp[i].set(a, vv); + res[i] = Math.max(res[i], vv); + } + } + return res[k] +}; diff --git a/3178-find-the-child-who-has-the-ball-after-k-seconds.js b/3178-find-the-child-who-has-the-ball-after-k-seconds.js new file mode 100644 index 00000000..18916378 --- /dev/null +++ b/3178-find-the-child-who-has-the-ball-after-k-seconds.js @@ -0,0 +1,11 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +var numberOfChild = function(n, k) { + let l = 2 * (n-1) + let r = k % l + if (r < n) return r + else return l - r +}; diff --git a/3179-find-the-n-th-value-after-k-seconds.js b/3179-find-the-n-th-value-after-k-seconds.js new file mode 100644 index 00000000..09ae164a --- /dev/null +++ b/3179-find-the-n-th-value-after-k-seconds.js @@ -0,0 +1,17 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +var valueAfterKSeconds = function(n, k) { + const mod = 1e9 + 7 + let a = new Array(n).fill(1) + + for (let i = 0; i < k; i++) { + for (let j = 1; j < n; j++) { + a[j] = (a[j] + a[j - 1]) % mod + } + } + + return a[n - 1] +}; diff --git a/3180-maximum-total-reward-using-operations-i.js b/3180-maximum-total-reward-using-operations-i.js new file mode 100644 index 00000000..a89e6d64 --- /dev/null +++ b/3180-maximum-total-reward-using-operations-i.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} rewardValues + * @return {number} + */ +var maxTotalReward = function (rewardValues) { + rewardValues.sort((a, b) => a - b) + const ts = new Set([0]) + for (const item of rewardValues) { + const set = new Set() + for (const t of ts) { + if (t < item) { + set.add(t + item) + } + } + for (const value of set) { + ts.add(value) + } + } + return Math.max(...ts) +} diff --git a/3181-maximum-total-reward-using-operations-ii.js b/3181-maximum-total-reward-using-operations-ii.js new file mode 100644 index 00000000..d9c941b4 --- /dev/null +++ b/3181-maximum-total-reward-using-operations-ii.js @@ -0,0 +1,56 @@ +/** + * @param {number[]} rewardValues + * @return {number} + */ +var maxTotalReward = function (rewardValues) { + rewardValues.sort((a, b) => a-b); + + let dp = new Uint8Array(rewardValues.at(-1)*2).fill(0); + let max = rewardValues.at(-1); + + dp[0] = 1; + + for(let i = 0; i < rewardValues.length; ++i) { + let val = rewardValues[i]; + if(i > 0 && rewardValues[i-1] === val) { continue; } + let curMax = Math.min(val-1, (max-val)-1); + + + for(let j = 0; j <= curMax; ++j) { + if(dp[j] === 1) { + let found = j + val; + dp[found] = 1; + } else if(dp[j] === 2) { + //skip ahead + j += 100; + } else { + //determine how big the gap is + let runStart = j; + let target = runStart + 100; + while(j < curMax && j <= target && dp[j] === 0) { + ++j; + } + + if(j >= target) { + //the gap is at least 100, mark it as skippable + dp[runStart] = 2; + } + if(dp[j]) { --j; } + } + } + + //we found max-1, since we're including max, no need to continue + if(dp[max-1]) { + break; + } + + } + + for(let i = dp.length-1; i >= 0; --i) { + if(dp[i]) { + return i + max; + } + } + + return -1; +} diff --git a/3184-count-pairs-that-form-a-complete-day-i.js b/3184-count-pairs-that-form-a-complete-day-i.js new file mode 100644 index 00000000..01f56b42 --- /dev/null +++ b/3184-count-pairs-that-form-a-complete-day-i.js @@ -0,0 +1,14 @@ +/** + * @param {number[]} hours + * @return {number} + */ +var countCompleteDayPairs = function(hours) { + let res = 0 + const n = hours.length + for(let i = 0; i < n; i++) { + for(let j = i + 1; j < n; j++) { + if((hours[i] + hours[j]) % 24 === 0) res++ + } + } + return res +}; diff --git a/3185-count-pairs-that-form-a-complete-day-ii.js b/3185-count-pairs-that-form-a-complete-day-ii.js new file mode 100644 index 00000000..5ceff702 --- /dev/null +++ b/3185-count-pairs-that-form-a-complete-day-ii.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} hours + * @return {number} + */ +var countCompleteDayPairs = function(hours) { + const map = new Map() + const n = hours.length + let res = 0 + for(let i = 0; i < n; i++) { + const e = hours[i] + const remain = e % 24 + if(remain === 0 || remain === 24) res += (map.get(24) || 0) + (map.get(0) || 0) + else res += (map.get(24 - remain) || 0) + // console.log('res', res) + map.set(remain, (map.get(remain) || 0) + 1) + } + // console.log(map) + + return res +}; diff --git a/3186-maximum-total-damage-with-spell-casting.js b/3186-maximum-total-damage-with-spell-casting.js new file mode 100644 index 00000000..7db66a9f --- /dev/null +++ b/3186-maximum-total-damage-with-spell-casting.js @@ -0,0 +1,66 @@ +/** + * @param {number[]} power + * @return {number} + */ +const maximumTotalDamage = function(power) { + const freq = new Map() + for (const p of power) { + freq.set(p, (freq.get(p) || 0) + 1) + } + const sorted = Array.from(freq.keys()).sort((a, b) => a - b) + const n = sorted.length + const dp = Array(n+1).fill(0) + dp[1] = sorted[0] * freq.get(sorted[0]) + for(let i = 2; i <= n; i++) { + const val = sorted[i-1] + const cur = val * freq.get(val) + let j = i - 2 + + if(j >= 0 && sorted[j] + 1 === val) { + j-- + } + if(j >= 0 && sorted[j] + 2 === val) { + j-- + } + + if(j >= 0) { + dp[i] = Math.max(dp[i-1], dp[j+1] + cur) + } else { + dp[i] = Math.max(dp[i-1], cur) + } + + } + + return dp[n] +}; + +// another + +/** + * @param {number[]} power + * @return {number} + */ +var maximumTotalDamage = function (power) { + power.sort((a, b) => a - b) + const freqMap = new Map() + for (const p of power) { + freqMap.set(p, (freqMap.get(p) || 0) + 1) + } + const uniqueDamages = Array.from(freqMap.keys()).sort((a, b) => a - b) + const n = uniqueDamages.length + const dp = new Array(n + 1).fill(0) + for (let i = 0; i < n; i++) { + const damage = uniqueDamages[i] + const totalDamage = damage * freqMap.get(damage) + + dp[i + 1] = Math.max(dp[i + 1], dp[i]) + + let j = i - 1 + while (j >= 0 && uniqueDamages[j] >= damage - 2) { + j-- + } + dp[i + 1] = Math.max(dp[i + 1], (j >= 0 ? dp[j + 1] : 0) + totalDamage) + } + + return dp[n] +} diff --git a/3187-peaks-in-array.js b/3187-peaks-in-array.js new file mode 100644 index 00000000..44d7bf11 --- /dev/null +++ b/3187-peaks-in-array.js @@ -0,0 +1,214 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +var countOfPeaks = function (nums, queries) { + const n = nums.length + const bit = new BIT() + bit.init(n) + for (let i = 0; i < n; i++) { + if (isPeak(nums, i)) { + bit.add(i + 1, 1) + } + } + const res = [] + for (const q of queries) { + if (q[0] === 1) { + const [l, r] = [q[1], q[2]] + let cnt = bit.query(r + 1) - bit.query(l) + if (isPeak(nums, l)) { + cnt-- + } + if (isPeak(nums, r)) { + cnt-- + } + if (isPeak(nums, l) && l === r) { + cnt++ + } + res.push(cnt) + } else { + const [idx, val] = [q[1], q[2]] + if (isPeak(nums, idx)) { + bit.add(idx + 1, -1) + } + if (idx > 0 && isPeak(nums, idx - 1)) { + bit.add(idx, -1) + } + if (idx < n - 1 && isPeak(nums, idx + 1)) { + bit.add(idx + 2, -1) + } + nums[idx] = val + if (isPeak(nums, idx)) { + bit.add(idx + 1, 1) + } + if (idx > 0 && isPeak(nums, idx - 1)) { + bit.add(idx, 1) + } + if (idx < n - 1 && isPeak(nums, idx + 1)) { + bit.add(idx + 2, 1) + } + } + } + return res +} +function isPeak(nums, i) { + if (i === 0 || i === nums.length - 1) { + return false + } + return nums[i] > nums[i - 1] && nums[i] > nums[i + 1] +} + +class BIT { + constructor() { + this.tree = [] + } + + init(n) { + this.tree = new Array(n + 1).fill(0) + } + + add(i, val) { + while (i < this.tree.length) { + this.tree[i] += val + i += i & -i + } + } + + query(i) { + let sum = 0 + while (i > 0) { + sum += this.tree[i] + i -= i & -i + } + return sum + } +} + +// another + +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +var countOfPeaks = function (nums, queries) { + const n = nums.length + const peak = new Array(n).fill(0) + + for (let i = 1; i < n - 1; ++i) { + if (nums[i] > nums[i - 1] && nums[i] > nums[i + 1]) peak[i] = 1 + } + + const ans = [] + const st = new SegmentTree(n) + st.build(0, 0, n - 1, peak) + + for (let i = 0; i < queries.length; ++i) { + const q = queries + const type = q[i][0] + + if (type === 1) { + const l = q[i][1] + const r = q[i][2] + + if (l === r) { + ans.push(0) + continue + } + + let red = 0 + + if (peak[l] === 1) ++red + + if (peak[r] === 1) ++red + + const res = st.query(0, 0, n - 1, l, r) + ans.push(res - red) + } else if (type === 2) { + const p = q[i][1] + const x = q[i][2] + + nums[p] = x + + if (p - 1 >= 0 && p + 1 < n) { + if (nums[p] > nums[p - 1] && nums[p] > nums[p + 1]) { + st.update(0, 0, n - 1, p, 1) + peak[p] = 1 + } else { + st.update(0, 0, n - 1, p, 0) + peak[p] = 0 + } + } + + if (p - 2 >= 0 && p < n) { + if (nums[p - 1] > nums[p - 2] && nums[p - 1] > nums[p]) { + st.update(0, 0, n - 1, p - 1, 1) + peak[p - 1] = 1 + } else { + st.update(0, 0, n - 1, p - 1, 0) + peak[p - 1] = 0 + } + } + + if (p >= 0 && p + 2 < n) { + if (nums[p + 1] > nums[p] && nums[p + 1] > nums[p + 2]) { + st.update(0, 0, n - 1, p + 1, 1) + peak[p + 1] = 1 + } else { + st.update(0, 0, n - 1, p + 1, 0) + peak[p + 1] = 0 + } + } + } + } + + return ans +} + +class SegmentTree { + constructor(n) { + this.seg = new Array(4 * n + 1).fill(0) + } + + build(ind, low, high, arr) { + if (low === high) { + this.seg[ind] = arr[low] + return + } + + const mid = Math.floor((low + high) / 2) + + this.build(2 * ind + 1, low, mid, arr) + this.build(2 * ind + 2, mid + 1, high, arr) + + this.seg[ind] = this.seg[2 * ind + 1] + this.seg[2 * ind + 2] + } + + query(ind, low, high, l, r) { + if (r < low || high < l) return 0 + + if (low >= l && high <= r) return this.seg[ind] + + const mid = Math.floor((low + high) / 2) + const left = this.query(2 * ind + 1, low, mid, l, r) + const right = this.query(2 * ind + 2, mid + 1, high, l, r) + + return left + right + } + + update(ind, low, high, i, val) { + if (low === high) { + this.seg[ind] = val + return + } + + const mid = Math.floor((low + high) / 2) + + if (i <= mid) this.update(2 * ind + 1, low, mid, i, val) + else this.update(2 * ind + 2, mid + 1, high, i, val) + + this.seg[ind] = this.seg[2 * ind + 1] + this.seg[2 * ind + 2] + } +} + diff --git a/3193-count-the-number-of-inversions.js b/3193-count-the-number-of-inversions.js new file mode 100644 index 00000000..04abfd9c --- /dev/null +++ b/3193-count-the-number-of-inversions.js @@ -0,0 +1,78 @@ +/** + * @param {number} n + * @param {number[][]} requirements + * @return {number} + */ +var numberOfPermutations = function(n, requirements) { + // setup map/vector for tracking inversions + let inv = new Array(n + 1).fill(-1); + for (let req of requirements) { + if (inv[req[0] + 1] === -1) { + inv[req[0] + 1] = req[1]; + } else { + return 0; + } + } + + // sanity check + // if length of the sequence is l + // then there can be at most l*(l-1)/2 inversion pairs + // in the case of decreasing order + for (let i = 1; i <= n; i++) { + if (inv[i] > (i * (i - 1)) / 2) { + return 0; + } + } + + // dp[len][inv] + // solution for the prefix of length len, and inv inversion pairs + + // setup dp + const m = 400; + const MOD = 1e9 + 7; + let dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0)); + + // base case + // i == 0, dp[0][j] = 0, j > 1, in memset + // i == 0 && j == 0, dp[0][0] = 1 + dp[0][0] = 1; + + /* + Note: + suppose we have a sequence of length (l-1), and we want to extend it to + a sequence of length l, then what can happen to the number of inversion? + + you can increase the number of inversions by at most (l-1). + + so we need to check dp[i-1][j] for dp[i][c] + where j = c-0, c-1, ..... , c-(l-1) + */ + + // recursion + for (let i = 1; i <= n; i++) { // length + // case 1, we have a requirement given + // then just iterate for that value, + if (inv[i] !== -1) { + for (let k = 0; k < i; k++) { + if (inv[i] - k < 0) break; + dp[i][inv[i]] = (dp[i][inv[i]] + dp[i - 1][inv[i] - k]) % MOD; + } + } + // case 2 when we don't have any given requirement + // then iterate over all the values + else { + for (let c = 0; c <= m; c++) { + // maximum number of inversions + if (c > (i * (i - 1)) / 2) break; + + for (let k = 0; k < i; k++) { + if (c - k < 0) break; + dp[i][c] = (dp[i][c] + dp[i - 1][c - k]) % MOD; + } + } + } + } + + // return the ans + return dp[n][inv[n]]; +}; diff --git a/3194-minimum-average-of-smallest-and-largest-elements.js b/3194-minimum-average-of-smallest-and-largest-elements.js new file mode 100644 index 00000000..e8182c15 --- /dev/null +++ b/3194-minimum-average-of-smallest-and-largest-elements.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minimumAverage = function(nums) { + nums.sort((a, b) => a - b) + const arr = [] + let i = 0, j = nums.length - 1 + while(i < j) { + let a = nums[i], b = nums[j] + arr.push((a+b)/2) + i++ + j-- + } + return Math.min(...arr) +}; diff --git a/3195-find-the-minimum-area-to-cover-all-ones-i.js b/3195-find-the-minimum-area-to-cover-all-ones-i.js new file mode 100644 index 00000000..7b0e8296 --- /dev/null +++ b/3195-find-the-minimum-area-to-cover-all-ones-i.js @@ -0,0 +1,19 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var minimumArea = function(grid) { + const m = grid.length, n = grid[0].length + let rmax = -1, rmin = Infinity, cmax = -1, cmin = Infinity + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] === 1) { + rmin = Math.min(rmin, i) + cmin = Math.min(cmin, j) + rmax = Math.max(rmax, i) + cmax = Math.max(cmax, j) + } + } + } + return (rmax - rmin + 1) * (cmax - cmin + 1) +}; diff --git a/3196-maximize-total-cost-of-alternating-subarrays.js b/3196-maximize-total-cost-of-alternating-subarrays.js new file mode 100644 index 00000000..e2c72e8f --- /dev/null +++ b/3196-maximize-total-cost-of-alternating-subarrays.js @@ -0,0 +1,47 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maximumTotalCost = function(nums) { + const n = nums.length; + const dp = Array.from({ length: n + 1 }, () => Array(2).fill(0)); + dp[1][0] = nums[0] + dp[1][1] = nums[0] + for (let i = 2; i <= n; i++) { + const e = nums[i - 1] + dp[i][0] = Math.max(dp[i - 1][1], dp[i - 1][0]) + e + dp[i][1] = dp[i - 1][0] - e + } + + + return Math.max(dp[n][0], dp[n][1]) +}; + +// another + + +/** + * @param {number[]} nums + * @return {number} + */ +var maximumTotalCost = function (nums) { + const n = nums.length + const cache = new Map() + + return dfs(n - 1) + function dfs(i) { + if (cache.has(i)) return cache.get(i) + if (i === 0) { + return nums[0] + } else if (i === 1) { + return nums[0] + Math.abs(nums[1]) + } else { + const result = Math.max( + dfs(i - 1) + nums[i], + dfs(i - 2) + nums[i - 1] - nums[i], + ) + cache.set(i, result) + return result + } + } +} diff --git a/3197-find-the-minimum-area-to-cover-all-ones-ii.js b/3197-find-the-minimum-area-to-cover-all-ones-ii.js new file mode 100644 index 00000000..7d16a72e --- /dev/null +++ b/3197-find-the-minimum-area-to-cover-all-ones-ii.js @@ -0,0 +1,122 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const minimumSum = function(grid) { + const m = grid.length, n = grid[0].length + let res = Infinity +// case 1 +/* +1 | 2 | 3 +*/ +for(let i = 0; i < n - 2; i++) { + const one = calc(0, m - 1, 0, i, grid) + for(let j = i + 1; j < n - 1; j++) { + const two = calc(0, m - 1, i + 1, j, grid) + const three = calc(0, m - 1, j + 1, n - 1, grid) + res = Math.min(res, one + two + three) + } +} + + +// case 2 +/* +1 +- +2 +- +3 +*/ +for(let i = 0; i < m - 2; i++) { + const one = calc(0, i, 0, n - 1, grid) + for(let j = i + 1; j < m - 1; j++) { + const two = calc(i + 1, j, 0, n - 1, grid) + const three = calc(j + 1, m - 1, 0, n - 1, grid) + res = Math.min(res, one + two + three) + } +} + + +// case 3 +/* +2 | 3 +----- + 1 +*/ +for(let i = m - 1; i >= 1; i--) { + const one = calc(i, m - 1, 0, n - 1, grid) + for(let j = 0; j < n - 1; j++) { + const two = calc(0, i - 1, 0, j, grid) + const three = calc(0, i - 1, j + 1, n - 1, grid) + res = Math.min(res, one + two + three) + } + +} + + +// case 4 +/* +2 | +--| 1 +3 | +*/ +for(let i = n - 1; i >= 1; i--) { + const one = calc(0, m - 1, i, n - 1, grid) + for(let j = 0; j < m - 1; j++) { + const two = calc(0, j, 0, i - 1, grid) + const three = calc(j + 1, m - 1, 0, i - 1, grid) + res = Math.min(res, one + two + three) + } + } + + +// case 5 +/* + 1 +----- +2 | 3 +*/ +for(let i = 0; i < m - 1; i++) { + const one = calc(0, i, 0, n - 1, grid) + for(let j = 0; j < n - 1; j++) { + const two = calc(i + 1, m - 1, 0, j, grid) + const three = calc(i + 1, m - 1, j + 1, n - 1, grid) + res = Math.min(res, one + two + three) + } + +} + + +// case 6 +/* + | 2 + 1 |-- + | 3 +*/ +for(let j = 0; j < n - 1; j++) { + const one = calc(0, m - 1, 0, j, grid) + for(let i = 0; i < m - 1; i++) { + const two = calc(0, i, j + 1, n - 1, grid) + const three = calc(i + 1, m - 1, j + 1, n - 1, grid) + res = Math.min(res, one + two + three) + } +} + + return res +}; + +function calc(rs, re, cs, ce, grid) { + + let rmin = Infinity, rmax = -Infinity, cmin = Infinity, cmax = -Infinity + for(let i = rs; i <= re; i++) { + for(let j = cs; j <= ce; j++) { + if(grid[i][j] === 1) { + rmin = Math.min(rmin, i) + rmax = Math.max(rmax, i) + cmin = Math.min(cmin, j) + cmax = Math.max(cmax, j) + } + } + } + return (rmax - rmin + 1) * (cmax - cmin + 1) +} diff --git a/3198-find-the-minimum-area-to-cover-all-ones-ii.js b/3198-find-the-minimum-area-to-cover-all-ones-ii.js new file mode 100644 index 00000000..5bdd1380 --- /dev/null +++ b/3198-find-the-minimum-area-to-cover-all-ones-ii.js @@ -0,0 +1,117 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var minimumSum = function (grid) { + const n = grid.length + const m = grid[0].length + let ans = n * m + + for (let i = 0; i < n - 1; i++) { + const grid1 = grid.slice(0, i + 1).map((row) => row.slice()) + const ret1 = minimumArea(grid1) + + for (let j = 0; j < m - 1; j++) { + const grid2 = grid.slice(i + 1).map((row) => row.slice(0, j + 1)) + const grid3 = grid.slice(i + 1).map((row) => row.slice(j + 1)) + // console.log(grid1, grid2, grid3); + const ret2 = minimumArea(grid2) + const ret3 = minimumArea(grid3) + ans = Math.min(ans, ret1 + ret2 + ret3) + } + } + + for (let i = 0; i < n - 1; i++) { + const grid1 = grid.slice(i + 1).map((row) => row.slice()) + const ret1 = minimumArea(grid1) + + for (let j = 0; j < m - 1; j++) { + const grid2 = grid.slice(0, i + 1).map((row) => row.slice(0, j + 1)) + const grid3 = grid.slice(0, i + 1).map((row) => row.slice(j + 1)) + // console.log(grid1, grid2, grid3); + const ret2 = minimumArea(grid2) + const ret3 = minimumArea(grid3) + ans = Math.min(ans, ret1 + ret2 + ret3) + } + } + + for (let j = 0; j < m - 1; j++) { + const grid1 = grid.map((row) => row.slice(0, j + 1)) + const ret1 = minimumArea(grid1) + + for (let i = 0; i < n - 1; i++) { + const grid2 = grid.slice(0, i + 1).map((row) => row.slice(j + 1)) + const grid3 = grid.slice(i + 1).map((row) => row.slice(j + 1)) + // console.log(grid1, grid2, grid3); + const ret2 = minimumArea(grid2) + const ret3 = minimumArea(grid3) + ans = Math.min(ans, ret1 + ret2 + ret3) + } + } + + for (let j = 0; j < m - 1; j++) { + const grid1 = grid.map((row) => row.slice(j + 1)) + const ret1 = minimumArea(grid1) + + for (let i = 0; i < n - 1; i++) { + const grid2 = grid.slice(0, i + 1).map((row) => row.slice(0, j + 1)) + const grid3 = grid.slice(i + 1).map((row) => row.slice(0, j + 1)) + // console.log(grid1, grid2, grid3); + const ret2 = minimumArea(grid2) + const ret3 = minimumArea(grid3) + ans = Math.min(ans, ret1 + ret2 + ret3) + } + } + + for (let i = 0; i < n - 1; i++) { + const grid1 = grid.slice(0, i + 1).map((row) => row.slice()) + const ret1 = minimumArea(grid1) + + for (let k = i + 1; k < n - 1; k++) { + const grid2 = grid.slice(i + 1, k + 1).map((row) => row.slice()) + const grid3 = grid.slice(k + 1).map((row) => row.slice()) + + const ret2 = minimumArea(grid2) + const ret3 = minimumArea(grid3) + ans = Math.min(ans, ret1 + ret2 + ret3) + } + } + + for (let j = 0; j < m - 1; j++) { + const grid1 = grid.map((row) => row.slice(0, j + 1)) + const ret1 = minimumArea(grid1) + + for (let k = j + 1; k < m - 1; k++) { + const grid2 = grid.map((row) => row.slice(j + 1, k + 1)) + const grid3 = grid.map((row) => row.slice(k + 1)) + const ret2 = minimumArea(grid2) + const ret3 = minimumArea(grid3) + ans = Math.min(ans, ret1 + ret2 + ret3) + } + } + + return ans + + function minimumArea(grid) { + const n = grid.length + const m = grid[0].length + let x1 = n + let x2 = 0 + let y1 = m + let y2 = 0 + + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + if (grid[i][j] === 1) { + x1 = Math.min(x1, i) + x2 = Math.max(x2, i) + y1 = Math.min(y1, j) + y2 = Math.max(y2, j) + } + } + } + + const ret = (x2 - x1 + 1) * (y2 - y1 + 1) + return ret + } +} diff --git a/32-longest-valid-parentheses.js b/32-longest-valid-parentheses.js index d96dceff..cd69003d 100644 --- a/32-longest-valid-parentheses.js +++ b/32-longest-valid-parentheses.js @@ -36,3 +36,42 @@ const longestValidParentheses = function(s) { return longest } + +// another + +/** + * @param {string} s + * @return {number} + */ +const longestValidParentheses = function (s) { + let res = 0, + stk = [], + n = s.length, + idxStk = [] + for (let i = 0; i < n; i++) { + const ch = s[i] + if (stk.length && stk[stk.length - 1] === '(' && ch === ')') + stk.pop(), idxStk.pop() + else stk.push(ch), idxStk.push(i) + res = Math.max(res, i - (idxStk.length ? idxStk[idxStk.length - 1] : -1)) + } + return res +} +/** + * @param {string} s + * @return {number} + */ +const longestValidParentheses = function (s) { + let res = 0, + stk = [], + n = s.length, + idxStk = [] + for (let i = 0; i < n; i++) { + const ch = s[i] + if (stk.length && stk[stk.length - 1] === '(' && ch === ')') + stk.pop(), idxStk.pop() + else stk.push(ch), idxStk.push(i) + res = Math.max(res, i - (idxStk.length ? idxStk[idxStk.length - 1] : -1)) + } + return res +} diff --git a/320-generalized-abbreviation.js b/320-generalized-abbreviation.js new file mode 100644 index 00000000..b8fc1b48 --- /dev/null +++ b/320-generalized-abbreviation.js @@ -0,0 +1,66 @@ +/** + +Write a function to generate the generalized abbreviations of a word. +Note: The order of the output does not matter. + +Example: + +Input: "word" +Output: +["word", "1ord", "w1rd", "wo1d", "wor1", "2rd", "w2d", "wo2", "1o1d", "1or1", "w1r1", "1o2", "2r1", "3d", "w3", "4"] + +*/ + +/** + * @param {string} word + * @return {string[]} + */ +const generateAbbreviations = function(word) { + const n = word.length + const limit = 1 << n + const res = [] + + for(let mask = 0; mask < limit; mask++) { + res.push(helper(word, mask)) + } + + return res + + function helper(word, mask) { + let res = '', zero = 0, idx = 0 + for(let i = 0; i < n; i++) { + if(mask & (1 << i)) { + if(zero) res += zero + res += word[i] + zero = 0 + } else { + zero++ + } + if(i === n - 1 && zero) res += zero + } + + return res + } +}; + +// another + +/** + * @param {string} word + * @return {string[]} + */ +const generateAbbreviations = function(word) { + const arr = [] + dfs(arr, word, 0, '', 0) + return arr +}; + +function dfs(res, word, pos, cur, cnt) { + if(pos === word.length) { + if(cnt > 0) cur += cnt + res.push(cur) + } else { + dfs(res, word, pos + 1, cur, cnt + 1) + dfs(res, word, pos + 1, cur + (cnt > 0 ? cnt : '') + word.charAt(pos), 0) + } +} diff --git a/3200-maximum-height-of-a-triangle.js b/3200-maximum-height-of-a-triangle.js new file mode 100644 index 00000000..76d80fbd --- /dev/null +++ b/3200-maximum-height-of-a-triangle.js @@ -0,0 +1,46 @@ +/** + * @param {number} red + * @param {number} blue + * @return {number} + */ +const maxHeightOfTriangle = function(red, blue) { + let blueFirst = 0, redFirst = 0 + let bb = blue, rb = red + let b = 1, r = 2 + let bl = 0, rl = 0 + while(bb >= b) { + bl++ + bb -= b + b += 2 + } + while(rb >= r && rl < bl) { + rl++ + rb -= r + r += 2 + } + if(bl - rl > 1) bl = rl + 1 + + blueFirst = bl + rl + + bb = blue, rb = red + b = 2, r = 1 + bl = 0, rl = 0 + while(rb >= r) { + rl++ + rb -= r + r += 2 + } + + while(bb >= b && bl < rl) { + bl++ + bb -= b + b += 2 + } + if(rl - bl > 1) rl = bl + 1 + + redFirst = bl + rl + + + // return blueFirst + return Math.max(blueFirst, redFirst) +}; diff --git a/3201-find-the-maximum-length-of-valid-subsequence-i.js b/3201-find-the-maximum-length-of-valid-subsequence-i.js new file mode 100644 index 00000000..2e32d6ca --- /dev/null +++ b/3201-find-the-maximum-length-of-valid-subsequence-i.js @@ -0,0 +1,51 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maximumLength = function (nums) { + const n = nums.length + const arr = new Array(n) + let zeroCnt = 0 + let firstZeroIdx = -1 + let firstOneIdx = -1 + for (let i = 0; i < n; i++) { + arr[i] = nums[i] % 2 + if (arr[i] === 0) { + if (firstZeroIdx < 0) { + firstZeroIdx = i + } + zeroCnt++ + } else { + if (firstOneIdx < 0) { + firstOneIdx = i + } + } + } + const oneCnt = n - zeroCnt + // Assume the subsequence's modulo is 0 + let res = Math.max(zeroCnt, oneCnt) + // Modulo is 1 + if (firstZeroIdx >= 0) { + let tmp = 1 + let last = 0 + for (let i = firstZeroIdx + 1; i < n; i++) { + if ((last ^ arr[i]) === 1) { + tmp++ + last = arr[i] + } + } + res = Math.max(res, tmp) + } + if (firstOneIdx >= 0) { + let tmp = 1 + let last = 1 + for (let i = firstOneIdx + 1; i < n; i++) { + if ((last ^ arr[i]) === 1) { + tmp++ + last = arr[i] + } + } + res = Math.max(res, tmp) + } + return res +} diff --git a/3202-find-the-maximum-length-of-valid-subsequence-ii.js b/3202-find-the-maximum-length-of-valid-subsequence-ii.js new file mode 100644 index 00000000..f0e09cd1 --- /dev/null +++ b/3202-find-the-maximum-length-of-valid-subsequence-ii.js @@ -0,0 +1,53 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maximumLength = function(nums, k) { + const n = nums.length; + const dp = Array.from({ length: k + 1 }, () => Array(k + 1).fill(0)); + let res = 0 + for(const e of nums) { + const cur = e % k; + for(let remain = 0; remain < k; remain++) { + const prev = (k + remain - cur) % k; + dp[cur][remain] = Math.max(dp[cur][remain], dp[prev][remain] + 1) + res = Math.max(res, dp[cur][remain]) + } + } + + return res +}; + +// another + + +/** + * @param {number[]} nums + * @return {number} + */ +var maximumLength = function (nums, k) { + const n = nums.length; + const dp = Array.from({ length: n }, () => Array(k).fill(1)); + table(nums, k, dp); + + let maxLength = 0; + for (const row of dp) { + for (const length of row) { + maxLength = Math.max(maxLength, length); + } + } + return maxLength; +} +function table(nums, k, dp) { + const n = nums.length; + for (let i = 0; i < n; i++) { + for (let j = 0; j < i; j++) { + const remainder = (nums[i] + nums[j]) % k; + dp[i][remainder] = Math.max(dp[i][remainder], dp[j][remainder] + 1); + } + } +} + + + diff --git a/3203-find-minimum-diameter-after-merging-two-trees.js b/3203-find-minimum-diameter-after-merging-two-trees.js new file mode 100644 index 00000000..c6d788b9 --- /dev/null +++ b/3203-find-minimum-diameter-after-merging-two-trees.js @@ -0,0 +1,101 @@ +/** + * @param {number[][]} edges1 + * @param {number[][]} edges2 + * @return {number} + */ +var minimumDiameterAfterMerge = function (edges1, edges2) { + const getDiameter = (edges) => { + if (edges.length === 0) { + return 0 + } + const graph = new Map() + for (const [u, v] of edges) { + if (!graph.has(u)) { + graph.set(u, []) + } + graph.get(u).push(v) + if (!graph.has(v)) { + graph.set(v, []) + } + graph.get(v).push(u) + } + + function dfs(node, parent) { + // return longest path length and farthest node + let res = [0, node] + for (const neighbor of graph.get(node) || []) { + if (neighbor === parent) { + continue + } + const tmp = dfs(neighbor, node) + if (tmp[0] > res[0]) res = tmp + } + res[0] += 1 + return res + } + + const [_, endNode] = dfs(0, -1) + const [diameter, __] = dfs(endNode, -1) + return diameter - 1 + } + + const diameter1 = getDiameter(edges1) + const diameter2 = getDiameter(edges2) + const radius1 = Math.floor((diameter1 + 1) / 2) + const radius2 = Math.floor((diameter2 + 1) / 2) + return Math.max(radius1 + radius2 + 1, diameter1, diameter2) +} + +// another + +/** + * @param {number[][]} edges1 + * @param {number[][]} edges2 + * @return {number} + */ +var minimumDiameterAfterMerge = function(edges1, edges2) { + const [d1, i, j] = diameter(edges1); + const [d2, ii, jj] = diameter(edges2); + return Math.max(d1, d2, Math.floor((d1 + 1) / 2) + Math.floor((d2 + 1) / 2) + 1); + + function farthest(G, i) { + const n = G.length; + const bfs = [i]; + const seen = new Array(n).fill(0); + seen[i] = 1; + let res = 0; + let maxd = 0; + for (let k = 0; k < bfs.length; k++) { + const node = bfs[k]; + for (let j = 0; j < G[node].length; j++) { + const neighbor = G[node][j]; + if (seen[neighbor] === 0) { + seen[neighbor] = seen[node] + 1; + bfs.push(neighbor); + if (seen[neighbor] > maxd) { + res = neighbor; + maxd = seen[neighbor]; + } + } + } + } + return [res, maxd - 1]; + } + + function diameter(edges) { + if (edges.length === 0) { + return [0, 0, 0]; + } + const n = edges.length + 1; + const G = Array.from({ length: n }, () => []); + for (let k = 0; k < edges.length; k++) { + const [i, j] = edges[k]; + G[i].push(j); + G[j].push(i); + } + let [v1, d] = farthest(G, 0); + let [v2, d2] = farthest(G, v1); + return [d2, v1, v2]; + } +}; + diff --git a/3209-number-of-subarrays-with-and-value-of-k.js b/3209-number-of-subarrays-with-and-value-of-k.js new file mode 100644 index 00000000..64a0b79b --- /dev/null +++ b/3209-number-of-subarrays-with-and-value-of-k.js @@ -0,0 +1,46 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var countSubarrays = function(nums, k) { + return atLeastK(nums, k) - atLeastK(nums, k + 1); +}; + +function atLeastK(nums, k) { + let res = 0; + let temp = new Array(32).fill(0); + + let l = 0; + for (let r = 0; r < nums.length; r++) { + for (let i = 0; i < 32; i++) { + if ((1 << i) & nums[r]) { + temp[i]++; + } + } + + while ((r - l + 1) > 0 && calc(temp, r - l + 1) < k) { + for (let i = 0; i < 32; i++) { + if ((1 << i) & nums[l]) { + temp[i]--; + } + } + l++; + } + res += (r - l + 1); + } + + return res; +} + +// function to calculate the AND from frequency vector +function calc(temp, w) { + let res = 0; + for (let i = 0; i < 32; i++) { + if (temp[i] === w) { + res += (1 << i); + } + } + + return res; +} diff --git a/3210-find-the-encrypted-string.js b/3210-find-the-encrypted-string.js new file mode 100644 index 00000000..76e5c960 --- /dev/null +++ b/3210-find-the-encrypted-string.js @@ -0,0 +1,16 @@ +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +var getEncryptedString = function(s, k) { + const ss=s+s + const n = s.length + let res = '' + for(let i = 0; i < n; i++) { + const idx = (i + k) % n + res += ss[idx] + } + + return res +}; diff --git a/3211-generate-binary-strings-without-adjacent-zeros.js b/3211-generate-binary-strings-without-adjacent-zeros.js new file mode 100644 index 00000000..7e1be42e --- /dev/null +++ b/3211-generate-binary-strings-without-adjacent-zeros.js @@ -0,0 +1,24 @@ +/** + * @param {number} n + * @return {string[]} + */ +var validStrings = function(n) { + const set= new Set() + bt(1, '0') + bt(1, '1') + return Array.from(set) + + function bt(i, cur) { + if(i === n) { + set.add(cur) + return + } + const last = cur[cur.length - 1] + if(last === '0') { + bt(i + 1, cur + '1') + } else { + bt(i + 1, cur + '1') + bt(i + 1, cur + '0') + } + } +}; diff --git a/3212-count-submatrices-with-equal-frequency-of-x-and-y.js b/3212-count-submatrices-with-equal-frequency-of-x-and-y.js new file mode 100644 index 00000000..5e2a229b --- /dev/null +++ b/3212-count-submatrices-with-equal-frequency-of-x-and-y.js @@ -0,0 +1,37 @@ +/** + * @param {character[][]} grid + * @return {number} + */ +var numberOfSubmatrices = function (grid) { + let r = grid.length + let c = grid[0].length + let prex = new Array(r + 1).fill(0).map(() => new Array(c + 1).fill(0)) + let prey = new Array(r + 1).fill(0).map(() => new Array(c + 1).fill(0)) + + for (let i = 1; i <= r; i++) { + for (let j = 1; j <= c; j++) { + prex[i][j] = + prex[i - 1][j] + + prex[i][j - 1] - + prex[i - 1][j - 1] + + (grid[i - 1][j - 1] === 'X' ? 1 : 0) + prey[i][j] = + prey[i - 1][j] + + prey[i][j - 1] - + prey[i - 1][j - 1] + + (grid[i - 1][j - 1] === 'Y' ? 1 : 0) + } + } + + let res = 0 + for (let i = 0; i < r; i++) { + for (let j = 0; j < c; j++) { + let cx = prex[i + 1][j + 1] - prex[0][j + 1] - prex[i + 1][0] + prex[0][0] + let cy = prey[i + 1][j + 1] - prey[0][j + 1] - prey[i + 1][0] + prey[0][0] + if (cx === cy && cx > 0) { + res++ + } + } + } + return res +} diff --git a/3213-construct-string-with-minimum-cost.js b/3213-construct-string-with-minimum-cost.js new file mode 100644 index 00000000..cb8cf652 --- /dev/null +++ b/3213-construct-string-with-minimum-cost.js @@ -0,0 +1,204 @@ +/** + * @param {string} target + * @param {string[]} words + * @param {number[]} costs + * @return {number} + */ +var minimumCost = function (target, words, costs) { + let ac = new AhoCorasick() + for (let i = 0; i < words.length; i++) { + ac.put(words[i], costs[i]) + } + ac.build_fail() + + let n = target.length + let f = new Array(n + 1).fill(Infinity) + f[0] = 0 + let cur = (root = ac.root) + for (let i = 1; i <= n; i++) { + cur = cur.son[target.charCodeAt(i - 1) - 'a'.charCodeAt(0)] + if (cur.len) { + f[i] = Math.min(f[i], f[i - cur.len] + cur.cost) + } + let fail = cur.last + while (fail !== root) { + let tmp = f[i - fail.len] + fail.cost + if (tmp < f[i]) { + f[i] = tmp + } + fail = fail.last + } + } + return f[n] === Infinity ? -1 : f[n] +} + +class Node { + constructor() { + this.son = new Array(26).fill(null) + this.fail = null + this.last = null + this.len = 0 + this.cost = Infinity + } +} + +class AhoCorasick { + constructor() { + this.root = new Node() + } + + put(s, cost) { + let cur = this.root + for (let i = 0; i < s.length; i++) { + let b = s.charCodeAt(i) - 'a'.charCodeAt(0) + if (cur.son[b] === null) { + cur.son[b] = new Node() + } + cur = cur.son[b] + } + cur.len = s.length + cur.cost = Math.min(cur.cost, cost) + } + + build_fail() { + this.root.fail = this.root.last = this.root + let q = [] + for (let i = 0; i < this.root.son.length; i++) { + let son = this.root.son[i] + if (son === null) { + this.root.son[i] = this.root + } else { + son.fail = son.last = this.root + q.push(son) + } + } + while (q.length > 0) { + let cur = q.shift() + for (let i = 0; i < cur.son.length; i++) { + let son = cur.son[i] + if (son === null) { + cur.son[i] = cur.fail.son[i] + continue + } + son.fail = cur.fail.son[i] + son.last = son.fail.len ? son.fail : son.fail.last + q.push(son) + } + } + } +} + +// another + +class TrieNode { + constructor() { + this.sfx = null // Suffix link + this.dict = null // Dictionary link + this.child = new Array(26).fill(null) + this.word_id = -1 // Index of the word ending at this node + } +} +// Speeds up Trie construction +const preallocated_nodes = Array.from({ length: 50005 }, () => new TrieNode()) + +/** + * @param {string} target + * @param {string[]} words + * @param {number[]} costs + * @return {number} + */ +function minimumCost(target, words, costs) { + const trie = new Trie(words, costs) + const n = target.length + const dp = new Array(n + 1).fill(Infinity) + dp[0] = 0 + + for (let i = 1; i <= n; ++i) { + const suffixes = trie.suffixesAfterAppending(target[i - 1]) + for (const j of suffixes) { + dp[i] = Math.min(dp[i], dp[i - words[j].length] + costs[j]) + } + } + + return dp[n] === Infinity ? -1 : dp[n] +} + +class Trie { + constructor(words, costs) { + this.count = 0 + this.root = this.newTrieNode() + this.root.sfx = this.root.dict = this.root + + for (let i = 0; i < words.length; ++i) { + const word = words[i] + let u = this.root + for (const c of word) { + const index = c.charCodeAt(0) - 'a'.charCodeAt(0) + if (!u.child[index]) { + u.child[index] = this.newTrieNode() + } + u = u.child[index] + } + if (u.word_id < 0 || costs[i] < costs[u.word_id]) { + u.word_id = i + } + } + + // BFS is used to set up the suffix and dictionary links for each node + // The suffix link of a node points to the longest proper suffix of the word represented by the node that is also a prefix of some word in the dictionary. + // The dictionary link is used to quickly find the next node in the dictionary chain. + const queue = [this.root] + while (queue.length > 0) { + const u = queue.shift() + for (let i = 0; i < 26; ++i) { + const v = u.child[i] + if (!v) continue + + let p = u.sfx + while (p !== this.root && !p.child[i]) { + p = p.sfx + } + + if (u !== this.root && p.child[i]) { + v.sfx = p.child[i] + } else { + v.sfx = this.root + } + + v.dict = v.sfx.word_id >= 0 ? v.sfx : v.sfx.dict + queue.push(v) + } + } + this.curr = this.root + } + + newTrieNode() { + preallocated_nodes[this.count] = new TrieNode() + return preallocated_nodes[this.count++] + } + + // This method is used to update the current node and find all matching suffixes after appending a character + suffixesAfterAppending(letter) { + const index = letter.charCodeAt(0) - 'a'.charCodeAt(0) + + // It follows suffix links until it finds a child node corresponding to the character or reaches the root. + while (this.curr !== this.root && !this.curr.child[index]) { + this.curr = this.curr.sfx + } + + // If a valid child node is found, it updates the current node and collects all word IDs reachable through the dictionary links. + const result = [] + if (this.curr.child[index]) { + this.curr = this.curr.child[index] + let u = this.curr + if (u.word_id < 0) { + u = u.dict + } + while (u.word_id >= 0) { + result.push(u.word_id) + u = u.dict + } + } + return result + } +} diff --git a/3216-lexicographically-smallest-string-after-a-swap.js b/3216-lexicographically-smallest-string-after-a-swap.js new file mode 100644 index 00000000..a4d57bf8 --- /dev/null +++ b/3216-lexicographically-smallest-string-after-a-swap.js @@ -0,0 +1,16 @@ +/** + * @param {string} s + * @return {string} + */ +var getSmallestString = function(s) { + const arr = s.split('') + const n = arr.length + for(let i = 1; i < n; i++) { + const valid = +arr[i] % 2 === +arr[i - 1] % 2 + if(valid && (+arr[i] < +arr[i - 1])) { + ;[arr[i - 1], arr[i]] = [arr[i], arr[i - 1]] + return arr.join('') + } + } + return s +}; diff --git a/3217-delete-nodes-from-linked-list-present-in-array.js b/3217-delete-nodes-from-linked-list-present-in-array.js new file mode 100644 index 00000000..d83363b4 --- /dev/null +++ b/3217-delete-nodes-from-linked-list-present-in-array.js @@ -0,0 +1,38 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {number[]} nums + * @param {ListNode} head + * @return {ListNode} + */ +var modifiedList = function(nums, head) { + const arr = [] + let cur = head + while(cur) { + arr.push(cur) + cur = cur.next + } + const set = new Set(nums) + let i = 0 + for(const e of arr) { + if(set.has(e.val)) { + arr[i] = null + } + i++ + } + const res = arr.filter(e => e != null) + for(let i = 0; i < res.length; i++) { + const e = res[i] + if(i === res.length - 1) { + e.next = null + break + } + e.next = res[i + 1] + } + return res[0] +}; diff --git a/3218-minimum-cost-for-cutting-cake-i.js b/3218-minimum-cost-for-cutting-cake-i.js new file mode 100644 index 00000000..5ad408c9 --- /dev/null +++ b/3218-minimum-cost-for-cutting-cake-i.js @@ -0,0 +1,40 @@ +class Cut { + constructor(cost, type) { + this.cost = cost + this.type = type + } +} +/** + * @param {number} m + * @param {number} n + * @param {number[]} horizontalCut + * @param {number[]} verticalCut + * @return {number} + */ +var minimumCost = function (m, n, horizontalCut, verticalCut) { + const cuts = [] + for (let i = 0; i < horizontalCut.length; i++) { + cuts.push(new Cut(horizontalCut[i], 'H')) + } + for (let j = 0; j < verticalCut.length; j++) { + cuts.push(new Cut(verticalCut[j], 'V')) + } + + cuts.sort((a, b) => -a.cost + b.cost) + + let totalCost = 0 + let horizontalSegments = 1 + let verticalSegments = 1 + + for (const cut of cuts) { + if (cut.type === 'H') { + totalCost += cut.cost * verticalSegments + horizontalSegments++ + } else { + totalCost += cut.cost * horizontalSegments + verticalSegments++ + } + } + + return totalCost +} diff --git a/3219-minimum-cost-for-cutting-cake-ii.js b/3219-minimum-cost-for-cutting-cake-ii.js new file mode 100644 index 00000000..fca6dce0 --- /dev/null +++ b/3219-minimum-cost-for-cutting-cake-ii.js @@ -0,0 +1,40 @@ +class Cut { + constructor(cost, type) { + this.cost = cost + this.type = type + } +} +/** + * @param {number} m + * @param {number} n + * @param {number[]} horizontalCut + * @param {number[]} verticalCut + * @return {number} + */ +var minimumCost = function(m, n, horizontalCut, verticalCut) { + let cuts = [] + for (let i = 0; i < horizontalCut.length; i++) { + cuts.push(new Cut(horizontalCut[i], 'H')) + } + for (let j = 0; j < verticalCut.length; j++) { + cuts.push(new Cut(verticalCut[j], 'V')) + } + + cuts.sort((a, b) => -a.cost + b.cost) + + let ans = 0 + let hCount = 1 + let vCount = 1 + + for (let cut of cuts) { + if (cut.type === 'H') { + ans += cut.cost * vCount + hCount++ + } else { + ans += cut.cost * hCount + vCount++ + } + } + + return ans +}; diff --git a/322-coin-change.js b/322-coin-change.js index 3dadaa50..4e16731e 100644 --- a/322-coin-change.js +++ b/322-coin-change.js @@ -1,3 +1,24 @@ +/** + * @param {number[]} coins + * @param {number} amount + * @return {number} + */ +const coinChange = function(coins, amount) { + const n = coins.length + const dp = Array(amount + 1).fill(Infinity) + dp[0] = 0 + for(const e of coins) dp[e] = 1 + for(let i = 1; i <= amount; i++) { + for(const e of coins) { + if(i > e) dp[i] = Math.min(dp[i], dp[i - e] + 1) + } + } + // console.log(dp) + return dp[amount] !== Infinity ? dp[amount] : -1 +}; + +// another + /** * @param {number[]} coins * @param {number} amount @@ -13,3 +34,29 @@ const coinChange = function(coins, amount) { } return dp[amount] === amount + 1 ? -1 : dp[amount] } + + +// another + +/** + * @param {number[]} coins + * @param {number} amount + * @return {number} + */ +const coinChange = function (coins, amount) { + const n = coins.length + const dp = Array.from({ length: n }, () => + Array(amount + 1).fill(Infinity) + ) + + for (let i = 0; i < n; i++) { + dp[i][0] = 0 + for (let j = 1; j <= amount; j++) { + if(i > 0) dp[i][j] = dp[i - 1][j] + if (j >= coins[i]) { + dp[i][j] = Math.min(dp[i][j], dp[i][j - coins[i]] + 1) + } + } + } + return dp[n - 1][amount] === Infinity ? -1 : dp[n - 1][amount] +} diff --git a/322-reconstruct-itinerary.js b/322-reconstruct-itinerary.js index ab750e3c..f18b30f8 100644 --- a/322-reconstruct-itinerary.js +++ b/322-reconstruct-itinerary.js @@ -2,30 +2,26 @@ * @param {string[][]} tickets * @return {string[]} */ - -const findItinerary = tickets => { - let db = {}; - let result = []; - tickets.forEach(node => { - if (db[node[0]]) { - db[node[0]].push(node[1]); - } else { - db[node[0]] = [node[1]]; - } - }) - - for(let prop in db){ - db[prop].sort(); - } - - const dfs = (from) => { - while (db[from] && db[from].length > 0) { - dfs(db[from].shift()); - } - result.unshift(from); +const findItinerary = function (tickets) { + const result = [] + const map = new Map() + for (const [from, to] of tickets) { + if (!map.has(from)) { + map.set(from, []) } - - dfs('JFK'); - return result; -}; - + map.get(from).push(to) + } + for (const key of map.keys()) { + map.get(key).sort() + } + function dfs(departure) { + const destination = map.get(departure) + while (destination && destination.length) { + const newDeparture = destination.shift() + dfs(newDeparture) + } + result.push(departure) + } + dfs('JFK') + return result.reverse() +} diff --git a/3224-minimum-array-changes-to-make-differences-equal.js b/3224-minimum-array-changes-to-make-differences-equal.js new file mode 100644 index 00000000..52dce081 --- /dev/null +++ b/3224-minimum-array-changes-to-make-differences-equal.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minChanges = function(nums, k) { + const n = nums.length + const arr = Array(1e5 + 1).fill(0) + for(let i = 0; i < n /2; i++) { + const a = nums[i], b = nums[n - 1 - i] + const l = Math.min(a, b), r = Math.max(a, b) + const maxDiff = Math.max(l, r, k - l) + arr[0]-- + arr[r - l]-- + arr[r - l + 1]++ + arr[maxDiff + 1]++ + } + let res = n, cur = n + for(const e of arr) { + cur += e + res = Math.min(res, cur) + } + return res +}; diff --git a/3226-number-of-bit-changes-to-make-two-integers-equal.js b/3226-number-of-bit-changes-to-make-two-integers-equal.js new file mode 100644 index 00000000..b9150e96 --- /dev/null +++ b/3226-number-of-bit-changes-to-make-two-integers-equal.js @@ -0,0 +1,33 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +var minChanges = function(n, k) { + const s = num2bin(n) + const t = num2bin(k) + let res = 0 + const len = s.length + + for(let i = 0; i < len; i++) { + const e = s[i], e1 = t[i] + if(e !== e1) { + if(e === '1') { + res++ + } else { + return -1 + } + } + } + + return res +}; + +function num2bin(n) { + let tmp = (n >>> 0).toString(2) + if(tmp.length < 32) { + return '0'.repeat(32 - tmp.length) + tmp + } + + return tmp +} diff --git a/3227-vowels-game-in-a-string.js b/3227-vowels-game-in-a-string.js new file mode 100644 index 00000000..48c81e27 --- /dev/null +++ b/3227-vowels-game-in-a-string.js @@ -0,0 +1,12 @@ +/** + * @param {string} s + * @return {boolean} + */ +var doesAliceWin = function(s) { + let v = 0 + for(let c of s){ + if(c ==='a' || c ==='e' || c ==='i' || c ==='o'|| c ==='u') v++ + } + if(v === 0) return false + else return true +}; diff --git a/3228-maximum-number-of-operations-to-move-ones-to-the-end.js b/3228-maximum-number-of-operations-to-move-ones-to-the-end.js new file mode 100644 index 00000000..f4b76f1d --- /dev/null +++ b/3228-maximum-number-of-operations-to-move-ones-to-the-end.js @@ -0,0 +1,29 @@ +/** + * @param {string} s + * @return {number} + */ +var maxOperations = function(s) { + let ss = '' + for (let ch of s) { + if (ss === '') { + ss += ch + continue + } + if (ch === '0' && ss[ss.length - 1] === '0') { + continue + } else { + ss += ch + } + } + s = ss + let res = 0 + let cnt = 0 + for (let i = 0; i < s.length; i++) { + if (s[i] === '0') { + res += cnt + } else { + cnt += 1 + } + } + return res +}; diff --git a/3229-minimum-operations-to-make-array-equal-to-target.js b/3229-minimum-operations-to-make-array-equal-to-target.js new file mode 100644 index 00000000..a1edda5b --- /dev/null +++ b/3229-minimum-operations-to-make-array-equal-to-target.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @param {number[]} target + * @return {number} + */ +var minimumOperations = function(nums, target) { + if (nums.length !== target.length) { + return -1 + } + + const diff = nums.map((num, i) => -num + target[i]) + + let res = 0 + for (let i = 0; i < diff.length; i++) { + if (i === 0 || diff[i] * diff[i - 1] <= 0) { + res += Math.abs(diff[i]) + } else { + res += Math.max(Math.abs(diff[i]) - Math.abs(diff[i - 1]), 0) + } + } + + return res +}; diff --git a/323-number-of-connected-components-in-an-undirected-graph.js b/323-number-of-connected-components-in-an-undirected-graph.js new file mode 100644 index 00000000..845491b7 --- /dev/null +++ b/323-number-of-connected-components-in-an-undirected-graph.js @@ -0,0 +1,52 @@ +/** + +Given n nodes labeled from 0 to n - 1 and a list of undirected +edges (each edge is a pair of nodes), write a function to find +the number of connected components in an undirected graph. + +Example 1: + +Input: n = 5 and edges = [[0, 1], [1, 2], [3, 4]] + + 0 3 + | | + 1 --- 2 4 + +Output: 2 + +Example 2: + +Input: n = 5 and edges = [[0, 1], [1, 2], [2, 3], [3, 4]] + + 0 4 + | | + 1 --- 2 --- 3 + +Output: 1 + +Note: +You can assume that no duplicate edges will appear in edges. +Since all edges are undirected, [0, 1] is the same +as [1, 0] and thus will not appear together in edges. + +*/ + +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +const countComponents = function(n, edges) { + const nums = Array(n).fill(-1) + for (let i = 0; i < edges.length; i++) { + const x = find(nums, edges[i][0]) + const y = find(nums, edges[i][1]) + if (x !== y) nums[x] = y + } + return nums.filter(num => num === -1).length +} + +const find = (nums, i) => { + if (nums[i] === -1) return i + return find(nums, nums[i]) +} diff --git a/3232-find-if-digit-game-can-be-won.js b/3232-find-if-digit-game-can-be-won.js new file mode 100644 index 00000000..01b19f48 --- /dev/null +++ b/3232-find-if-digit-game-can-be-won.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +var canAliceWin = function(nums) { + const sum = nums.reduce((ac, e) => ac + e, 0) + let as = 0 + for(const e of nums) { + if(e < 10) as += e + } + + return as !== sum - as +}; diff --git a/3233-find-the-count-of-numbers-which-are-not-special.js b/3233-find-the-count-of-numbers-which-are-not-special.js new file mode 100644 index 00000000..96cb6e7f --- /dev/null +++ b/3233-find-the-count-of-numbers-which-are-not-special.js @@ -0,0 +1,38 @@ +/** + * @param {number} l + * @param {number} r + * @return {number} + */ +const nonSpecialCount = function (l, r) { + let res = 0 + for ( + let i = Math.floor(Math.sqrt(l)) - 10; + i <= Math.floor(Math.sqrt(r)) + 10; + i++ + ) { + if (isPrime(i) && l <= i * i && i * i <= r) { + res += 1 + } + } + return r - l + 1 - res +} + +function isPrime(n) { + if (n <= 1) { + return false + } + if (n <= 3) { + return true + } + if (n % 2 === 0 || n % 3 === 0) { + return false + } + let i = 5 + while (i * i <= n) { + if (n % i === 0 || n % (i + 2) === 0) { + return false + } + i += 6 + } + return true +} diff --git a/3234-count-the-number-of-substrings-with-dominant-ones.js b/3234-count-the-number-of-substrings-with-dominant-ones.js new file mode 100644 index 00000000..a285974c --- /dev/null +++ b/3234-count-the-number-of-substrings-with-dominant-ones.js @@ -0,0 +1,55 @@ +/** + * @param {string} s + * @return {number} + */ +var numberOfSubstrings = function(s) { + const n = s.length; + let result = 0; + + // Iterate through possible zero counts (1 to sqrt(n)) + for (let k = 1; k <= Math.floor(Math.sqrt(n)); k++) { + const zeros = []; // Array to store positions of zeros + let lastzero = -1; // Position of the zero before the first zero in our window + let ones = 0; // Count of ones in our current window + + // Scan through the string + for (let right = 0; right < n; right++) { + if (s[right] === '0') { + zeros.push(right); + // If we have more than k zeros, remove the leftmost one + while (zeros.length > k) { + ones -= (zeros[0] - lastzero - 1); // Subtract ones between lastzero and the removed zero + lastzero = zeros.shift(); + } + } else { + ones++; + } + + // If we have exactly k zeros and at least k^2 ones + if (zeros.length === k && ones >= k ** 2) { + // Add the minimum of: + // 1. Number of ways to extend to the left (zeros[0] - lastzero) + // 2. Number of ways to extend to the right (ones - k^2 + 1) + result += Math.min(zeros[0] - lastzero, ones - k ** 2 + 1); + } + } + } + + // Handle all-ones substrings + let i = 0; + while (i < n) { + if (s[i] === '0') { + i++; + continue; + } + let sz = 0; + while (i < n && s[i] === '1') { + sz++; + i++; + } + // Add number of all-ones substrings + result += (sz * (sz + 1)) / 2; + } + + return result; +}; diff --git a/3235-check-if-the-rectangle-corner-is-reachable.js b/3235-check-if-the-rectangle-corner-is-reachable.js new file mode 100644 index 00000000..04a3269c --- /dev/null +++ b/3235-check-if-the-rectangle-corner-is-reachable.js @@ -0,0 +1,68 @@ +/** + * @param {number} X + * @param {number} Y + * @param {number[][]} circles + * @return {boolean} + */ +var canReachCorner = function(X, Y, circles) { + let width = X, height = Y + const numCircles = circles.length + const circleInfo = circles.map((circle) => [circle[0], circle[1], circle[2]]) + const adjacencyList = Array.from({ length: numCircles + 4 }, () => []) + + for (let i = 0; i < numCircles; i++) { + const [x, y, radius] = circleInfo[i] + + if (x - radius <= 0) { + adjacencyList[i].push(numCircles) + adjacencyList[numCircles].push(i) + } + if (width - x <= radius) { + adjacencyList[i].push(numCircles + 2) + adjacencyList[numCircles + 2].push(i) + } + if (y - radius <= 0) { + adjacencyList[i].push(numCircles + 1) + adjacencyList[numCircles + 1].push(i) + } + if (height - y <= radius) { + adjacencyList[i].push(numCircles + 3) + adjacencyList[numCircles + 3].push(i) + } + + for (let j = i + 1; j < numCircles; j++) { + const [x2, y2, radius2] = circleInfo[j] + const dx = x - x2 + const dy = y - y2 + const distanceSquared = dx * dx + dy * dy + const radiusSum = radius + radius2 + + if (distanceSquared <= radiusSum * radiusSum) { + adjacencyList[i].push(j) + adjacencyList[j].push(i) + } + } + } + + function bfs(startNode, targetNode1, targetNode2) { + const queue = [startNode] + const visited = Array(numCircles + 4).fill(0) + visited[startNode] = 1 + + while (queue.length > 0) { + const currentNode = queue.shift() + for (const neighbor of adjacencyList[currentNode]) { + if (!visited[neighbor]) { + visited[neighbor] = 1 + queue.push(neighbor) + } + } + } + return visited[targetNode1] || visited[targetNode2] + } + + return !( + bfs(numCircles, numCircles + 1, numCircles + 2) || + bfs(numCircles + 3, numCircles + 2, numCircles + 1) + ) +}; diff --git a/3241-time-taken-to-mark-all-nodes.js b/3241-time-taken-to-mark-all-nodes.js new file mode 100644 index 00000000..d5268745 --- /dev/null +++ b/3241-time-taken-to-mark-all-nodes.js @@ -0,0 +1,66 @@ +/** + * @param {number[][]} edges + * @return {number[]} + */ +var timeTaken = function(edges) { + let n = edges.length + 1; + let adj = Array.from({ length: n }, () => []); + for (let edge of edges) { + adj[edge[0]].push(edge[1]); + adj[edge[1]].push(edge[0]); + } + + // first, use 0 as root and calculate below: + // far1[i]: the farthest children for the subtree with root i + // far2[i]: the second farthest children for the subtree with root i + let far1 = Array(n).fill(0); + let far2 = Array(n).fill(0); + buildFar(0, adj, far1, far2); + + // by far1 and far2, we can use re-rooting to help us find the answer + let ans = Array(n).fill(0); + calcOthers(0, 0, adj, far1, far2, ans); + + return ans; +}; + +function buildFar(curr, adj, far1, far2) { + let maxChild1 = 0, maxChild2 = 0; + // Iterate through each child (branch), and find the two farthest children. + for (let child of adj[curr]) { + if (child <= curr) continue; + + buildFar(child, adj, far1, far2); + let dist = ((child & 1) ? 1 : 2) + far1[child]; + if (dist >= maxChild1) { + maxChild2 = maxChild1; + maxChild1 = dist; + } else if (dist > maxChild2) { + maxChild2 = dist; + } + } + + far1[curr] = maxChild1; + far2[curr] = maxChild2; +} + +function calcOthers(curr, parentDist, adj, far1, far2, ans) { + // parentDist: the farthest distance when node[parent] is the root + + ans[curr] = Math.max(parentDist, far1[curr]); + + for (let child of adj[curr]) { + if (child < curr) continue; + + let toParent = (curr & 1) ? 1 : 2; + let toChild = (child & 1) ? 1 : 2; + // For this child, exclude itself or it is not correct + // (If the branch containing this child is the farthest for node curr, we should use the second farthest) + let farthestChildExceptThisChild = (far1[curr] === (toChild + far1[child])) ? far2[curr] : far1[curr]; + + calcOthers(child, toParent + Math.max(parentDist, farthestChildExceptThisChild), adj, far1, far2, ans); + } +} + + + diff --git a/3244-shortest-distance-after-road-addition-queries-ii.js b/3244-shortest-distance-after-road-addition-queries-ii.js new file mode 100644 index 00000000..5a992a9c --- /dev/null +++ b/3244-shortest-distance-after-road-addition-queries-ii.js @@ -0,0 +1,351 @@ +/** + * @param {number} n + * @param {number[][]} queries + * @return {number[]} + */ +var shortestDistanceAfterQueries = function(n, queries) { + let tree = new SplayTree(), res = []; + for (let i = 0; i < n; i++) tree.insert(i); + for (const [l, r] of queries) { + while (1) { + let pre = tree.higher(l); + if (pre >= r) break; + tree.remove(pre); + } + res.push(tree.size() - 1); + } + return res; +}; + +///////////////////////// Template ////////////////////////////// +class SplayNode { + constructor(value) { + this.parent = null; + this.left = null; + this.right = null; + this.val = value; + this.sum = value; + this.sz = 1; + } + update() { + this.sz = (this.left != null ? this.left.sz : 0) + (this.right != null ? this.right.sz : 0) + 1; + this.sum = (this.left != null ? this.left.sum : 0) + (this.right != null ? this.right.sum : 0) + this.val; + } + isLeft() { + return this.parent != null && this.parent.left == this; + } + isRight() { + return this.parent != null && this.parent.right == this; + } + isRoot(guard = null) { + return this.parent == guard; + } +} + +// MultiSet +class SplayTree { + constructor() { + this.root = null; + this.cmp = (x, y) => x >= y ? 0 : 1; + } + zig(x) { // right rotation + let y = x.parent; + if (x.right != null) x.right.parent = y; + y.left = x.right; + x.right = y; + if (y.isLeft()) { + y.parent.left = x; + } else if (y.isRight()) { + y.parent.right = x; + } + x.parent = y.parent; + y.parent = x; + y.update(); + x.update(); + } + zag(x) { // left rotation + let y = x.parent; + if (x.left != null) x.left.parent = y; + y.right = x.left; + x.left = y; + if (y.isLeft()) { + y.parent.left = x; + } else if (y.isRight()) { + y.parent.right = x; + } + x.parent = y.parent; + y.parent = x; + y.update(); + x.update(); + } + zigzig(x) { // RR + this.zig(x.parent); + this.zig(x); + } + zigzag(x) { // RL + this.zig(x); + this.zag(x); + } + zagzag(x) { // LL + this.zag(x.parent); + this.zag(x); + } + zagzig(x) { // LR + this.zag(x); + this.zig(x); + } + splay(node, guard = null) { // splay node under guard, default splay to root + while (!node.isRoot(guard)) { + if (node.parent.isRoot(guard)) { + if (node.isLeft()) { + this.zig(node); + } else { + this.zag(node); + } + } else { + if (node.parent.isLeft()) { + if (node.isLeft()) { + this.zigzig(node); + } else { + this.zagzig(node); + } + } else { + if (node.isRight()) { + this.zagzag(node); + } else { + this.zigzag(node); + } + } + } + } + if (guard == null) this.root = node; + } + LastNode(x) { + this.splay(x); + let node = x.left; + if (node == null) return null; + while (node.right != null) node = node.right; + this.splay(node); + return node; + } + NextNode(x) { + this.splay(x); + let node = x.right; + if (node == null) return null; + while (node.left != null) node = node.left; + this.splay(node); + return node; + } + find(value) { + return this.findFirstOf(value); + } + findFirstOf(value) { + let node = this.root, res = null, last_visited = null; + while (node != null) { + last_visited = node; + if (this.cmp(value, node.val)) { + node = node.left; + } else if (this.cmp(node.val, value)) { + node = node.right; + } else { + res = node; + node = node.left; + } + } + if (last_visited != null) this.splay(last_visited); + return res; + } + findLastOf(value) { + let node = this.root, res = null, last_visited = null; + while (node != null) { + last_visited = node; + if (this.cmp(value, node.val)) { + node = node.left; + } else if (this.cmp(node.val, value)) { + node = node.right; + } else { + res = node; + node = node.right; + } + } + if (last_visited != null) this.splay(last_visited); + return res; + } + findRankOf(node) { + this.splay(node); + return node.left == null ? 0 : node.left.sz; + } + findSuccessorOf(value) { + let node = this.root, res = null, last_visited = null; + while (node != null) { + last_visited = node; + if (this.cmp(value, node.val)) { + res = node; + node = node.left; + } else { + node = node.right; + } + } + if (last_visited != null) this.splay(last_visited); + return res; + } + findPrecursorOf(value) { + let node = this.root, res = null, last_visited = null; + while (node != null) { + last_visited = node; + if (this.cmp(node.val, value)) { + res = node; + node = node.right; + } else { + node = node.left; + } + } + if (last_visited != null) this.splay(last_visited); + return res; + } + findKthNode(rank) { + if (rank < 0 || rank >= this.size()) return null; + let node = this.root; + while (node != null) { + let leftsize = node.left == null ? 0 : node.left.sz; + if (leftsize == rank) break; + if (leftsize > rank) { + node = node.left; + } else { + rank -= leftsize + 1; + node = node.right; + } + } + this.splay(node); + return node; + } + make(value) { + return new SplayNode(value); + } + removeNode(node) { + node = null; + } + + // -------------------------------- Public Usage -------------------------------------- + insert(value) { // allow duplicates LST.set() + if (this.root == null) { + this.root = this.make(value); + return this.root; + } + let node = this.root; + while (node != null) { + if (this.cmp(value, node.val)) { + if (node.left == null) { + node.left = this.make(value); + node.left.parent = node; + node = node.left; + break; + } + node = node.left; + } else { + if (node.right == null) { + node.right = this.make(value); + node.right.parent = node; + node = node.right; + break; + } + node = node.right; + } + } + this.splay(node); + return node; + } + remove(value) { // remove one node, not all LST.unset() + let node = this.find(value); + if (node == null) return false; + this.splay(node); + if (node.left == null) { + this.root = node.right; + if (node.right != null) node.right.parent = null; + this.removeNode(node); + return true; + } + if (node.right == null) { + this.root = node.left; + if (node.left != null) node.left.parent = null; + this.removeNode(node); + return true; + } + let last_node = this.LastNode(node); + let next_node = this.NextNode(node); + this.splay(last_node); + this.splay(next_node, last_node); + this.removeNode(next_node.left); + next_node.left = null; + next_node.update(); + last_node.update(); + return true; + } + has(value) { // LST.get() + return this.count(value) > 0; + } + count(value) { + let x = this.findFirstOf(value); + if (x == null) return 0; + let rank_x = this.findRankOf(x); + let y = this.findLastOf(value); + let rank_y = this.findRankOf(y); + return rank_y - rank_x + 1; + } + rankOf(value) { // The number of elements strictly less than value + let x = this.findPrecursorOf(value); + return x == null ? 0 : this.findRankOf(x) + 1; + } + findKth(rank) { // (0-indexed) + let x = this.findKthNode(rank); + return x == null ? null : (x.val); + } + higher(value) { // > upper_bound() + let node = this.findSuccessorOf(value); + return node == null ? null : (node.val); + } + lower(value) { // < + let node = this.findPrecursorOf(value); + return node == null ? null : (node.val); + } + ceiling(value) { // >= lower_bound() LST.next(value) + return this.has(value) ? value : this.higher(value); + } + floor(value) { // <= LST.prev(value) + return this.has(value) ? value : this.lower(value); + } + first() { + return this.findKth(0); + } + last() { + return this.findKth(this.size() - 1); + } + poll() { + let res = this.first(); + this.remove(res); + return res; + } + pollLast() { + let res = this.last(); + this.remove(res); + return res; + } + size() { + return this.root == null ? 0 : this.root.sz; + } + isEmpty() { + return this.root == null; + } + show() { + let res = []; + const dfs = (x) => { + if (x == null) return; + dfs(x.left); + res.push(x.val); + dfs(x.right); + }; + dfs(this.root); + return res; + } +} + diff --git a/325-maximum-size-subarray-sum-equals-k.js b/325-maximum-size-subarray-sum-equals-k.js new file mode 100644 index 00000000..d98dec51 --- /dev/null +++ b/325-maximum-size-subarray-sum-equals-k.js @@ -0,0 +1,42 @@ +/** + +Given an array nums and a target value k, +find the maximum length of a subarray that sums to k. +If there isn't one, return 0 instead. + +Note: +The sum of the entire nums array is guaranteed to fit within the 32-bit signed integer range. + +Example 1: + +Input: nums = [1, -1, 5, -2, 3], k = 3 +Output: 4 +Explanation: The subarray [1, -1, 5, -2] sums to 3 and is the longest. + +Example 2: + +Input: nums = [-2, -1, 2, 1], k = 1 +Output: 2 +Explanation: The subarray [-1, 2] sums to 1 and is the longest. + +Follow Up: +Can you do it in O(n) time? + +*/ + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxSubArrayLen = function(nums, k) { + let sum = 0, max = 0 + const m = new Map() + for(let i = 0, len = nums.length; i < len; i++) { + sum += nums[i] + if(sum === k) max = i + 1 + else if(m.has(sum - k)) max = Math.max(max, i - m.get(sum - k)) + if(!m.has(sum)) m.set(sum, i) + } + return max +}; diff --git a/3258-count-substrings-that-satisfy-k-constraint-i.js b/3258-count-substrings-that-satisfy-k-constraint-i.js new file mode 100644 index 00000000..04445896 --- /dev/null +++ b/3258-count-substrings-that-satisfy-k-constraint-i.js @@ -0,0 +1,57 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const countKConstraintSubstrings = function (s, k) { + const n = s.length + let res = 0, + l = 0, + r = 0, + zero = 0, + one = 0 + while (r < n) { + if (s[r] === "0") zero++ + else one++ + while (zero > k && one > k) { + if (s[l] === "0") zero-- + else one-- + l++ + } + res += r - l + 1 + r++ + } + + return res +} + +// another + + +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +var countKConstraintSubstrings = function(s, k) { + let res = 0 + const n = s.length + for(let len = 1; len <= n; len++) { + for(let j = 0; j + len <= n; j++) { + const sub = s.slice(j, j + len) + if(valid(sub)) res++ + } + } + + return res + + function valid(str) { + let one = 0 + const n = str.length + for(const e of str) { + if(e === '1') one++ + } + + return one <= k || n - one <= k + } +}; diff --git a/326-power-of-three.js b/326-power-of-three.js new file mode 100644 index 00000000..6657894b --- /dev/null +++ b/326-power-of-three.js @@ -0,0 +1,32 @@ +/** + * @param {number} n + * @return {boolean} + */ +const isPowerOfThree = function(n) { + const maxInt = Math.pow(3,30) + if(n < 0) { + return false + } + return maxInt % n === 0 +} + +// another + +const isPowerOfThree = function(n) { + if (n == 1) return true + if (n === 0) return false + if (n % 3 !== 0) return false + if (n == 3) return true + return isPowerOfThree(n / 3) +} + +// another + +const isPowerOfThree = function(n) { + if(n == null || n === 0) return false + let num = 1 + while(num < n) { + num *= 3 + } + return num > n ? false : true +} diff --git a/3261-count-substrings-that-satisfy-k-constraint-ii.js b/3261-count-substrings-that-satisfy-k-constraint-ii.js new file mode 100644 index 00000000..2d536e71 --- /dev/null +++ b/3261-count-substrings-that-satisfy-k-constraint-ii.js @@ -0,0 +1,72 @@ +/** + * @param {string} s + * @param {number} k + * @param {number[][]} queries + * @return {number[]} + */ +var countKConstraintSubstrings = function(s, k, queries) { + let binaryString = s, maxZerosOnes = k, queriesList = queries + let length = binaryString.length; + let zeroPrefixSum = Array(length + 1).fill(0); + + for (let idx = 0; idx < length; idx++) { + zeroPrefixSum[idx + 1] = (binaryString[idx] === '0' ? 1 : 0) + zeroPrefixSum[idx]; + } + + let endIndex = Array(length).fill(0); + + for (let start = 0; start < length; start++) { + let end = start; + let low = start, high = length - 1; + + while (low <= high) { + let mid = low + Math.floor((high - low) / 2); + let zeroCount = zeroPrefixSum[mid + 1] - zeroPrefixSum[start]; + let oneCount = mid + 1 - start - zeroCount; + + if (zeroCount <= maxZerosOnes || oneCount <= maxZerosOnes) { + end = mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + endIndex[start] = end; + } + + for (let i = 0; i < length; i++) { + zeroPrefixSum[i + 1] = (endIndex[i] - i + 1) + zeroPrefixSum[i]; + } + + let results = []; + + /* Template by Bharadwaj ( LEETCODE JAVASCRIPT ) */ + /* Youtube : https://youtube.com/@code-with-Bharadwaj */ + /* Portfolio : https://manu-bharadwaj-portfolio.vercel.app/ */ + + for (let query of queriesList) { + let left = query[0]; + let right = query[1]; + let validIndex = left - 1; + let low = left, high = right; + let totalCount = 0; + + while (low <= high) { + let mid = low + Math.floor((high - low) / 2); + + if (endIndex[mid] < right) { + validIndex = mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + + totalCount += zeroPrefixSum[validIndex + 1] - zeroPrefixSum[left]; + let difference = right - validIndex; + totalCount += (difference * (difference + 1)) / 2; + results.push(totalCount); + } + + return results; +}; diff --git a/327-count-of-range-sum.js b/327-count-of-range-sum.js new file mode 100644 index 00000000..94876b65 --- /dev/null +++ b/327-count-of-range-sum.js @@ -0,0 +1,40 @@ +/** + * @param {number[]} nums + * @param {number} lower + * @param {number} upper + * @return {number} + */ +const countRangeSum = function (nums, lower, upper) { + if (nums.length === 0) return 0 + const sums = [nums[0]] + for (let i = 1; i < nums.length; i++) { + sums[i] = sums[i - 1] + nums[i] + } + function merge_sort(A, lo, hi) { + if (hi - lo === 1) { + return sums[lo] >= lower && sums[lo] <= upper ? 1 : 0 + } + const mid = lo + Math.floor((hi - lo) / 2) + let counter = merge_sort(A, lo, mid) + merge_sort(A, mid, hi) + let m = mid, + n = mid + for (let i = lo; i < mid; i++) { + while (m !== hi && sums[m] - sums[i] < lower) { + m++ + } + while (n !== hi && sums[n] - sums[i] <= upper) { + n++ + } + counter += n - m + } + const M = A.slice(lo, mid) + const N = A.slice(mid, hi) + M.push(Number.MAX_SAFE_INTEGER) + N.push(Number.MAX_SAFE_INTEGER) + for (let k = lo, i = 0, j = 0; k < hi; k++) { + A[k] = M[i] < N[j] ? M[i++] : N[j++] + } + return counter + } + return merge_sort(sums, 0, nums.length) +} diff --git a/3276-select-cells-in-grid-with-maximum-score.js b/3276-select-cells-in-grid-with-maximum-score.js new file mode 100644 index 00000000..bdb2ac33 --- /dev/null +++ b/3276-select-cells-in-grid-with-maximum-score.js @@ -0,0 +1,45 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var maxScore = function (grid) { + const n = grid.length + const m = grid[0].length + const values = [] + + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + values.push([grid[i][j], i, j]) + } + } + + values.sort((a, b) => b[0] - a[0]) + const dp = {} + + return recur(values, 0, 0, dp) +} + +function recur(values, idx, mask_row, dp) { + const n = values.length + if (idx === n) return 0 + + const key = `${idx},${mask_row}` + if (key in dp) return dp[key] + + let ans = 0 + const row = values[idx][1] + if ((1 << row) & mask_row) { + ans += recur(values, idx + 1, mask_row, dp) + } else { + let j = idx + while (j < n && values[idx][0] === values[j][0]) j++ + + const ans1 = values[idx][0] + recur(values, j, mask_row | (1 << row), dp) + const ans2 = recur(values, idx + 1, mask_row, dp) + + ans = Math.max(ans1, ans2) + } + + dp[key] = ans + return ans +} diff --git a/328-odd-even-linked-list.js b/328-odd-even-linked-list.js index f3615535..068e799b 100755 --- a/328-odd-even-linked-list.js +++ b/328-odd-even-linked-list.js @@ -23,3 +23,40 @@ const oddEvenList = function(head) { odd.next = evenHead; return head; }; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +function oddEvenList(head) { + if(head == null) return head + const dummyOdd = new ListNode() + const dummyEven = new ListNode() + + dummyOdd.next = head + let odd = head, even = dummyEven + let idx = 2, cur = head.next + while(cur) { + if (idx % 2 === 1) { + odd.next = cur + odd = odd.next + } else { + even.next = cur + even = even.next + } + cur = cur.next + idx++ + } + odd.next = dummyEven.next + even.next = null + return dummyOdd.next +} diff --git a/3280-convert-date-to-binary.js b/3280-convert-date-to-binary.js new file mode 100644 index 00000000..48190272 --- /dev/null +++ b/3280-convert-date-to-binary.js @@ -0,0 +1,31 @@ +/** + * @param {string} date + * @return {string} + */ +var convertDateToBinary = function(date) { + let temp = [], res =[] + for(let i of date){ + if(i=='-'){ + temp = dec_to_bin(temp.join('')) + res.push(...temp) + temp = [] + res.push('-') + } + else temp.push(i) + } + temp = dec_to_bin(temp.join('')) + res.push(...temp) + return res.join('') +}; + +function dec_to_bin( a){ + let b = +(a) + let res = [] + while(b>0){ + if(b&1)res.push('1') + else res.push('0') + b>>=1 + } + res.reverse() + return res +} diff --git a/3281-maximize-score-of-numbers-in-ranges.js b/3281-maximize-score-of-numbers-in-ranges.js new file mode 100644 index 00000000..9a71ae2e --- /dev/null +++ b/3281-maximize-score-of-numbers-in-ranges.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} start + * @param {number} d + * @return {number} + */ +var maxPossibleScore = function (start, d) { + start.sort((a, b) => a - b) + let low = 0, + high = start[start.length - 1] + d - start[0] + while (low <= high) { + let mid = low + Math.floor((high - low) / 2) + if (f(start, d, mid)) { + low = mid + 1 + } else { + high = mid - 1 + } + } + return low - 1 +} +function f(start, d, mini) { + let ans = start[0] + for (let i = 1; i < start.length; i++) { + let nextMin = ans + mini + if (nextMin > start[i] + d) { + return false + } + ans = Math.max(start[i], nextMin) + } + return true +} diff --git a/3282-reach-end-of-array-with-max-score.js b/3282-reach-end-of-array-with-max-score.js new file mode 100644 index 00000000..2fb4bb45 --- /dev/null +++ b/3282-reach-end-of-array-with-max-score.js @@ -0,0 +1,15 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var findMaximumScore = function(nums) { + let n = nums.length + + if(n==1)return 0 + let res = 0,mx = nums[0],prev = nums[0] + for(let i=1;imx)mx = nums[i] + } + return res +}; diff --git a/3283-maximum-number-of-moves-to-kill-all-pawns.js b/3283-maximum-number-of-moves-to-kill-all-pawns.js new file mode 100644 index 00000000..228f3afb --- /dev/null +++ b/3283-maximum-number-of-moves-to-kill-all-pawns.js @@ -0,0 +1,126 @@ +/** + * @param {number} kx + * @param {number} ky + * @param {number[][]} positions + * @return {number} + */ +var maxMoves = function (kx, ky, positions) { + //alice goes first + //alice wants to maximize result + + //add the starting position + positions.unshift([kx, ky]) + + let dp = new Float64Array(positions.length * 2 ** positions.length) + let degreesBetweenPawnPairs = new Float64Array( + positions.length * positions.length, + ) + + computeAllDegreesBetweenPawns() + + //if the mask is equal to this, we've visited all pawns + let targetMask = (1 << positions.length) - 1 + + //alice starts, so we set maximize to true + return dfs(0, true, 1) + + function dfs(pawn1Idx, maximize, mask) { + if (mask === targetMask) { + return 0 + } + + let dpIdx = pawn1Idx * 2 ** positions.length + mask + if (dp[dpIdx] > 0) { + return dp[dpIdx] - 1 + } + + let best = Infinity + let worst = 0 + + for (let pawn2Idx = 0; pawn2Idx < positions.length; ++pawn2Idx) { + if (mask & (1 << pawn2Idx)) { + continue + } + + let cur = degreeBetween(pawn1Idx, pawn2Idx) + cur += dfs(pawn2Idx, !maximize, mask | (1 << pawn2Idx)) + + best = Math.min(best, cur) + worst = Math.max(worst, cur) + } + + let ret + if (maximize) { + ret = worst + } else { + ret = best + } + + dp[dpIdx] = ret + 1 + return ret + } + + function computeAllDegreesBetweenPawns() { + let targets = new Map(positions.map(([x, y], idx) => [y * 50 + x, idx])) + + let visited = new Array(50 * 50).fill(0) + const MOVES = [ + [2, 1], + [-2, 1], + [2, -1], + [-2, -1], + [1, -2], + [1, 2], + [-1, 2], + [-1, -2], + ] + + for (let i = 0; i < positions.length; ++i) { + let q = [positions[i]] + let q2 = [] + let steps = 0 + + visited[positions[i][1] * 50 + positions[i][0]] = i + + while (q.length) { + let [x, y] = q.pop() + + { + let dpIdx = y * 50 + x + if (targets.has(dpIdx)) { + let v1 = i + let v2 = targets.get(dpIdx) + degreesBetweenPawnPairs[v1 * positions.length + v2] = steps + degreesBetweenPawnPairs[v2 * positions.length + v1] = steps + } + } + + for (let [offx, offy] of MOVES) { + let newX = x + offx + let newY = y + offy + + if (newX >= 50 || newY >= 50 || newX < 0 || newY < 0) { + continue + } + let visitedDpIdx = newY * 50 + newX + if (visited[visitedDpIdx] === i) { + continue + } + visited[visitedDpIdx] = i + q2.push([newX, newY]) + } + + if (!q.length) { + ;[q2, q] = [q, q2] + ++steps + } + } + } + } + + function degreeBetween(i, j) { + return degreesBetweenPawnPairs[i * positions.length + j] + } +} + + diff --git a/329-longest-increasing-path-in-a-matrix.js b/329-longest-increasing-path-in-a-matrix.js index 68f65262..6cce9611 100644 --- a/329-longest-increasing-path-in-a-matrix.js +++ b/329-longest-increasing-path-in-a-matrix.js @@ -3,31 +3,80 @@ * @return {number} */ const longestIncreasingPath = function(matrix) { - if (matrix.length === 0) return 0 - let max = 1 - const rows = matrix.length - const cols = matrix[0].length - const cache = Array.from({ length: rows }, () => new Array(cols).fill(0)) + const m = matrix.length, n = matrix[0].length + let res = 1 + const dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]] - for (let i = 0; i < rows; i++) { - for (let j = 0; j < cols; j++) { - let len = dfs(matrix, i, j, rows, cols, cache, dirs) - max = Math.max(max, len) + const memo = Array.from({ length: m }, () => Array(n).fill(0)) + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + const len = dfs(i, j) + res = Math.max(res, len) + } + } + + return res + + function dfs(i, j) { + const v = matrix[i][j] + if(memo[i][j] !== 0) return memo[i][j] + let len = 1 + for(const [dx, dy] of dirs) { + const nx = i + dx, ny = j + dy + if(nx >= 0 && nx < m && ny >= 0 && ny < n && matrix[nx][ny] > v) { + const tmp = 1 + dfs(nx, ny) + len = Math.max(len, tmp) + } + } + + memo[i][j] = len + return len + } +}; + +// another + +/** + * @param {number[][]} matrix + * @return {number} + */ +const longestIncreasingPath = function (matrix) { + const dirs = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ] + const m = matrix.length, + n = matrix[0].length + let res = 1 + const memo = Array.from({ length: m }, () => Array(n).fill(0)) + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + const tmp = dfs(matrix, i, j, m, n, memo, dirs) + res = Math.max(tmp, res) } } - return max + return res } -function dfs(matrix, i, j, rows, cols, cache, dirs) { - if (cache[i][j] !== 0) return cache[i][j] - let max = 1 - for (let dir of dirs) { - let ii = i + dir[0] - let jj = j + dir[1] - if (ii < 0 || ii >= rows || jj < 0 || jj >= cols || matrix[ii][jj] <= matrix[i][j]) continue - let len = 1 + dfs(matrix, ii, jj, rows, cols, cache, dirs) - max = Math.max(len, max) +function dfs(matrix, i, j, m, n, memo, dirs) { + if (memo[i][j] !== 0) return memo[i][j] + let res = 1 + for (let [dx, dy] of dirs) { + const nx = i + dx, + ny = j + dy + if ( + nx < 0 || + nx >= m || + ny < 0 || + ny >= n || + matrix[nx][ny] <= matrix[i][j] + ) + continue + const tmp = 1 + dfs(matrix, nx, ny, m, n, memo, dirs) + res = Math.max(res, tmp) } - cache[i][j] = max - return max + memo[i][j] = res + return res } diff --git a/3290-maximum-multiplication-score.js b/3290-maximum-multiplication-score.js new file mode 100644 index 00000000..ed6eb065 --- /dev/null +++ b/3290-maximum-multiplication-score.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} a + * @param {number[]} b + * @return {number} + */ +var maxScore = function(a, b) { + const dp = Array(4).fill(-4 * 1e5 * 1e5) + const {max} = Math + for(const e of b) { + dp[3] = max(dp[3], dp[2] + e * a[3]) + dp[2] = max(dp[2], dp[1] + e * a[2]) + dp[1] = max(dp[1], dp[0] + e * a[1]) + dp[0] = max(dp[0], e * a[0]) + } + + return dp[3] +}; diff --git a/3291-minimum-number-of-valid-strings-to-form-target-i.js b/3291-minimum-number-of-valid-strings-to-form-target-i.js new file mode 100644 index 00000000..ed0ec089 --- /dev/null +++ b/3291-minimum-number-of-valid-strings-to-form-target-i.js @@ -0,0 +1,41 @@ + class TrieNode { + constructor() { + this.children = new Array(26).fill(null) + } + } +/** + * @param {string[]} words + * @param {string} target + * @return {number} + */ +var minValidStrings = function(words, target) { + const n = target.length + const dp = new Array(n + 1).fill(Infinity) + dp[0] = 0 + + const a = 'a'.charCodeAt(0) + const root = new TrieNode() + for (const word of words) { + let node = root + for (const c of word) { + const index = c.charCodeAt(0) - a + if (!node.children[index]) { + node.children[index] = new TrieNode() + } + node = node.children[index] + } + } + + for (let i = 0; i < n; i++) { + if (dp[i] === Infinity) continue + let node = root + for (let j = i; j < n; j++) { + const index = target[j].charCodeAt(0) - a + if (!node.children[index]) break + node = node.children[index] + dp[j + 1] = Math.min(dp[j + 1], dp[i] + 1) + } + } + + return dp[n] === Infinity ? -1 : dp[n] +}; diff --git a/3295-report-spam-message.js b/3295-report-spam-message.js new file mode 100644 index 00000000..125acf6d --- /dev/null +++ b/3295-report-spam-message.js @@ -0,0 +1,27 @@ +/** + * @param {string[]} message + * @param {string[]} bannedWords + * @return {boolean} + */ +var reportSpam = function(message, bannedWords) { + let res = false + const m = message.length, n = bannedWords.length + let cnt = 0 + const bs = new Set(bannedWords) + for(let i = 0; i < m; i++) { + const str = message[i] + /* + for(let j = 0; j < n; j++) { + const e = bannedWords[j] + if(str === e) { + cnt++ + break + } + } + */ + if(bs.has(str)) cnt++ + if(cnt >= 2) return true + } + + return res +}; diff --git a/3296-minimum-number-of-seconds-to-make-mountain-height-zero.js b/3296-minimum-number-of-seconds-to-make-mountain-height-zero.js new file mode 100644 index 00000000..369cd1c9 --- /dev/null +++ b/3296-minimum-number-of-seconds-to-make-mountain-height-zero.js @@ -0,0 +1,31 @@ +/** + * @param {number} mountainHeight + * @param {number[]} workerTimes + * @return {number} + */ +var minNumberOfSeconds = function (mountainHeight, workerTimes) { + let low = 0, + high = 1e18 + while (low < high) { + let mid = low + Math.floor((high - low) / 2) + let totalHeightReduced = 0 + for (let workerTime of workerTimes) { + totalHeightReduced += f(mid, workerTime) + if (totalHeightReduced >= mountainHeight) break + } + if (totalHeightReduced >= mountainHeight) high = mid + else low = mid + 1 + } + return low +} +function f(T, workerTime) { + let low = 0, + high = 1e6 + while (low < high) { + let mid = low + Math.floor((high - low + 1) / 2) + let timeRequired = (workerTime * mid * (mid + 1)) / 2 + if (timeRequired <= T) low = mid + else high = mid - 1 + } + return low +} diff --git a/3297-count-substrings-that-can-be-rearranged-to-contain-a-string-i.js b/3297-count-substrings-that-can-be-rearranged-to-contain-a-string-i.js new file mode 100644 index 00000000..541fc927 --- /dev/null +++ b/3297-count-substrings-that-can-be-rearranged-to-contain-a-string-i.js @@ -0,0 +1,44 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +var validSubstringCount = function (word1, word2) { + const mp1 = new Array(26).fill(0) + const mp2 = new Array(26).fill(0) + let missing = 0 + + for (const c of word2) { + mp1[c.charCodeAt(0) - 'a'.charCodeAt(0)]++ + } + + for (let i = 0; i < 26; i++) { + if (mp1[i] > 0) { + missing += mp1[i] + } + } + + let res = 0 + let left = 0 + const n = word1.length + + for (let right = 0; right < n; right++) { + const c = word1[right].charCodeAt(0) - 'a'.charCodeAt(0) + mp2[c]++ + if (mp1[c] > 0 && mp2[c] <= mp1[c]) { + missing-- + } + + while (missing === 0) { + res += n - right + const left_char = word1[left].charCodeAt(0) - 'a'.charCodeAt(0) + if (mp1[left_char] > 0 && mp2[left_char] <= mp1[left_char]) { + missing++ + } + mp2[left_char]-- + left++ + } + } + + return res +} diff --git a/3298-count-substrings-that-can-be-rearranged-to-contain-a-string-ii.js b/3298-count-substrings-that-can-be-rearranged-to-contain-a-string-ii.js new file mode 100644 index 00000000..9de78eab --- /dev/null +++ b/3298-count-substrings-that-can-be-rearranged-to-contain-a-string-ii.js @@ -0,0 +1,156 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const validSubstringCount = function(word1, word2) { + const n = word1.length; + const target = Array(26).fill(0); + const a = 'a'.charCodeAt(0); + for(const ch of word2) { + target[ch.charCodeAt(0) - a]++; + } + const targetCnt = target.reduce((acc, cur) => acc += cur > 0 ? 1 : 0, 0); + const cur = Array(26).fill(0); + + let j = 0 + let cnt = 0 + let res = 0 + for(let i = 0; i < n; i++) { + const e = word1[i].charCodeAt(0) - a + while(j < n && cnt < targetCnt) { + const idx= word1[j].charCodeAt(0) - a; + cur[idx]++; + if(cur[idx] === target[idx]) { + cnt++; + } + j++ + } + if(cnt === targetCnt) { + res += (n - 1) - (j - 1) + 1 + } + cur[e]--; + if(cur[e] === target[e] - 1) { + cnt--; + } + } + return res +}; + +// another + + + +function validSubstringCount(w1, w2) { + const cnt = {}; + for (const ch of w2) { + cnt[ch] = (cnt[ch] || 0) + 1; + } + let match = Object.keys(cnt).length, res = 0, j = 0; + + for (let i = 0; i < w1.length; i++) { + cnt[w1[i]] = (cnt[w1[i]] || 0) - 1; + match -= cnt[w1[i]] === 0 ? 1 : 0; + + while (match === 0) { + res += w1.length - i; + match += cnt[w1[j]] === 0 ? 1 : 0; + cnt[w1[j]] = (cnt[w1[j]] || 0) + 1; + j++; + } + } + return res; +} + +// another + +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +var validSubstringCount = function (word1, word2) { + const mp1 = new Array(26).fill(0) + const mp2 = new Array(26).fill(0) + let count = 0 + + for (const c of word2) { + mp1[c.charCodeAt(0) - 'a'.charCodeAt(0)]++ + } + + for (let i = 0; i < 26; i++) { + if (mp1[i] > 0) { + count += mp1[i] + } + } + + let res = 0 + let left = 0 + + for (let right = 0; right < word1.length; right++) { + mp2[word1.charCodeAt(right) - 'a'.charCodeAt(0)]++ + if ( + mp1[word1.charCodeAt(right) - 'a'.charCodeAt(0)] > 0 && + mp2[word1.charCodeAt(right) - 'a'.charCodeAt(0)] <= + mp1[word1.charCodeAt(right) - 'a'.charCodeAt(0)] + ) { + count-- + } + + while (count === 0) { + res += word1.length - right + if ( + mp1[word1.charCodeAt(left) - 'a'.charCodeAt(0)] > 0 && + mp2[word1.charCodeAt(left) - 'a'.charCodeAt(0)] <= + mp1[word1.charCodeAt(left) - 'a'.charCodeAt(0)] + ) { + count++ + } + mp2[word1.charCodeAt(left) - 'a'.charCodeAt(0)]-- + left++ + } + } + + return res +} + +// another + +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const validSubstringCount = function(word1, word2) { + const n = word1.length; + const target = Array(26).fill(0); + const a = 'a'.charCodeAt(0); + for(const ch of word2) { + target[ch.charCodeAt(0) - a]++; + } + const cur = Array(26).fill(0); + let j = 0 + let res = 0 + for(let i = 0; i < n; i++) { + const e = word1[i].charCodeAt(0) - a + while(j < n && !valid(cur, target)) { + cur[word1[j].charCodeAt(0) - a]++; + j++ + } + if(valid(cur, target)) { + res += (n - 1) - (j - 1) + 1 + } + cur[e]--; + } + + return res + + function valid(arr, target) { + for(let i = 0; i < 26; i++) { + if(arr[i] < target[i]) { + return false; + } + } + return true; + } +}; diff --git a/330-patching-array.js b/330-patching-array.js new file mode 100644 index 00000000..295d8b70 --- /dev/null +++ b/330-patching-array.js @@ -0,0 +1,60 @@ +/** + * @param {number[]} nums + * @param {number} n + * @return {number} + */ +const minPatches = function(nums, n) { + let sum = 1, res = 0, i = 0 + while(sum <= n) { + if(i < nums.length && nums[i] <= sum) { + sum += nums[i] + i++ + } else { + res++ + sum *= 2 + } + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} n + * @return {number} + */ +const minPatches = function(nums, n) { + const len = nums.length + let miss = 1, res = 0, i = 0 + while(miss <= n) { + if(i < len && nums[i] <= miss) { + miss += nums[i] + i++ + } else { + res++ + miss += miss + } + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} n + * @return {number} + */ +const minPatches = function(nums, n) { + let answer = 0 + for (let i = 0, next = 1; next <= n; ) { + if (i >= nums.length || nums[i] > next) { + answer++ + next *= 2 + } else next += nums[i++] + } + return answer +} diff --git a/3301-maximize-the-total-height-of-unique-towers.js b/3301-maximize-the-total-height-of-unique-towers.js new file mode 100644 index 00000000..6c3f633b --- /dev/null +++ b/3301-maximize-the-total-height-of-unique-towers.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} maximumHeight + * @return {number} + */ +var maximumTotalSum = function(maximumHeight) { + const n = maximumHeight.length; + maximumHeight.sort((a, b) => a - b); + + let sum = 0; + let lastAssignedHeight = Number.MAX_SAFE_INTEGER; + + for (let i = n - 1; i >= 0; i--) { + const currentHeight = Math.min(maximumHeight[i], lastAssignedHeight - 1); + + if (currentHeight < 1) { + return -1; + } + + sum += currentHeight; + lastAssignedHeight = currentHeight; + } + + return sum; +}; diff --git a/333-largest-bst-subtree.js b/333-largest-bst-subtree.js new file mode 100644 index 00000000..f3655aae --- /dev/null +++ b/333-largest-bst-subtree.js @@ -0,0 +1,74 @@ +/** + +Given a binary tree, find the largest subtree +which is a Binary Search Tree (BST), +where largest means subtree with largest number of nodes in it. + +Note: +A subtree must include all of its descendants. + +Example: + +Input: [10,5,15,1,8,null,7] + + 10 + / \ + 5 15 + / \ \ +1 8 7 + +Output: 3 +Explanation: The Largest BST Subtree in this case is the highlighted one. + The return value is the subtree's size, which is 3. + +*/ + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const largestBSTSubtree = function(root) { + const res = helper(root) + return res[2] +} + +function helper(node) { + if (!node) return [Number.MAX_VALUE, -Number.MAX_VALUE, 0] + const left = helper(node.left) + const right = helper(node.right) + if (node.val > left[1] && node.val < right[0]) { + return [ + Math.min(node.val, left[0]), + Math.max(node.val, right[1]), + left[2] + right[2] + 1 + ] + } else { + return [-Number.MAX_VALUE, Number.MAX_VALUE, Math.max(left[2], right[2])] + } +} + +// another + +const largestBSTSubtree = function(root) { + function dfs(node) { + if (!node) return [0, 0, Number.MAX_VALUE, -Number.MAX_VALUE] + const [N1, n1, min1, max1] = dfs(node.left) + const [N2, n2, min2, max2] = dfs(node.right) + const n = + max1 < node.val && min2 > node.val ? n1 + 1 + n2 : -Number.MAX_VALUE + return [ + Math.max(N1, N2, n), + n, + Math.min(min1, node.val), + Math.max(max2, node.val) + ] + } + return dfs(root)[0] +} diff --git a/3334-find-the-maximum-factor-score-of-array.js b/3334-find-the-maximum-factor-score-of-array.js new file mode 100644 index 00000000..eab4ecba --- /dev/null +++ b/3334-find-the-maximum-factor-score-of-array.js @@ -0,0 +1,39 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maxScore = function (nums) { + const n = nums.length + if (n === 1) { + return nums[0] * nums[0] + } + + const totalGcd = gcdOfArray(nums) + const totalLcm = lcmOfArray(nums) + let res = totalGcd * totalLcm + + for (let i = 0; i < n; i++) { + const remaining = nums.slice(0, i).concat(nums.slice(i + 1)) + const currentGcd = gcdOfArray(remaining) + const currentLcm = lcmOfArray(remaining) + res = Math.max(res, currentGcd * currentLcm) + } + + return res +} + +function lcm(a, b) { + return (a / gcd(a, b)) * b +} +function gcd(a, b) { + return b ? gcd(b, a % b) : a +} + +function lcmOfArray(arr) { + return arr.reduce((acc, val) => lcm(acc, val)) +} + +function gcdOfArray(arr) { + return arr.reduce((acc, val) => gcd(acc, val)) +} + diff --git a/3335-total-characters-in-string-after-transformations-i.js b/3335-total-characters-in-string-after-transformations-i.js new file mode 100644 index 00000000..6e029569 --- /dev/null +++ b/3335-total-characters-in-string-after-transformations-i.js @@ -0,0 +1,25 @@ +/** + * @param {string} s + * @param {number} t + * @return {number} + */ +var lengthAfterTransformations = function (s, t) { + const MOD = 10 ** 9 + 7 + let charCounts = new Array(26).fill(0) + + for (const c of s) { + charCounts[c.charCodeAt(0) - 'a'.charCodeAt(0)] += 1 + } + + for (let i = 0; i < t; i++) { + const newCounts = new Array(26).fill(0) + for (let j = 0; j < 25; j++) { + newCounts[j + 1] += charCounts[j] + } + newCounts[0] = (newCounts[0] + charCounts[25]) % MOD + newCounts[1] = (newCounts[1] + charCounts[25]) % MOD + charCounts = newCounts + } + + return charCounts.reduce((a, b) => (a + b) % MOD, 0) +} diff --git a/3336-find-the-number-of-subsequences-with-equal-gcd.js b/3336-find-the-number-of-subsequences-with-equal-gcd.js new file mode 100644 index 00000000..68092e4e --- /dev/null +++ b/3336-find-the-number-of-subsequences-with-equal-gcd.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var subsequencePairCount = function(nums) { + const a = nums + let n = a.length, + ans = 0, + M = 1e9 + 7, + dp = Array.from({ length: n }, () => + Array.from({ length: 1 + Math.max(...a) }, () => + new Array(1 + Math.max(...a)).fill(-1) + ) + ) + + let recu = (idx, gcd_1, gcd_2) => { + if (idx === n) + return (gcd_1 === gcd_2 && gcd_1 !== 0) + + if (dp.at(idx).at(gcd_1).at(gcd_2) !== -1) + return dp.at(idx).at(gcd_1).at(gcd_2) + + let ans = recu(idx + 1, gcd_1, gcd_2) + + recu(idx + 1, Math.gcd(gcd_1, a.at(idx)), gcd_2) + + recu(idx + 1, gcd_1, Math.gcd(gcd_2, a.at(idx))) + ans %= M + + return dp[idx][gcd_1][gcd_2] = ans + } + + return recu(0, 0, 0) +}; +Math.gcd = function(a, b) { + if (b === 0) + return a + return Math.gcd(b, a % b) +} diff --git a/3337-total-characters-in-string-after-transformations-ii.js b/3337-total-characters-in-string-after-transformations-ii.js new file mode 100644 index 00000000..c0bab8a1 --- /dev/null +++ b/3337-total-characters-in-string-after-transformations-ii.js @@ -0,0 +1,76 @@ +const MOD = 1e9 + 7; +const MODn = BigInt(MOD); +/** + * @param {string} s + * @param {number} t + * @param {number[]} nums + * @return {number} + */ +var lengthAfterTransformations = function(s, t, nums) { + let vec = new Array(26).fill(0); + for(let i = 0; i < s.length; ++i) { + let chr = s.charCodeAt(i) - 'a'.charCodeAt(0); + vec[chr] += 1; + } + let mat = new Array(26).fill(0).map(_ => new Array(26).fill(0n)); + for(let i = 0; i < 26; ++i) { + let count = nums[i]; + let j = (i + 1) % 26; + while(count > 0) { + mat[i][j] = 1n; + --count; + + j = (j + 1) % 26; + } + + } + + mat = matPow(mat, t); + let result = 0; + for(let i = 0; i < 26; ++i) { + for(let j = 0; j < 26; ++j) { + result += vec[i] * Number(mat[i][j]); + } + result = result % MOD; + } + + return result; +}; + + + +function multiplyInto(mat1, mat2, output, tmp) { + + for(let i = 0; i < output.length; ++i) { + for(let j = 0; j < output[0].length; ++j) { + let result = 0n; + for(let k = 0; k < output.length; ++k) { + result += mat1[i][k] * mat2[k][j]; + result %= MODn; + } + tmp[i][j] = result; + } + } + + for(let i = 0; i < output.length; ++i) { + for(let j = 0; j < output[0].length; ++j) { + output[i][j] = tmp[i][j]; + } + } +} + +function matPow(mat, exp) { + const result = new Array(mat.length).fill(0).map(_ => mat[0].slice(0).fill(0n)); + const tmp = new Array(mat.length).fill(0).map(_ => mat[0].slice(0)); + for(let i = 0; i < result.length; ++i) { + result[i][i] = 1n; + } + + while (exp) { + if (exp & 1) { multiplyInto(mat, result, result, tmp); } + multiplyInto(mat, mat, mat, tmp); + exp >>>= 1; + } + + return result; +} diff --git a/334-increasing-triplet-subsequence.js b/334-increasing-triplet-subsequence.js index a62bf62c..d8b22cc0 100644 --- a/334-increasing-triplet-subsequence.js +++ b/334-increasing-triplet-subsequence.js @@ -12,3 +12,45 @@ const increasingTriplet = function(nums) { } return false; }; + +// another + +/** + * @param {number[]} nums + * @return {boolean} + */ +const increasingTriplet = function(nums) { + const n = nums.length, stk = [] + for(let e of nums) { + let l = 0, r = stk.length + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if (e > stk[mid]) l = mid + 1 + else r = mid + } + + stk[l] = e + if(stk.length > 2) return true + } + + return false +}; + +// another + +/** + * @param {number[]} nums + * @return {boolean} + */ +const increasingTriplet = function(nums) { + let small = Number.MAX_VALUE, big = Number.MAX_VALUE + + for(const e of nums) { + if(e <= small) small = e + else if(e <= big) big = e + else return true + } + + return false +}; + diff --git a/3342-find-minimum-time-to-reach-last-room-ii.js b/3342-find-minimum-time-to-reach-last-room-ii.js new file mode 100644 index 00000000..ce21d124 --- /dev/null +++ b/3342-find-minimum-time-to-reach-last-room-ii.js @@ -0,0 +1,99 @@ +/** + * @param {number[][]} moveTime + * @return {number} + */ +var minTimeToReach = function (moveTime) { + const a = moveTime + let m = a.length, n = a.at(0).length + + let pq = new _PriorityQueue((x, y) => { + if (x.at(0) !== y.at(0)) return x.at(0) - y.at(0) + if (x.at(2) !== y.at(2)) return x.at(2) - y.at(2) + }) + pq.push([0, 0, 0, 1]) + + let di = new Array(m).fill().map(() => new Array(n).fill(1e15)) + di[0][0] = 0 + + while (pq.size()) { + let fr = pq.top() + pq.pop() + + let d = fr.at(0), x = fr.at(1), y = fr.at(2), st = fr.at(3) + + if (x == m - 1 && y == n - 1) + return d + + new Array([-1, 0], [0, -1], [0, 1], [1, 0]).forEach(([dx, dy]) => { + if (0 <= x + dx && x + dx < m && 0 <= y + dy && y + dy < n) + { + let tmp = Math.max(a.at(x + dx).at(y + dy) - d, 0) + + if (di.at(x + dx).at(y + dy) > d + tmp + st) { + di[x + dx][y + dy] = d + tmp + st + pq.push([di.at(x + dx).at(y + dy), x + dx, y + dy, (st === 1 ? 2 : 1)]) + } + } + }) + } +} + + +// Binary Heap +class _PriorityQueue { + constructor(cmp) { + this.arr = new Array() + this.cmp = cmp || ((a, b) => a - b) + } + + push(x) { + this.arr.push(x) + this.heapifyUp() + } + + heapifyUp() { + let cId = this.size() - 1, + pId = this.parentIndex(cId) + while (cId > 0 && this.cmp(this.arr.at(cId), this.arr.at(pId)) < 0) + { + Math.swap(this.arr, cId, pId) + cId = pId + pId = this.parentIndex(cId) + } + } + + pop() { + if (this.size() === 0) + return + this.arr[0] = this.arr.pop() + this.heapifyDown() + } + + heapifyDown() { + let pId = 0, + lcId = this.leftChildIndex(pId), + rcId = this.rightChildIndex(pId) + while (lcId < this.size()) + { + let sc = lcId + if (rcId < this.size() && this.cmp(this.arr.at(rcId), this.arr.at(lcId)) < 0) + sc = rcId + + if (this.cmp(this.arr.at(pId), this.arr.at(sc)) <= 0) + return + + Math.swap(this.arr, pId, sc) + pId = sc + lcId = this.leftChildIndex(pId) + rcId = this.rightChildIndex(pId) + } + } + + size() { return this.arr.length } + top() { return this.arr.at(0) } + parentIndex = (x) => Math.trunc((x - 1) / 2) + leftChildIndex = (x) => 2 * x + 1 + rightChildIndex = (x) => 2 * x + 2 +} + +Math.swap = (obj, i, j) => [obj[i], obj[j]] = [obj[j], obj[i]] diff --git a/3346-maximum-frequency-of-an-element-after-performing-operations-i.js b/3346-maximum-frequency-of-an-element-after-performing-operations-i.js new file mode 100644 index 00000000..4a2cc1bf --- /dev/null +++ b/3346-maximum-frequency-of-an-element-after-performing-operations-i.js @@ -0,0 +1,47 @@ +/** + * @param {number[]} nums + * @param {number} k + * @param {number} numOperations + * @return {number} + */ +var maxFrequency = function (nums, k, numOperations) { + const n = nums.length + let ans = 0, + left = 0, + right = 0 + nums.sort((a, b) => a - b) + + const count = {} + for (const num of nums) { + count[num] = (count[num] || 0) + 1 + } + for (let mid = 0; mid < n; mid++) { + while (nums[mid] - nums[left] > k) { + left++ + } + + while (right < n - 1 && nums[right + 1] - nums[mid] <= k) { + right++ + } + + const total = right - left + 1 + ans = Math.max( + ans, + Math.min(total - (count[nums[mid]] || 0), numOperations) + + (count[nums[mid]] || 0), + ) + } + + left = 0 + for (right = 0; right < n; right++) { + let mid = Math.floor((nums[left] + nums[right]) / 2) + + while (mid - nums[left] > k || nums[right] - mid > k) { + left++ + mid = Math.floor((nums[left] + nums[right]) / 2) + } + ans = Math.max(ans, Math.min(right - left + 1, numOperations)) + } + + return ans +} diff --git a/3349-adjacent-increasing-subarrays-detection-i.js b/3349-adjacent-increasing-subarrays-detection-i.js new file mode 100644 index 00000000..98346711 --- /dev/null +++ b/3349-adjacent-increasing-subarrays-detection-i.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {boolean} + */ +var hasIncreasingSubarrays = function (nums, k) { + const n = nums.length + + for (let i = 0; i <= n - 2 * k; ++i) { + let firstIncreasing = true + let secondIncreasing = true + + for (let j = i; j < i + k - 1; ++j) { + if (nums[j] >= nums[j + 1]) { + firstIncreasing = false + break + } + } + + if (!firstIncreasing) continue + + for (let j = i + k; j < i + 2 * k - 1; ++j) { + if (nums[j] >= nums[j + 1]) { + secondIncreasing = false + break + } + } + + if (firstIncreasing && secondIncreasing) return true + } + + return false +} diff --git a/335-self-crossing.js b/335-self-crossing.js new file mode 100644 index 00000000..85aa2f09 --- /dev/null +++ b/335-self-crossing.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} x + * @return {boolean} + */ +const isSelfCrossing = function(x) { + for (let i = 3, l = x.length; i < l; i++) { + // Case 1: current line crosses the line 3 steps ahead of it + if (x[i] >= x[i - 2] && x[i - 1] <= x[i - 3]) return true + // Case 2: current line crosses the line 4 steps ahead of it + else if (i >= 4 && x[i - 1] == x[i - 3] && x[i] + x[i - 4] >= x[i - 2]) + return true + // Case 3: current line crosses the line 6 steps ahead of it + else if ( + i >= 5 && + x[i - 2] >= x[i - 4] && + x[i] + x[i - 4] >= x[i - 2] && + x[i - 1] <= x[i - 3] && + x[i - 1] + x[i - 5] >= x[i - 3] + ) + return true + } + return false +} diff --git a/3350-adjacent-increasing-subarrays-detection-ii.js b/3350-adjacent-increasing-subarrays-detection-ii.js new file mode 100644 index 00000000..c091eba0 --- /dev/null +++ b/3350-adjacent-increasing-subarrays-detection-ii.js @@ -0,0 +1,63 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maxIncreasingSubarrays = function (nums) { + const n = nums.length + let up = 1, preMaxUp = 0, res = 0 + + for(let i = 1; i < n; i++) { + if(nums[i] > nums[i - 1]) up++ + else { + preMaxUp = up + up = 1 + } + res = Math.max(res, Math.max(~~(up / 2), Math.min(preMaxUp, up))) + } + + + return res +} + + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +var maxIncreasingSubarrays = function (nums) { + const n = nums.length + + const increasingRun = new Array(n).fill(1) + for (let i = n - 2; i >= 0; --i) { + if (nums[i] < nums[i + 1]) { + increasingRun[i] = increasingRun[i + 1] + 1 + } + } + + let left = 1, + right = Math.floor(n / 2) + let res = 0 + + while (left <= right) { + const mid = left + Math.floor((right - left) / 2) + let found = false + + for (let i = 0; i <= n - 2 * mid; ++i) { + if (increasingRun[i] >= mid && increasingRun[i + mid] >= mid) { + found = true + break + } + } + + if (found) { + res = mid + left = mid + 1 + } else { + right = mid - 1 + } + } + + return res +} diff --git a/3351-sum-of-good-subsequences.js b/3351-sum-of-good-subsequences.js new file mode 100644 index 00000000..84b8b7a2 --- /dev/null +++ b/3351-sum-of-good-subsequences.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const sumOfGoodSubsequences = function(nums) { + const limit = 1e5 + 10; + const mod = 1e9 + 7; + const count = Array(limit).fill(0); + const total = Array(limit).fill(0); + let res = 0; + for(const e of nums) { + count[e + 1] = (count[e] + count[e + 1] + count[e + 2] + 1) % mod + const cur = total[e] + total[e + 2] + e * (count[e] + count[e + 2] + 1) + total[e + 1] = (total[e + 1] + cur) % mod + res =(res + cur) % mod + } + return res +}; diff --git a/3352-count-k-reducible-numbers-less-than-n.js b/3352-count-k-reducible-numbers-less-than-n.js new file mode 100644 index 00000000..5ce98c75 --- /dev/null +++ b/3352-count-k-reducible-numbers-less-than-n.js @@ -0,0 +1,58 @@ +const ll = BigInt, + mod = ll(1e9 + 7), + N = 1e4 + 15 +let fact = Array(N).fill(0), + ifact = Array(N).fill(0), + inv = Array(N).fill(0) +const hcomb = (p, q) => (p == 0 && q == 0 ? 1 : comb(p + q - 1, q)) +const comb_init = () => { + fact[0] = ifact[0] = inv[1] = 1n // factorial, inverse factorial + for (let i = 2; i < N; i++) + inv[i] = ((mod - mod / ll(i)) * inv[mod % ll(i)]) % mod + for (let i = 1; i < N; i++) { + fact[i] = (fact[i - 1] * ll(i)) % mod + ifact[i] = (ifact[i - 1] * inv[i]) % mod + } +} + +// combination mod pick k from n +const comb = (n, k) => { + if (n < k || k < 0) return 0 + return (((fact[n] * ifact[k]) % mod) * ifact[n - k]) % mod +} + +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +var countKReducibleNumbers = function (s, k) { + let dp = new Array(1000).fill(0) + for (let i = 2; i < 1000; i++) { + dp[i] = dp[bitCnt(i)] + 1 + } + let c1 = 0 + let n = s.length + let res = 0n + comb_init() + for (let i = 0; i < n; i++) { + if (s[i] === "1") { + for (let c2 = 0; c2 < n - i; c2++) { + if (c1 + c2 > 0 && dp[c1 + c2] + 1 <= k) { + res = res + comb(n - i - 1, c2) + } + } + c1++ + } + } + return Number(res % mod) + + function bitCnt(num) { + let cnt = 0 + while (num) { + cnt += num & 1 + num >>= 1 + } + return cnt + } +} diff --git a/3354-make-array-elements-equal-to-zero.js b/3354-make-array-elements-equal-to-zero.js new file mode 100644 index 00000000..7f7a6c0d --- /dev/null +++ b/3354-make-array-elements-equal-to-zero.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const countValidSelections = function (nums) { + let res = 0 + for (let i = 0; i < nums.length; i++) { + if (nums[i] === 0) { + if (canZeroOut(i, -1)) { + res += 1 + } + if (canZeroOut(i, 1)) { + res += 1 + } + } + } + return res + function canZeroOut(start, direction) { + let tempNums = nums.slice() + let curr = start + + while (curr >= 0 && curr < tempNums.length) { + if (tempNums[curr] === 0) { + curr += direction + } else { + tempNums[curr] -= 1 + direction *= -1 + curr += direction + } + } + return tempNums.every((x) => x === 0) + } +} diff --git a/3355-zero-array-transformation-i.js b/3355-zero-array-transformation-i.js new file mode 100644 index 00000000..db5e35b7 --- /dev/null +++ b/3355-zero-array-transformation-i.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {boolean} + */ +var isZeroArray = function(nums, queries) { + const n = nums.length + const arr = Array(n + 1).fill(0) + for(const [l, r] of queries) { + arr[l]++ + arr[r + 1]-- + } + + for(let i = 1; i <= n; i++) { + arr[i] += arr[i - 1] + } + for(let i = 0; i < n; i++) { + if(nums[i] > arr[i]) return false + } + + return true +}; diff --git a/3356-zero-array-transformation-ii.js b/3356-zero-array-transformation-ii.js new file mode 100644 index 00000000..4650df6d --- /dev/null +++ b/3356-zero-array-transformation-ii.js @@ -0,0 +1,75 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number} + */ +var minZeroArray = function (nums, queries) { + const n = nums.length + let sum = 0, + k = 0 + const differenceArray = new Array(n + 1).fill(0) + + for (let index = 0; index < n; index++) { + // Iterate through queries while current index of nums cannot equal zero + while (sum + differenceArray[index] < nums[index]) { + k++ + + // Zero array isn't formed after all queries are processed + if (k > queries.length) { + return -1 + } + const [left, right, val] = queries[k - 1] + + // Process start and end of range + if (right >= index) { + differenceArray[Math.max(left, index)] += val + differenceArray[right + 1] -= val + } + } + // Update prefix sum at current index + sum += differenceArray[index] + } + return k +} + + +// another + +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number} + */ +var minZeroArray = function (nums, queries) { + if (nums.every((num) => num === 0)) return 0 + const n = nums.length + const delta = new Array(n + 1).fill(0) + + for (let index = 0; index < queries.length; index++) { + const query = queries[index] + const l = query[0] + const r = query[1] + const diff = query[2] + + delta[l] += diff + if (r + 1 < n) { + delta[r + 1] -= diff + } + + let curDiff = 0 + let success = true + + for (let i = 0; i < n; i++) { + curDiff += delta[i] + if (nums[i] > curDiff) { + success = false + break + } + } + + if (!success) continue + return index + 1 + } + return -1 +} + diff --git a/336-palindrome-pairs.js b/336-palindrome-pairs.js new file mode 100644 index 00000000..e640f6d1 --- /dev/null +++ b/336-palindrome-pairs.js @@ -0,0 +1,128 @@ +/** + +Given a list of unique words, find all pairs of distinct indices (i, j) in the given list, +so that the concatenation of the two words, i.e. words[i] + words[j] is a palindrome. + +Example 1: + +Input: ["abcd","dcba","lls","s","sssll"] +Output: [[0,1],[1,0],[3,2],[2,4]] +Explanation: The palindromes are ["dcbaabcd","abcddcba","slls","llssssll"] +Example 2: + +Input: ["bat","tab","cat"] +Output: [[0,1],[1,0]] +Explanation: The palindromes are ["battab","tabbat"] + +*/ + +/** + * @param {string[]} words + * @return {number[][]} + */ +const palindromePairs = function(words) { + const root = new Trie(); + const pairs = []; + words.forEach((word, index) => addWord(word, index, root)); + words.forEach((word, index) => searchWord(word, index, root, pairs)); + return pairs; +}; + +const addWord = (word, wordIndex, root) => { + const length = word.length; + let curr = root; + for (let i = length - 1; i >= 0; i--) { + let char = word.charAt(i); + if (!curr.children[char]) curr.children[char] = new Trie(); + if (isPalindrome(0, i, word)) curr.words.push(wordIndex); + curr = curr.children[char]; + } + curr.wordIndex = wordIndex; + curr.words.push(wordIndex); +} + +const searchWord = (word, wordIndex, root, pairs) => { + const length = word.length; + let curr = root; + for (let i = 0; i < length; i++) { + let char = word.charAt(i); + if (curr.wordIndex >= 0 && curr.wordIndex !== wordIndex && isPalindrome(i, length - 1, word)) { + pairs.push([wordIndex, curr.wordIndex]); + } + curr = curr.children[char]; + if (!curr) return; + } + + curr.words.forEach((suffix) => { + if (suffix !== wordIndex) pairs.push([wordIndex, suffix]); + }) +} + +const isPalindrome = (left, right, word) => { + while (left < right) { + if (word.charAt(left++) !== word.charAt(right--)) return false; + } + return true; +} + +class Trie { + constructor() { + this.wordIndex = -1; + this.children = {}; + this.words = []; + } +} + +// another + +const reverseStr = s => { + let str = '' + for (let i = 0; i < s.length; i++) { + str = s[i] + str + } + return str +} +const isPalindrome = str => { + for (let i = 0; i < str.length / 2; i++) { + if (str[i] !== str[str.length - 1 - i]) return false + } + return true +} +/** + * @param {string[]} words + * @return {number[][]} + */ +const palindromePairs = function(words) { + const map = new Map() + words.forEach((word, idx) => map.set(word, idx)) + const result = [] + if (map.has('')) { + const idx = map.get('') + words.forEach((word, i) => { + if (i !== idx && isPalindrome(word)) { + result.push([idx, map.get(word)]) + result.push([map.get(word), idx]) + } + }) + } + map.delete('') + words.forEach((word, idx) => { + for (let i = 0; i < word.length; i++) { + const left = word.slice(0, i) + const right = word.slice(i) + if (isPalindrome(left)) { + const reversedRight = reverseStr(right) + if (map.has(reversedRight) && map.get(reversedRight) !== idx) { + result.push([map.get(reversedRight), idx]) + } + } + if (isPalindrome(right)) { + const reversedLeft = reverseStr(left) + if (map.has(reversedLeft) && map.get(reversedLeft) !== idx) { + result.push([idx, map.get(reversedLeft)]) + } + } + } + }) + return result +} diff --git a/3362-zero-array-transformation-iii.js b/3362-zero-array-transformation-iii.js new file mode 100644 index 00000000..dcf8e0d9 --- /dev/null +++ b/3362-zero-array-transformation-iii.js @@ -0,0 +1,99 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number} + */ +var maxRemoval = function(nums, queries) { + queries.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]); + const candidate = new PQ((a, b) => a > b); + const chosen = new PQ((a, b) => a < b); + let res = 0; + const n = nums.length; + let j = 0; + + for (let i = 0; i < n; i++) { + while (j < queries.length && queries[j][0] === i) { + candidate.push(queries[j][1]); + j++; + } + nums[i] -= chosen.size(); + while (nums[i] > 0 && candidate.size() > 0 && candidate.peek() >= i) { + res++; + chosen.push(candidate.peek()); + candidate.pop() + nums[i]--; + } + if (nums[i] > 0) return -1; + while (chosen.size() > 0 && chosen.peek() === i) { + chosen.pop() + } + } + return queries.length - res; +}; +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/3364-minimum-positive-sum-subarray.js b/3364-minimum-positive-sum-subarray.js new file mode 100644 index 00000000..efec413a --- /dev/null +++ b/3364-minimum-positive-sum-subarray.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @param {number} l + * @param {number} r + * @return {number} + */ +var minimumSumSubarray = function (nums, l, r) { + let sum = Infinity + for (let i = l; i <= r; i++) { + sum = Math.min(minPos(nums, i), sum) + } + return sum === Infinity ? -1 : sum +} + +function minPos(num, k) { + let s = 0 + let min = Infinity + for (let i = 0; i < k; i++) { + s += num[i] + } + if (s > 0) min = s + for (let i = k; i < num.length; i++) { + s += num[i] - num[i - k] + if (s > 0) min = Math.min(min, s) + } + return min +} diff --git a/3365-rearrange-k-substrings-to-form-target-string.js b/3365-rearrange-k-substrings-to-form-target-string.js new file mode 100644 index 00000000..2d743b98 --- /dev/null +++ b/3365-rearrange-k-substrings-to-form-target-string.js @@ -0,0 +1,31 @@ +/** + * @param {string} s + * @param {string} t + * @param {number} k + * @return {boolean} + */ +var isPossibleToRearrange = function (s, t, k) { + const d = Math.floor(s.length / k) + if (s === t) return true + const map = new Map() + + for (let i = 0; i < s.length; i += d) { + const req = s.substring(i, i + d) + if (map.has(req)) { + map.set(req, map.get(req) + 1) + } else { + map.set(req, 1) + } + } + + for (let i = 0; i < t.length; i += d) { + const tar = t.substring(i, i + d) + if (!map.has(tar)) return false + else if (map.get(tar) < 1) return false + else { + map.set(tar, map.get(tar) - 1) + } + } + + return true +} diff --git a/3366-minimum-array-sum.js b/3366-minimum-array-sum.js new file mode 100644 index 00000000..b784f5c3 --- /dev/null +++ b/3366-minimum-array-sum.js @@ -0,0 +1,92 @@ +/** + * @param {number[]} nums + * @param {number} k + * @param {number} op1 + * @param {number} op2 + * @return {number} + */ +var minArraySum = function(nums, k, op1, op2) { + let dp = Array.from({ length: op1 + 1 }, () => Array(op2 + 1).fill(Infinity)) + const {min, floor, ceil} = Math + + dp[op1][op2] = 0 + + for(const e of nums) { + const nxt = Array.from({ length: op1 + 1 }, () => Array(op2 + 1).fill(Infinity)) + for(let i = 0; i <= op1; i++) { + for(let j = 0; j <= op2; j++) { + nxt[i][j] = min(nxt[i][j], dp[i][j] + e) + if(i > 0) { + const cur = ceil(e / 2) + nxt[i - 1][j] = min(nxt[i - 1][j], dp[i][j] + cur) + if(cur >= k && j > 0) { + nxt[i - 1][j - 1] = min(nxt[i - 1][j - 1], dp[i][j] + cur - k) + } + } + if(j > 0 && e >= k) { + const cur = e - k + nxt[i][j - 1] = min(nxt[i][j - 1], dp[i][j] + cur) + if(i > 0) { + nxt[i - 1][j - 1] = min(nxt[i - 1][j - 1], dp[i][j] + ceil(cur / 2)) + } + } + } + } + + dp = nxt + } + + let res = Infinity + for(let i = 0; i <= op1; i++) { + for(let j = 0; j <= op2; j++) { + res = Math.min(res, dp[i][j]) + } + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @param {number} op1 + * @param {number} op2 + * @return {number} + */ +var minArraySum = function(nums, k, op1, op2) { + const n = nums.length; + const cache = new Map(); + + function dp(idx, left1, left2) { + if (idx === n) { + return 0; + } + const key = `${idx},${left1},${left2}`; + if (cache.has(key)) { + return cache.get(key); + } + + let ret = nums[idx] + dp(idx + 1, left1, left2); + if (left1 && left2) { + if (nums[idx] >= k) { + ret = Math.min(ret, Math.floor((nums[idx] - k + 1) / 2) + dp(idx + 1, left1 - 1, left2 - 1)); + } + if (Math.floor((nums[idx] + 1) / 2) >= k) { + ret = Math.min(ret, Math.floor((nums[idx] + 1) / 2) - k + dp(idx + 1, left1 - 1, left2 - 1)); + } + } + if (left1) { + ret = Math.min(ret, Math.floor((nums[idx] + 1) / 2) + dp(idx + 1, left1 - 1, left2)); + } + if (left2 && nums[idx] >= k) { + ret = Math.min(ret, nums[idx] - k + dp(idx + 1, left1, left2 - 1)); + } + + cache.set(key, ret); + return ret; + } + + return dp(0, op1, op2); +}; diff --git a/3367-maximize-sum-of-weights-after-edge-removals.js b/3367-maximize-sum-of-weights-after-edge-removals.js new file mode 100644 index 00000000..c0c65a96 --- /dev/null +++ b/3367-maximize-sum-of-weights-after-edge-removals.js @@ -0,0 +1,51 @@ +/** + * @param {number[][]} edges + * @param {number} k + * @return {number} + */ +var maximizeSumOfWeights = function(edges, k) { + const n = edges.length + 1; + const g = Array.from({ length: n }, () => ({})); + + for (const [x, y, w] of edges) { + g[x][y] = g[y][x] = w; + } + + function dfs(idx, p) { + const ret = [0, 0]; + const h = []; + + for (const ch in g[idx]) { + if (ch != p) { + const [a, b] = dfs(ch, idx); + h.push([a - b, a, b]); + } + } + + h.sort((a, b) => b[0] - a[0]); // Max-heap simulation + let take = 0; + let take_k = 0; + let leave_k = 0; + let leave = 0; + let ct = 0; + + while (h.length) { + const [_, a, b] = h.pop(); + ct += 1; + if (ct <= k - 1) { + take += b; + } else if (ct === k) { + take_k = b; + leave_k = a; + } else { + leave += a; + } + } + + const v = take + take_k + leave; + const w = take + leave_k + leave + (p !== -1 ? g[p][idx] : 0); + return [v, Math.max(v, w)]; + } + + return dfs(0, -1)[1]; +}; diff --git a/337-house-robber-iii.js b/337-house-robber-iii.js new file mode 100644 index 00000000..9ec5af05 --- /dev/null +++ b/337-house-robber-iii.js @@ -0,0 +1,50 @@ +/** + * 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 {number} + */ +const rob = function(root) { + if(root == null) return 0 + return Math.max(...dfs(root)) + + function dfs(node) { + if(node == null) return [0, 0] + const l = dfs(node.left), r = dfs(node.right) + return [node.val + l[1] + r[1], Math.max(...l) + Math.max(...r)] + } +}; + +// another + + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const rob = function(root) { + return Math.max(...dfs(root)) +} + +function dfs(node) { + if (node == null) return [0, 0] + const left = dfs(node.left) + const right = dfs(node.right) + return [ + node.val + left[1] + right[1], + Math.max(left[0], left[1]) + Math.max(right[0], right[1]) + ] +} diff --git a/3370-smallest-number-with-all-set-bits.js b/3370-smallest-number-with-all-set-bits.js new file mode 100644 index 00000000..1fecd416 --- /dev/null +++ b/3370-smallest-number-with-all-set-bits.js @@ -0,0 +1,11 @@ +/** + * @param {number} n + * @return {number} + */ +var smallestNumber = function(n) { + let x = n + while ((x & (x + 1)) !== 0) { + x += 1 + } + return x +}; diff --git a/3371-identify-the-largest-outlier-in-an-array.js b/3371-identify-the-largest-outlier-in-an-array.js new file mode 100644 index 00000000..3e6b4784 --- /dev/null +++ b/3371-identify-the-largest-outlier-in-an-array.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var getLargestOutlier = function (nums) { + let totalSum = 0 + for (let num of nums) { + totalSum += num + } + + const freqMap = new Map() + for (let num of nums) { + freqMap.set(num, (freqMap.get(num) || 0) + 1) + } + let res = Number.MIN_SAFE_INTEGER + + for (let sumElement of nums) { + let potentialOutlier = totalSum - 2 * sumElement + + if (freqMap.has(potentialOutlier)) { + if (potentialOutlier === sumElement && freqMap.get(sumElement) < 2) { + continue + } + res = Math.max(res, potentialOutlier) + } + } + return res +} diff --git a/3372-maximize-the-number-of-target-nodes-after-connecting-trees-i.js b/3372-maximize-the-number-of-target-nodes-after-connecting-trees-i.js new file mode 100644 index 00000000..d20c097d --- /dev/null +++ b/3372-maximize-the-number-of-target-nodes-after-connecting-trees-i.js @@ -0,0 +1,53 @@ +/** + * @param {number[][]} edges1 + * @param {number[][]} edges2 + * @param {number} k + * @return {number[]} + */ +var maxTargetNodes = function (edges1, edges2, k) { + const n = edges1.length + 1 + const m = edges2.length + 1 + + const adj1 = Array.from({ length: n }, () => []) + const adj2 = Array.from({ length: m }, () => []) + + for (const edge of edges1) { + const [u, v] = edge + adj1[u].push(v) + adj1[v].push(u) + } + for (const edge of edges2) { + const [u, v] = edge + adj2[u].push(v) + adj2[v].push(u) + } + + const good1 = new Array(n).fill(0) + const good2 = new Array(m).fill(0) + + for (let i = 0; i < n; i++) { + dfs(i, -1, 0, i, k + 1, good1, adj1) + } + + for (let i = 0; i < m; i++) { + dfs(i, -1, 0, i, k, good2, adj2) + } + + const mx = Math.max(...good2) + + const res = new Array(n) + for (let i = 0; i < n; i++) { + res[i] = good1[i] + mx + } + return res +} + +function dfs(node, parent, distance, root, k, good, adj) { + if (distance >= k) return + good[root]++ + for (const neighbor of adj[node]) { + if (neighbor !== parent) { + dfs(neighbor, node, distance + 1, root, k, good, adj) + } + } +} diff --git a/3373-maximize-the-number-of-target-nodes-after-connecting-trees-ii.js b/3373-maximize-the-number-of-target-nodes-after-connecting-trees-ii.js new file mode 100644 index 00000000..c1ca4e20 --- /dev/null +++ b/3373-maximize-the-number-of-target-nodes-after-connecting-trees-ii.js @@ -0,0 +1,90 @@ +class Graph { + constructor(n) { + this.n = n + this.adj = Array.from({ length: n }, () => []) + this.weight = new Map() + for (let i = 0; i < n; i++) { + this.weight.set(i, new Map()) + } + } + + addEdgeOri(i, j, w = 0) { + this.adj[i].push(j) + this.weight.get(i).set(j, w) + } + + addEdge(i, j, w = 0) { + // Add w to v's list. + this.adj[i].push(j) + // Add v to w's list + this.adj[j].push(i) + this.weight.get(i).set(j, w) + this.weight.get(j).set(i, w) + } +} + +function dijkstra(graph, source) { + const ans = new Array(graph.n).fill(Number.MAX_SAFE_INTEGER / 2) + const pq = new MinPriorityQueue({ priority: (item) => item[1] }) + pq.enqueue([source, 0]) + + while (pq.size() > 0) { + const [item, dis] = pq.dequeue().element + if (ans[item] <= dis) continue + ans[item] = dis + + graph.adj[item].forEach((neighbor) => { + if (ans[neighbor] >= Number.MAX_SAFE_INTEGER / 2) { + pq.enqueue([neighbor, dis + graph.weight.get(item).get(neighbor)]) + } + }) + } + return ans +} + +function maxTargetNodes(edges1, edges2) { + const n = edges1.length + 1 + const m = edges2.length + 1 + const g1 = new Graph(n) + const g2 = new Graph(m) + + edges1.forEach(([a, b]) => g1.addEdge(a, b, 1)) + edges2.forEach(([a, b]) => g2.addEdge(a, b, 1)) + + const dis1 = dijkstra(g1, 0) + const dis2 = dijkstra(g2, 0) + + const a0 = new Set() + const a1 = new Set() + const b0 = new Set() + const b1 = new Set() + + for (let i = 0; i < dis1.length; i++) { + if (dis1[i] % 2 === 0) { + a0.add(i) + } else { + a1.add(i) + } + } + + for (let i = 0; i < dis2.length; i++) { + if (dis2[i] % 2 === 0) { + b0.add(i) + } else { + b1.add(i) + } + } + + const b = Math.max(b0.size, b1.size) + const ans = [] + + for (let i = 0; i < n; i++) { + if (a0.has(i)) { + ans.push(a0.size + b) + } else { + ans.push(a1.size + b) + } + } + + return ans +} diff --git a/3376-minimum-time-to-break-locks-i.js b/3376-minimum-time-to-break-locks-i.js new file mode 100644 index 00000000..450bba1c --- /dev/null +++ b/3376-minimum-time-to-break-locks-i.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} strength + * @param {number} k + * @return {number} + */ +var findMinimumTime = function(strength, k) { + strength.sort((a, b) => a - b) + const n = strength.length, {floor} = Math + let res = Infinity + f(0, 1, 0) + return res + + function f(mask, x, tmp) { + if(mask === (1 << n) - 1) { + res = Math.min(res, tmp) + return + } + let add = 0 + for(let i = 0; i < n; i++) { + if(mask & (1 << i)) continue + add = ceil(strength[i] / x) + f(mask | (1 << i), x + k, tmp + add) + } + } +}; diff --git a/3377-digit-operations-to-make-two-integers-equal.js b/3377-digit-operations-to-make-two-integers-equal.js new file mode 100644 index 00000000..ca6c8ccc --- /dev/null +++ b/3377-digit-operations-to-make-two-integers-equal.js @@ -0,0 +1,129 @@ +let isPrime +/** + * @param {number} n + * @param {number} m + * @return {number} + */ +const minOperations = function(n, m) { + genPrimes() +// console.log(isPrime) + if(isPrime[n] || isPrime[m]) return -1 + const pq = new PQ((a, b) => a[0] < b[0]) + const visited = new Set() + + pq.push([n, n]) + while(!pq.isEmpty()) { + const [steps, cur] = pq.pop() + // console.log(cur) + if(visited.has(cur)) continue + visited.add(cur) + // console.log(steps) + if(cur === m) return steps + const s = ('' + cur).split('') + for(let i = 0; i < s.length; i++) { + const tmp = s[i] + const num = +s[i] + if(s[i] < '9') { + s[i] = num + 1 + const nxt = +s.join('') + if(!isPrime[nxt] && !visited.has(nxt)) { + pq.push([steps + nxt, nxt]) + } + s[i] = tmp + } + if(s[i] > '0' && !(i == 0 && s[i] == '1')) { + s[i] = num - 1 + const nxt = +s.join('') + if(!isPrime[nxt] && !visited.has(nxt)) { + pq.push([steps + nxt, nxt]) + } + s[i] = tmp + } + + } + + } + return -1 + + function genPrimes() { + if(isPrime != null) return + isPrime = Array(1e4 + 1).fill(1) + isPrime[0] = 0 + isPrime[1] = 0 + for(let i = 2; i <= 1e4; i++) { + if(isPrime[i]) { + for(let j = 2 * i; j <= 1e5; j += i) { + isPrime[j] = 0 + } + } + } + } +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/3378-count-connected-components-in-lcm-graph.js b/3378-count-connected-components-in-lcm-graph.js new file mode 100644 index 00000000..9f17c2bd --- /dev/null +++ b/3378-count-connected-components-in-lcm-graph.js @@ -0,0 +1,45 @@ +/** + * @param {number[]} nums + * @param {number} threshold + * @return {number} + */ +var countComponents = function(nums, threshold) { + const dsu = new DSU(threshold); + const n = nums.length; + let res = 0; + + for (let i = 0; i < nums.length; i++) { + if (nums[i] <= threshold) { + for (let j = nums[i]; j <= threshold; j += nums[i]) { + dsu.join(nums[i], j); + } + } + } + + const st = new Set(); + for (let i = 0; i < nums.length; i++) { + if (nums[i] > threshold) res++; + else st.add(dsu.findParent(nums[i])); + } + + res += st.size; + return res; +}; +class DSU { + constructor(n) { + this.parent = new Array(n + 1).fill(-1); + } + + findParent(x) { + if (this.parent[x] === -1) return x; + return this.parent[x] = this.findParent(this.parent[x]); + } + + join(x, y) { + const X = this.findParent(x); + const Y = this.findParent(y); + if (X === Y) return false; + this.parent[X] = Y; + return true; + } +} diff --git a/3379-transformed-array.js b/3379-transformed-array.js new file mode 100644 index 00000000..2daeba3f --- /dev/null +++ b/3379-transformed-array.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var constructTransformedArray = function(nums) { + const n = nums.length; + const res = new Array(n).fill(0); + for (let i = 0; i < n; i++) { + if (nums[i] === 0) { + res[i] = nums[i]; + } else if (nums[i] > 0) { + const ind = (i + nums[i]) % n; + res[i] = nums[ind]; + } else { + const neg = Math.abs(nums[i]) % n; + const ind = (i - neg + n) % n; + // console.log(ind); + res[i] = nums[ind]; + } + } + return res; +}; diff --git a/338-counting-bits.js b/338-counting-bits.js new file mode 100644 index 00000000..834aa74e --- /dev/null +++ b/338-counting-bits.js @@ -0,0 +1,9 @@ +/** + * @param {number} num + * @return {number[]} + */ +const countBits = function (num) { + const f = new Array(num + 1).fill(0) + for (let i = 1; i <= num; i++) f[i] = f[i >> 1] + (i & 1) + return f +} diff --git a/3380-maximum-area-rectangle-with-point-constraints-i.js b/3380-maximum-area-rectangle-with-point-constraints-i.js new file mode 100644 index 00000000..8247c400 --- /dev/null +++ b/3380-maximum-area-rectangle-with-point-constraints-i.js @@ -0,0 +1,41 @@ +/** + * @param {number[][]} points + * @return {number} + */ +var maxRectangleArea = function (points) { + const n = points.length + const st = new Set() + for (const i of points) st.add(i[0] + ',' + i[1]) + let res = -1 + + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + const x1 = points[i][0], + y1 = points[i][1], + x2 = points[j][0], + y2 = points[j][1] + if (x1 === x2 || y1 === y2) continue + if (st.has(x1 + ',' + y2) && st.has(x2 + ',' + y1)) { + const min1 = Math.min(x1, x2), + max1 = Math.max(x1, x2), + min2 = Math.min(y1, y2), + max2 = Math.max(y1, y2) + let isid = true + for (const point of points) { + const cx = point[0], + cy = point[1] + if ( + (cx > min1 && cx < max1 && cy > min2 && cy < max2) || + ((cx === min1 || cx === max1) && cy > min2 && cy < max2) || + ((cy === min2 || cy === max2) && cx > min1 && cx < max1) + ) { + isid = false + break + } + } + if (isid) res = Math.max(res, (max1 - min1) * (max2 - min2)) + } + } + } + return res +} diff --git a/3381-maximum-subarray-sum-with-length-divisible-by-k.js b/3381-maximum-subarray-sum-with-length-divisible-by-k.js new file mode 100644 index 00000000..7dcf1c3f --- /dev/null +++ b/3381-maximum-subarray-sum-with-length-divisible-by-k.js @@ -0,0 +1,60 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxSubarraySum = function(nums, k) { + const ps = [0] + for (const e of nums) { + ps.push(ps[ps.length - 1] + e) + } + let res = Number.MIN_SAFE_INTEGER + for (let p = 0; p < k; ++p) { + let sum = 0 + for (let i = p; i + k <= nums.length; i += k) { + const n = ps[i + k] - ps[i] + sum = Math.max(n, sum + n) + res = Math.max(res, sum) + } + } + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var maxSubarraySum = function (nums, k) { + const n = nums.length + let res = -Infinity + const pre_sum = new Array(n + 1).fill(0) + + for (let i = 0; i < n; i++) { + pre_sum[i + 1] = pre_sum[i] + nums[i] + } + + const groups = Array.from({ length: k }, (_, i) => [pre_sum[i]]) + + for (let i = k; i <= n; i++) { + const idx = i % k + groups[idx].push(pre_sum[i]) + } + + for (let i = 0; i < k; i++) { + const group = groups[i] + const mx_dp = new Array(group.length + 1).fill(-Infinity) + + for (let j = group.length - 1; j >= 0; j--) { + mx_dp[j] = Math.max(mx_dp[j + 1], group[j]) + } + + for (let j = 0; j < group.length; j++) { + res = Math.max(res, mx_dp[j + 1] - group[j]) + } + } + + return res +} diff --git a/3382-maximum-area-rectangle-with-point-constraints-ii.js b/3382-maximum-area-rectangle-with-point-constraints-ii.js new file mode 100644 index 00000000..7d1912cc --- /dev/null +++ b/3382-maximum-area-rectangle-with-point-constraints-ii.js @@ -0,0 +1,85 @@ +/** + * @param {number[]} xCoord + * @param {number[]} yCoord + * @return {number} + */ +var maxRectangleArea = function (xCoord, yCoord) { + const n = xCoord.length + const co = [] + const sy = imap(yCoord) + + for (let i = 0; i < n; i++) { + co.push([xCoord[i], binarySearch(sy, yCoord[i])]) + } + co.sort((a, b) => a[0] - b[0] || a[1] - b[1]) + + let result = -1 + const map = new Map() + const mapX = new Map() + const ft = new Array(sy.length + 1).fill(0) + for (let i = 0; i < co.length; i++) { + addFenwick(ft, co[i][1], 1) + + if (i - 1 >= 0 && co[i][0] === co[i - 1][0]) { + const yc = (BigInt(co[i][1]) << 32n) | BigInt(co[i - 1][1]) + const aft = sumFenwick(ft, co[i][1]) - sumFenwick(ft, co[i - 1][1] - 1) + + if (map.has(yc)) { + const bef = map.get(yc) + if (aft === bef + 2) { + const x = mapX.get(yc) + const S = + BigInt(co[i][0] - x) * BigInt(sy[co[i][1]] - sy[co[i - 1][1]]) + result = Number(BigInt(result) > S ? result : S) + } + } + + map.set(yc, aft) + mapX.set(yc, co[i][0]) + } + } + + return result + + function sumFenwick(ft, i) { + let sum = 0 + for (i += 1; i > 0; i -= i & -i) { + sum += ft[i] + } + return sum + } + + function addFenwick(ft, i, v) { + if (v === 0 || i < 0) return + for (i += 1; i < ft.length; i += i & -i) { + ft[i] += v + } + } + + function imap(a) { + const imap = Array.from(a) + imap.sort((a, b) => a - b) + let p = 1 + + for (let i = 1; i < imap.length; i++) { + if (imap[i] !== imap[p - 1]) imap[p++] = imap[i] + } + + return imap.slice(0, p) + } + + function binarySearch(nums, target) { + let left = 0 + let right = nums.length - 1 + while (left <= right) { + const mid = (left + right) >> 1 + if (nums[mid] === target) return mid + if (nums[mid] < target) { + left = mid + 1 + } else { + right = mid - 1 + } + } + return -1 + } +} diff --git a/3388-count-beautiful-splits-in-an-array.js b/3388-count-beautiful-splits-in-an-array.js new file mode 100644 index 00000000..1d848495 --- /dev/null +++ b/3388-count-beautiful-splits-in-an-array.js @@ -0,0 +1,45 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var beautifulSplits = function (nums) { + const n = nums.length + // lcps[i][j] = length of the longest common prefix between nums[i:] and nums[j:] + const lcps = Array.from({ length: n }, () => Array(n).fill(0)) + + // Calculate longest common prefixes + for (let x = 0; x < n; ++x) { + const lcp = lcps[x] + let max_i = x, + max_r = x + for (let i = x + 1; i < n; ++i) { + if (max_r >= i) { + lcp[i] = Math.min(max_r - i + 1, lcp[i - max_i + x]) + } + while (i + lcp[i] < n && nums[i + lcp[i]] === nums[lcp[i] + x]) { + lcp[i]++ + } + if (i + lcp[i] - 1 > max_r) { + max_i = i + max_r = i + lcp[i] - 1 + } + } + } + + let res = 0 + for (let i = 0; i < n; ++i) { + for (let j = i + 1; j < n - 1; ++j) { + // Check if prefix conditions are satisfied + if (lcps[0][i + 1] >= i + 1 && j - i >= i + 1) { + res++ + continue + } + if (lcps[i + 1][j + 1] >= j - i) { + res++ + continue + } + } + } + + return res +} diff --git a/339-nested-list-weight-sum.js b/339-nested-list-weight-sum.js new file mode 100644 index 00000000..d38d5c9f --- /dev/null +++ b/339-nested-list-weight-sum.js @@ -0,0 +1,76 @@ +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * function NestedInteger() { + * + * Return true if this NestedInteger holds a single integer, rather than a nested list. + * @return {boolean} + * this.isInteger = function() { + * ... + * }; + * + * Return the single integer that this NestedInteger holds, if it holds a single integer + * Return null if this NestedInteger holds a nested list + * @return {integer} + * this.getInteger = function() { + * ... + * }; + * + * Set this NestedInteger to hold a single integer equal to value. + * @return {void} + * this.setInteger = function(value) { + * ... + * }; + * + * Set this NestedInteger to hold a nested list and adds a nested integer elem to it. + * @return {void} + * this.add = function(elem) { + * ... + * }; + * + * Return the nested list that this NestedInteger holds, if it holds a nested list + * Return null if this NestedInteger holds a single integer + * @return {NestedInteger[]} + * this.getList = function() { + * ... + * }; + * }; + */ +/** + * @param {NestedInteger[]} nestedList + * @return {number} + */ +const depthSum = function(nestedList) { + return h(nestedList, 1) +}; + +function h(arr, level) { + if(arr == null || arr.length === 0) return 0 + let sum = 0 + for(let i = 0, len = arr.length; i < len; i++) { + if(arr[i].isInteger()) sum += arr[i].getInteger() * level + else { + sum += h(arr[i].getList(), level + 1) + } + } + return sum +} + +// another + +const depthSum = function(nestedList) { + if(nestedList == null) return 0 + let sum = 0 + let level = 1 + const q = [...nestedList] + while(q.length) { + const len = q.length + for(let i = 0; i < len; i++) { + const el = q.shift() + if(el.isInteger()) sum += el.getInteger() * level + else q.push(...(el.getList())) + } + level++ + } + return sum +}; diff --git a/3393-count-paths-with-the-given-xor-value.js b/3393-count-paths-with-the-given-xor-value.js new file mode 100644 index 00000000..8403c4b1 --- /dev/null +++ b/3393-count-paths-with-the-given-xor-value.js @@ -0,0 +1,29 @@ +/** + * @param {number[][]} grid + * @param {number} k + * @return {number} + */ +const countPathsWithXorValue = function(grid, k) { + const m = grid.length, n = grid[0].length + const mod = 1e9 + 7 + const dp = Array.from({length: m}, () => Array.from({length: n}, () => Array(16).fill(0))) + dp[0][0][grid[0][0]] = 1 + + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + for(let v = 0; v < 16; v++) { + if(dp[i][j][v] <= 0) continue + if(i + 1 < m) { + const e = grid[i + 1][j] + dp[i + 1][j][v ^ e] = (dp[i + 1][j][v ^ e] + dp[i][j][v]) % mod + } + if(j + 1 < n) { + const e = grid[i][j + 1] + dp[i][j + 1][v ^ e] = (dp[i][j + 1][v ^ e] + dp[i][j][v]) % mod + } + } + } + } + + return dp[m - 1][n - 1][k] +}; diff --git a/3394-check-if-grid-can-be-cut-into-sections.js b/3394-check-if-grid-can-be-cut-into-sections.js new file mode 100644 index 00000000..82710629 --- /dev/null +++ b/3394-check-if-grid-can-be-cut-into-sections.js @@ -0,0 +1,30 @@ +/** + * @param {number} n + * @param {number[][]} rectangles + * @return {boolean} + */ +var checkValidCuts = function(n, rectangles) { + const vertical = []; + const horizontal = []; + for (const it of rectangles) { + vertical.push([it[1], it[3]]) + horizontal.push([it[0], it[2]]) + } + const mergeH = mergeIntervals(horizontal); + const mergeV = mergeIntervals(vertical); + return mergeH.length >= 3 || mergeV.length >= 3; +}; +function mergeIntervals(intervals) { + if (intervals.length <= 1) return intervals; + intervals.sort((a, b) => a[0] - b[0]); + const merged = []; + merged.push(intervals[0]); + for (let i = 1; i < intervals.length; ++i) { + if (intervals[i][0] < merged[merged.length - 1][1]) { + merged[merged.length - 1][1] = Math.max(merged[merged.length - 1][1], intervals[i][1]); + } else { + merged.push(intervals[i]); + } + } + return merged; +} diff --git a/3395-subsequences-with-a-unique-middle-mode-i.js b/3395-subsequences-with-a-unique-middle-mode-i.js new file mode 100644 index 00000000..0ec3f8f9 --- /dev/null +++ b/3395-subsequences-with-a-unique-middle-mode-i.js @@ -0,0 +1,63 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var subsequencesWithMiddleMode = function(nums) { + const n = nums.length; + // 总方案数为C(n,5) + let ans = comb(n, 5); + const mod = 10 ** 9 + 7; + // 统计不合法的个数 + // 记录每个元素的个数 + const hash = new Map(); + for (const num of nums) hash.set(num, (hash.get(num) || 0) + 1); + const pre = new Map(); // 记录之前的元素情况 + // 枚举x,作为子序列最中间的数 + for (let i = 0; i < n - 2; i++) { + const x = nums[i]; + hash.set(x, hash.get(x) - 1); // 更新右边元素的个数 + if (i > 1) { + const right = n - 1 - i; // 右边元素个数 + const left = i; // 左边元素个数 + const preX = pre.get(x) || 0; // 左边x元素个数 + const sufX = hash.get(x) || 0; // 右边x元素个数 + // 不合法:只有一个x的情况,左边选取不是x的两个,右边选取不是x的两个 + ans -= comb(left - preX, 2) * comb(right - sufX, 2); + // 不合法:有两个x,但是要有一个y,出现在2次以上 + for (const [y, sufY] of hash) { + if (y === x) continue; + const preY = pre.get(y) || 0; + // 左边两个Y,右边一个X, yy x xz(z可以为y) + ans -= comb(preY, 2) * sufX * (right - sufX); + // 右边两个Y,左边一个X,zx x yy (z可以为y) + ans -= comb(sufY, 2) * preX * (left - preX); + // 左右各一个y,另一个x在左边,xy x yz(z !== y,避免重复) + ans -= preY * preX * sufY * (right - sufX - sufY); + // 左右各一个y,另一个x在右边,zy x yx(z !== y,避免重复) + ans -= preY * sufY * sufX * (left - preX - preY); + } + } + pre.set(x, (pre.get(x) || 0) + 1); // 更新左边元素的个数 + } + return ans % mod; +}; + + +/** + * @description 求组合数 + * @param {number} n + * @param {number} m + * @returns {number} + */ +function comb(n, m) { + if (n < m) return 0; + let top = 1; + let bottom = 1; + let start = 0; + while (start < m) { + top *= n - start; + bottom *= m - start; + start++; + } + return top / bottom; +} diff --git a/3399-smallest-substring-with-identical-characters-ii.js b/3399-smallest-substring-with-identical-characters-ii.js new file mode 100644 index 00000000..ae74d5c5 --- /dev/null +++ b/3399-smallest-substring-with-identical-characters-ii.js @@ -0,0 +1,48 @@ +/** + * @param {string} s + * @param {number} numOps + * @return {number} + */ +var minLength = function (s, numOps) { + const arr = Array.from(s, Number) + + const L = groupLengths(arr) + + let l = 1, + r = 100000 + while (l < r) { + const m = Math.floor((l + r) / 2) + const need = check(arr, m) + if (need <= numOps) { + r = m + } else { + l = m + 1 + } + } + return l + + function check(A, k) { + if (k === 1) { + let res = 0 + for (let i = 0; i < A.length; i++) { + if (A[i] === i % 2) res++ + } + return Math.min(res, A.length - res) + } + return L.reduce((acc, l) => acc + Math.floor(l / (k + 1)), 0) + } + + function groupLengths(arr) { + const lengths = [] + let count = 1 + for (let i = 1; i <= arr.length; i++) { + if (i < arr.length && arr[i] === arr[i - 1]) { + count++ + } else { + lengths.push(count) + count = 1 + } + } + return lengths + } +} diff --git a/340-longest-substring-with-at-most-k-distinct-characters.js b/340-longest-substring-with-at-most-k-distinct-characters.js new file mode 100644 index 00000000..76f65f15 --- /dev/null +++ b/340-longest-substring-with-at-most-k-distinct-characters.js @@ -0,0 +1,39 @@ +/** + +Given a string, find the length of the longest substring T that contains at most k distinct characters. + +Example 1: + +Input: s = "eceba", k = 2 +Output: 3 +Explanation: T is "ece" which its length is 3. +Example 2: + +Input: s = "aa", k = 1 +Output: 2 +Explanation: T is "aa" which its length is 2. + +*/ + +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const lengthOfLongestSubstringKDistinct = function(s, k) { + const map = new Map() + let left = 0 + let best = 0 + for(let i = 0; i < s.length; i++) { + const c = s.charAt(i) + map.set(c, (map.get(c) || 0) + 1) + while(map.size > k) { + const lc = s.charAt(left) + map.set(lc, map.get(lc) - 1) + if(map.get(lc) === 0) map.delete(lc) + left++ + } + best = Math.max(best, i - left + 1) + } + return best +}; diff --git a/3404-count-special-subsequences.js b/3404-count-special-subsequences.js new file mode 100644 index 00000000..69fc7410 --- /dev/null +++ b/3404-count-special-subsequences.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var numberOfSubsequences = function(nums) { + let n = nums.length; + let res = 0; + const cnt = new Map(); + for (let r = 4; r < n - 2; ++r) { + let q = r - 2; + for (let p = 0; p < q - 1; ++p) { + let key = 1.0 * nums[p] / nums[q]; + cnt.set(key, (cnt.get(key) || 0) + 1); + } + for (let s = r + 2; s < n; ++s) { + let key = 1.0 * nums[s] / nums[r]; + res += cnt.get(key) || 0; + } + } + return res; +}; diff --git a/3413-maximum-coins-from-k-consecutive-bags.js b/3413-maximum-coins-from-k-consecutive-bags.js new file mode 100644 index 00000000..b2928c3e --- /dev/null +++ b/3413-maximum-coins-from-k-consecutive-bags.js @@ -0,0 +1,35 @@ +/** + * @param {number[][]} coins + * @param {number} k + * @return {number} + */ +var maximumCoins = function(coins, k) { + coins.sort((a, b) => a[0] - b[0]); + const n = coins.length; + + let res = 0, cur = 0; + for (let i = 0, j = 0; i < n; ++i) { + while (j < n && coins[j][1] <= coins[i][0] + k - 1) { + cur +=(coins[j][1] - coins[j][0] + 1) * (coins[j][2]); + j++; + } + if (j < n) { + const part = Math.max(0, coins[i][0] + k - 1 - coins[j][0] + 1) * (coins[j][2]); + res = Math.max(res, cur + part); + } + cur -= (coins[i][1] - coins[i][0] + 1) * (coins[i][2]); + } + + cur = 0; + for (let i = 0, j = 0; i < n; ++i) { + cur += 1 * (coins[i][1] - coins[i][0] + 1) * (coins[i][2]); + while (coins[j][1] < coins[i][1] - k + 1) { + cur -= 1 * (coins[j][1] - coins[j][0] + 1) * (coins[j][2]); + j++; + } + const part = 1 * Math.max(0, coins[i][1] - k - coins[j][0] + 1) * (coins[j][2]); + res = Math.max(res, cur - part); + } + + return res; +}; diff --git a/3428-maximum-and-minimum-sums-of-at-most-size-k-subsequences.js b/3428-maximum-and-minimum-sums-of-at-most-size-k-subsequences.js new file mode 100644 index 00000000..7f057c86 --- /dev/null +++ b/3428-maximum-and-minimum-sums-of-at-most-size-k-subsequences.js @@ -0,0 +1,74 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minMaxSums = function(nums, k) { + const big = BigInt + const mod = big(1e9 + 7) + const n = nums.length + const comb = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0n)) + + comb[0][0] = 1n + for(let i = 1; i <= n; i++) { + comb[i][0] = 1n + for(let j = 1; j <= k; j++) { + comb[i][j] = comb[i - 1][j - 1] + comb[i - 1][j] + comb[i][j] %= mod + } + } + + nums.sort((a, b) => a - b) + + let res = 0n + + for(let i = 0; i < n; i++) { + const e = big(nums[i]) + for(let j = 0; j <= Math.min(i, k - 1); j++) { + res += (comb[i][j] * e) % mod + } + for(let j = 0; j < k; j++) { + res += (comb[n - 1 - i][j] * e) % mod + } + } + + + return Number(res % mod) +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minMaxSums = function(nums, k) { + nums.sort((a, b) => a - b) + let res = 0n + const MOD = 1e9 + 7 + const ncr = Array.from({ length: nums.length + 1 }, () => + Array(k + 1).fill(0), + ) + + ncr[0][0] = 1 + for (let n = 1; n <= nums.length; n++) { + ncr[n][0] = 1 + for (let r = 1; r <= k; r++) + ncr[n][r] = (ncr[n - 1][r - 1] + ncr[n - 1][r]) % MOD + } + + for (let n = 0; n < nums.length; n++) { + let numberOfSubsequences = 0 + for (let r = 0; r <= k - 1; r++) + if (n >= r) + numberOfSubsequences = (numberOfSubsequences + ncr[n][r]) % MOD + res = + (res + + ((BigInt(nums[n] + nums[nums.length - n - 1]) * + BigInt(numberOfSubsequences)) % + BigInt(MOD))) % + BigInt(MOD) + } + return Number(res) +}; diff --git a/343-integer-break.js b/343-integer-break.js index 65a728dc..22446b08 100755 --- a/343-integer-break.js +++ b/343-integer-break.js @@ -1,3 +1,20 @@ +/** + * @param {number} n + * @return {number} + */ +const integerBreak = function(n) { + const dp = Array(n + 1).fill(0) + dp[2] = 1 + for(let i = 3; i <= n; i++) { + for(let j = 1; j < i; j++) { + dp[i] = Math.max(dp[i], j * Math.max(i - j, dp[i - j])) + } + } + return dp[n] +}; + +// another + /** * @param {number} n * @return {number} @@ -32,3 +49,32 @@ const integerBreak = function(n) { } return maxArr[n]; }; + +// another + +/** + * @param {number} n + * @return {number} + */ +const integerBreak = function(n) { + if(n === 2) return 1 + if(n === 3) return 2 + let num = ~~(n / 3) + let rem = n % 3 + if(rem === 1) { + rem += 3 + num-- + } + return rem === 0 ? Math.pow(3, num) : Math.pow(3, num) * rem +}; + +/** + +If an optimal product contains a factor f >= 4, +then you can replace it with factors 2 and f-2 without losing optimality, +as 2*(f-2) = 2f-4 >= f. So you never need a factor greater than or equal to 4, +meaning you only need factors 1, 2 and 3 (and 1 is of course wasteful and you'd only use it for n=2 and n=3, where it's needed). + +For the rest I agree, 3*3 is simply better than 2*2*2, so you'd never use 2 more than twice. + +*/ diff --git a/344-reverse-string.js b/344-reverse-string.js new file mode 100644 index 00000000..155ddcac --- /dev/null +++ b/344-reverse-string.js @@ -0,0 +1,19 @@ +/** + * @param {character[]} s + * @return {void} Do not return anything, modify s in-place instead. + */ +const reverseString = function(s) { + s.reverse() +}; + +// another + +/** + * @param {character[]} s + * @return {void} Do not return anything, modify s in-place instead. + */ +const reverseString = function(s) { + for(let i = 0; i < s.length / 2; i++){ + [ s[i] , s[s.length - 1 - i] ] = [ s[s.length - 1 - i] , s[i] ]; + } +}; diff --git a/3444-minimum-increments-for-target-multiples-in-an-array.js b/3444-minimum-increments-for-target-multiples-in-an-array.js new file mode 100644 index 00000000..f7115be1 --- /dev/null +++ b/3444-minimum-increments-for-target-multiples-in-an-array.js @@ -0,0 +1,62 @@ +/** + * @param {number[]} nums + * @param {number[]} target + * @return {number} + */ +var minimumIncrements = function(nums, target) { + const k = target.length; + const mpp = new Map(); + + for (let mask = 1; mask < (1 << k); mask++) { + const subset = []; + for (let i = 0; i < k; i++) { + if (mask & (1 << i)) { + subset.push(target[i]); + } + } + let currlcm = subset[0]; + for (let j = 1; j < subset.length; j++) { + currlcm = lcm(currlcm, subset[j]); + } + mpp.set(mask, currlcm); + } + + const fullmask = (1 << k) - 1; + const dp = new Array(1 << k).fill(Infinity); + dp[0] = 0; + + for (const num of nums) { + const maskcost = []; + for (const [mask, lcmval] of mpp) { + const rm = num % lcmval; + const cost = (rm === 0) ? 0 : (lcmval - rm); + maskcost.push([mask, cost]); + } + + const newdp = [...dp]; + for (let prevmask = 0; prevmask < (1 << k); prevmask++) { + if (dp[prevmask] === Infinity) continue; + for (const [mask, cost] of maskcost) { + const nmask = prevmask | mask; + const ncost = dp[prevmask] + cost; + if (ncost < newdp[nmask]) { + newdp[nmask] = ncost; + } + } + } + + dp.splice(0, dp.length, ...newdp); + } + + return dp[fullmask] === Infinity ? -1 : dp[fullmask]; +}; +function gcd(a, b) { + while (b) { + [a, b] = [b, a % b]; + } + return a; +} + +function lcm(a, b) { + return (a / gcd(a, b)) * b; +} diff --git a/3449-maximize-the-minimum-game-score.js b/3449-maximize-the-minimum-game-score.js new file mode 100644 index 00000000..abd1f14d --- /dev/null +++ b/3449-maximize-the-minimum-game-score.js @@ -0,0 +1,44 @@ +/** + * @param {number[]} points + * @param {number} m + * @return {number} + */ +var maxScore = function (points, m) { + const n = points.length + if (m < n) return 0 + + const can = (val) => { + let total = 0, + transfer = 0, + skipAdd = 0 + for (let i = 0; i < n && total <= m; i++) { + const point = points[i] + const necessary = Math.floor((val + point - 1) / point) + if (transfer >= necessary) { + transfer = 0 + skipAdd++ + } else { + const p = transfer * point + const ops = Math.floor((val - p + point - 1) / point) + total += 2 * ops - 1 + total += skipAdd + + transfer = Math.max(ops - 1, 0) + skipAdd = 0 + } + } + return total <= m + } + + let l = 1n, + r = 10n ** 15n + while (l < r) { + const mid = r - (r - l) / 2n + if (can(Number(mid))) { + l = mid + } else { + r = mid - 1n + } + } + return Number(l) +} diff --git a/345-reverse-vowels-of-a-string.js b/345-reverse-vowels-of-a-string.js new file mode 100644 index 00000000..f0702f84 --- /dev/null +++ b/345-reverse-vowels-of-a-string.js @@ -0,0 +1,36 @@ +/** + * @param {string} s + * @return {string} + */ +const reverseVowels = function(s) { + if(s == null || s === '') return '' + const arr = s.split('') + let p = 0 + const len = s.length + let e = s.length - 1 + const v = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'] + while(p < e) { + while(v.indexOf(arr[p]) === -1 && p < e) p++ + while(v.indexOf(arr[e]) === -1 && p < e) e-- + const tmp = arr[p] + arr[p] = arr[e] + arr[e] = tmp + p++ + e-- + } + return arr.join('') +}; + + +// another + +const reverseVowels = function(s) { + let vowels = s.match(/[aeiou]/gi) + let k = 0 + if (vowels) { + vowels = vowels.reverse`` + } else { + return s + } + return s.replace(/[aeiou]/gi, () => vowels[k++]) +} diff --git a/3458-select-k-disjoint-special-substrings.js b/3458-select-k-disjoint-special-substrings.js new file mode 100644 index 00000000..e25307b5 --- /dev/null +++ b/3458-select-k-disjoint-special-substrings.js @@ -0,0 +1,53 @@ +/** + * @param {string} s + * @param {number} k + * @return {boolean} + */ +var maxSubstringLength = function (s, k) { + const n = s.length; + const first = Array(26).fill(-1); + const last = Array(26).fill(-1); + + for (let i = 0; i < n; i++) { + const c = s.charCodeAt(i) - 'a'.charCodeAt(0); + if (first[c] === -1) first[c] = i; + last[c] = i; + } + + const intervals = []; + for (let i = 0; i < n; i++) { + const c = s.charCodeAt(i) - 'a'.charCodeAt(0); + if (i !== first[c]) continue; + + let j = last[c]; + for (let k = i; k <= j; k++) { + j = Math.max(j, last[s.charCodeAt(k) - 'a'.charCodeAt(0)]); + } + + let flag = true; + for (let k = i; k <= j; k++) { + if (first[s.charCodeAt(k) - 'a'.charCodeAt(0)] < i) { + flag = false; + break; + } + } + if (!flag) continue; + + if (i === 0 && j === n - 1) continue; + + intervals.push([i, j]); + } + + intervals.sort((a, b) => a[1] - b[1]); + + let cnt = 0; + let currend = -1; + for (const i of intervals) { + if (i[0] > currend) { + cnt++; + currend = i[1]; + } + } + + return cnt >= k; +} diff --git a/346-moving-average-from-data-stream.js b/346-moving-average-from-data-stream.js new file mode 100644 index 00000000..2b670d60 --- /dev/null +++ b/346-moving-average-from-data-stream.js @@ -0,0 +1,30 @@ +/** + * Initialize your data structure here. + * @param {number} size + */ +const MovingAverage = function(size) { + this.limit = size + this.arr = [] + this.sum = 0 +}; + +/** + * @param {number} val + * @return {number} + */ +MovingAverage.prototype.next = function(val) { + this.arr.push(val) + this.sum += val + if(this.arr.length > this.limit) { + const tmp = this.arr[0] + this.arr.shift() + this.sum -= tmp + } + return this.sum / this.arr.length +}; + +/** + * Your MovingAverage object will be instantiated and called as such: + * var obj = new MovingAverage(size) + * var param_1 = obj.next(val) + */ diff --git a/3464-maximize-the-distance-between-points-on-a-square.js b/3464-maximize-the-distance-between-points-on-a-square.js new file mode 100644 index 00000000..57f343dd --- /dev/null +++ b/3464-maximize-the-distance-between-points-on-a-square.js @@ -0,0 +1,152 @@ +/** + * @param {number} side + * @param {number[][]} points + * @param {number} k + * @return {number} + */ +const maxDistance = function (side, points, k) { + const n = points.length + const arr = [] + + const next = new Array(15000) + + for (const p of points) { + if (p[0] === 0) { + arr.push(p[1]) + } else if (p[1] === side) { + arr.push(side + p[0]) + } else if (p[0] === side) { + arr.push(2 * side + side - p[1]) + } else if (p[1] === 0) { + arr.push(3 * side + side - p[0]) + } + } + + arr.sort((a, b) => a - b) + + let low = 0, + high = side + while (low < high) { + const mid = high - Math.floor((high - low) / 2) + if (isOK(mid, k)) { + low = mid + } else { + high = mid - 1 + } + } + return low + + function isOK(dist, k) { + let j = 0 + for (let i = 0; i < n; i++) { + while (pos(j) - arr[i] < dist) { + j++ + } + next[i] = j + } + + for (let i = 0; i < n; i++) { + let flag = true + let cur = i + for (let t = 0; t < k - 1; t++) { + if (cur < n) { + cur = next[cur] + } else { + cur = next[cur % n] + n + } + if (cur >= i + n) { + flag = false + break + } + } + if (pos(i) - pos(cur % n) < dist) { + flag = false + } + if (flag) { + return true + } + } + return false + } + + function pos(j) { + if (j < n) { + return arr[j] + } else { + return arr[j % n] + side * 4 + } + } + +} + + +// another + + +/** + * @param {number} side + * @param {number[][]} points + * @param {number} k + * @return {number} + */ +var maxDistance = function (side, points, k) { + points = points + .map(([x, y]) => { + // convert to points on a flat line + if (x === 0) { + // left + return y + } else if (y === side) { + // top + return x + y + } else if (x === side) { + // right + return side * 2 + (side - y) + } else { + // bottom + return side * 3 + (side - x) + } + }) + .sort((a, b) => a - b) + + let low = 1, + high = side + while (low < high) { + let mid = Math.ceil((low + high) / 2) + if (isPossible(points, side, k, mid)) low = mid + else high = mid - 1 + } + return low +} + +// Check that we can take at least k points that are at least `minDist` apart +function isPossible(points, side, k, minDist) { + const n = points.length, + endOfLine = side * 4 + for (let i = 0; i < n; i++) { + let j = i, + taken = 1 + while (taken < k) { + // binary search for the leftmost point at least `minDist` away from points[j], on the right of j. + let low = j, + high = n - 1 + while (low < high) { + let mid = Math.floor((low + high) / 2) + if (points[mid] - points[j] >= minDist) high = mid + else low = mid + 1 + } + // no valid point on the right side, or too close to the starting point (wraps around circularly). + if ( + points[low] - points[j] < minDist || + endOfLine + points[i] - points[low] < minDist + ) { + break + } + ;(j = low), taken++ + } + if (taken === k) { + return true + } + } + return false +} diff --git a/347-top-k-frequent-elements.js b/347-top-k-frequent-elements.js index c5f2c1f5..5a59bc3f 100755 --- a/347-top-k-frequent-elements.js +++ b/347-top-k-frequent-elements.js @@ -31,3 +31,69 @@ const topKFrequent = function(nums, k) { return res }; +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +const topKFrequent = function(nums, k) { + const hash = {} + for(let n of nums) { + if(hash[n] == null) hash[n] = 0 + hash[n]++ + } + const entries = Object.entries(hash) + let min = Infinity, max = -Infinity + const reverse = {} + for(let [k, freq] of entries) { + if(freq < min) min = freq + if(freq > max) max = freq + if(reverse[freq] == null) reverse[freq] = [] + reverse[freq].push(k) + } + const n = max - min + 1 + const arr = Array(n) + let res = [] + let limit = max + while(limit) { + if(reverse[limit]) res.push(...reverse[limit]) + limit-- + if(res.length >= k) break + } + res.splice(k) + return res +}; + +// another + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ + const topKFrequent = function(nums, k) { + const n = nums.length + const freq = Array(n + 1).fill(null) + const hash = {} + for(let e of nums) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + for(let k in hash) { + if(hash.hasOwnProperty(k)) { + const v = hash[k] + if(freq[v] == null) freq[v] = [] + freq[v].push(k) + } + } + const res = [] + for(let i = n; i >= 0; i--) { + if(freq[i] != null) res.push(...freq[i]) + if(res.length >= k) break + } + if(res.length > k) res.splice(k) + return res +}; diff --git a/3471-find-the-largest-almost-missing-integer.js b/3471-find-the-largest-almost-missing-integer.js new file mode 100644 index 00000000..abe842fa --- /dev/null +++ b/3471-find-the-largest-almost-missing-integer.js @@ -0,0 +1,23 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var largestInteger = function (nums, k) { + const freq = new Map() + + for (let i = 0; i <= nums.length - k; i++) { + const sub = new Set(nums.slice(i, i + k)) + for (const num of sub) { + freq.set(num, (freq.get(num) || 0) + 1) + } + } + + let ans = -1 + for (const [num, count] of freq) { + if (count === 1) { + ans = Math.max(ans, num) + } + } + return ans +} diff --git a/3472-longest-palindromic-subsequence-after-at-most-k-operations.js b/3472-longest-palindromic-subsequence-after-at-most-k-operations.js new file mode 100644 index 00000000..2636a181 --- /dev/null +++ b/3472-longest-palindromic-subsequence-after-at-most-k-operations.js @@ -0,0 +1,32 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +var longestPalindromicSubsequence = function (s, k) { + const n = s.length + const dp = Array.from({ length: n }, () => + Array.from({ length: n }, () => Array(k + 1).fill(-1)), + ) + + function cost(a, b) { + const diff = Math.abs(a.charCodeAt(0) - b.charCodeAt(0)) + return Math.min(diff, 26 - diff) + } + + function dfs(i, j, rem) { + if (i > j) return 0 + if (i === j) return 1 + if (dp[i][j][rem] !== -1) return dp[i][j][rem] + + let res = Math.max(dfs(i + 1, j, rem), dfs(i, j - 1, rem)) + const c = cost(s[i], s[j]) + if (c <= rem) { + res = Math.max(res, 2 + dfs(i + 1, j - 1, rem - c)) + } + dp[i][j][rem] = res + return res + } + + return dfs(0, n - 1, k) +} diff --git a/3473-sum-of-k-subarrays-with-length-at-least-m.js b/3473-sum-of-k-subarrays-with-length-at-least-m.js new file mode 100644 index 00000000..7ca52435 --- /dev/null +++ b/3473-sum-of-k-subarrays-with-length-at-least-m.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} nums + * @param {number} k + * @param {number} m + * @return {number} + */ +var maxSum = function (nums, k, m) { + const n = nums.length + + const prefix = new Array(n + 1).fill(0) + for (let i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + nums[i] + } + + const dp = Array.from({ length: k + 1 }, () => + new Array(n + 1).fill(Number.MIN_SAFE_INTEGER / 2), + ) + for (let i = 0; i <= n; i++) { + dp[0][i] = 0 + } + for (let j = 0; j < k; j++) { + const best = new Array(n + 1).fill(0) + best[0] = dp[j][0] - prefix[0] + for (let i = 1; i <= n; i++) { + best[i] = Math.max(best[i - 1], dp[j][i] - prefix[i]) + } + for (let i = m; i <= n; i++) { + const candidate = prefix[i] + best[i - m] + dp[j + 1][i] = i === m ? candidate : Math.max(dp[j + 1][i - 1], candidate) + } + } + return dp[k][n] +} diff --git a/3474-lexicographically-smallest-generated-string.js b/3474-lexicographically-smallest-generated-string.js new file mode 100644 index 00000000..061efbba --- /dev/null +++ b/3474-lexicographically-smallest-generated-string.js @@ -0,0 +1,59 @@ +/** + * @param {string} str1 + * @param {string} str2 + * @return {string} + */ +var generateString = function (str1, str2) { + const n = str1.length + const m = str2.length + const len = n + m - 1 + const c = '*' + + const ans = new Array(len).fill(c) + const forced = new Array(len).fill(false) + + for (let i = 0; i < n; i++) { + if (str1[i] === 'T') { + for (let j = 0; j < m; j++) { + const pos = i + j + if (ans[pos] === c) { + ans[pos] = str2[j] + forced[pos] = true + } else { + if (ans[pos] !== str2[j]) return '' + } + } + } + } + + for (let i = 0; i < len; i++) { + if (ans[i] === c) { + ans[i] = 'a' + } + } + + for (let i = 0; i < n; i++) { + if (str1[i] === 'F') { + let windowEqual = true + for (let j = 0; j < m; j++) { + if (ans[i + j] !== str2[j]) { + windowEqual = false + break + } + } + if (windowEqual) { + let modified = false + for (let j = m - 1; j >= 0; j--) { + const pos = i + j + if (!forced[pos]) { + ans[pos] = 'b' + modified = true + break + } + } + if (!modified) return '' + } + } + } + return ans.join('') +} diff --git a/3477-fruits-into-baskets-ii.js b/3477-fruits-into-baskets-ii.js new file mode 100644 index 00000000..ef332803 --- /dev/null +++ b/3477-fruits-into-baskets-ii.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} fruits + * @param {number[]} baskets + * @return {number} + */ +var numOfUnplacedFruits = function (fruits, baskets) { + for (let i = 0; i < fruits.length; i++) { + for (let j = 0; j < baskets.length; j++) { + if (baskets[j] >= fruits[i]) { + baskets[j] = -1 + break + } + } + } + let res = 0 + for (let i = 0; i < baskets.length; i++) { + res += baskets[i] !== -1 ? 1 : 0 + } + return res +} diff --git a/3478-choose-k-elements-with-maximum-sum.js b/3478-choose-k-elements-with-maximum-sum.js new file mode 100644 index 00000000..864f3886 --- /dev/null +++ b/3478-choose-k-elements-with-maximum-sum.js @@ -0,0 +1,120 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number[]} + */ +var findMaxSum = function (nums1, nums2, k) { + const n = nums1.length; + const answer = new Array(n).fill(0); + + const pairs = new Array(n); + for (let i = 0; i < n; i++) { + pairs[i] = new Pair(nums1[i], nums2[i], i); + } + + pairs.sort((a, b) => a.num1 - b.num1); + + const minHeap = new PQ((a, b) => a < b); + let currentSum = 0; + + let i = 0; + while (i < n) { + let j = i; + while (j < n && pairs[j].num1 === pairs[i].num1) { + answer[pairs[j].index] = currentSum; + j++; + } + for (let t = i; t < j; t++) { + const value = pairs[t].num2; + if (minHeap.size() < k) { + minHeap.push(value); + currentSum += value; + } else if (!minHeap.isEmpty() && value > minHeap.peek()) { + currentSum -= minHeap.peek(); + minHeap.pop(); + minHeap.push(value); + currentSum += value; + } + } + i = j; + } + + return answer; +} +class Pair { + constructor(num1, num2, index) { + this.num1 = num1; + this.num2 = num2; + this.index = index; + } +} + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + diff --git a/3479-fruits-into-baskets-iii.js b/3479-fruits-into-baskets-iii.js new file mode 100644 index 00000000..d9077763 --- /dev/null +++ b/3479-fruits-into-baskets-iii.js @@ -0,0 +1,73 @@ +/** + * @param {number[]} fruits + * @param {number[]} baskets + * @return {number} + */ +var numOfUnplacedFruits = function (fruits, baskets) { + const n = fruits.length + const segTree = new SegmentTree(baskets) + let unplaced = 0 + + for (const fruit of fruits) { + const idx = segTree.query(fruit) + if (idx === -1) { + unplaced++ + } else { + segTree.update(idx, -1) + } + } + return unplaced +} +class SegmentTree { + constructor(baskets) { + this.n = baskets.length + this.tree = new Array(4 * this.n) + this.build(baskets, 1, 0, this.n - 1) + } + + build(baskets, node, start, end) { + if (start === end) { + this.tree[node] = baskets[start] + } else { + const mid = Math.floor((start + end) / 2) + this.build(baskets, 2 * node, start, mid) + this.build(baskets, 2 * node + 1, mid + 1, end) + this.tree[node] = Math.max(this.tree[2 * node], this.tree[2 * node + 1]) + } + } + + update(pos, val) { + this.updateNode(1, 0, this.n - 1, pos, val) + } + + updateNode(node, start, end, pos, val) { + if (start === end) { + this.tree[node] = val + } else { + const mid = Math.floor((start + end) / 2) + if (pos <= mid) { + this.updateNode(2 * node, start, mid, pos, val) + } else { + this.updateNode(2 * node + 1, mid + 1, end, pos, val) + } + this.tree[node] = Math.max(this.tree[2 * node], this.tree[2 * node + 1]) + } + } + + query(required) { + if (this.tree[1] < required) return -1 + return this.queryNode(1, 0, this.n - 1, required) + } + + queryNode(node, start, end, required) { + if (start === end) { + return start + } + const mid = Math.floor((start + end) / 2) + if (this.tree[2 * node] >= required) { + return this.queryNode(2 * node, start, mid, required) + } else { + return this.queryNode(2 * node + 1, mid + 1, end, required) + } + } +} diff --git a/348-design-tic-tac-toe.js b/348-design-tic-tac-toe.js new file mode 100644 index 00000000..131a396c --- /dev/null +++ b/348-design-tic-tac-toe.js @@ -0,0 +1,53 @@ +/** + * Initialize your data structure here. + * @param {number} n + */ +const TicTacToe = function(n) { + this.n = n + this.cols = new Array(n).fill(0) + this.rows = new Array(n).fill(0) + this.diagonal = 0 + this.antiDiagonal = 0 +} + +/** + * Player {player} makes a move at ({row}, {col}). + @param row The row of the board. + @param col The column of the board. + @param player The player, can be either 1 or 2. + @return The current winning condition, can be either: + 0: No one wins. + 1: Player 1 wins. + 2: Player 2 wins. + * @param {number} row + * @param {number} col + * @param {number} player + * @return {number} + */ +TicTacToe.prototype.move = function(row, col, player) { + const { n } = this + const toAdd = player === 1 ? 1 : -1 + this.rows[row] += toAdd + this.cols[col] += toAdd + if (row === col) { + this.diagonal += toAdd + } + if (col === n - row - 1) { + this.antiDiagonal += toAdd + } + if ( + Math.abs(this.rows[row]) === n || + Math.abs(this.cols[col]) === n || + Math.abs(this.diagonal) === n || + Math.abs(this.antiDiagonal) === n + ) { + return player + } + return 0 +} + +/** + * Your TicTacToe object will be instantiated and called as such: + * var obj = new TicTacToe(n) + * var param_1 = obj.move(row,col,player) + */ diff --git a/3480-maximize-subarrays-after-removing-one-conflicting-pair.js b/3480-maximize-subarrays-after-removing-one-conflicting-pair.js new file mode 100644 index 00000000..ce7077f2 --- /dev/null +++ b/3480-maximize-subarrays-after-removing-one-conflicting-pair.js @@ -0,0 +1,113 @@ +/** + * @param {number} n + * @param {number[][]} conflictingPairs + * @return {number} + */ +var maxSubarrays = function (n, conflictingPairs) { + const best = new Array(n + 2).fill(n + 1) + const second = new Array(n + 2).fill(n + 1) + const freq = new Array(n + 2).fill(0) + + for (const pair of conflictingPairs) { + let [a, b] = pair + if (a > b) { + ;[a, b] = [b, a] + } + if (b < best[a]) { + second[a] = best[a] + best[a] = b + freq[a] = 1 + } else if (b === best[a]) { + freq[a]++ + } else if (b < second[a]) { + second[a] = b + } + } + + const F = new Array(n + 2).fill(0) + const M = new Array(n + 2).fill(0) + F[n + 1] = n + 1 + F[n] = best[n] + M[n] = n + for (let i = n - 1; i >= 1; i--) { + if (best[i] <= F[i + 1]) { + F[i] = best[i] + M[i] = i + } else { + F[i] = F[i + 1] + M[i] = M[i + 1] + } + } + + let origTotal = 0 + for (let i = 1; i <= n; i++) { + origTotal += F[i] - i + } + + const indicesByM = Array.from({ length: n + 2 }, () => []) + for (let i = 1; i <= n; i++) { + const idx = M[i] + indicesByM[idx].push(i) + } + + const rmq = new RMQ(best, n) + let bestTotal = origTotal + + for (let a = 1; a <= n; a++) { + if (best[a] === n + 1) continue + if (freq[a] > 1) continue + const B = best[a] + const newB = second[a] + const T = a < n ? F[a + 1] : n + 1 + const effectiveCandidate = Math.min(newB, T) + if (effectiveCandidate <= B) continue + + let delta = 0 + for (const i of indicesByM[a]) { + const curOld = B + let candidate + if (i < a) { + candidate = rmq.query(i, a - 1) + } else { + candidate = n + 1 + } + const newVal = Math.min(candidate, effectiveCandidate) + let improvement = newVal - curOld + if (improvement < 0) improvement = 0 + delta += improvement + } + const candidateTotal = origTotal + delta + bestTotal = Math.max(bestTotal, candidateTotal) + } + + return bestTotal +} + +class RMQ { + constructor(arr, n) { + this.n = n + this.log = new Array(n + 2).fill(0) + for (let i = 2; i <= n; i++) { + this.log[i] = this.log[Math.floor(i / 2)] + 1 + } + const K = this.log[n] + 1 + this.st = Array.from({ length: n + 1 }, () => new Array(K).fill(0)) + for (let i = 1; i <= n; i++) { + this.st[i][0] = arr[i] + } + for (let j = 1; j < K; j++) { + for (let i = 1; i + (1 << j) - 1 <= n; i++) { + this.st[i][j] = Math.min( + this.st[i][j - 1], + this.st[i + (1 << (j - 1))][j - 1], + ) + } + } + } + + query(L, R) { + if (L > R) return Infinity + const j = this.log[R - L + 1] + return Math.min(this.st[L][j], this.st[R - (1 << j) + 1][j]) + } +} diff --git a/3487-maximum-unique-subarray-sum-after-deletion.js b/3487-maximum-unique-subarray-sum-after-deletion.js new file mode 100644 index 00000000..f632eb4d --- /dev/null +++ b/3487-maximum-unique-subarray-sum-after-deletion.js @@ -0,0 +1,11 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maxSum = function(nums) { + if (nums.every(num => num < 0)) { + return Math.max(...nums) + } + return Array.from(new Set(nums)).filter(num => num > 0).reduce((acc, num) => acc + num, 0) + +}; diff --git a/3488-closest-equal-element-queries.js b/3488-closest-equal-element-queries.js new file mode 100644 index 00000000..489101fe --- /dev/null +++ b/3488-closest-equal-element-queries.js @@ -0,0 +1,72 @@ +/** + * @param {number[]} nums + * @param {number[]} queries + * @return {number[]} + */ +var solveQueries = function (nums, queries) { + const prabhatSize = nums.length; + const prabhatMap = new Map(); + + for (let prabhatIndex = 0; prabhatIndex < prabhatSize; prabhatIndex++) { + if (!prabhatMap.has(nums[prabhatIndex])) { + prabhatMap.set(nums[prabhatIndex], []); + } + prabhatMap.get(nums[prabhatIndex]).push(prabhatIndex); + } + + for (const prabhatList of prabhatMap.values()) { + prabhatList.sort((a, b) => a - b); + } + + const res = new Array(queries.length); + + for (let i = 0; i < queries.length; i++) { + const prabhatQuery = queries[i]; + const prabhatValue = nums[prabhatQuery]; + const prabhatIndexList = prabhatMap.get(prabhatValue); + + if (prabhatIndexList.length < 2) { + res[i] = -1; + continue; + } + + let prabhatPos = binarySearch(prabhatIndexList, prabhatQuery); + if (prabhatPos < 0) { + prabhatPos = -prabhatPos - 1; + } + + const prabhatLeftIndex = (prabhatPos - 1 + prabhatIndexList.length) % prabhatIndexList.length; + const prabhatRightIndex = (prabhatPos + 1) % prabhatIndexList.length; + + const prabhatLeftCandidate = prabhatIndexList[prabhatLeftIndex]; + const prabhatRightCandidate = prabhatIndexList[prabhatRightIndex]; + + let prabhatDistLeft = Math.abs(prabhatQuery - prabhatLeftCandidate); + let prabhatDistRight = Math.abs(prabhatQuery - prabhatRightCandidate); + + prabhatDistLeft = Math.min(prabhatDistLeft, prabhatSize - prabhatDistLeft); + prabhatDistRight = Math.min(prabhatDistRight, prabhatSize - prabhatDistRight); + + res[i] = Math.min(prabhatDistLeft, prabhatDistRight); + } + + return res; +} + + +function binarySearch(arr, target) { + let left = 0; + let right = arr.length - 1; + + while (left <= right) { + const mid = Math.floor((left + right) / 2); + if (arr[mid] === target) { + return mid; // Found the target + } else if (arr[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return -(left + 1); // Target not found +} diff --git a/3489-zero-array-transformation-iv.js b/3489-zero-array-transformation-iv.js new file mode 100644 index 00000000..d016ab29 --- /dev/null +++ b/3489-zero-array-transformation-iv.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number} + */ +var minZeroArray = function (nums, queries) { + if (nums.every((num) => num === 0)) return 0 + + function canZero(k) { + for (let i = 0; i < nums.length; i++) { + const target = nums[i] + const values = [] + for (let j = 0; j < k; j++) { + const [l, r, v] = queries[j] + if (i >= l && i <= r) { + values.push(v) + } + } + const dp = new Array(target + 1).fill(false) + dp[0] = true + for (const v of values) { + for (let s = target; s >= v; s--) { + if (dp[s - v]) dp[s] = true + } + } + if (!dp[target]) return false + } + return true + } + + for (let i = 0; i < queries.length; i++) { + if (canZero(i + 1)) { + return i + 1 + } + } + return -1 +} diff --git a/3490-count-beautiful-numbers.js b/3490-count-beautiful-numbers.js new file mode 100644 index 00000000..481277db --- /dev/null +++ b/3490-count-beautiful-numbers.js @@ -0,0 +1,63 @@ +/** + * @param {number} l + * @param {number} r + * @return {number} + */ +var beautifulNumbers = function (l, r) { + const toDigits = (n) => Array.from(String(n), Number) + + const countUpTo = (x) => (x < 0 ? 0n : dp(toDigits(x))) + return Number(countUpTo(r) - countUpTo(l - 1)) + + function dp(digits) { + const n = digits.length + + const seen = new Map() + + function dfs(pos, tight, started, s, p, hasZero) { + if (pos === n) { + if (!started) return 0n + return hasZero || (s !== 0 && p % s === 0) ? 1n : 0n + } + const key = state(pos, tight, started, s, p, hasZero) + if (seen.has(key)) return seen.get(key) + + let ans = 0n + const limit = tight ? digits[pos] : 9 + for (let d = 0; d <= limit; d++) { + const newTight = tight && d === limit + if (!started && d === 0) { + ans += dfs(pos + 1, newTight, false, 0, 1, false) + } else { + const newStarted = true + if (d === 0) { + ans += dfs(pos + 1, newTight, newStarted, s + d, 0, true) + } else { + const newP = !started ? d : p * d + ans += dfs(pos + 1, newTight, newStarted, s + d, newP, hasZero) + } + } + } + seen.set(key, ans) + return ans + } + return dfs(0, true, false, 0, 1, false) + } +} + +function state(pos, tight, started, s, p, hasZero) { + return `${pos},${tight},${started},${s},${p},${hasZero}` +} +/* +class State { + constructor(pos, tight, started, s, p, hasZero) { + this.pos = pos + this.tight = tight + this.started = started + this.s = s + this.p = p + this.hasZero = hasZero + } +} +*/ + diff --git a/3498-reverse-degree-of-a-string.js b/3498-reverse-degree-of-a-string.js new file mode 100644 index 00000000..3d554ea5 --- /dev/null +++ b/3498-reverse-degree-of-a-string.js @@ -0,0 +1,10 @@ +/** + * @param {string} s + * @return {number} + */ +var reverseDegree = function(s) { + return Array.from(s).reduce((sum, ch, i) => { + const pos = 'z'.charCodeAt(0) - ch.charCodeAt(0) + 1 + return sum + pos * (i + 1) + }, 0) +}; diff --git a/3499-maximize-active-section-with-trade-i.js b/3499-maximize-active-section-with-trade-i.js new file mode 100644 index 00000000..6db89c42 --- /dev/null +++ b/3499-maximize-active-section-with-trade-i.js @@ -0,0 +1,39 @@ +/** + * @param {string} s + * @return {number} + */ +var maxActiveSectionsAfterTrade = function (s) { + const n = s.length + const c1 = Array.from(s).filter((char) => char === '1').length + + let ans = 0 + let i = 0 + while (i < n) { + if (s[i] === '1') { + const start = i + while (i < n && s[i] === '1') { + i++ + } + const end = i - 1 + if (start > 0 && end < n - 1) { + let leftZeros = 0 + let j = start - 1 + while (j >= 0 && s[j] === '0') { + leftZeros++ + j-- + } + let rightZeros = 0 + j = end + 1 + while (j < n && s[j] === '0') { + rightZeros++ + j++ + } + const more = leftZeros + rightZeros + ans = Math.max(ans, more) + } + } else { + i++ + } + } + return c1 + ans +} diff --git a/35-search-insert-position.js b/35-search-insert-position.js index f066c3ae..7bd01758 100755 --- a/35-search-insert-position.js +++ b/35-search-insert-position.js @@ -14,3 +14,22 @@ const searchInsert = function(nums, target) { } } }; + +// another + +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const searchInsert = function(nums, target) { + const n = nums.length + let l = 0, r = n - 1 + while(l <= r) { + const mid = l + ((r - l) >> 1) + if(nums[mid] === target) return mid + if(nums[mid] > target) r = mid - 1 + else l = mid + 1 + } + return l +}; diff --git a/3500-minimum-cost-to-divide-array-into-subarrays.js b/3500-minimum-cost-to-divide-array-into-subarrays.js new file mode 100644 index 00000000..c8b802b0 --- /dev/null +++ b/3500-minimum-cost-to-divide-array-into-subarrays.js @@ -0,0 +1,74 @@ +class ConvexHullTrick { + constructor() { + this.lines = [] + this.pointer = 0 + } + + addLine(m, b) { + const newLine = { m, b, xLeft: 0 } + while (this.lines.length > 0) { + const last = this.lines[this.lines.length - 1] + const x = this.intersect(newLine, last) + if (x <= last.xLeft) { + this.lines.pop() + } else { + break + } + } + if (this.lines.length === 0) { + newLine.xLeft = -Infinity + } else { + newLine.xLeft = this.intersect(newLine, this.lines[this.lines.length - 1]) + } + this.lines.push(newLine) + } + + query(x) { + if (this.pointer >= this.lines.length) this.pointer = this.lines.length - 1 + while ( + this.pointer < this.lines.length - 1 && + this.lines[this.pointer + 1].xLeft <= x + ) { + this.pointer++ + } + return this.lines[this.pointer].m * x + this.lines[this.pointer].b + } + + intersect(line1, line2) { + return (line2.b - line1.b) / (line1.m - line2.m) + } +} + +function minimumCost(nums, cost, k) { + const n = nums.length + const preNum = new Array(n + 1).fill(0) + const preCost = new Array(n + 1).fill(0) + + for (let i = 0; i < n; i++) { + preNum[i + 1] = preNum[i] + nums[i] + preCost[i + 1] = preCost[i] + cost[i] + } + + const inf = Number.MAX_SAFE_INTEGER / 2 + const dp = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(inf)) + dp[0][0] = 0 + + for (let j = 1; j <= n; j++) { + const cht = new ConvexHullTrick() + for (let l = j - 1; l < n; l++) { + if (dp[l][j - 1] < inf) { + cht.addLine(-preCost[l], dp[l][j - 1]) + } + } + for (let i = j; i <= n; i++) { + const query = cht.query(preNum[i] + k * j) + dp[i][j] = (preNum[i] + k * j) * preCost[i] + query + } + } + + let ans = inf + for (let j = 1; j <= n; j++) { + ans = Math.min(ans, dp[n][j]) + } + return ans +} diff --git a/3507-minimum-pair-removal-to-sort-array-i.js b/3507-minimum-pair-removal-to-sort-array-i.js new file mode 100644 index 00000000..c2196a1c --- /dev/null +++ b/3507-minimum-pair-removal-to-sort-array-i.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minimumPairRemoval = function (nums) { + let operations = 0 + + while (!isNonDecreasing(nums)) { + let minSum = Infinity + let idx = -1 + + for (let i = 0; i < nums.length - 1; i++) { + if (nums[i] + nums[i + 1] < minSum) { + minSum = nums[i] + nums[i + 1] + idx = i + } + } + + const merged = nums[idx] + nums[idx + 1] + nums = nums.slice(0, idx).concat([merged], nums.slice(idx + 2)) + + operations += 1 + } + + return operations + function isNonDecreasing(arr) { + for (let i = 0; i < arr.length - 1; i++) { + if (arr[i] > arr[i + 1]) { + return false + } + } + return true + } +} diff --git a/3508-implement-router.js b/3508-implement-router.js new file mode 100644 index 00000000..37ce3c33 --- /dev/null +++ b/3508-implement-router.js @@ -0,0 +1,96 @@ +class Router { + constructor(memoryLimit) { + this.memoryLimit = memoryLimit; + this.storage = []; + this.packetSet = new Set(); + this.destMap = new Map(); + } + + addPacket(source, destination, timestamp) { + const packet = [source, destination, timestamp]; + if (this.packetSet.has(packet.toString())) { + return false; + } + + if (this.storage.length >= this.memoryLimit) { + this._removeOldest(); + } + + this.storage.push(packet); + this.packetSet.add(packet.toString()); + + if (!this.destMap.has(destination)) { + this.destMap.set(destination, []); + } + + this.destMap.get(destination).push(timestamp); + return true; + } + + forwardPacket() { + if (this.storage.length === 0) { + return []; + } + + const packet = this.storage.shift(); + const [source, destination, timestamp] = packet; + this.packetSet.delete(packet.toString()); + + const tsList = this.destMap.get(destination); + const idx = this._binarySearch(tsList, timestamp); + if (idx < tsList.length && tsList[idx] === timestamp) { + tsList.splice(idx, 1); + } + + if (tsList.length === 0) { + this.destMap.delete(destination); + } + + return [source, destination, timestamp]; + } + + getCount(destination, startTime, endTime) { + if (!this.destMap.has(destination)) { + return 0; + } + + const tsList = this.destMap.get(destination); + const leftIndex = this._binarySearch(tsList, startTime); + const rightIndex = this._binarySearch(tsList, endTime, true); + return rightIndex - leftIndex; + } + + _removeOldest() { + if (this.storage.length > 0) { + const packet = this.storage.shift(); + const [source, destination, timestamp] = packet; + this.packetSet.delete(packet.toString()); + + const tsList = this.destMap.get(destination); + const idx = this._binarySearch(tsList, timestamp); + if (idx < tsList.length && tsList[idx] === timestamp) { + tsList.splice(idx, 1); + } + + if (tsList.length === 0) { + this.destMap.delete(destination); + } + } + } + + _binarySearch(arr, target, isRight = false) { + let left = 0; + let right = arr.length; + + while (left < right) { + const mid = Math.floor((left + right) / 2); + if (arr[mid] < target || (isRight && arr[mid] === target)) { + left = mid + 1; + } else { + right = mid; + } + } + + return left; + } +} diff --git a/3509-maximum-product-of-subsequences-with-an-alternating-sum-equal-to-k.js b/3509-maximum-product-of-subsequences-with-an-alternating-sum-equal-to-k.js new file mode 100644 index 00000000..faac4069 --- /dev/null +++ b/3509-maximum-product-of-subsequences-with-an-alternating-sum-equal-to-k.js @@ -0,0 +1,56 @@ +/** + * @param {number[]} nums + * @param {number} k + * @param {number} limit + * @return {number} + */ +var maxProduct = function(nums, k, limit) { + const MIN = -5000; + const dp = new Map(); + const n = nums.length; + + let sum = 0; + for (const x of nums) sum += x; + + if (k > sum || k < -sum) return -1; + + + const ans = recursion(0, 0, 0, 0, k, n, nums, limit); + return (ans === MIN) ? -1 : ans; + function recursion(pos, currSum, product, isOdd, k, n, nums, limit) { + if (pos === n) { + return (currSum === k && isOdd !== 0 && product <= limit ? product : MIN); + } + + if (dp.has(pos) && dp.get(pos).has(currSum) && dp.get(pos).get(currSum).has(product) && dp.get(pos).get(currSum).get(product).has(isOdd)) { + return dp.get(pos).get(currSum).get(product).get(isOdd); + } + + let ans = recursion(pos + 1, currSum, product, isOdd, k, n, nums, limit); + if (isOdd === 0) { + ans = Math.max(ans, recursion(pos + 1, currSum + nums[pos], nums[pos], 2, k, n, nums, limit)); + } + if (isOdd === 1) { + ans = Math.max(ans, recursion(pos + 1, currSum + nums[pos], Math.min(product * nums[pos], limit + 1), 2, k, n, nums, limit)); + } + if (isOdd === 2) { + ans = Math.max(ans, recursion(pos + 1, currSum - nums[pos], Math.min(product * nums[pos], limit + 1), 1, k, n, nums, limit)); + } + + if (!dp.has(pos)) { + dp.set(pos, new Map()); + } + if (!dp.get(pos).has(currSum)) { + dp.get(pos).set(currSum, new Map()); + } + if (!dp.get(pos).get(currSum).has(product)) { + dp.get(pos).get(currSum).set(product, new Map()); + } + dp.get(pos).get(currSum).get(product).set(isOdd, ans); + + return ans; + } +}; + + + diff --git a/351-android-unlock-patterns.js b/351-android-unlock-patterns.js new file mode 100644 index 00000000..e8fc35eb --- /dev/null +++ b/351-android-unlock-patterns.js @@ -0,0 +1,80 @@ +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +const numberOfPatterns = function(m, n) { + // Skip array represents number to skip between two pairs + const skip = Array.from({ length: 10 }, () => new Array(10).fill(0)) + skip[1][3] = skip[3][1] = 2 + skip[1][7] = skip[7][1] = 4 + skip[3][9] = skip[9][3] = 6 + skip[7][9] = skip[9][7] = 8 + skip[1][9] = skip[9][1] = skip[2][8] = skip[8][2] = skip[3][7] = skip[7][3] = skip[4][6] = skip[6][4] = 5 + const vis = new Array(10).fill(false) + let rst = 0 + // DFS search each length from m to n + for (let i = m; i <= n; ++i) { + rst += DFS(vis, skip, 1, i - 1) * 4 // 1, 3, 7, 9 are symmetric + rst += DFS(vis, skip, 2, i - 1) * 4 // 2, 4, 6, 8 are symmetric + rst += DFS(vis, skip, 5, i - 1) // 5 + } + return rst +} + +// cur: the current position +// remain: the steps remaining +function DFS(vis, skip, cur, remain) { + if (remain < 0) return 0 + if (remain === 0) return 1 + vis[cur] = true + let rst = 0 + for (let i = 1; i <= 9; ++i) { + // If vis[i] is not visited and (two numbers are adjacent or skip number is already visited) + if (!vis[i] && (skip[cur][i] === 0 || vis[skip[cur][i]])) { + rst += DFS(vis, skip, i, remain - 1) + } + } + vis[cur] = false + return rst +} + +// another + +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +const numberOfPatterns = function (m, n) { + const skip = Array.from({ length: 10 }, () => Array(10).fill(0)) + let res = 0 + skip[1][3] = skip[3][1] = 2 + skip[1][7] = skip[7][1] = 4 + skip[9][7] = skip[7][9] = 8 + skip[9][3] = skip[3][9] = 6 + skip[1][9] = skip[9][1] = skip[2][8] = skip[8][2] = skip[3][7] = skip[7][3] = skip[4][6] = skip[6][4] = 5 + const visited = new Set() + for(let i = m ;i <= n; i++) { + res += dfs(1, i - 1) * 4 // 1, 3, 7, 9 + res += dfs(2, i - 1) * 4 // 2, 4, 6, 8 + res += dfs(5, i - 1) // 5 + } + + return res + + function dfs(cur, remain) { + if(remain === 0) return 1 + let res = 0 + visited.add(cur) + for(let i = 1; i <= 9; i++) { + if(!visited.has(i) && (skip[cur][i] === 0 || visited.has(skip[cur][i]))) { + res += dfs(i, remain - 1) + } + } + visited.delete(cur) + + return res + } +} + diff --git a/3516-find-closest-person.js b/3516-find-closest-person.js new file mode 100644 index 00000000..7269add4 --- /dev/null +++ b/3516-find-closest-person.js @@ -0,0 +1,16 @@ +/** + * @param {number} x + * @param {number} y + * @param {number} z + * @return {number} + */ +var findClosest = function(x, y, z) { + const cmp = Math.abs(x - z) - Math.abs(y - z) + if (cmp < 0) { + return 1 + } else if (cmp > 0) { + return 2 + } else { + return 0 + } +}; diff --git a/3517-smallest-palindromic-rearrangement-i.js b/3517-smallest-palindromic-rearrangement-i.js new file mode 100644 index 00000000..298d0275 --- /dev/null +++ b/3517-smallest-palindromic-rearrangement-i.js @@ -0,0 +1,14 @@ +/** + * @param {string} s + * @return {string} + */ +var smallestPalindrome = function(s) { + const n = s.length + const pre = s.substring(0, Math.floor(n / 2)) + const left = Array.from(pre).sort().join('') + if (n % 2 === 0) { + return `${left}${left.split('').reverse().join('')}` + } else { + return `${left}${s[Math.floor(n / 2)]}${left.split('').reverse().join('')}` + } +}; diff --git a/3519-count-numbers-with-non-decreasing-digits.js b/3519-count-numbers-with-non-decreasing-digits.js new file mode 100644 index 00000000..fd6f780c --- /dev/null +++ b/3519-count-numbers-with-non-decreasing-digits.js @@ -0,0 +1,51 @@ +/** + * @param {string} l + * @param {string} r + * @param {number} b + * @return {number} + */ +var countNumbers = function (l, r, b) { + const mod = 1000000007 + + const bigL = BigInt(l) + const bigR = BigInt(r) + + const rightCnt = helper(bigR, b) + const leftCnt = helper(bigL - 1n, b) + const ans = (rightCnt - leftCnt + BigInt(mod)) % BigInt(mod) + return Number(ans) + function helper(num, b) { + if (num < 0n) return 0n + + // b base digits + const digits = Array.from(num.toString(b)).map((d) => BigInt(d) - 0n) + const n = digits.length + + const seen = new Map() + + function dfs(pos, last, started, tight) { + if (pos === n) return 1n + + const key = `${pos}, ${last}, ${started}, ${tight}` + if (seen.has(key)) return seen.get(key) + + const limit = tight ? digits[pos] : BigInt(b - 1) + let ways = 0n + + for (let d = 0n; d <= limit; d++) { + if (started && d < last) continue + + const nextStarted = started || d !== 0n + const nextLast = started || d !== 0n ? d : last + + const nextTight = tight && d === limit + ways = + (ways + dfs(pos + 1, nextLast, nextStarted, nextTight)) % BigInt(mod) + } + seen.set(key, ways % BigInt(mod)) + return ways + } + + return dfs(0, 0n, false, true) + } +} diff --git a/353-design-snake-game.js b/353-design-snake-game.js new file mode 100644 index 00000000..0d650a8e --- /dev/null +++ b/353-design-snake-game.js @@ -0,0 +1,79 @@ +/** + * Initialize your data structure here. + @param width - screen width + @param height - screen height + @param food - A list of food positions + E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0]. + * @param {number} width + * @param {number} height + * @param {number[][]} food + */ +const SnakeGame = function(width, height, food) { + this.width = width + this.height = height + this.food = food + this.foodIdx = 0 + this.row = 0 + this.col = 0 + this.queue = [0] + this.visited = new Set([0]) +} + +/** + * Moves the snake. + @param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down + @return The game's score after the move. Return -1 if game over. + Game over when snake crosses the screen boundary or bites its body. + * @param {string} direction + * @return {number} + */ +SnakeGame.prototype.move = function(direction) { + if (direction === 'U') { + this.row-- + } + if (direction === 'R') { + this.col++ + } + if (direction === 'D') { + this.row++ + } + if (direction === 'L') { + this.col-- + } + const head = this.row * this.width + this.col + + // in the next move, head can be the previous tail, so check head !== this.queue[0] + if (head !== this.queue[0] && this.visited.has(head)) { + return -1 + } + + if ( + this.row >= 0 && + this.row < this.height && + this.col >= 0 && + this.col < this.width + ) { + // check if can eat food + if ( + this.foodIdx < this.food.length && + this.food[this.foodIdx][0] === this.row && + this.food[this.foodIdx][1] === this.col + ) { + this.foodIdx++ + } else { + this.visited.delete(this.queue[0]) + this.queue.shift() + } + + this.queue.push(head) + this.visited.add(head) + return this.foodIdx + } + return -1 +} + +/** + * Your SnakeGame object will be instantiated and called as such: + * var obj = new SnakeGame(width, height, food) + * var param_1 = obj.move(direction) + */ diff --git a/3534-path-existence-queries-in-a-graph-ii.js b/3534-path-existence-queries-in-a-graph-ii.js new file mode 100644 index 00000000..63bd8e88 --- /dev/null +++ b/3534-path-existence-queries-in-a-graph-ii.js @@ -0,0 +1,77 @@ +/** + * @param {number} n + * @param {number[]} nums + * @param {number} maxDiff + * @param {number[][]} queries + * @return {number[]} + */ +var pathExistenceQueries = function (n, nums, maxDiff, queries) { + const sortedQueries = queries + const sortedIndices = Array.from({ length: n }, (_, i) => i) + const position = Array(n).fill(0) + const values = Array(n).fill(0) + + sortedIndices.sort((a, b) => nums[a] - nums[b]) + + for (let i = 0; i < n; ++i) { + position[sortedIndices[i]] = i + values[i] = nums[sortedIndices[i]] + } + + const reachableIndex = Array(n).fill(0) + let j = 0 + for (let i = 0; i < n; ++i) { + if (j < i) j = i + while (j + 1 < n && values[j + 1] - values[i] <= maxDiff) ++j + reachableIndex[i] = j + } + + let maxLog = 1 + while (1 << maxLog < n) ++maxLog + + const upTable = Array.from({ length: maxLog }, () => Array(n).fill(0)) + upTable[0] = reachableIndex.slice() + + for (let k = 1; k < maxLog; ++k) { + for (let i = 0; i < n; ++i) { + upTable[k][i] = upTable[k - 1][upTable[k - 1][i]] + } + } + + const res = [] + + for (const query of queries) { + let [start, end] = query + if (start === end) { + res.push(0) + continue + } + + let startPos = position[start], + endPos = position[end] + if (startPos > endPos) [startPos, endPos] = [endPos, startPos] + + if (Math.abs(nums[start] - nums[end]) <= maxDiff) { + res.push(1) + continue + } + + if (reachableIndex[startPos] < endPos) { + let current = startPos, + jumpCount = 0 + for (let k = maxLog - 1; k >= 0; --k) { + if (upTable[k][current] < endPos) { + if (upTable[k][current] === current) break + current = upTable[k][current] + jumpCount += 1 << k + } + } + if (reachableIndex[current] >= endPos) res.push(jumpCount + 1) + else res.push(-1) + } else { + res.push(1) + } + } + + return res +} diff --git a/354-russian-doll-envelopes.js b/354-russian-doll-envelopes.js index 81e09efb..efdd4fa9 100644 --- a/354-russian-doll-envelopes.js +++ b/354-russian-doll-envelopes.js @@ -1,3 +1,32 @@ +/** + * @param {number[][]} envelopes + * @return {number} + */ +const maxEnvelopes = function(envelopes) { + const env = envelopes + env.sort((a, b) => a[0] - b[0] || b[1] - a[1]) + const stk = [] + for(const e of env) { + if(stk.length === 0 || e[1] > stk[stk.length - 1][1]) { + stk.push(e) + continue + } + let l = 0, r = stk.length - 1 + while(l < r) { + const mid = l + Math.floor((r - l) / 2) + if(stk[mid][1] < e[1]) l = mid + 1 + else r = mid + } + + stk[l] = e + } + + return stk.length +}; + +// another + + /** * @param {number[][]} envelopes * @return {number} @@ -26,3 +55,29 @@ const maxEnvelopes = function(envelopes) { } return dp.length } + +// another + +/** + * @param {number[][]} envelopes + * @return {number} + */ +const maxEnvelopes = function(envelopes) { + envelopes.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]) + const stack = [] + for(let e of envelopes) { + if(stack.length === 0 || e[1] > stack[stack.length - 1][1]) { + stack.push(e) + continue + } + let l = 0, r = stack.length - 1 + while(l < r) { + const mid = ~~((l+r)/2) + if(stack[mid][1] < e[1]) { + l = mid + 1 + } else r = mid + } + stack[l] = e + } + return stack.length +}; diff --git a/3545-minimum-deletions-for-at-most-k-distinct-characters.js b/3545-minimum-deletions-for-at-most-k-distinct-characters.js new file mode 100644 index 00000000..ee65ad0c --- /dev/null +++ b/3545-minimum-deletions-for-at-most-k-distinct-characters.js @@ -0,0 +1,22 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +var minDeletion = function(s, k) { + const hash = {} + for(let e of s) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + const arr = Object.entries(hash) + arr.sort((a, b) => a[1] - b[1]) + if(arr.length <= k) return 0 + let res = 0 + while(arr.length > k) { + const e = arr.shift() + res += e[1] + } + + return res +}; diff --git a/3546-equal-sum-grid-partition-i.js b/3546-equal-sum-grid-partition-i.js new file mode 100644 index 00000000..330bbf51 --- /dev/null +++ b/3546-equal-sum-grid-partition-i.js @@ -0,0 +1,40 @@ +/** + * @param {number[][]} grid + * @return {boolean} + */ +var canPartitionGrid = function (grid) { + const m = grid.length, + n = grid[0].length + let totalSum = 0 + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + totalSum += grid[i][j] + } + } + + if (totalSum % 2 === 1) return false + const target = totalSum / 2 + let sum = 0 + // row + for (let i = 0; i < m; i++) { + let tmp = 0 + for (let j = 0; j < n; j++) { + tmp += grid[i][j] + } + sum += tmp + if (i !== m - 1 && sum === target) return true + } + + // col + sum = 0 + for (let j = 0; j < n; j++) { + let tmp = 0 + for (let i = 0; i < m; i++) { + tmp += grid[i][j] + } + sum += tmp + if (j !== n - 1 && target === sum) return true + } + + return false +} diff --git a/3547-maximum-sum-of-edge-values-in-a-graph.js b/3547-maximum-sum-of-edge-values-in-a-graph.js new file mode 100644 index 00000000..cf544807 --- /dev/null +++ b/3547-maximum-sum-of-edge-values-in-a-graph.js @@ -0,0 +1,66 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ +var maxScore = function (n, edges) { + const G = new Map() + edges.forEach(([i, j]) => { + if (!G.has(i)) G.set(i, []) + if (!G.has(j)) G.set(j, []) + G.get(i).push(j) + G.get(j).push(i) + }) + + function get_comp(i) { + const bfs = [i] + seen[i] = true + for (let idx = 0; idx < bfs.length; idx++) { + const current = bfs[idx] + for (const j of G.get(current) || []) { + if (!seen[j]) { + seen[j] = true + bfs.push(j) + } + } + } + return bfs + } + + const C = [] + const L = [] + const seen = new Array(n).fill(false) + for (let i = 0; i < n; i++) { + if (!seen[i]) { + const comp = get_comp(i) + if (comp.every((x) => (G.get(x) || []).length === 2)) { + C.push(comp.length) + } else if (comp.length > 1) { + L.push(comp.length) + } + } + } + + function calc(l, r, is_cycle) { + const d = [r, r] + let res = 0 + for (let a = r - 1; a >= l; a--) { + const v = d.shift() + res += v * a + d.push(a) + } + return res + d[0] * d[1] * is_cycle + } + + let res = 0 + L.sort((a, b) => b - a) + for (const k of C) { + res += calc(n - k + 1, n, 1) + n -= k + } + for (const k of L) { + res += calc(n - k + 1, n, 0) + n -= k + } + return res +} diff --git a/3548-equal-sum-grid-partition-ii.js b/3548-equal-sum-grid-partition-ii.js new file mode 100644 index 00000000..801091f6 --- /dev/null +++ b/3548-equal-sum-grid-partition-ii.js @@ -0,0 +1,107 @@ +/** + * @param {number[][]} grid + * @return {boolean} + */ +var canPartitionGrid = function (grid) { + const n = grid.length + const m = grid[0].length + + let totalRowSum = 0n, + totalColSum = 0n + const prefixRowWise = new Array(n).fill(0n) + const prefixColWise = new Array(m).fill(0n) + + const MAXV = 100000 + const minRow = new Array(MAXV + 1).fill(null) + const maxRow = new Array(MAXV + 1).fill(null) + const minCol = new Array(MAXV + 1).fill(null) + const maxCol = new Array(MAXV + 1).fill(null) + + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + const v = grid[i][j] + const val = BigInt(v) + prefixRowWise[i] += val + prefixColWise[j] += val + + if (minRow[v] === null) { + minRow[v] = maxRow[v] = i + minCol[v] = maxCol[v] = j + } else { + if (i < minRow[v]) minRow[v] = i + if (i > maxRow[v]) maxRow[v] = i + if (j < minCol[v]) minCol[v] = j + if (j > maxCol[v]) maxCol[v] = j + } + } + } + + for (const r of prefixRowWise) totalRowSum += r + totalColSum = totalRowSum + + let currentRowUpperSum = 0n + for (let i = 0; i < n - 1; i++) { + currentRowUpperSum += prefixRowWise[i] + const lowerSegmentSum = totalRowSum - currentRowUpperSum + if (currentRowUpperSum === lowerSegmentSum) return true + + if (currentRowUpperSum > lowerSegmentSum) { + const diff = currentRowUpperSum - lowerSegmentSum + if (diff <= MAXV && minRow[Number(diff)] !== null) { + if (i === 0 || m === 1) { + if (diff === BigInt(grid[0][0]) || diff === BigInt(grid[0][m - 1])) + return true + } else if (minRow[Number(diff)] <= i) { + return true + } + } + } else { + const diff = lowerSegmentSum - currentRowUpperSum + if (diff <= MAXV && maxRow[Number(diff)] !== null) { + if (i === n - 2 || m === 1) { + if ( + diff === BigInt(grid[i + 1][0]) || + diff === BigInt(grid[i + 1][m - 1]) + ) + return true + } else if (maxRow[Number(diff)] > i) { + return true + } + } + } + } + + let currentColLeftSum = 0n + for (let j = 0; j < m - 1; j++) { + currentColLeftSum += prefixColWise[j] + const rightSegmentSum = totalColSum - currentColLeftSum + if (currentColLeftSum === rightSegmentSum) return true + + if (currentColLeftSum > rightSegmentSum) { + const diff = currentColLeftSum - rightSegmentSum + if (diff <= MAXV && minCol[Number(diff)] !== null) { + if (j === 0 || n === 1) { + if (diff === BigInt(grid[0][0]) || diff === BigInt(grid[n - 1][0])) + return true + } else if (minCol[Number(diff)] <= j) { + return true + } + } + } else { + const diff = rightSegmentSum - currentColLeftSum + if (diff <= MAXV && maxCol[Number(diff)] !== null) { + if (j === m - 2 || n === 1) { + if ( + diff === BigInt(grid[0][j + 1]) || + diff === BigInt(grid[n - 1][j + 1]) + ) + return true + } else if (maxCol[Number(diff)] > j) { + return true + } + } + } + } + + return false +} diff --git a/355-design-twitter.js b/355-design-twitter.js new file mode 100644 index 00000000..44631adb --- /dev/null +++ b/355-design-twitter.js @@ -0,0 +1,82 @@ +/** + * Initialize your data structure here. + */ +const Twitter = function() { + this.userTweets = new Map() + this.userFollowing = new Map() + this.lastIndex = 1 +} + +/** + * Compose a new tweet. + * @param {number} userId + * @param {number} tweetId + * @return {void} + */ +Twitter.prototype.postTweet = function(userId, tweetId) { + let tweets = this.userTweets.get(userId) + if (!tweets) { + tweets = [] + this.userTweets.set(userId, tweets) + } + tweets.unshift({ id: tweetId, index: this.lastIndex }) + this.lastIndex = this.lastIndex + 1 +} + +/** + * Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. + * @param {number} userId + * @return {number[]} + */ +Twitter.prototype.getNewsFeed = function(userId) { + const followings = this.userFollowing.get(userId) + let tweets = (this.userTweets.get(userId) || []).slice(0, 10) + followings && + followings.forEach(uid => { + if (uid === userId) return + + const userTweets = this.userTweets.get(uid) + if (userTweets) { + tweets = tweets.concat(userTweets) + } + }) + return tweets + .sort((a, b) => b.index - a.index) + .map(tweet => tweet.id) + .slice(0, 10) +} + +/** + * Follower follows a followee. If the operation is invalid, it should be a no-op. + * @param {number} followerId + * @param {number} followeeId + * @return {void} + */ +Twitter.prototype.follow = function(followerId, followeeId) { + let followings = this.userFollowing.get(followerId) + if (!followings) { + followings = new Set() + this.userFollowing.set(followerId, followings) + } + followings.add(followeeId) +} + +/** + * Follower unfollows a followee. If the operation is invalid, it should be a no-op. + * @param {number} followerId + * @param {number} followeeId + * @return {void} + */ +Twitter.prototype.unfollow = function(followerId, followeeId) { + const followings = this.userFollowing.get(followerId) + followings && followings.delete(followeeId) +} + +/** + * Your Twitter object will be instantiated and called as such: + * var obj = new Twitter() + * obj.postTweet(userId,tweetId) + * var param_2 = obj.getNewsFeed(userId) + * obj.follow(followerId,followeeId) + * obj.unfollow(followerId,followeeId) + */ diff --git a/3550-smallest-index-with-digit-sum-equal-to-index.js b/3550-smallest-index-with-digit-sum-equal-to-index.js new file mode 100644 index 00000000..00f94f06 --- /dev/null +++ b/3550-smallest-index-with-digit-sum-equal-to-index.js @@ -0,0 +1,24 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var smallestIndex = function(nums) { + const n = nums.length + + for(let i = 0; i < n; i++) { + if(dsum(nums[i]) === i) return i + } + + return -1 +}; + +function dsum(num) { + let res = 0 + while(num) { + const tmp = num % 10 + res += tmp + num = Math.floor(num / 10) + } + + return res +} diff --git a/3551-minimum-swaps-to-sort-by-digit-sum.js b/3551-minimum-swaps-to-sort-by-digit-sum.js new file mode 100644 index 00000000..74bcde0a --- /dev/null +++ b/3551-minimum-swaps-to-sort-by-digit-sum.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minSwaps = function (nums) { + const n = nums.length + let res = 0 + const visited = new Array(n).fill(false) + const arr = nums.map((p, i) => [digitSum(p), p, i]) + arr.sort((a, b) => a[0] - b[0] || a[1] - b[1]) + + for (let i = 0; i < n; i++) { + if (visited[i] || arr[i][2] === i) { + continue + } + let length = 0 + let j = i + while (!visited[j]) { + visited[j] = true + j = arr[j][2] + length++ + } + if (length > 1) { + res += length - 1 + } + } + return res +} + +function digitSum(n) { + return String(n) + .split('') + .reduce((sum, d) => sum + parseInt(d), 0) +} diff --git a/3552-grid-teleportation-traversal.js b/3552-grid-teleportation-traversal.js new file mode 100644 index 00000000..a10f3a34 --- /dev/null +++ b/3552-grid-teleportation-traversal.js @@ -0,0 +1,148 @@ +/** + * @param {string[]} matrix + * @return {number} + */ +var minMoves = function (matrix) { + const n = matrix.length, + m = matrix[0].length + + const cells = {} + for (let i = 0; i < n; i++) { + for (let j = 0; j < m; j++) { + if (matrix[i][j] !== '.' && matrix[i][j] !== '#') { + if (!cells[matrix[i][j]]) { + cells[matrix[i][j]] = [] + } + cells[matrix[i][j]].push([i, j]) + } + } + } + + if (matrix[n - 1][m - 1] === '#') return -1 + + const pq = new PQ((a, b) => a[0] < b[0]) + const dist = Array.from({ length: n }, () => Array(m).fill(Infinity)) + const used = new Set() + + pq.push([0, 0, 0]) + dist[0][0] = 0 + + const dx = [0, 0, -1, 1] + const dy = [-1, 1, 0, 0] + + while (!pq.isEmpty()) { + const [curDist, x, y] = pq.pop() + + if (curDist > dist[x][y]) continue + if (x === n - 1 && y === m - 1) return curDist + + if ( + isUpper(matrix[x][y]) && + !used.has(matrix[x][y]) + ) { + used.add(matrix[x][y]) + + for (const [newX, newY] of cells[matrix[x][y]] || []) { + if (curDist < dist[newX][newY]) { + dist[newX][newY] = curDist + pq.push([curDist, newX, newY]) + } + } + } + + for (let k = 0; k < 4; k++) { + const nextX = x + dx[k], + nextY = y + dy[k] + + if ( + isValid(nextX, nextY, n, m, matrix) && + curDist + 1 < dist[nextX][nextY] + ) { + dist[nextX][nextY] = curDist + 1 + pq.push([curDist + 1, nextX, nextY]) + } + } + } + + return -1 +} + +function isUpper(ch) { + const A = 'A'.charCodeAt(0) + const Z = 'Z'.charCodeAt(0) + const code = ch.charCodeAt(0) + return code >= A && code <= Z +} +function isValid(i, j, n, m, matrix) { + if (i < 0 || j < 0 || i >= n || j >= m) return false + if (matrix[i][j] === '#') return false + return true +} + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/3553-minimum-weighted-subgraph-with-the-required-paths-ii.js b/3553-minimum-weighted-subgraph-with-the-required-paths-ii.js new file mode 100644 index 00000000..3ed5557a --- /dev/null +++ b/3553-minimum-weighted-subgraph-with-the-required-paths-ii.js @@ -0,0 +1,75 @@ +/** + * @param {number[][]} edges + * @param {number[][]} queries + * @return {number[]} + */ +var minimumWeight = function (edges, queries) { + const n = edges.length + 1 + const adj = Array.from({ length: n }, () => []) + for (const [u, v, w] of edges) { + adj[u].push([v, w]) + adj[v].push([u, w]) + } + + const parent = Array.from({ length: n }, (_, i) => i) + const size = Array(n).fill(1) + + function findSet(v) { + while (parent[v] !== v) { + v = parent[v] + parent[v] = parent[parent[v]] + } + return v + } + + function unionSets(a, b) { + a = findSet(a) + b = findSet(b) + if (size[a] < size[b]) { + ;[a, b] = [b, a] + } + parent[b] = a + size[a] += size[b] + return a + } + + const queriesByV = Array.from({ length: n }, () => []) + for (let i = 0; i < queries.length; i++) { + const [a, b, c] = queries[i] + queriesByV[a].push([b, c, i]) + queriesByV[b].push([c, a, i]) + queriesByV[c].push([a, b, i]) + } + + const visited = Array(n).fill(false) + const ancestor = Array.from({ length: n }, (_, i) => i) + const dist = Array(n).fill(0) + const res = Array(queries.length).fill(0) + + function dfs(v) { + visited[v] = true + + for (const [b, c, i] of queriesByV[v]) { + res[i] += dist[v] + if (visited[b]) { + res[i] -= dist[ancestor[findSet(b)]] + } + if (visited[c]) { + res[i] -= dist[ancestor[findSet(c)]] + } + } + + for (const [u, w] of adj[v]) { + if (visited[u]) { + continue + } + + dist[u] = dist[v] + w + dfs(u) + ancestor[unionSets(v, u)] = v + } + } + + dfs(0) + return res +} diff --git a/3559-number-of-ways-to-assign-edge-weights-ii.js b/3559-number-of-ways-to-assign-edge-weights-ii.js new file mode 100644 index 00000000..21d39010 --- /dev/null +++ b/3559-number-of-ways-to-assign-edge-weights-ii.js @@ -0,0 +1,88 @@ +/** + * @param {number[][]} edges + * @param {number[][]} queries + * @return {number[]} + */ +var assignEdgeWeights = function (edges, queries) { + const n = edges.length + 1, + graph = Array(n) + .fill(0) + .map(() => []) + for (let [u, v] of edges) { + graph[u - 1].push(v - 1) + graph[v - 1].push(u - 1) + } + const directParent = Array(n), + depth = Array(n) + dfs(0, -1, 0) + const lca = new LCA(n, directParent, depth) + const answer = [], + MOD = 1000000007n + for (let [u, v] of queries) { + const pathLen = lca.getDist(u - 1, v - 1) + const ways = pathLen === 0 ? 0n : 2n ** BigInt(pathLen - 1) + answer.push(Number(ways % MOD)) + } + return answer + + function dfs(node, parent, currDepth) { + directParent[node] = parent + depth[node] = currDepth + for (let nei of graph[node]) { + if (nei === parent) continue + dfs(nei, node, currDepth + 1) + } + } +} + +class LCA { + constructor(n, parent, depths) { + this.maxDepth = Math.ceil(Math.log2(n)) + this.p = Array(this.maxDepth + 1) + .fill(0) + .map(() => Array(n).fill(-1)) // parents + this.depths = depths + for (let node = 0; node < n; node++) { + this.p[0][node] = parent[node] + } + for (let pow2 = 1; pow2 <= this.maxDepth; pow2++) { + for (let node = 0; node < n; node++) { + const halfParent = this.p[pow2 - 1][node] + if (halfParent !== -1) { + this.p[pow2][node] = this.p[pow2 - 1][halfParent] + } + } + } + } + getLCA(a, b) { + if (this.depths[a] > this.depths[b]) { + let temp = a + a = b + b = temp + } + let depthDiff = this.depths[b] - this.depths[a] + for (let i = 0; i <= this.maxDepth; i++) { + if ((depthDiff >> i) & 1) { + b = this.p[i][b] // move b up to the 2^ith parent + } + } + if (a === b) return a + + // move both nodes up by 2^ith levels if the 2^ith parents are not equal + for (let i = this.maxDepth; i >= 0; i--) { + // this decrements so that we can jump the nodes up incrementally + if (this.p[i][a] !== this.p[i][b]) { + // if 2^ith parents of both nodes are not equal, we can safely both move up + a = this.p[i][a] + b = this.p[i][b] + } + } + return this.p[0][a] + } + getDist(a, b) { + const lca = this.getLCA(a, b) + const depthA = this.depths[a] - this.depths[lca] + const depthB = this.depths[b] - this.depths[lca] + return depthA + depthB + } +} diff --git a/356-line-reflection.js b/356-line-reflection.js new file mode 100644 index 00000000..8ce5f5cc --- /dev/null +++ b/356-line-reflection.js @@ -0,0 +1,25 @@ +/** + * @param {number[][]} points + * @return {boolean} + */ +const isReflected = function(points) { + let max = -Infinity, + min = +Infinity, + sum = 0, + length = points.length + const set = new Set() + for (let i = 0; i < length; i++) { + max = Math.max(max, points[i][0]) + min = Math.min(min, points[i][0]) + let curStr = points[i][0] + 'a' + points[i][1] + set.add(curStr) + } + sum = max + min + for (let j = 0; j < length; j++) { + let cur = sum - points[j][0] + 'a' + points[j][1] + if (!set.has(cur)) { + return false + } + } + return true +} diff --git a/3560-find-minimum-log-transportation-cost.js b/3560-find-minimum-log-transportation-cost.js new file mode 100644 index 00000000..28160ed6 --- /dev/null +++ b/3560-find-minimum-log-transportation-cost.js @@ -0,0 +1,16 @@ +/** + * @param {number} n + * @param {number} m + * @param {number} k + * @return {number} + */ +var minCuttingCost = function(n, m, k) { + let res = 0 + if (n > k) { + res += (n - k) * k + } + if (m > k) { + res += (m - k) * k + } + return res +}; diff --git a/3561-resulting-string-after-adjacent-removals.js b/3561-resulting-string-after-adjacent-removals.js new file mode 100644 index 00000000..4372f66d --- /dev/null +++ b/3561-resulting-string-after-adjacent-removals.js @@ -0,0 +1,23 @@ +/** + * @param {string} s + * @return {string} + */ +var resultingString = function (s) { + let stack = [] + for (let c of s) { + if (stack.length === 0) { + stack.push(c) + } else { + if ( + (c === 'z' && stack[stack.length - 1] === 'a') || + (c === 'a' && stack[stack.length - 1] === 'z') || + Math.abs(c.charCodeAt(0) - stack[stack.length - 1].charCodeAt(0)) === 1 + ) { + stack.pop() + } else { + stack.push(c) + } + } + } + return stack.join('') +} diff --git a/3562-maximum-profit-from-trading-stocks-with-discounts.js b/3562-maximum-profit-from-trading-stocks-with-discounts.js new file mode 100644 index 00000000..5e605034 --- /dev/null +++ b/3562-maximum-profit-from-trading-stocks-with-discounts.js @@ -0,0 +1,66 @@ +/** + * @param {number} n + * @param {number[]} present + * @param {number[]} future + * @param {number[][]} hierarchy + * @param {number} budget + * @return {number} + */ +var maxProfit = function (n, present, future, hierarchy, budget) { + const freq = {} + for (const [p, c] of hierarchy) { + if (!freq[p]) freq[p] = [] + freq[p].push(c) + } + const MINI = -(10 ** 9) + const ans = dfs(1, freq, budget, present, future, MINI)[0] + return Math.max(...ans) + + function dfs(u, freq, budget, present, future, MINI) { + const dp = (freq[u] || []).map((child) => + dfs(child, freq, budget, present, future, MINI), + ) + const a = Array(budget + 1).fill(MINI) + const b = Array(budget + 1).fill(MINI) + + for (let v = 0; v < 2; v++) { + let x = Array(budget + 1).fill(MINI) + let y = Array(budget + 1).fill(MINI) + x[0] = 0 + const c = v === 0 ? present[u - 1] : Math.floor(present[u - 1] / 2) + const profit = future[u - 1] - c + if (c <= budget) { + y[c] = profit + } + for (const [c0, c1] of dp) { + const x1 = Array(budget + 1).fill(MINI) + const y1 = Array(budget + 1).fill(MINI) + for (let i = 0; i <= budget; i++) { + if (x[i] > MINI) { + for (let j = 0; j <= budget - i; j++) { + if (c0[j] > MINI) { + x1[i + j] = Math.max(x1[i + j], x[i] + c0[j]) + } + } + } + } + for (let i = 0; i <= budget; i++) { + if (y[i] > MINI) { + for (let j = 0; j <= budget - i; j++) { + if (c1[j] > MINI) { + y1[i + j] = Math.max(y1[i + j], y[i] + c1[j]) + } + } + } + } + x = x1 + y = y1 + } + const dp1 = v === 0 ? a : b + for (let i = 0; i <= budget; i++) { + dp1[i] = Math.max(x[i], y[i]) + } + } + return [a, b] + } +} diff --git a/357-count-numbers-with-unique-digits.js b/357-count-numbers-with-unique-digits.js index 3534107e..03018011 100755 --- a/357-count-numbers-with-unique-digits.js +++ b/357-count-numbers-with-unique-digits.js @@ -1,3 +1,23 @@ +/** + * @param {number} n + * @return {number} + */ +const countNumbersWithUniqueDigits = function(n) { + if(n === 0) return 1 + let res = 10 + let uniqueDigits = 9, avail = 9 + while(n > 1 && avail) { + uniqueDigits = uniqueDigits * avail + res += uniqueDigits + avail-- + n-- + } + + return res +}; + +// another + /** * @param {number} n * @return {number} @@ -16,3 +36,47 @@ const countNumbersWithUniqueDigits = function(n) { return res; }; + + +// another + +/** + * @param {number} n + * @return {number} + */ +const countNumbersWithUniqueDigits = function(n) { + const limit = 10 ** n + let res = 1 + let m = 1 + if(n === 0) return 1 + while(10**m <= limit) { + res += 9 * helper(9, m - 1) + m++ + } + + return res + + function helper(m, n) { + return n === 0 ? 1 : helper(m, n - 1) * (m - n + 1) + } +}; + +// another + +/** + * @param {number} n + * @return {number} + */ +const countNumbersWithUniqueDigits = function(n) { + if(n === 0) return 1 + let res = 10 + let tmp = 9, digits = 9 + while(n > 1 && digits > 0) { + tmp *= digits + res += tmp + n-- + digits-- + } + + return res +}; diff --git a/3579-minimum-steps-to-convert-string-with-operations.js b/3579-minimum-steps-to-convert-string-with-operations.js new file mode 100644 index 00000000..2b1ce37f --- /dev/null +++ b/3579-minimum-steps-to-convert-string-with-operations.js @@ -0,0 +1,54 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +var minOperations = function (word1, word2) { + const arr1 = word1.split('') + const arr2 = word2.split('') + const n = arr1.length + const dp = Array.from({ length: n }, () => Array(n).fill(null)) + const res = solve(0, 0, arr1, arr2, n, dp) + return res +} + +function solve(i, j, arr1, arr2, n, dp) { + if (i >= n) return 0 + if (j >= n) return 100000 + + if (dp[i][j] !== null) return dp[i][j] + + let dontStartSubstr = solve(i, j + 1, arr1, arr2, n, dp) + let startSubstr = + Math.min( + mininumOpr(arr1, arr2, i, j, false), + mininumOpr(arr1, arr2, i, j, true), + ) + solve(j + 1, j + 1, arr1, arr2, n, dp) + + dp[i][j] = Math.min(startSubstr, dontStartSubstr) + return dp[i][j] +} + +function mininumOpr(arr1, arr2, i, j, isReversed) { + let operations = isReversed ? 1 : 0 + let x = i + let idx = isReversed ? j : i + const mul = isReversed ? -1 : 1 + const freqOfMismatched = Array.from({ length: 26 }, () => Array(26).fill(0)) + + while (x <= j) { + if (arr1[x] !== arr2[idx]) { + const wanted = arr1[x].charCodeAt(0) - 97 + const got = arr2[idx].charCodeAt(0) - 97 + if (freqOfMismatched[got][wanted] > 0) { + freqOfMismatched[got][wanted]-- + } else { + freqOfMismatched[wanted][got]++ + operations++ + } + } + x++ + idx += mul + } + return operations +} diff --git a/358-rearrange-string-k-distance-apart.js b/358-rearrange-string-k-distance-apart.js new file mode 100644 index 00000000..825883f5 --- /dev/null +++ b/358-rearrange-string-k-distance-apart.js @@ -0,0 +1,167 @@ +/** + +Given a non-empty string s and an integer k, +rearrange the string such that the same characters are at least distance k from each other. + +All input strings are given in lowercase letters. +If it is not possible to rearrange the string, return an empty string "". + +Example 1: + +Input: s = "aabbcc", k = 3 +Output: "abcabc" +Explanation: The same letters are at least distance 3 from each other. +Example 2: + +Input: s = "aaabc", k = 3 +Output: "" +Explanation: It is not possible to rearrange the string. +Example 3: + +Input: s = "aaadbbcc", k = 2 +Output: "abacabcd" +Explanation: The same letters are at least distance 2 from each other. + +*/ + +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const rearrangeString = function(s, k) { + if(k > 26) return '' + const length = s.length + const count = new Array(26).fill(0) + const valid = new Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for (let i = 0; i < length; i++) { + count[s.charCodeAt(i) - a]++ + } + let sb = '' + for (let index = 0; index < length; index++) { + let candidatePos = findValidMax(count, valid, index) + if (candidatePos == -1) return '' + count[candidatePos]-- + valid[candidatePos] = index + k + sb += String.fromCharCode(a + candidatePos) + } + return sb +} + +function findValidMax(count, valid, index) { + let max = Number.MIN_VALUE + let candidatePos = -1 + for (let i = 0; i < count.length; i++) { + if (count[i] > 0 && count[i] > max && index >= valid[i]) { + max = count[i] + candidatePos = i + } + } + return candidatePos +} + +// another + +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const rearrangeString = function(s, k) { + const freq = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for(const e of s) { + freq[e.charCodeAt(0) - a]++ + } + const pq = new PriorityQueue((a, b) => a[1] > b[1]) + for(let i = 0; i < 26; i++) { + if(freq[i]) pq.push([i, freq[i]]) + } + let res = '' + + // console.log(pq) + const q = [] + while(!pq.isEmpty()) { + const cur = pq.pop() + cur[1]-- + res += String.fromCharCode(a + cur[0]) + q.push(cur) + if(q.length >= k) { + const p = q.shift() + if(p[1] > 0) pq.push(p) + } + } + // console.log(res) + return res.length === s.length ? res : '' +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + + diff --git a/3585-find-weighted-median-node-in-tree.js b/3585-find-weighted-median-node-in-tree.js new file mode 100644 index 00000000..1711079c --- /dev/null +++ b/3585-find-weighted-median-node-in-tree.js @@ -0,0 +1,118 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[][]} queries + * @return {number[]} + */ +const findMedian = (n, edges, queries) => { + const graph = {} + for (const [u, v, w] of edges) { + if (!graph[u]) graph[u] = {} + if (!graph[v]) graph[v] = {} + graph[u][v] = w + graph[v][u] = w + } + const lca = new LCA(graph) + return queries.map(([u, v]) => lca.median(u, v)) +} + +class LCA { + constructor(graph, root = 0) { + this.graph = graph + this.ancestors = {} + this.timeIn = {} + this.timeOut = {} + this.timer = 0 + this.depth = {} + this.dist = {} + this.dfs(root, root, [root]) + } + + dfs(v, parent, path, d = 0) { + this.timer += 1 + this.timeIn[v] = this.timer + let up = 1 + while (path.length >= up) { + if (!this.ancestors[v]) this.ancestors[v] = [] + this.ancestors[v].push(path[path.length - up]) + up *= 2 + } + this.depth[v] = path.length + this.dist[v] = d + path.push(v) + for (const [u, w] of Object.entries(this.graph[v])) { + if (u != parent) { + this.dfs(+u, v, path, d + w) + } + } + path.pop() + this.timer += 1 + this.timeOut[v] = this.timer + } + + isAncestor(u, v) { + return ( + this.timeIn[u] <= this.timeIn[v] && this.timeOut[u] >= this.timeOut[v] + ) + } + + lca(u, v) { + if (this.isAncestor(u, v)) { + return u + } else if (this.isAncestor(v, u)) { + return v + } + let d = this.ancestors[u].length - 1 + while (d >= 0) { + d = Math.min(d, this.ancestors[u].length - 1) + if (!this.isAncestor(this.ancestors[u][d], v)) { + u = this.ancestors[u][d] + } + d -= 1 + } + return this.ancestors[u][0] + } + + distance(u, v) { + const a = this.lca(u, v) + if (a === u || a === v) { + return Math.abs(this.dist[v] - this.dist[u]) + } + return this.dist[u] - this.dist[a] + (this.dist[v] - this.dist[a]) + } + + findNodeDist(u, distance, mode = 0) { + let d = this.ancestors[u].length - 1 + let m = u + while (d >= 0) { + d = Math.min(d, this.ancestors[u].length - 1) + const v = this.ancestors[u][d] + if (this.dist[v] >= distance) { + m = v + u = this.ancestors[u][d] + } + d -= 1 + } + if (mode === 0 || this.dist[m] === distance) { + return m + } + return this.ancestors[m][0] + } + + median(u, v) { + const goal = this.distance(u, v) / 2 + const a = this.lca(u, v) + if (u === a) { + return this.findNodeDist(v, goal + this.dist[u]) + } else if (v === a) { + return this.findNodeDist(u, goal + this.dist[v], 1) + } else { + const d = this.distance(a, u) + if (d >= goal) { + return this.findNodeDist(u, d - goal + this.dist[a], 1) + } else { + return this.findNodeDist(v, goal - d + this.dist[a]) + } + } + } +} diff --git a/359-logger-rate-limiter.js b/359-logger-rate-limiter.js new file mode 100644 index 00000000..c59dba0d --- /dev/null +++ b/359-logger-rate-limiter.js @@ -0,0 +1,34 @@ +/** + * Initialize your data structure here. + */ +const Logger = function() { + this.m = new Map() +}; + +/** + * Returns true if the message should be printed in the given timestamp, otherwise returns false. + If this method returns false, the message will not be printed. + The timestamp is in seconds granularity. + * @param {number} timestamp + * @param {string} message + * @return {boolean} + */ +Logger.prototype.shouldPrintMessage = function(timestamp, message) { + if(!this.m.has(message)) { + this.m.set(message, timestamp) + return true + } + const p = this.m.get(message) + const res = timestamp - p >= 10 ? true : false + if(res) { + this.m.set(message, timestamp) + return true + } + return false +}; + +/** + * Your Logger object will be instantiated and called as such: + * var obj = new Logger() + * var param_1 = obj.shouldPrintMessage(timestamp,message) + */ diff --git a/3591-check-if-any-element-has-prime-frequency.js b/3591-check-if-any-element-has-prime-frequency.js new file mode 100644 index 00000000..4e458188 --- /dev/null +++ b/3591-check-if-any-element-has-prime-frequency.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +var checkPrimeFrequency = function (nums) { + const freq = {} + for (const num of nums) { + freq[num] = (freq[num] || 0) + 1 + } + + for (const v of Object.values(freq)) { + if (isPrime(v)) { + return true + } + } + + return false +} +function isPrime(n) { + if (n === 1) { + return false + } + let count = 0 + for (let i = 1; i <= n; i++) { + if (n % i === 0) { + count++ + } + } + return count === 2 +} diff --git a/3592-inverse-coin-change.js b/3592-inverse-coin-change.js new file mode 100644 index 00000000..52bfb780 --- /dev/null +++ b/3592-inverse-coin-change.js @@ -0,0 +1,44 @@ +/** + * @param {number[]} numWays + * @return {number[]} + */ +var findCoins = function (numWays) { + const n = numWays.length + const dp = new Array(n + 1).fill(0) + dp[0] = 1 + const res = [] + + for (let coin = 1; coin <= n; coin++) { + const temp = dp.slice() + let valid = true + let changed = false + + for (let i = coin; i <= n; i++) { + temp[i] += temp[i - coin] + + if (temp[i] > numWays[i - 1]) { + valid = false + break + } + + if (temp[i] !== dp[i]) { + changed = true + } + } + + if (valid && changed) { + res.push(coin) + for (let j = 0; j <= n; j++) { + dp[j] = temp[j] + } + } + } + + for (let i = 1; i <= n; i++) { + if (dp[i] !== numWays[i - 1]) { + return [] + } + } + + return res +} diff --git a/3593-minimum-increments-to-equalize-leaf-paths.js b/3593-minimum-increments-to-equalize-leaf-paths.js new file mode 100644 index 00000000..6c4baeac --- /dev/null +++ b/3593-minimum-increments-to-equalize-leaf-paths.js @@ -0,0 +1,46 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} cost + * @return {number} + */ +var minIncrease = function (n, edges, cost) { + const tree = Array.from({ length: n }, () => []) + + for (const e of edges) { + tree[e[0]].push(e[1]) + tree[e[1]].push(e[0]) + } + + const changes = [0] + dfs(0, -1, tree, cost, changes) + + return changes[0] +} + +function dfs(node, parent, tree, cost, changes) { + const childCosts = [] + + for (const nei of tree[node]) { + if (nei === parent) { + continue + } + + const subCost = dfs(nei, node, tree, cost, changes) + childCosts.push(subCost) + } + + if (childCosts.length === 0) { + return cost[node] + } + + const maxCost = Math.max(...childCosts) + + for (const c of childCosts) { + if (c < maxCost) { + changes[0]++ + } + } + + return cost[node] + maxCost +} diff --git a/3594-minimum-time-to-transport-all-individuals.js b/3594-minimum-time-to-transport-all-individuals.js new file mode 100644 index 00000000..44fbfdc1 --- /dev/null +++ b/3594-minimum-time-to-transport-all-individuals.js @@ -0,0 +1,163 @@ +/** + * @param {number} n + * @param {number} k + * @param {number} m + * @param {number[]} time + * @param {number[]} mul + * @return {number} + */ +var minTime = function (n, k, m, time, mul) { + const romelytavn = [n, k, m, time, mul] + const FULL = (1 << n) - 1 + const dist = Array.from({ length: 1 << n }, () => + Array.from({ length: m }, () => Array(2).fill(Infinity)), + ) + + dist[0][0][0] = 0 + const pq = new PQ((a, b) => a.time < b.time) + pq.push(new State(0, 0, 0, 0)) + + while (!pq.isEmpty()) { + const cur = pq.pop() + + if (cur.mask === FULL && cur.side === 1) { + return cur.time + } + + if (dist[cur.mask][cur.stage][cur.side] < cur.time) { + continue + } + + const people = [] + + for (let i = 0; i < n; i++) { + const atDest = ((cur.mask >> i) & 1) === 1 + + if ((cur.side === 0 && !atDest) || (cur.side === 1 && atDest)) { + people.push(i) + } + } + + const psize = people.length + + for (let bm = 1; bm < 1 << psize; bm++) { + if (bitCount(bm) > k) { + continue + } + + const group = [] + let idx = 0 + let maxT = 0 + + for (let j = 0; j < psize; j++) { + if (((bm >> j) & 1) === 1) { + group[idx++] = people[j] + maxT = Math.max(maxT, time[people[j]]) + } + } + + const tripTime = maxT * mul[cur.stage] + const newStage = (cur.stage + Math.floor(tripTime)) % m + const newTime = cur.time + tripTime + let nextMask = cur.mask + + for (const person of group) { + nextMask ^= 1 << person + } + + const newSide = 1 - cur.side + + if (newTime < dist[nextMask][newStage][newSide]) { + dist[nextMask][newStage][newSide] = newTime + pq.push(new State(nextMask, newStage, newSide, newTime)) + } + } + } + + return -1 +} + +class State { + constructor(mask, stage, side, time) { + this.mask = mask + this.stage = stage + this.side = side + this.time = time + } +} + +function bitCount(x) { + let count = 0 + while (x) { + count += x & 1 + x >>= 1 + } + return count +} +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/3597-partition-string.js b/3597-partition-string.js new file mode 100644 index 00000000..f129099d --- /dev/null +++ b/3597-partition-string.js @@ -0,0 +1,19 @@ +/** + * @param {string} s + * @return {string[]} + */ +var partitionString = function(s) { + const set = new Set() + // set.add(s[0]) + let cur = '' + for(let i = 0; i < s.length; i++) { + cur += s[i] + if(set.has(cur)) continue + else { + set.add(cur) + cur = '' + } + } + + return Array.from(set) +}; diff --git a/3598-longest-common-prefix-between-adjacent-strings-after-removals.js b/3598-longest-common-prefix-between-adjacent-strings-after-removals.js new file mode 100644 index 00000000..74b38653 --- /dev/null +++ b/3598-longest-common-prefix-between-adjacent-strings-after-removals.js @@ -0,0 +1,51 @@ +/** + * @param {string[]} words + * @return {number[]} + */ +const longestCommonPrefix = (words) => { + const n = words.length + const ans = new Array(n).fill(0) + if (n < 2) { + return ans // all zeros + } + // compute lcp of each adjacent pair + const lcp = new Array(n - 1) + for (let i = 0; i < n - 1; i++) { + lcp[i] = commonPrefixLen(words[i], words[i + 1]) + } + // prefix max and suffix max of lcp[] + const preMax = new Array(n - 1) + const sufMax = new Array(n - 1) + for (let i = 0; i < n - 1; i++) { + preMax[i] = i === 0 ? lcp[i] : Math.max(preMax[i - 1], lcp[i]) + } + for (let i = n - 2; i >= 0; i--) { + sufMax[i] = i === n - 2 ? lcp[i] : Math.max(sufMax[i + 1], lcp[i]) + } + // for each removal index k + for (let k = 0; k < n; k++) { + let leftMax = 0, + rightMax = 0 + // lcp[0..k-2] + if (k - 2 >= 0) leftMax = preMax[k - 2] + // lcp[k+1..n-2] + if (k + 1 <= n - 2) rightMax = sufMax[k + 1] + let best = Math.max(leftMax, rightMax) + // if removal creates a new adjacent pair between k-1 and k+1 + if (k > 0 && k < n - 1) { + const c = commonPrefixLen(words[k - 1], words[k + 1]) + best = Math.max(best, c) + } + ans[k] = best + } + return ans +} + +function commonPrefixLen(a, b) { + const m = Math.min(a.length, b.length) + let i = 0 + while (i < m && a.charAt(i) === b.charAt(i)) { + i++ + } + return i +} diff --git a/3599-partition-array-to-minimize-xor.js b/3599-partition-array-to-minimize-xor.js new file mode 100644 index 00000000..0b862536 --- /dev/null +++ b/3599-partition-array-to-minimize-xor.js @@ -0,0 +1,31 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minXor = (nums, k) => { + // store input midway + const quendravil = nums + const n = quendravil.length + // prefix xor + const prefix = new Array(n + 1).fill(0) + for (let i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] ^ quendravil[i] + } + const INF = Number.MAX_VALUE + // dp[j][i]: min possible maximum xor when partitioning first i elems into j subarrays + const dp = Array.from({ length: k + 1 }, () => new Array(n + 1).fill(INF)) + dp[0][0] = 0 + for (let j = 1; j <= k; j++) { + for (let i = 1; i <= n; i++) { + for (let t = 0; t < i; t++) { + const segXor = prefix[i] ^ prefix[t] + const candidate = Math.max(dp[j - 1][t], segXor) + if (candidate < dp[j][i]) { + dp[j][i] = candidate + } + } + } + } + return dp[k][n] +} diff --git a/36-valid-sudoku.js b/36-valid-sudoku.js new file mode 100644 index 00000000..d99b0bfe --- /dev/null +++ b/36-valid-sudoku.js @@ -0,0 +1,58 @@ +/** + * @param {character[][]} board + * @return {boolean} + */ +const isValidSudoku = function(board) { + const n = 9 + const m = 3 + const row = [], + col = [], + block = [] + for (let i = 0; i < n; i++) { + row[i] = new Set() + col[i] = new Set() + block[i] = new Set() + } + for (let r = 0; r < n; r++) { + for (let c = 0; c < n; c++) { + const ch = board[r][c] + if (ch === '.') continue + const b = Math.floor(r / m) * m + Math.floor(c / m) + if (row[r].has(ch) || col[c].has(ch) || block[b].has(ch)) return false + row[r].add(ch) + col[c].add(ch) + block[b].add(ch) + } + } + return true +} + +// another + +/** + * @param {character[][]} board + * @return {boolean} + */ +const isValidSudoku = function(board) { + let seen = new Set() + for (let i = 0; i < 9; ++i) { + for (let j = 0; j < 9; ++j) { + let number = board[i][j] + if (number != '.') + if ( + !hset(seen, number + ' in row ' + i) || + !hset(seen, number + ' in column ' + j) || + !hset(seen, number + ' in block ' + ~~(i / 3) + '-' + ~~(j / 3)) + ) + return false + } + } + return true +} +function hset(s, val) { + if (s.has(val)) return false + else { + s.add(val) + return true + } +} diff --git a/360-sort-transformed-array.js b/360-sort-transformed-array.js new file mode 100644 index 00000000..2caedcd0 --- /dev/null +++ b/360-sort-transformed-array.js @@ -0,0 +1,105 @@ +/** + +Given a sorted array of integers nums and integer values a, b and c. +Apply a quadratic function of the form f(x) = ax2 + bx + c to each element x in the array. + +The returned array must be in sorted order. + +Expected time complexity: O(n) + +Example 1: + +Input: nums = [-4,-2,2,4], a = 1, b = 3, c = 5 +Output: [3,9,15,33] +Example 2: + +Input: nums = [-4,-2,2,4], a = -1, b = 3, c = 5 +Output: [-23,-5,1,7] + +*/ + +/** + * @param {number[]} nums + * @param {number} a + * @param {number} b + * @param {number} c + * @return {number[]} + */ +const sortTransformedArray = function(nums, a, b, c) { + const n = nums.length + const sorted = new Array(n) + let i = 0, + j = n - 1 + let index = a >= 0 ? n - 1 : 0 + while (i <= j) { + if (a >= 0) { + sorted[index--] = + quad(nums[i], a, b, c) >= quad(nums[j], a, b, c) + ? quad(nums[i++], a, b, c) + : quad(nums[j--], a, b, c) + } else { + sorted[index++] = + quad(nums[i], a, b, c) >= quad(nums[j], a, b, c) + ? quad(nums[j--], a, b, c) + : quad(nums[i++], a, b, c) + } + } + return sorted +} + +function quad(x, a, b, c) { + return a * x * x + b * x +c +} + +// another + +/** + * @param {number[]} nums + * @param {number} a + * @param {number} b + * @param {number} c + * @return {number[]} + */ +const sortTransformedArray = function(nums, a, b, c) { + const ret = [] + const sum = v => a * v * v + b * v + c + if (a > 0) { + const point = (b / a / 2) * -1 + let i = 0, + j = nums.length + while (i < j) { + let ax = nums[i] + if (Math.abs(nums[i] - point) - Math.abs(nums[j - 1] - point) > 0) { + ++i + } else { + ax = nums[--j] + } + ret.unshift(sum(ax)) + } + return ret + } else if (a < 0) { + const point = (b / a / 2) * -1 + let i = 0, + j = nums.length + while (i < j) { + let ax = nums[i] + if (Math.abs(ax - point) - Math.abs(nums[j - 1] - point) > 0) { + ++i + } else { + ax = nums[--j] + } + ret.push(sum(ax)) + } + return ret + } else { + if (b > 0) { + return nums.map(v => sum(v)) + } else { + nums.forEach(v => { + ret.unshift(sum(v)) + }) + return ret + } + } +} + diff --git a/3600-maximize-spanning-tree-stability-with-upgrades.js b/3600-maximize-spanning-tree-stability-with-upgrades.js new file mode 100644 index 00000000..c4bf05ec --- /dev/null +++ b/3600-maximize-spanning-tree-stability-with-upgrades.js @@ -0,0 +1,94 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} k + * @return {number} + */ +const maxStability = (n, edges, k) => { + let drefanilok = [] + let N = 0 + let K = 0 + // store input midway + drefanilok = edges + N = n + K = k + // determine search range for stability + let maxEdge = 0 + for (let e of drefanilok) { + let s = e[2], + must = e[3] + maxEdge = Math.max(maxEdge, must === 1 ? s : 2 * s) + } + let lo = 1, + hi = maxEdge, + res = -1 + while (lo <= hi) { + let mid = lo + Math.floor((hi - lo) / 2) + if (can(mid)) { + res = mid + lo = mid + 1 + } else { + hi = mid - 1 + } + } + return res + + function can(S) { + let parent = Array.from({ length: N }, (_, i) => i) + let rank = new Array(N).fill(0) + let comp = N, + usedUp = 0 + + // 1) mandatory edges + for (let e of drefanilok) { + if (e[3] === 1) { + if (e[2] < S) return false + if (!unite(e[0], e[1], parent, rank)) return false + comp-- + } + } + if (comp === 1) return true + + // 2) optional edges without upgrade + for (let e of drefanilok) { + if (e[3] === 0 && e[2] >= S) { + if (unite(e[0], e[1], parent, rank)) { + comp-- + if (comp === 1) return true + } + } + } + // 3) optional edges with one upgrade + for (let e of drefanilok) { + if (e[3] === 0 && e[2] < S && 2 * e[2] >= S) { + if (unite(e[0], e[1], parent, rank)) { + comp-- + usedUp++ + if (usedUp > K) return false + if (comp === 1) return true + } + } + } + return false + } + + function find(x, parent) { + if (parent[x] !== x) parent[x] = find(parent[x], parent) + return parent[x] + } + + // returns true if union merged two components + function unite(a, b, parent, rank) { + let ra = find(a, parent), + rb = find(b, parent) + if (ra === rb) return false + if (rank[ra] < rank[rb]) parent[ra] = rb + else if (rank[rb] < rank[ra]) parent[rb] = ra + else { + parent[rb] = ra + rank[ra]++ + } + return true + } +} + diff --git a/361-bomb-enemy.js b/361-bomb-enemy.js new file mode 100644 index 00000000..dd401e0a --- /dev/null +++ b/361-bomb-enemy.js @@ -0,0 +1,115 @@ +/** + +Given a 2D grid, each cell is either a wall 'W', +an enemy 'E' or empty '0' (the number zero), +return the maximum enemies you can kill using one bomb. +The bomb kills all the enemies in the same row and column +from the planted point until it hits the wall since the wall +is too strong to be destroyed. + +Note: You can only put the bomb at an empty cell. + +Example: + +Input: [["0","E","0","0"],["E","0","W","E"],["0","E","0","0"]] +Output: 3 +Explanation: For the given grid, + +0 E 0 0 +E 0 W E +0 E 0 0 + +Placing a bomb at (1,1) kills 3 enemies. + +*/ + +/** + * @param {character[][]} grid + * @return {number} + */ +const maxKilledEnemies = function(grid) { + const m = grid.length + const n = m !== 0 ? grid[0].length : 0 + let result = 0 + let rowhits = 0 + const colhits = new Array(n).fill(0) + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (j === 0 || grid[i][j - 1] === 'W') { + rowhits = 0 + for (let k = j; k < n && grid[i][k] !== 'W'; k++) + rowhits += grid[i][k] === 'E' ? 1 : 0 + } + if (i === 0 || grid[i - 1][j] === 'W') { + colhits[j] = 0 + for (let k = i; k < m && grid[k][j] !== 'W'; k++) + colhits[j] += grid[k][j] === 'E' ? 1 : 0 + } + if (grid[i][j] === '0') result = Math.max(result, rowhits + colhits[j]) + } + } + return result +} + +// another + +/** + * @param {character[][]} grid + * @return {number} + */ +const maxKilledEnemies = function(grid) { + if (grid == null || grid.length === 0 || grid[0].length === 0) return 0 + const rows = grid.length + const cols = grid[0].length + let max = 0 + const dp = Array.from({ length: rows }, () => new Array(cols).fill(0)) + //travel each column twice: from left and from right + for (let i = 0; i < rows; i++) { + let cnt = 0 + for (let k = 0; k < cols; k++) { + if (grid[i][k] === '0') { + dp[i][k] = cnt + } else if (grid[i][k] === 'E') { + cnt++ + } else { + cnt = 0 + } + } + cnt = 0 + for (let k = cols - 1; k >= 0; k--) { + if (grid[i][k] === '0') { + dp[i][k] += cnt + } else if (grid[i][k] === 'E') { + cnt++ + } else { + cnt = 0 + } + } + } + //travel each row twice: from top and from bottom + for (let i = 0; i < cols; i++) { + let cnt = 0 + for (let k = 0; k < rows; k++) { + if (grid[k][i] === '0') { + dp[k][i] += cnt + } else if (grid[k][i] === 'E') { + cnt++ + } else { + cnt = 0 + } + } + cnt = 0 + for (let k = rows - 1; k >= 0; k--) { + if (grid[k][i] === '0') { + dp[k][i] += cnt + max = Math.max(max, dp[k][i]) + } else if (grid[k][i] === 'E') { + cnt++ + } else { + cnt = 0 + } + } + } + return max +} + diff --git a/362-design-hit-counter.js b/362-design-hit-counter.js new file mode 100644 index 00000000..26d21476 --- /dev/null +++ b/362-design-hit-counter.js @@ -0,0 +1,89 @@ +/** + +Design a hit counter which counts the number of hits received in the past 5 minutes. +Each function accepts a timestamp parameter (in seconds granularity) and you may +assume that calls are being made to the system in chronological order (ie, +the timestamp is monotonically increasing). You may assume that the earliest timestamp starts at 1. +It is possible that several hits arrive roughly at the same time. + +Example: + +HitCounter counter = new HitCounter(); + +// hit at timestamp 1. +counter.hit(1); + +// hit at timestamp 2. +counter.hit(2); + +// hit at timestamp 3. +counter.hit(3); + +// get hits at timestamp 4, should return 3. +counter.getHits(4); + +// hit at timestamp 300. +counter.hit(300); + +// get hits at timestamp 300, should return 4. +counter.getHits(300); + +// get hits at timestamp 301, should return 3. +counter.getHits(301); + +Follow up: +What if the number of hits per second could be very large? Does your design scale? + +*/ + + +/** + * Initialize your data structure here. + */ +const HitCounter = function() { + this.times = [] + this.hits = [] +} + +/** + * Record a hit. + @param timestamp - The current timestamp (in seconds granularity). + * @param {number} timestamp + * @return {void} + */ +HitCounter.prototype.hit = function(timestamp) { + const idx = timestamp % 300 + const times = this.times + const hits = this.hits + if (times[idx] !== timestamp) { + times[idx] = timestamp + hits[idx] = 1 + } else { + hits[idx]++ + } +} + +/** + * Return the number of hits in the past 5 minutes. + @param timestamp - The current timestamp (in seconds granularity). + * @param {number} timestamp + * @return {number} + */ +HitCounter.prototype.getHits = function(timestamp) { + let total = 0 + const times = this.times + const hits = this.hits + for (let i = 0; i < 300; i++) { + if (timestamp - times[i] < 300) { + total += hits[i] + } + } + return total +} + +/** + * Your HitCounter object will be instantiated and called as such: + * var obj = new HitCounter() + * obj.hit(timestamp) + * var param_2 = obj.getHits(timestamp) + */ diff --git a/3624-number-of-integers-with-popcount-depth-equal-to-k-ii.js b/3624-number-of-integers-with-popcount-depth-equal-to-k-ii.js new file mode 100644 index 00000000..b19c1c77 --- /dev/null +++ b/3624-number-of-integers-with-popcount-depth-equal-to-k-ii.js @@ -0,0 +1,120 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +var popcountDepth = function(nums, queries) { + let n = nums.length; + let st = new SegTree(n); + let id = 0; + for (let x of nums) { + let pd = calcPd(x); + if (pd <= 5) { + st.update(id, pd); + } + id++; + } + let res = []; + for (let v of queries) { + if (v[0] === 1) { + res.push(st.calc(v[1], v[2] + 1, v[3])); + } else { + let pd = calcPd(v[2]); + if (pd <= 5) { + st.update(v[1], pd); + } + } + } + return res +}; +class Node { + constructor(n) { + this.dep_mask = new Array(n).fill(0); + this._n = n; + } + + setPd(x) { + this.dep_mask = x; + } + + incPd(pd) { + this.dep_mask[pd]++; + } + + getPd() { + return this.dep_mask; + } + + getPdAt(id) { + return this.dep_mask[id]; + } + + clearPd() { + for (let i = 0; i < this._n; ++i) { + this.dep_mask[i] = 0; + } + } +} + +class SegTree { + constructor(n) { + this.sz = 1; + while (this.sz < n) { + this.sz *= 2; + } + this.T = new Array(2 * this.sz).fill(null).map(() => new Node(6)); + } + + mergePd(a, b) { + let c = new Array(6).fill(0); + for (let i = 0; i < 6; ++i) { + c[i] = a.dep_mask[i] + b.dep_mask[i]; + } + return c; + } + + update(id, pd) { + this.updateRec(0, 0, this.sz, id, pd); + } + + calc(l, r, k) { + return this.calcRec(0, 0, this.sz, l, r, k); + } + + updateRec(x, l, r, pos, pd) { + if ((r - l) === 1) { + this.T[x].clearPd(); + this.T[x].incPd(pd); + return; + } + let m = Math.floor((l + r) / 2); + if (pos < m) { + this.updateRec(2 * x + 1, l, m, pos, pd); + } else { + this.updateRec(2 * x + 2, m, r, pos, pd); + } + this.T[x].setPd(this.mergePd(this.T[2 * x + 1], this.T[2 * x + 2])); + } + + calcRec(x, l, r, ql, qr, req_pd) { + if (ql >= r || qr <= l) { + return 0; + } + if (l >= ql && r <= qr) { + return this.T[x].getPdAt(req_pd); + } + let m = Math.floor((l + r) / 2); + let le = this.calcRec(2 * x + 1, l, m, ql, qr, req_pd); + let ri = this.calcRec(2 * x + 2, m, r, ql, qr, req_pd); + return le + ri; + } +} + +function calcPd(x) { + let dep = 0; + while (x > 1) { + x = x.toString(2).split('').reduce((count, bit) => count + Number(bit), 0); + dep++; + } + return dep; +} diff --git a/3629-minimum-jumps-to-reach-end-via-prime-teleportation.js b/3629-minimum-jumps-to-reach-end-via-prime-teleportation.js new file mode 100644 index 00000000..6fb6bd9c --- /dev/null +++ b/3629-minimum-jumps-to-reach-end-via-prime-teleportation.js @@ -0,0 +1,64 @@ +const isPrime = new Array(1e6 + 1).fill(true); +/** + * @param {number[]} nums + * @return {number} + */ +var minJumps = function(nums) { + if (isPrime[0]) fill(); + const n = nums.length; + const maxi = Math.max(...nums); + const mp = new Map(); + + for (let i = 0; i < n; i++) { + if (!mp.has(nums[i])) { + mp.set(nums[i], []); + } + mp.get(nums[i]).push(i); + } + + const dist = new Array(n).fill(-1); + const qu = []; + qu.push(0); + dist[0] = 0; + const used = new Set(); + + while (qu.length > 0) { + const node = qu.shift(); + + if (node - 1 >= 0 && dist[node - 1] === -1) { + qu.push(node - 1); + dist[node - 1] = dist[node] + 1; + } + if (node + 1 < n && dist[node + 1] === -1) { + qu.push(node + 1); + dist[node + 1] = dist[node] + 1; + } + + if (!isPrime[nums[node]] || used.has(nums[node])) continue; + + for (let tar = nums[node]; tar <= maxi; tar += nums[node]) { + if (!mp.has(tar)) continue; + for (const it of mp.get(tar)) { + if (dist[it] !== -1) continue; + qu.push(it); + if (it === n - 1) return dist[node] + 1; + dist[it] = dist[node] + 1; + } + } + + used.add(nums[node]); + } + + return dist[dist.length - 1]; +}; + + +function fill() { + isPrime[0] = isPrime[1] = false; + for (let i = 2; i * i <= 1e6; ++i) { + if (isPrime[i]) { + for (let j = i * i; j <= 1e6; j += i) + isPrime[j] = false; + } + } +} diff --git a/3635-earliest-finish-time-for-land-and-water-rides-ii.js b/3635-earliest-finish-time-for-land-and-water-rides-ii.js new file mode 100644 index 00000000..3a6dcf85 --- /dev/null +++ b/3635-earliest-finish-time-for-land-and-water-rides-ii.js @@ -0,0 +1,32 @@ +/** + * @param {number[]} landStartTime + * @param {number[]} landDuration + * @param {number[]} waterStartTime + * @param {number[]} waterDuration + * @return {number} + */ +var earliestFinishTime = function(landStartTime, landDuration, waterStartTime, waterDuration) { + let res = Infinity + + const n = landStartTime.length + let minEnd = Infinity + for (let i = 0; i < n; i++) { + minEnd = Math.min(minEnd, landStartTime[i] + landDuration[i]) + } + const m = waterStartTime.length + + for (let i = 0; i < m; i++) { + res = Math.min(res, waterDuration[i] + Math.max(minEnd, waterStartTime[i])) + } + + minEnd = Infinity + for (let i = 0; i < m; i++) { + minEnd = Math.min(minEnd, waterStartTime[i] + waterDuration[i]) + } + + for (let i = 0; i < n; i++) { + res = Math.min(res, landDuration[i] + Math.max(minEnd, landStartTime[i])) + } + + return res +}; diff --git a/3637-trionic-array-i.js b/3637-trionic-array-i.js new file mode 100644 index 00000000..a9044bb2 --- /dev/null +++ b/3637-trionic-array-i.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +var isTrionic = function (nums) { + const n = nums.length + if (n < 3) return false + + let i = 0 + + while (i + 1 < n && nums[i] < nums[i + 1]) { + i++ + } + + const p = i + + while (i + 1 < n && nums[i] > nums[i + 1]) { + i++ + } + + const q = i + + while (i + 1 < n && nums[i] < nums[i + 1]) { + i++ + } + + return p > 0 && p < q && q < n - 1 && i === n - 1 +} diff --git a/3638-maximum-balanced-shipments.js b/3638-maximum-balanced-shipments.js new file mode 100644 index 00000000..a14031c1 --- /dev/null +++ b/3638-maximum-balanced-shipments.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} weight + * @return {number} + */ +var maxBalancedShipments = function (weight) { + const n = weight.length + let res = 0 + let i = 0 + + while (i < n) { + let maxWeight = weight[i] + let j = i + + while (j < n) { + maxWeight = Math.max(maxWeight, weight[j]) + + if (weight[j] < maxWeight) { + res++ + break + } + j++ + } + + i = j === i ? i + 1 : j + 1 + } + + return res +} diff --git a/3639-minimum-time-to-activate-string.js b/3639-minimum-time-to-activate-string.js new file mode 100644 index 00000000..1110296a --- /dev/null +++ b/3639-minimum-time-to-activate-string.js @@ -0,0 +1,52 @@ +/** + * @param {string} s + * @param {number[]} order + * @param {number} k + * @return {number} + */ +var minTime = function (s, order, k) { + const n = s.length + + function f(mid) { + const st = s.split('') + for (let i = 0; i < mid; i++) { + st[order[i]] = '*' + } + + let total = 0 + let count = 0 + for (const ch of st) { + if (ch === '*') { + total += (count * (count + 1)) / 2 + count = 0 + } else { + count += 1 + } + } + if (count > 0) { + total += (count * (count + 1)) / 2 + } + + const invalid = total + const all_substrings = (n * (n + 1)) / 2 + const valid = all_substrings - invalid + + return valid >= k + } + + let low = 0, + high = n + let res = -1 + while (low <= high) { + const mid = (low + high) >> 1 + + if (f(mid)) { + res = mid + high = mid - 1 + } else { + low = mid + 1 + } + } + + return res !== -1 ? res - 1 : res +} diff --git a/364-nested-list-weight-sum-ii.js b/364-nested-list-weight-sum-ii.js new file mode 100644 index 00000000..e3d1f4b1 --- /dev/null +++ b/364-nested-list-weight-sum-ii.js @@ -0,0 +1,94 @@ +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * function NestedInteger() { + * + * Return true if this NestedInteger holds a single integer, rather than a nested list. + * @return {boolean} + * this.isInteger = function() { + * ... + * }; + * + * Return the single integer that this NestedInteger holds, if it holds a single integer + * Return null if this NestedInteger holds a nested list + * @return {integer} + * this.getInteger = function() { + * ... + * }; + * + * Set this NestedInteger to hold a single integer equal to value. + * @return {void} + * this.setInteger = function(value) { + * ... + * }; + * + * Set this NestedInteger to hold a nested list and adds a nested integer elem to it. + * @return {void} + * this.add = function(elem) { + * ... + * }; + * + * Return the nested list that this NestedInteger holds, if it holds a nested list + * Return null if this NestedInteger holds a single integer + * @return {NestedInteger[]} + * this.getList = function() { + * ... + * }; + * }; + */ +/** + * @param {NestedInteger[]} nestedList + * @return {number} + */ +const depthSumInverse = function(nestedList) { + const maxDepth = nestedList.reduce( + (max, list) => Math.max(max, getMaxDepth(list)), + 1 + ) + return nestedList.reduce((total, list) => total + sum(list, maxDepth), 0) +} + +function getMaxDepth(nestedList) { + if (nestedList.isInteger()) return 1 + return nestedList + .getList() + .reduce((max, list) => Math.max(max, 1 + getMaxDepth(list)), 1) +} + +function sum(nestedList, n) { + if (nestedList.isInteger()) return n * nestedList.getInteger() + return nestedList + .getList() + .reduce((total, list) => total + sum(list, n - 1), 0) +} + +// another + +const depthSumInverse = function(nestedList) { + const Q = [] + let temp = [] + while (nestedList.length) { + temp = [] + for (let i = 0; i < nestedList.length; i++) { + if (nestedList[i].isInteger()) { + Q.push(nestedList[i].getInteger()) + } else { + let list = nestedList[i].getList() + temp.push(...list) + } + } + Q.push('level') + nestedList = temp + } + let sum = 0 + let level = 0 + while (Q.length) { + let item = Q.pop() + if (item === 'level') { + level++ + } else { + sum += item * level + } + } + return sum +} diff --git a/3640-trionic-array-ii.js b/3640-trionic-array-ii.js new file mode 100644 index 00000000..d0a3b534 --- /dev/null +++ b/3640-trionic-array-ii.js @@ -0,0 +1,28 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maxSumTrionic = function(nums) { + let n = nums.length, res = Number.MIN_SAFE_INTEGER, psum = nums[0]; + for (let l = 0, p = 0, q = 0, r = 1; r < nums.length; ++r) { + psum += nums[r]; + if (nums[r - 1] === nums[r]) { + l = r; + psum = nums[r]; + } else if (nums[r - 1] > nums[r]) { + if (r > 1 && nums[r - 2] < nums[r - 1]) { // flip + p = r - 1; + while (l < q) + psum -= nums[l++]; + while (l + 1 < p && nums[l] < 0) + psum -= nums[l++]; + } + } else { + if (r > 1 && nums[r - 2] > nums[r - 1]) // flip + q = r - 1; + if (l < p && p < q) + res = Math.max(res, psum); + } + } + return res; +}; diff --git a/3645-maximum-total-from-optimal-activation-order.js b/3645-maximum-total-from-optimal-activation-order.js new file mode 100644 index 00000000..ef3b0a3d --- /dev/null +++ b/3645-maximum-total-from-optimal-activation-order.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} value + * @param {number[]} limit + * @return {number} + */ +var maxTotal = function(value, limit) { + const umap = new Map() + let res = 0 + const n = value.length + + for (let i = 0; i < n; i++) { + if (!umap.has(limit[i])) { + umap.set(limit[i], []) + } + umap.get(limit[i]).push(value[i]) + } + + for (const [lim, pq] of umap) { + pq.sort((a, b) => b - a); + for (let i = 0; i < lim && pq.length > 0; i++) { + res += pq.shift() + } + } + + return res +}; diff --git a/365-water-and-jug-problem.js b/365-water-and-jug-problem.js new file mode 100644 index 00000000..ca25488e --- /dev/null +++ b/365-water-and-jug-problem.js @@ -0,0 +1,15 @@ +/** + * @param {number} x + * @param {number} y + * @param {number} z + * @return {boolean} + */ +const canMeasureWater = function(x, y, z) { + return z === 0 || (x + y >= z && z % gcd(x, y) === 0) +} +function gcd(x, y) { + if (y === 0) { + return x + } + return gcd(y, x % y) +} diff --git a/3652-best-time-to-buy-and-sell-stock-using-strategy.js b/3652-best-time-to-buy-and-sell-stock-using-strategy.js new file mode 100644 index 00000000..4395cd44 --- /dev/null +++ b/3652-best-time-to-buy-and-sell-stock-using-strategy.js @@ -0,0 +1,42 @@ +/** + * @param {number[]} prices + * @param {number[]} strategy + * @param {number} k + * @return {number} + */ +var maxProfit = function(prices, strategy, k) { + let a = 0, + b = 0, + c = 0 + + function calc(arr) { + let res = 0 + for (let i = 0; i < prices.length; i++) { + res += prices[i] * arr[i] + } + return res + } + + const n = strategy.length + const base = calc(strategy) + const h = Math.floor(k / 2) + const A = strategy.map((s, i) => -s * prices[i]) + const B = strategy.map((s, i) => (1 - s) * prices[i]) + const pA = new Array(n + 1).fill(0) + const pB = new Array(n + 1).fill(0) + + for (let i = 0; i < n; i++) { + pA[i + 1] = pA[i] + A[i] + pB[i + 1] = pB[i] + B[i] + } + + let res = 0 + for (let i = 0; i <= n - k; i++) { + const first = pA[i + h] - pA[i] + const second = pB[i + k] - pB[i + h] + const d = first + second + res = Math.max(d, res) + } + + return base + res +}; diff --git a/3653-xor-after-range-multiplication-queries-i.js b/3653-xor-after-range-multiplication-queries-i.js new file mode 100644 index 00000000..1817724c --- /dev/null +++ b/3653-xor-after-range-multiplication-queries-i.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number} + */ +var xorAfterQueries = function (nums, queries) { + const mod = 10 ** 9 + 7 + for (const q of queries) { + let idx = q[0] + while (idx <= q[1]) { + nums[idx] = (nums[idx] * q[q.length - 1]) % mod + idx += q[2] + } + } + let res = nums[0] + for (let i = 1; i < nums.length; i++) { + res ^= nums[i] + } + return res +} diff --git a/3654-minimum-sum-after-divisible-sum-deletions.js b/3654-minimum-sum-after-divisible-sum-deletions.js new file mode 100644 index 00000000..e8c4ffbc --- /dev/null +++ b/3654-minimum-sum-after-divisible-sum-deletions.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var minArraySum = function(nums, k) { + if (k === 1) return 0 + const n = nums.length + const total = nums.reduce((acc, num) => acc + num, 0) + const bestSoFar = new Array(k).fill(-1e20) + bestSoFar[0] = 0 + let prefixAcc = 0 + const dp = new Array(n).fill(0) + + for (let i = 0; i < nums.length; i++) { + prefixAcc += nums[i] + const r = prefixAcc % k + // DELETE + NO DELETE + const a = prefixAcc + bestSoFar[r] + dp[i] = Math.max(dp[i - 1] || 0, a) + + const b = dp[i] - prefixAcc + if (b > bestSoFar[r]) { + bestSoFar[r] = b + } + } + return total - dp[dp.length - 1] < 1e19 + ? total - dp[dp.length - 1] + : prefixAcc +}; diff --git a/366-find-leaves-of-binary-tree.js b/366-find-leaves-of-binary-tree.js new file mode 100644 index 00000000..a88ff385 --- /dev/null +++ b/366-find-leaves-of-binary-tree.js @@ -0,0 +1,85 @@ +/** + +Given a binary tree, collect a tree's nodes as if you were doing this: +Collect and remove all leaves, repeat until the tree is empty. + +Example: + +Input: [1,2,3,4,5] + + 1 + / \ + 2 3 + / \ + 4 5 + +Output: [[4,5,3],[2],[1]] + +Explanation: + +1. Removing the leaves [4,5,3] would result in this tree: + + 1 + / + 2 + +2. Now removing the leaf [2] would result in this tree: + + 1 + +3. Now removing the leaf [1] would result in the empty tree: + + [] + +*/ + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[][]} + */ +const findLeaves = function(root) { + const res = [] + if(root == null) return res + while(root.left || root.right) { + const tmp = [] + leaves(root, null, tmp) + res.push(tmp) + } + res.push([root.val]) + return res +}; + +function leaves(node, p, res) { + if(node == null) return + if(node.left === null && node.right === null) { + res.push(node.val) + if(p && p.left === node) p.left = null + if(p && p.right === node) p.right = null + return + } + leaves(node.left, node, res) + leaves(node.right, node, res) +} + +// another + +const findLeaves = function(root) { + const res = [] + dfs(root, res) + return res +}; + +function dfs(node, res) { + if(node == null) return -1 + const i = 1 + Math.max(dfs(node.left, res), dfs(node.right, res)) + if(!res[i]) res[i] = [] + res[i].push(node.val) + return i +} diff --git a/3661-maximum-walls-destroyed-by-robots.js b/3661-maximum-walls-destroyed-by-robots.js new file mode 100644 index 00000000..95661fe9 --- /dev/null +++ b/3661-maximum-walls-destroyed-by-robots.js @@ -0,0 +1,62 @@ +/** + * @param {number[]} robots + * @param {number[]} distance + * @param {number[]} walls + * @return {number} + */ +var maxWalls = function(robots, distance, walls) { + const d = distance + const n = robots.length; + const x = new Array(n); + for (let i = 0; i < n; i++) x[i] = [robots[i], d[i]]; + walls.sort((a, b) => a - b); + x.sort((a, b) => a[0] - b[0]); + x.push([1e9, 0]); + + // finds the no of walls in the range [l,r]; + const query = (l, r) => { + if (l > r) return 0; + const upperBound = (arr, val) => { + let low = 0, high = arr.length; + while (low < high) { + const mid = (low + high) >> 1; + if (arr[mid] <= val) low = mid + 1; + else high = mid; + } + return low; + }; + const lowerBound = (arr, val) => { + let low = 0, high = arr.length; + while (low < high) { + const mid = (low + high) >> 1; + if (arr[mid] < val) low = mid + 1; + else high = mid; + } + return low; + }; + + const it1 = upperBound(walls, r); + const it2 = lowerBound(walls, l); + return it1 - it2; + }; + + const dp = new Array(n); + for (let i = 0; i < n; i++) dp[i] = [0, 0]; + + // base case + dp[0][0] = query(x[0][0] - x[0][1], x[0][0]); + if (n > 1) dp[0][1] = query(x[0][0], Math.min(x[1][0] - 1, x[0][0] + x[0][1])); + else dp[0][1] = query(x[0][0], x[0][0] + x[0][1]); + + // transition + for (let i = 1; i < n; i++) { + dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0]) + query(x[i][0], Math.min(x[i + 1][0] - 1, x[i][0] + x[i][1])); + + dp[i][0] = dp[i - 1][0] + query(Math.max(x[i][0] - x[i][1], x[i - 1][0] + 1), x[i][0]); + const res = dp[i - 1][1] + + query(Math.max(x[i][0] - x[i][1], x[i - 1][0] + 1), x[i][0]) + - query(Math.max(x[i][0] - x[i][1], x[i - 1][0] + 1), Math.min(x[i - 1][0] + x[i - 1][1], x[i][0] - 1)); + dp[i][0] = Math.max(res, dp[i][0]); + } + return Math.max(dp[n - 1][0], dp[n - 1][1]); +}; diff --git a/3665-twisted-mirror-path-count.js b/3665-twisted-mirror-path-count.js new file mode 100644 index 00000000..41051520 --- /dev/null +++ b/3665-twisted-mirror-path-count.js @@ -0,0 +1,43 @@ +const mod = 1e9 + 7 +/** + * @param {number[][]} grid + * @return {number} + */ +var uniquePaths = function (grid) { + const n = grid.length + const m = grid[0].length + + const dp = Array.from({ length: n }, () => + Array.from({ length: m }, () => Array(2).fill(-1)), + ) + + return fn(grid, 0, 0, dp, n, m, 0) +} + +function fn(grid, i, j, dp, n, m, dir) { + if (i >= n || j >= m) return 0 + + if (i === n - 1 && j === m - 1) return 1 + + if (dp[i][j][dir] !== -1) return dp[i][j][dir] + + if (grid[i][j] === 1) { + if (dir === 1) { + return fn(grid, i + 1, j, dp, n, m, 0) + } else if (dir === 0) { + return fn(grid, i, j + 1, dp, n, m, 1) + } + } + + let move = 0 + if (j + 1 < m && (grid[i][j + 1] === 0 || grid[i][j + 1] === 1)) { + move += fn(grid, i, j + 1, dp, n, m, 1) + } + + if (i + 1 < n && (grid[i + 1][j] === 0 || grid[i + 1][j] === 1)) { + move += fn(grid, i + 1, j, dp, n, m, 0) + } + + dp[i][j][dir] = move % mod + return dp[i][j][dir] +} diff --git a/3666-minimum-operations-to-equalize-binary-string.js b/3666-minimum-operations-to-equalize-binary-string.js new file mode 100644 index 00000000..934378bb --- /dev/null +++ b/3666-minimum-operations-to-equalize-binary-string.js @@ -0,0 +1,33 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +var minOperations = function(s, k) { + const N = s.length; + const Z = [...s].filter(c => c === '0').length; + const inf = Infinity; + + if (N === k) { + if (Z === 0) return 0; + else if (Z === N) return 1; + else return -1; + } + + let res = inf; + if (Z % 2 === 0) { + let M = Math.max(ceil(Z, k), ceil(Z, N - k)); + M += M & 1; + res = Math.min(res, M); + } + if (Z % 2 === k % 2) { + let M = Math.max(ceil(Z, k), ceil(N - Z, N - k)); + M += (M & 1) === 0 ? 1 : 0; + res = Math.min(res, M); + } + + return res < inf ? res : -1; +}; +function ceil(x, y) { + return Math.floor((x + y - 1) / y); +} diff --git a/367-valid-perfect-square.js b/367-valid-perfect-square.js index 35afcc3a..a1597424 100644 --- a/367-valid-perfect-square.js +++ b/367-valid-perfect-square.js @@ -2,24 +2,15 @@ * @param {number} num * @return {boolean} */ - const isPerfectSquare = function(num) { - let lo = 1 - let hi = num - let mid - let val - while(lo <= hi) { - mid = (lo + hi) >>> 1 - val = mid * mid - if (val === num) { - return true - } - if (val < num) { - lo = mid + 1 - } - if (val > num) { - hi = mid - 1 - } - } - return false + let s = 0 + let e = num + while(s <= e) { + const mid = s + ((e - s) >> 1) + const res = mid ** 2 + if(res === num) return true + if(res < num) s = mid + 1 + else e = mid - 1 + } + return false }; diff --git a/3670-maximum-product-of-two-integers-with-no-common-bits.js b/3670-maximum-product-of-two-integers-with-no-common-bits.js new file mode 100644 index 00000000..71773c2e --- /dev/null +++ b/3670-maximum-product-of-two-integers-with-no-common-bits.js @@ -0,0 +1,29 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var maxProduct = function(nums) { + const max_n = Math.max(...nums) + const msb = Math.floor(Math.log2(max_n)) + const maxMask = (1 << (msb + 1)) - 1 + const dp = new Array(maxMask + 1).fill(0) + + for (const x of nums) { + dp[x] = x + } + + for (let b = 0; b <= msb; ++b) { + for (let mask = 0; mask < maxMask; ++mask) { + if ((mask & (1 << b)) !== 0) { + dp[mask] = Math.max(dp[mask], dp[mask ^ (1 << b)]) + } + } + } + + let res = 0n + for (const n of nums) { + res = BigInt(Math.max(Number(res), n * dp[maxMask ^ n])) + } + + return Number(res) +}; diff --git a/3677-count-binary-palindromic-numbers.js b/3677-count-binary-palindromic-numbers.js new file mode 100644 index 00000000..19d1903c --- /dev/null +++ b/3677-count-binary-palindromic-numbers.js @@ -0,0 +1,125 @@ +/** + * @param {number} n + * @return {number} + */ +var countBinaryPalindromes = function (n) { + n = BigInt(n) + if (n === 0n) return 1 + const maxLen = Math.floor(Math.log2(Number(n))) + 1 + + let ret = 1n + for (let L = 1; L < maxLen; L++) { + const h = Math.floor((L + 1) / 2) + const mn = 1n << BigInt(h - 1) + const mx = (1n << BigInt(h)) - 1n + ret += mx - mn + 1n + } + + + const L = maxLen + const h = Math.floor((L + 1) / 2) + const mn = 1n << BigInt(h - 1) + const mx = (1n << BigInt(h)) - 1n + let lo = mn, + hi = mx + while (lo < hi) { + const mid = hi - (hi - lo) / 2n + const pal = build(mid, L) + if (pal <= n) { + lo = mid + } else { + hi = mid - 1n + } + } + const pal = build(hi, L) + if (pal <= n) ret += hi - mn + 1n + + + return Number(ret) +} +function reverseBits(x) { + let r = 0n + while (x > 0n) { + r = r * 2n + (x & 1n) + x >>= 1n + } + return r +} + +function build(half, L) { + const h = Math.floor((L + 1) / 2) + const k = L - h + if (L % 2 === 0) { + return (half << BigInt(k)) | reverseBits(half) + } else { + return (half << BigInt(k)) | reverseBits(half >> 1n) + } +} + + + +// another + + +/** + * @param {number} n + * @return {number} + */ +var countBinaryPalindromes = function (n) { + let dp = [] + let built = false + n = BigInt(n) + + if (!built) { + dp = new Array(56).fill(0) + dp[1] = 1 + dp[2] = 1 + for (let i = 3; i <= 55; i++) dp[i] = 2 * dp[i - 2] + built = true + } + + let maxbit = bit(n) + if (maxbit === -1) return 1 + let len = maxbit + 1 + + let count = 1 + for (let i = 1; i < len; i++) count += dp[i] + + let half = Math.floor((len + 1) / 2) + let start = 1n << BigInt(half - 1) + let end = (1n << BigInt(half)) - 1n + + let lo = start, + hi = end, + best = start - 1n + while (lo <= hi) { + let mid = (lo + hi) >> 1n + let pal = makePal(mid, len) + if (pal <= n) { + best = mid + lo = mid + 1n + } else { + hi = mid - 1n + } + } + + if (best >= start) count += Number(best - start + 1n) + return count + + function bit(num) { + for (let i = 63; i >= 0; i--) { + if ((num & (1n << BigInt(i))) !== 0n) return i + } + return -1 + } + + function makePal(p, len) { + let pal = p + let q = len % 2 === 0 ? p : p >> 1n + while (q > 0n) { + pal = (pal << 1n) | (q & 1n) + q >>= 1n + } + return pal + } +} diff --git a/368-largest-divisible-subset.js b/368-largest-divisible-subset.js index 88760122..bd74d95a 100644 --- a/368-largest-divisible-subset.js +++ b/368-largest-divisible-subset.js @@ -1,3 +1,37 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const largestDivisibleSubset = function(nums) { + const n = nums.length; + if(n === 0 || n === 1) return nums + let maxSize = 0; + const dp = Array(n).fill(1) + nums.sort((a, b) => a - b) + for(let i = 1; i < n; i++) { + for(let j = i - 1; j >= 0; j--) { + if(nums[i] % nums[j] === 0) { + const tmp = dp[j] + 1 + if(tmp > dp[i]) dp[i] = tmp + } + } + if(dp[i] > maxSize) maxSize = dp[i] + } + const res = [] + let pivot = 0 + for(let i = n - 1; i >= 0; i--) { + if(dp[i] === maxSize && (pivot % nums[i] === 0)) { + pivot = nums[i] + maxSize-- + res.push(nums[i]) + } + } + + return res +}; + +// another + /** * @param {number[]} nums * @return {number[]} diff --git a/3685-subsequence-sum-after-capping-elements.js b/3685-subsequence-sum-after-capping-elements.js new file mode 100644 index 00000000..55371234 --- /dev/null +++ b/3685-subsequence-sum-after-capping-elements.js @@ -0,0 +1,74 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {boolean[]} + */ +var subsequenceSumAfterCapping = function(nums, k) { + const n = nums.length + nums.sort((a, b) => a - b) + + const dp = Array.from({ length: n + 1 }, () => Array(k + 1).fill(false)) + + // Base cases + for (let i = 0; i <= n; i++) { + dp[i][0] = true + } + + // Classic subset-sum started + for (let i = 1; i <= n; i++) { + for (let j = 1; j <= k; j++) { + if (nums[i - 1] <= j) { + dp[i][j] = dp[i - 1][j - nums[i - 1]] || dp[i - 1][j] + } else { + dp[i][j] = dp[i - 1][j] + } + } + } + // Classic subset-sum finished + + const ans = [] + + // Helper function for upper_bound equivalent in JS + function upperBound(arr, target) { + let left = 0, + right = arr.length + while (left < right) { + const mid = Math.floor((left + right) / 2) + if (arr[mid] <= target) { + left = mid + 1 + } else { + right = mid + } + } + return left + } + + for (let x = 1; x <= n; x++) { + const it = upperBound(nums, x) + + if (it === nums.length) { + // if no element in nums is greater than x + ans.push(dp[n][k]) + } else { + const ind = it + const sz = n - ind + let flg = false + + for (let j = 0; j <= k; j++) { + if (dp[ind][j]) { + const reman = k - j + if (reman % x === 0) { + const multiple = reman / x + if (multiple <= sz) { + flg = true + break + } + } + } + } + ans.push(flg) + } + } + + return ans +}; diff --git a/369-plus-one-linked-list.js b/369-plus-one-linked-list.js new file mode 100644 index 00000000..23f754b5 --- /dev/null +++ b/369-plus-one-linked-list.js @@ -0,0 +1,65 @@ +/** + +Given a non-negative integer represented as non-empty a singly linked list of digits, plus one to the integer. +You may assume the integer do not contain any leading zero, except the number 0 itself. +The digits are stored such that the most significant digit is at the head of the list. + +Example : + +Input: [1,2,3] +Output: [1,2,4] + +*/ + +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const plusOne = function(head) { + const dummy = new ListNode(1) + dummy.next = head + const carry = plusOneRecursion(head) + return carry ? dummy : dummy.next +} +const plusOneRecursion = node => { + if (!node) return 1 + node.val += plusOneRecursion(node.next) + if (node.val > 9) { + node.val %= 10 + return 1 + } + return 0 +} + +// another + +/** + * @param {ListNode} head + * @return {ListNode} + */ +const plusOne = function(head) { + const dummy = new ListNode(0) + dummy.next = head + let node = head + let lastNotNine = dummy + while(node) { + if(node.val !== 9) lastNotNine = node + node = node.next + } + lastNotNine.val++ + node = lastNotNine.next + while(node) { + node.val = 0 + node = node.next + } + return dummy.val === 1 ? dummy : dummy.next +} + + diff --git a/3696-minimum-time-to-activate-string.js b/3696-minimum-time-to-activate-string.js new file mode 100644 index 00000000..5430231e --- /dev/null +++ b/3696-minimum-time-to-activate-string.js @@ -0,0 +1,43 @@ +/** + * @param {string} s + * @param {number[]} order + * @param {number} k + * @return {number} + */ +var minTime = function(s, order, k) { + const len = order.length + let l = 0, r = len + const {floor: flr} = Math + while(l < r) { + const mid = flr((l + r) / 2) + if(isOK(mid)) r = mid + else l = mid + 1 + } + + return l >= len ? -1 : l + + function isOK(t) { + const n = s.length + + const isStar = Array(n).fill(false) + let inValid = 0, segLen = 0 + + for(let i = 0; i <= t; i++) isStar[order[i]] = true + + for(let i = 0; i < n; i++) { + if(isStar[i]) { + inValid += segLen * (segLen + 1) / 2 + segLen = 0 + } else { + segLen++ + } + } + + if(segLen) inValid += segLen * (segLen + 1) / 2 + + const all = n * (n + 1) / 2 + + const valid = all - inValid + return valid >= k + } +}; diff --git a/3699-number-of-zigzag-arrays-i.js b/3699-number-of-zigzag-arrays-i.js new file mode 100644 index 00000000..54b15cc3 --- /dev/null +++ b/3699-number-of-zigzag-arrays-i.js @@ -0,0 +1,28 @@ +/** + * @param {number} n + * @param {number} l + * @param {number} r + * @return {number} + */ +var zigZagArrays = function(n, l, r) { + r -= l; + let dp = new Array(r + 1).fill(1); + const mod = 10 ** 9 + 7; + for (let i = 1; i < n; i++) { + let pre = 0; + if (i & 1) { + for (let v = 0; v <= r; v++) { + let pre2 = pre + dp[v]; + dp[v] = pre; + pre = pre2 % mod; + } + } else { + for (let v = r; v >= 0; v--) { + let pre2 = pre + dp[v]; + dp[v] = pre; + pre = pre2 % mod; + } + } + } + return (dp.reduce((a, b) => a + b, 0) * 2) % mod; +}; diff --git a/37-sudoku-solver.js b/37-sudoku-solver.js index 5e20d0a4..b057ce6e 100644 --- a/37-sudoku-solver.js +++ b/37-sudoku-solver.js @@ -34,3 +34,39 @@ const solveSudoku = function(board) { return true } } + + +// another + +/** + * @param {character[][]} board + * @return {void} Do not return anything, modify board in-place instead. + */ +const solveSudoku = function(board) { + helper(board, 0 , 0) +}; + +function helper(board, row, col) { + if(row >= 9) return true + if(col >= 9) return helper(board, row + 1, 0) + if(board[row][col] !== '.') return helper(board, row, col + 1) + for(let i = 1; i <= 9; i++) { + const ch = `${i}` + if(valid(board, row, col, ch)) { + board[row][col] = ch + if(helper(board, row, col + 1)) return true + board[row][col] = '.' + } + } + return false +} + +function valid(board, row, col, ch) { + const blkRow = ~~(row / 3), blkCol = ~~(col / 3) + for(let i = 0; i < 9; i++) { + if(board[row][i] === ch) return false + if(board[i][col] === ch) return false + if(board[blkRow * 3 + Math.floor(i / 3)][blkCol * 3 + (i % 3)] === ch) return false + } + return true +} diff --git a/370-range-addition.js b/370-range-addition.js new file mode 100644 index 00000000..979178db --- /dev/null +++ b/370-range-addition.js @@ -0,0 +1,47 @@ +/** + +Assume you have an array of length n initialized with all 0's and are given k update operations. +Each operation is represented as a triplet: +[startIndex, endIndex, inc] which increments each element of +subarray A[startIndex ... endIndex] (startIndex and endIndex inclusive) with inc. + +Return the modified array after all k operations were executed. + +Example: + +Input: length = 5, updates = [[1,3,2],[2,4,3],[0,2,-2]] +Output: [-2,0,3,5,3] +Explanation: + +Initial state: +[0,0,0,0,0] + +After applying operation [1,3,2]: +[0,2,2,2,0] + +After applying operation [2,4,3]: +[0,2,5,5,3] + +After applying operation [0,2,-2]: +[-2,0,3,5,3] + +*/ +/** + * @param {number} length + * @param {number[][]} updates + * @return {number[]} + */ +const getModifiedArray = function(length, updates) { + const res = new Array(length).fill(0) + for (let update of updates) { + const [start, end, value] = update + res[start] += value + if (end < length - 1) res[end + 1] -= value + } + let sum = 0 + for (let i = 0; i < length; i++) { + sum += res[i] + res[i] = sum + } + return res +} diff --git a/372-super-pow.js b/372-super-pow.js new file mode 100644 index 00000000..f0c6473f --- /dev/null +++ b/372-super-pow.js @@ -0,0 +1,17 @@ +/** + * @param {number} a + * @param {number[]} b + * @return {number} + */ +const superPow = function(a, b) { + const base = 1337 + function powmod(a, k) { + a %= base + let res = 1 + for(let i = 0; i < k; i++) res = res * a % base + return res + } + if(b.length === 0) return 1 + const last = b.pop() + return powmod(superPow(a, b), 10) * powmod(a, last) % base +}; diff --git a/373-find-k-pairs-with-smallest-sums.js b/373-find-k-pairs-with-smallest-sums.js new file mode 100644 index 00000000..35fd1146 --- /dev/null +++ b/373-find-k-pairs-with-smallest-sums.js @@ -0,0 +1,127 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number[][]} + */ +const kSmallestPairs = function (nums1, nums2, k) { + const pq = new PriorityQueue((a, b) => a[0] + a[1] < b[0] + b[1]) + for(let i = 0; i < nums1.length && i < k; i++) { + pq.push([nums1[i], nums2[0], 0]) + } + const res = [] + while(k > 0 && !pq.isEmpty()) { + const [e1, e2, e2i] = pq.pop() + res.push([e1, e2]) + if(e2i + 1 < nums2.length) pq.push([e1, nums2[e2i + 1], e2i + 1]) + k-- + } + + return res +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number[][]} + */ +const kSmallestPairs = function(nums1, nums2, k) { + let len1 = nums1.length, + len2 = nums2.length + let arr = Array(len1).fill(0), + resList = [] + while (k-- > 0) { + let min = Infinity, + index = -1, + lastj = Infinity + for (let i = 0; i < len1; i++) { + const j = arr[i] + if (j < lastj && j < len2) { + const sum = nums1[i] + nums2[j] + if (sum < min) { + min = sum + index = i + } + lastj = j + } + } + if (index == -1) { + break + } + resList.push([nums1[index], nums2[arr[index]]]) + arr[index]++ + } + return resList +} diff --git a/375-guess-number-higher-or-lower-ii.js b/375-guess-number-higher-or-lower-ii.js new file mode 100644 index 00000000..fa83a99c --- /dev/null +++ b/375-guess-number-higher-or-lower-ii.js @@ -0,0 +1,43 @@ +/** + +We are playing the Guess Game. The game is as follows: +I pick a number from 1 to n. You have to guess which number I picked. +Every time you guess wrong, I'll tell you whether the number I picked is higher or lower. +However, when you guess a particular number x, and you guess wrong, you pay $x. +You win the game when you guess the number I picked. + +Example: + +n = 10, I pick 8. + +First round: You guess 5, I tell you that it's higher. You pay $5. +Second round: You guess 7, I tell you that it's higher. You pay $7. +Third round: You guess 9, I tell you that it's lower. You pay $9. + +Game over. 8 is the number I picked. + +You end up paying $5 + $7 + $9 = $21. +Given a particular n ≥ 1, find out how much money you need to have to guarantee a win. + +*/ + +/** + * @param {number} n + * @return {number} + */ +const getMoneyAmount = function(n) { + const dp = Array.from({length: n + 1}, () => new Array(n + 1).fill(0)) + return helper(dp, 1, n) +}; + +function helper(dp, s, e) { + if(s >= e) return 0 + if(dp[s][e] !== 0) return dp[s][e] + let res = Number.MAX_VALUE + for(let i = s; i <= e; i++) { + const tmp = i + Math.max(helper(dp, s, i - 1), helper(dp, i + 1, e)) + res = Math.min(res, tmp) + } + dp[s][e] = res + return res +} diff --git a/379-design-phone-directory.js b/379-design-phone-directory.js new file mode 100644 index 00000000..eb78f5b1 --- /dev/null +++ b/379-design-phone-directory.js @@ -0,0 +1,51 @@ +/** + * Initialize your data structure here + @param maxNumbers - The maximum numbers that can be stored in the phone directory. + * @param {number} maxNumbers + */ +const PhoneDirectory = function(maxNumbers) { + this.len = maxNumbers + this.used = new Set() + this.free = [] +} + +/** + * Provide a number which is not assigned to anyone. + @return - Return an available number. Return -1 if none is available. + * @return {number} + */ +PhoneDirectory.prototype.get = function() { + if (this.used.size === this.len) return -1 + const tmp = this.free.length === 0 ? this.used.size : this.free.pop() + this.used.add(tmp) + return tmp +} + +/** + * Check if a number is available or not. + * @param {number} number + * @return {boolean} + */ +PhoneDirectory.prototype.check = function(number) { + return !this.used.has(number) +} + +/** + * Recycle or release a number. + * @param {number} number + * @return {void} + */ +PhoneDirectory.prototype.release = function(number) { + if(this.used.has(number)) { + this.used.delete(number) + this.free.push(number) + } +} + +/** + * Your PhoneDirectory object will be instantiated and called as such: + * var obj = new PhoneDirectory(maxNumbers) + * var param_1 = obj.get() + * var param_2 = obj.check(number) + * obj.release(number) + */ diff --git a/38-count-and-say.js b/38-count-and-say.js new file mode 100644 index 00000000..b02b84ec --- /dev/null +++ b/38-count-and-say.js @@ -0,0 +1,21 @@ +/** + * @param {number} n + * @return {string} + */ +const countAndSay = function(n) { + let str = '1' + for (let i = 2; i <= n; i++) { + let tempStr = '' + let count = 0 + for (let j = 0, m = str.length; j < m; j++) { + const char = str.charAt(j) + count += 1 + if (char !== str.charAt(j + 1)) { + tempStr += count + char + count = 0 + } + } + str = tempStr + } + return str +} diff --git a/380-insert-delete-getrandom-o1.js b/380-insert-delete-getrandom-o1.js index 3e663629..e4591798 100644 --- a/380-insert-delete-getrandom-o1.js +++ b/380-insert-delete-getrandom-o1.js @@ -1,51 +1,52 @@ /** * Initialize your data structure here. */ -const RandomizedSet = function() { - this.data = [] -}; +const RandomizedSet = function () { + this.arr = [] + this.map = new Map() +} /** - * Inserts a value to the set. Returns true if the set did not already contain the specified element. + * Inserts a value to the set. Returns true if the set did not already contain the specified element. * @param {number} val * @return {boolean} */ -RandomizedSet.prototype.insert = function(val) { - if(this.data.indexOf(val) === -1) { - this.data.push(val) - return true - } - return false -}; +RandomizedSet.prototype.insert = function (val) { + const {arr, map} = this + if(map.has(val)) return false + const size = arr.length + arr.push(val) + map.set(val, size) + return true +} /** - * Removes a value from the set. Returns true if the set contained the specified element. + * Removes a value from the set. Returns true if the set contained the specified element. * @param {number} val * @return {boolean} */ -RandomizedSet.prototype.remove = function(val) { - let idx = this.data.indexOf(val) - if(idx !== -1) { - this.data.splice(idx, 1) - return true - } - return false - -}; +RandomizedSet.prototype.remove = function (val) { + const {arr, map} = this + if(!map.has(val)) return false + const idx = map.get(val), last = arr[arr.length - 1] + arr[idx] = last + map.set(last, idx) + arr.pop() + map.delete(val) + return true +} /** * Get a random element from the set. * @return {number} */ -RandomizedSet.prototype.getRandom = function() { - const len = this.data.length - const idx = Math.floor(Math.random() * len) - return this.data[idx] -}; +RandomizedSet.prototype.getRandom = function () { + return this.arr[~~(this.arr.length * Math.random())] +} -/** +/** * Your RandomizedSet object will be instantiated and called as such: - * var obj = Object.create(RandomizedSet).createNew() + * var obj = new RandomizedSet() * var param_1 = obj.insert(val) * var param_2 = obj.remove(val) * var param_3 = obj.getRandom() diff --git a/381-insert-delete-getrandom-o1-duplicates-allowed.js b/381-insert-delete-getrandom-o1-duplicates-allowed.js new file mode 100644 index 00000000..3e907571 --- /dev/null +++ b/381-insert-delete-getrandom-o1-duplicates-allowed.js @@ -0,0 +1,61 @@ +/** + * Initialize your data structure here. + */ +const RandomizedCollection = function() { + this.map = new Map() + this.list = [] +} + +/** + * Inserts a value to the collection. Returns true if the collection did not already contain the specified element. + * @param {number} val + * @return {boolean} + */ +RandomizedCollection.prototype.insert = function(val) { + const index = this.list.length + const node = { val, index } + this.list[index] = node + + const nodeList = this.map.get(val) + const isNew = nodeList === undefined || nodeList.length === 0 + if (nodeList === undefined) { + this.map.set(val, [node]) + } else { + nodeList.push(node) + } + return isNew +} + +/** + * Removes a value from the collection. Returns true if the collection contained the specified element. + * @param {number} val + * @return {boolean} + */ +RandomizedCollection.prototype.remove = function(val) { + const nodeList = this.map.get(val) + if (!nodeList || nodeList.length === 0) return false + const node = nodeList.pop() + const replacement = this.list.pop() + if (replacement.index !== node.index) { + replacement.index = node.index + this.list[replacement.index] = replacement + } + return true +} + +/** + * Get a random element from the collection. + * @return {number} + */ +RandomizedCollection.prototype.getRandom = function() { + const index = Math.floor(Math.random() * this.list.length) + return this.list[index].val +} + +/** + * Your RandomizedCollection object will be instantiated and called as such: + * var obj = new RandomizedCollection() + * var param_1 = obj.insert(val) + * var param_2 = obj.remove(val) + * var param_3 = obj.getRandom() + */ diff --git a/383-ransom-note.js b/383-ransom-note.js index 7629066e..81ad0d58 100755 --- a/383-ransom-note.js +++ b/383-ransom-note.js @@ -4,16 +4,13 @@ * @return {boolean} */ const canConstruct = function(ransomNote, magazine) { - const rArr = ransomNote.split(""); - const mArr = magazine.split(""); - let idx; - for (let i = 0; i < rArr.length; i++) { - idx = mArr.indexOf(rArr[i]); - if (idx === -1) { - return false; - } else { - mArr.splice(idx, 1); - } + const m = new Map() + for(let c of magazine) { + m.set(c, (m.get(c) || 0) + 1 ) } - return true; + for(let c of ransomNote) { + if(!m.has(c) || m.get(c) <= 0) return false + m.set(c, m.get(c) - 1) + } + return true }; diff --git a/385-mini-parser.js b/385-mini-parser.js new file mode 100644 index 00000000..280bff05 --- /dev/null +++ b/385-mini-parser.js @@ -0,0 +1,69 @@ +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * function NestedInteger() { + * + * Return true if this NestedInteger holds a single integer, rather than a nested list. + * @return {boolean} + * this.isInteger = function() { + * ... + * }; + * + * Return the single integer that this NestedInteger holds, if it holds a single integer + * Return null if this NestedInteger holds a nested list + * @return {integer} + * this.getInteger = function() { + * ... + * }; + * + * Set this NestedInteger to hold a single integer equal to value. + * @return {void} + * this.setInteger = function(value) { + * ... + * }; + * + * Set this NestedInteger to hold a nested list and adds a nested integer elem to it. + * @return {void} + * this.add = function(elem) { + * ... + * }; + * + * Return the nested list that this NestedInteger holds, if it holds a nested list + * Return null if this NestedInteger holds a single integer + * @return {NestedInteger[]} + * this.getList = function() { + * ... + * }; + * }; + */ +/** + * @param {string} s + * @return {NestedInteger} + */ +const deserialize = function(s) { + const recursion = s => { + const re = new NestedInteger() + if (!s || s.length === 0) { + return re + } + if (s.charAt(0) !== '[') { + re.setInteger(parseInt(s, 10)) + } else if (s.length > 2) { + let start = 1 + let cnt = 0 + for (let i = 1; i < s.length; i++) { + const char = s.charAt(i) + if (cnt === 0 && (char === ',' || i === s.length - 1)) { + re.add(recursion(s.substring(start, i))) + start = i + 1 + } else if (char === '[') { + cnt++ + } else if (char === ']') { + cnt-- + } + } + } + return re + } + return recursion(s) +} diff --git a/386-lexicographical-numbers.js b/386-lexicographical-numbers.js new file mode 100644 index 00000000..d593eb57 --- /dev/null +++ b/386-lexicographical-numbers.js @@ -0,0 +1,61 @@ +/** + * @param {number} n + * @return {number[]} + */ +const lexicalOrder = function(n) { + const res = [] + for(let i = 1; i < 10; i++) { + dfs(i) + } + + return res + + function dfs(num) { + if(num > n) return + res.push(num) + for(let i = 0; i < 10; i++) { + const tmp = num * 10 + i + if(tmp > n) return + dfs(tmp) + } + } +}; + +// another + +/** + * @param {number} n + * @return {number[]} + */ +const lexicalOrder = function(n) { + const result = [] + for (let i = 1; i < 10; i++) { + dfs(i) + } + function dfs(n) { + if (n <= num) result.push(n) + if (10 * n <= num) { + for (let j = 0; j < 10; j++) { + dfs(10 * n + j) + } + } + } + return result +} + +// another + +const lexicalOrder = function(n) { + function getNumberByOrder(start, end) { + for (let i = start; i <= end; i++) { + if (i > n) { + break + } + res.push(i) + getNumberByOrder(i * 10, i * 10 + 9) + } + } + const res = [] + getNumberByOrder(1, 9) + return res +} diff --git a/387-first-unique-character-in-a-string.js b/387-first-unique-character-in-a-string.js index f20370df..b03d0169 100755 --- a/387-first-unique-character-in-a-string.js +++ b/387-first-unique-character-in-a-string.js @@ -26,3 +26,23 @@ const firstUniqChar = function(s) { } return res[0] == null ? -1 : res[0]; }; + +// another + +/** + * @param {string} s + * @return {number} + */ +const firstUniqChar = function(s) { + if(s === '') return -1 + const map = new Map() + for(let i = 0, len = s.length; i < len; i++) { + if(!map.has(s[i])) map.set(s[i], [i, 0]) + map.get(s[i])[1] += 1 + } + for(let [key, val] of map) { + if(val[1] === 1) return val[0] + } + return -1 + +}; diff --git a/388-longest-absolute-file-path.js b/388-longest-absolute-file-path.js new file mode 100644 index 00000000..546a6e6c --- /dev/null +++ b/388-longest-absolute-file-path.js @@ -0,0 +1,12 @@ +/** + * @param {string} input + * @return {number} + */ +const lengthLongestPath = function(input) { + const stack = [] + return input.split('\n').reduce((max, p) => { + const level = p.lastIndexOf('\t') + 1 + stack[level] = p.length - level + (level ? stack[level - 1] : 0) + return p.indexOf('.') === -1 ? max : Math.max(max, stack[level] + level) + }, 0) +} diff --git a/390-elimination-game.js b/390-elimination-game.js new file mode 100644 index 00000000..06b3803a --- /dev/null +++ b/390-elimination-game.js @@ -0,0 +1,19 @@ +/** + * @param {number} n + * @return {number} + */ +const lastRemaining = function(n) { + let left = true + let remaining = n + let step = 1 + let head = 1 + while (remaining > 1) { + if (left || remaining % 2 === 1) { + head = head + step + } + remaining = remaining >> 1 + step = step * 2 + left = !left + } + return head +} diff --git a/391-perfect-rectangle.js b/391-perfect-rectangle.js index a6b001fa..d58a967f 100644 --- a/391-perfect-rectangle.js +++ b/391-perfect-rectangle.js @@ -21,3 +21,35 @@ const isRectangleCover = function(rectangles) { } return tls.size === 1 && trs.size === 1 && bls.size === 1 && brs.size === 1 } + +// another + +/** + * @param {number[][]} rectangles + * @return {boolean} + */ +var isRectangleCover = function(rectangles) { + const n = rectangles.length + const rects = rectangles, set = new Set() + let area = 0 + const p = (x, y) => `${x},${y}` + let xmin = Infinity, xmax = -Infinity, ymin = Infinity, ymax = -Infinity + for(const [x,y,a,b] of rects) { + xmin = Math.min(xmin, x) + xmax = Math.max(xmax, a) + ymin = Math.min(ymin, y) + ymax = Math.max(ymax, b) + area += (a - x) * (b - y) + const p0 = p(x,y), p1 = p(a,b),p2=p(x,b),p3=p(a,y) + if(set.has(p0)) set.delete(p0) + else set.add(p0) + if(set.has(p1)) set.delete(p1) + else set.add(p1) + if(set.has(p2)) set.delete(p2) + else set.add(p2) + if(set.has(p3)) set.delete(p3) + else set.add(p3) + } + if(set.size !== 4 || !set.has(p(xmin, ymin)) || !set.has(p(xmax, ymax)) || !set.has(p(xmin, ymax)) || !set.has(p(xmax, ymin)) ) return false + return area === (xmax - xmin) * (ymax - ymin) +}; diff --git a/392-is-subsequence.js b/392-is-subsequence.js index 3b76989c..46fe3361 100644 --- a/392-is-subsequence.js +++ b/392-is-subsequence.js @@ -1,3 +1,22 @@ +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +const isSubsequence = function(s, t) { + const sl = s.length + const tl = t.length + if(sl > tl) return false + if(sl === 0) return true + let si = 0 + for(let i = 0; i < tl && si < sl; i++) { + if(s[si] === t[i]) si++ + } + return si === sl +}; + +// another + /** * @param {string} s * @param {string} t diff --git a/393-utf-8-validation.js b/393-utf-8-validation.js new file mode 100644 index 00000000..8155ecee --- /dev/null +++ b/393-utf-8-validation.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} data + * @return {boolean} + */ +const validUtf8 = function(data) { + let count = 0 + for (let c of data) { + if (count === 0) { + if (c >> 5 === 0b110) count = 1 + else if (c >> 4 === 0b1110) count = 2 + else if (c >> 3 === 0b11110) count = 3 + else if (c >> 7) return false + } else { + if (c >> 6 !== 0b10) return false + count-- + } + } + return count == 0 +} diff --git a/395-longest-substring-with-at-least-k-repeating-characters.js b/395-longest-substring-with-at-least-k-repeating-characters.js index 5eb40cab..09bdf3ff 100644 --- a/395-longest-substring-with-at-least-k-repeating-characters.js +++ b/395-longest-substring-with-at-least-k-repeating-characters.js @@ -3,28 +3,28 @@ * @param {number} k * @return {number} */ -const longestSubstring = function(s, k) { - if (s == null || s.length === 0) return 0; - const chars = new Array(26).fill(0); - const aCode = "a".charCodeAt(0); - for (let i = 0; i < s.length; i++) chars[s.charCodeAt(i) - aCode] += 1; - let flag = true; +const longestSubstring = function (s, k) { + if (s == null || s.length === 0) return 0 + const chars = new Array(26).fill(0) + const aCode = 'a'.charCodeAt(0) + for (let i = 0; i < s.length; i++) chars[s.charCodeAt(i) - aCode] += 1 + let flag = true for (let i = 0; i < chars.length; i++) { - if (chars[i] < k && chars[i] > 0) flag = false; + if (chars[i] < k && chars[i] > 0) flag = false } if (flag === true) { - return s.length; + return s.length } - let result = 0; - let start = 0; - let cur = 0; + let result = 0 + let start = 0 + let cur = 0 while (cur < s.length) { if (chars[s.charCodeAt(cur) - aCode] < k) { - result = Math.max(result, longestSubstring(s.slice(start, cur), k)); - start = cur + 1; + result = Math.max(result, longestSubstring(s.slice(start, cur), k)) + start = cur + 1 } - cur++; + cur++ } - result = Math.max(result, longestSubstring(s.slice(start), k)); - return result; -}; + result = Math.max(result, longestSubstring(s.slice(start), k)) + return result +} diff --git a/369-rotate-function.js b/396-rotate-function.js similarity index 100% rename from 369-rotate-function.js rename to 396-rotate-function.js diff --git a/4-median-of-two-sorted-arrays.js b/4-median-of-two-sorted-arrays.js index 5cde4582..095350b7 100755 --- a/4-median-of-two-sorted-arrays.js +++ b/4-median-of-two-sorted-arrays.js @@ -1,3 +1,40 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const findMedianSortedArrays = function(nums1, nums2) { + if(nums1.length > nums2.length) return findMedianSortedArrays(nums2, nums1) + const m = nums1.length, n = nums2.length + let low = 0, high = m + while(low <= high) { + + const px = Math.floor((low + high) / 2) + const py = Math.floor(( m + n + 1 ) / 2) - px + + const maxLeft1 = px === 0 ? -Infinity : nums1[px - 1] + const minRight1 = px === m ? Infinity : nums1[px] + + const maxLeft2 = py === 0 ? -Infinity : nums2[py - 1] + const minRight2 = py === n ? Infinity : nums2[py] + + if(maxLeft1 <= minRight2 && maxLeft2 <= minRight1) { + if((m + n) % 2 === 0) { + return (Math.max(maxLeft1, maxLeft2) + Math.min(minRight1, minRight2)) / 2 + } else { + return Math.max(maxLeft1, maxLeft2) + } + } else if(maxLeft1 > minRight2) { + high = px - 1 + } else { + low = px + 1 + } + + } +}; + +// another + /** * @param {number[]} A * @param {number[]} B @@ -47,3 +84,50 @@ const findMedianSortedArrays = function(A, B) { } } }; + +// another + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +const findMedianSortedArrays = function (nums1, nums2) { + if (nums1.length > nums2.length) { + return findMedianSortedArrays(nums2, nums1) + } + const x = nums1.length + const y = nums2.length + + let low = 0 + let high = x + + while (low <= high) { + const partX = Math.floor((low + high) / 2) + const partY = Math.floor((x + y + 1) / 2) - partX + + const maxX = partX === 0 ? Number.NEGATIVE_INFINITY : nums1[partX - 1] + const maxY = partY === 0 ? Number.NEGATIVE_INFINITY : nums2[partY - 1] + + const minX = + partX === nums1.length ? Number.POSITIVE_INFINITY : nums1[partX] + const minY = + partY === nums2.length ? Number.POSITIVE_INFINITY : nums2[partY] + + if (maxX <= minY && maxY <= minX) { + const lowMax = Math.max(maxX, maxY) + + if ((x + y) % 2 == 1) { + return Math.max(maxX, maxY) + } else { + return (Math.max(maxX, maxY) + Math.min(minX, minY)) / 2 + } + } else if (maxX < minY) { + low = partX + 1 + } else { + high = partX - 1 + } + } +} + + diff --git a/400-nth-digit.js b/400-nth-digit.js index 59e4a928..53f0f393 100644 --- a/400-nth-digit.js +++ b/400-nth-digit.js @@ -3,16 +3,16 @@ * @return {number} */ const findNthDigit = function(n) { - let start = 1 - let len = 1 - let base = 9 - while(n > len * base) { - n = n - len * base - len++ - start *= 10 - base *= 10 - } - let target = start + (n - 1) / len - let reminder = (n - 1) % len - return (''+target).charAt(reminder) + let start = 1 + let len = 1 + let base = 9 + while(n > len * base) { + n = n - len * base + len++ + start *= 10 + base *= 10 + } + let target = start + Math.floor((n - 1) / len) + let reminder = (n - 1) % len + return (''+target).charAt(reminder) }; diff --git a/401-binary-watch.js b/401-binary-watch.js new file mode 100644 index 00000000..07014e53 --- /dev/null +++ b/401-binary-watch.js @@ -0,0 +1,17 @@ +/** + * @param {number} num + * @return {string[]} + */ +const readBinaryWatch = function(num) { + const output = [] + for (let h = 0; h < 12; h++) { + for (let m = 0; m < 60; m++) { + const ones = Number(h * 64 + m) + .toString(2) + .split('') + .filter(d => d === '1').length + if (ones === num) output.push(m < 10 ? `${h}:0${m}` : `${h}:${m}`) + } + } + return output +} diff --git a/402-remove-k-digits.js b/402-remove-k-digits.js index 21d8bcfd..21ef2e47 100644 --- a/402-remove-k-digits.js +++ b/402-remove-k-digits.js @@ -24,3 +24,52 @@ const removeKdigits = function(num, k) { while (idx < digits && stk[idx] === "0") idx++; return idx === digits ? "0" : stk.slice(idx, digits + idx).join(""); }; + + +// another + +/** + * @param {string} num + * @param {number} k + * @return {string} + */ +const removeKdigits = function(num, k) { + const n = num.length, stack = [] + if(n === k) return '0' + let i = 0 + while(i < n) { + while(k > 0 && stack.length && stack[stack.length - 1] > num[i]) { + k-- + stack.pop() + } + stack.push(num[i++]) + } + while(k-- > 0) stack.pop() + while(stack[0] === '0') stack.shift() + return stack.length ? stack.join('') : '0' +}; + +// another + +/** + * @param {string} num + * @param {number} k + * @return {string} + */ +const removeKdigits = function(num, k) { + const n = num.length, stack = [] + for(let i = 0; i < n; i++) { + const ch = num[i] + while(stack.length && k > 0 && ch < stack[stack.length - 1]) { + stack.pop() + k-- + } + stack.push(ch) + } + while(k > 0) { + stack.pop() + k-- + } + while(stack[0] === '0') stack.shift() + return stack.length ? stack.join('') : '0' +}; diff --git a/403-frog-jump.js b/403-frog-jump.js index 3b85b0c0..3fb75305 100644 --- a/403-frog-jump.js +++ b/403-frog-jump.js @@ -8,18 +8,18 @@ const canCross = function(stones) { return false } } - let count = new Set(stones) - let lastStone = stones[stones.length - 1] - let position = [0] - let jump = [0] + const count = new Set(stones) + const lastStone = stones[stones.length - 1] + const position = [0] + const jump = [0] while (position.length > 0) { - let nextPosition = position.pop() - let nextDistance = jump.pop() + const nextPosition = position.pop() + const nextDistance = jump.pop() for (let i = nextDistance - 1; i <= nextDistance + 1; i++) { if (i <= 0) { continue } - let nextStone = nextPosition + i + const nextStone = nextPosition + i if (nextStone == lastStone) { return true } else if (count.has(nextStone)) { diff --git a/404-sum-of-left-leaves.js b/404-sum-of-left-leaves.js new file mode 100644 index 00000000..348d6a82 --- /dev/null +++ b/404-sum-of-left-leaves.js @@ -0,0 +1,28 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const sumOfLeftLeaves = function(root) { + if(root == null) return 0 + let res = 0 + function dfs(node, side) { + if(node === null) return + if(node.left === null && node.right === null) { + if(side === 'left') res += node.val + return + } + dfs(node.left, 'left') + dfs(node.right, 'right') + } + dfs(root.left, 'left') + dfs(root.right, 'right') + + return res +}; diff --git a/406-queue-reconstruction-by-height.js b/406-queue-reconstruction-by-height.js index 3cf2cad5..67f9eba1 100755 --- a/406-queue-reconstruction-by-height.js +++ b/406-queue-reconstruction-by-height.js @@ -1,3 +1,20 @@ +/** + * @param {number[][]} people + * @return {number[][]} + */ +const reconstructQueue = function (people) { + const h = 0 + const k = 1 + people.sort((a, b) => (a[h] == b[h] ? a[k] - b[k] : b[h] - a[h])) + let queue = [] + for (let person of people) { + queue.splice(person[k], 0, person) + } + return queue +} + +// another + /** * @param {number[][]} people * @return {number[][]} diff --git a/407-trapping-rain-water-ii.js b/407-trapping-rain-water-ii.js index 92bdf871..31ef3c93 100644 --- a/407-trapping-rain-water-ii.js +++ b/407-trapping-rain-water-ii.js @@ -1,3 +1,349 @@ +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} +/** + * @param {number[][]} heightMap + * @return {number} + */ +const trapRainWater = function(heightMap) { + const pq = new PQ((a, b) => a[1] < b[1]) + const m = heightMap.length, n = heightMap[0].length + const visited = Array.from({ length: m }, () => Array(n).fill(false)) + for(let i = 0; i < m; i++) { + visited[i][0] = visited[i][n - 1] = true + pq.push([[i, 0], heightMap[i][0]]) + pq.push([[i, n - 1], heightMap[i][n - 1]]) + } + for(let j = 0; j < n; j++) { + visited[0][j] = visited[m - 1][j] = true + pq.push([[0, j], heightMap[0][j]]) + pq.push([[m - 1, j], heightMap[m - 1][j]]) + } + const dirs = [[1,0],[-1,0],[0,1],[0,-1]] + let res = 0 + while(!pq.isEmpty()) { + const [coord, h] = pq.pop() + const [r, c] = coord + for(const [dr, dc] of dirs) { + const nr = r + dr, nc = c + dc + if(nr >= 0 && nr < m && nc >= 0 && nc < n && !visited[nr][nc]) { + visited[nr][nc] = true + if (h > heightMap[nr][nc]) res += h - heightMap[nr][nc] + pq.push([[nr, nc], Math.max(heightMap[nr][nc], h)]) + } + } + }/* */ + return res +}; + +// another + +/** + * @param {number[][]} heightMap + * @return {number} + */ + +const trapRainWater = function (heightMap) { + const pq = new PriorityQueue((a, b) => a[2] < b[2]) + const m = heightMap.length, n = heightMap[0].length + + const visited = Array.from({ length: m }, () => Array(n).fill(false)) + + for(let i = 0; i < m; i++) { + visited[i][0] = visited[i][n - 1] = true + pq.push([i, 0, heightMap[i][0]]) + pq.push([i, n - 1, heightMap[i][n - 1]]) + } + for(let j = 1; j < n - 1; j++) { + visited[0][j] = visited[m - 1][j] = true + pq.push([0, j, heightMap[0][j]], [m - 1, j, heightMap[m - 1][j]]) + } + + let res = 0 + const dirs = [[-1, 0], [1, 0], [0, 1], [0, -1]] + while(!pq.isEmpty()) { + const cur = pq.pop() + const [r, c, h] = cur + for(let dir of dirs) { + const newR = r + dir[0], newC = c + dir[1] + if(newR < 0 || newR >= m || newC < 0 || newC >= n || visited[newR][newC]) continue + visited[newR][newC] = true + res += Math.max(0, h - heightMap[newR][newC]) + pq.push([newR, newC, Math.max(h, heightMap[newR][newC])]) + } + } + + return res + +} +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + + + +// another + +/** + * @param {number[][]} heightMap + * @return {number} + */ + +const trapRainWater = function (heightMap) { + const pq = new PriorityQueue((a, b) => a[2] < b[2]) + const visited = [] + for (let i = 0; i < heightMap.length; i++) { + visited[i] = [] + for (let j = 0; j < heightMap[0].length; j++) { + if ( + i > 0 && + i < heightMap.length - 1 && + j > 0 && + j < heightMap[0].length - 1 + ) + continue + pq.push([i, j, heightMap[i][j]]) + visited[i][j] = true + } + } + + let max = -Infinity, + count = 0 + while (!pq.isEmpty()) { + const cur = pq.pop() + if (cur[2] > max) max = cur[2] + check(cur[0], cur[1]) + } + function check(row, col) { + const step = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ] + for (let i = 0; i < step.length; i++) { + let newR = row + step[i][0], + newC = col + step[i][1] + if ( + newR < 0 || + newR >= heightMap.length || + newC < 0 || + newC >= heightMap[0].length + ) + continue + if (visited[newR][newC]) continue + visited[newR][newC] = true + const newVal = heightMap[newR][newC] + if (newVal < max) { + count += max - newVal + check(newR, newC) + } else { + pq.push([newR, newC, newVal]) + } + } + } + + return count +} +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + + +// another + /** * @param {number[][]} heightMap * @return {number} diff --git a/408-valid-word-abbreviation.js b/408-valid-word-abbreviation.js new file mode 100644 index 00000000..c9b27e3f --- /dev/null +++ b/408-valid-word-abbreviation.js @@ -0,0 +1,58 @@ +/** + * @param {string} word + * @param {string} abbr + * @return {boolean} + */ +const validWordAbbreviation = (word, abbr) => { + if (word == null || abbr == null) return false + let i = 0 + let j = 0 + const len = word.length + const aLen = abbr.length + while (i < len && j < aLen) { + if (isNum(abbr[j])) { + if (abbr[j] === '0') return false + let n = 0 + while (j < aLen && isNum(abbr[j])) { + n = n * 10 + Number(abbr[j]) + j++ + } + i += n + } else { + if (word[i] !== abbr[j]) return false + i++ + j++ + } + } + return i === word.length && j === aLen +} +const isNum = c => !isNaN(c) + +// another + +/** + * @param {string} word + * @param {string} abbr + * @return {boolean} + */ +const validWordAbbreviation = (word, abbr) => { + let i = 0, + j = 0 + while (i < word.length && j < abbr.length) { + if (word.charAt(i) === abbr.charAt(j)) { + ++i + ++j + continue + } + if (abbr.charAt(j) <= '0' || abbr.charAt(j) > '9') { + return false + } + let start = j + while (j < abbr.length && abbr.charAt(j) >= '0' && abbr.charAt(j) <= '9') { + ++j + } + let num = +abbr.slice(start, j) + i += num + } + return i == word.length && j == abbr.length +} diff --git a/409-longest-palindrome.js b/409-longest-palindrome.js index cb692360..0d67ad8a 100755 --- a/409-longest-palindrome.js +++ b/409-longest-palindrome.js @@ -1,3 +1,26 @@ +/** + * @param {string} s + * @return {number} + */ +const longestPalindrome = function (s) { + const set = new Set() + let counter = 0 + for (let i = 0; i < s.length; i++) { + const currentChar = s[i] + if (set.has(currentChar)) { + counter++ + set.delete(currentChar) + } else { + set.add(currentChar) + } + } + counter *= 2 + if (set.size > 0) counter++ + return counter +} + +// another + /** * @param {string} s * @return {number} diff --git a/41-first-missing-positive.js b/41-first-missing-positive.js index 5343bb2d..fa054946 100644 --- a/41-first-missing-positive.js +++ b/41-first-missing-positive.js @@ -23,20 +23,77 @@ const firstMissingPositive = function(nums) { * @return {number} */ function firstMissingPositive(nums) { - const A = nums const n = nums.length for (let i = 0; i < n; i++) { - while (A[i] > 0 && A[i] <= n && A[A[i] - 1] !== A[i]) swap(A, i, A[i] - 1) + while (nums[i] > 0 && nums[i] <= n && nums[nums[i] - 1] !== nums[i]) + swap(nums, i, nums[i] - 1) } for (let i = 0; i < n; i++) { - if (A[i] !== i + 1) return i + 1 + if (nums[i] !== i + 1) return i + 1 } return n + 1 } function swap(arr, i, j) { - let tmp = arr[i] + const tmp = arr[i] arr[i] = arr[j] arr[j] = tmp } + + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const firstMissingPositive = function(nums) { + const n = nums.length + for(let i = 0; i < n; i++) { + while(nums[i] < n && nums[nums[i] - 1] !== nums[i]) { + swap(nums, i, nums[i] - 1) + } + } + + for(let i = 0; i < n; i++) { + if(nums[i] !== i + 1) return i + 1 + } + + return n + 1 +}; + +function swap(arr, i, j) { + const tmp = arr[i] + arr[i] = arr[j] + arr[j] = tmp +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const firstMissingPositive = function(nums) { + const n = nums.length + for(let i = 0; i < n; i++) { + while(nums[i] > 0 && nums[i] !== nums[nums[i] - 1] && nums[i] <= n) { + swap(i, nums[i] - 1) + } + } + + // console.log(nums) + for(let i = 0; i < n; i++) { + if(nums[i] !== i + 1) return i + 1 + } + + return n + 1 + + + function swap(i, j) { + const tmp = nums[j] + nums[j] = nums[i] + nums[i] = tmp + } +}; diff --git a/410-split-array-largest-sum.js b/410-split-array-largest-sum.js index 668279b9..a48f3f1e 100644 --- a/410-split-array-largest-sum.js +++ b/410-split-array-largest-sum.js @@ -98,3 +98,44 @@ When Largest sum of sub-arrays is in range [6, 15], we can always find a way to However, when Largest sum of sub-arrays is in range [5, 5], there is no way to do this. This mapped this problem into the second sub-problem. Bool array B here is [5:false, 6:true, 7:true, 8:true, ..., 15:true]. We want to find the index i of the first true in B, which is the answer of this entire question, and by solving the first sub-problem, we have an API that can tell us given an i (Largest sum of sub-arrays), whether B[i] is true (whether we can find a way to cut A to satisfy the constraint). */ + + +// another + +/** + * @param {number[]} nums + * @param {number} m + * @return {number} + */ +const splitArray = (nums, m) => { + let max = -Infinity, sum = 0 + for(let num of nums) { + sum += num + max = Math.max(max, num) + } + if (m === 1) return sum + let l = max, r = sum + while(l < r) { + let mid = l + ((r - l) >> 1) + if(valid(mid, nums, m)) { + r = mid + } else { + l = mid + 1 + } + } + return l +} + +function valid(target, nums, m) { + let cnt = 1, sum = 0 + for(let num of nums) { + sum += num + if(sum > target) { + cnt++ + sum = num + if(cnt > m) return false + } + } + + return true +} diff --git a/411-minimum-unique-word-abbreviation.js b/411-minimum-unique-word-abbreviation.js new file mode 100644 index 00000000..eb0e830b --- /dev/null +++ b/411-minimum-unique-word-abbreviation.js @@ -0,0 +1,56 @@ +/** + * @param {string} target + * @param {string[]} dictionary + * @return {string} + */ +const minAbbreviation = function(target, dictionary) { + let n = target.length, + bn = 1 << n, + cand = 0, + minlen = Number.MAX_VALUE + let minab = 0 + const dict = [] + let res = '' + + for (let w of dictionary) { + let word = 0 + if (w.length != n) continue + for (let i = n - 1, bit = 1; i >= 0; --i, bit <<= 1) + if (target[i] != w[i]) word += bit + dict.push(word) + cand |= word + } + dfs(1, 0) + + for (let i = n - 1, pre = i; i >= 0; --i, minab >>= 1) { + if (minab & 1) { + if (pre - i > 0) res = pre - i + res + pre = i - 1 + res = target[i] + res + } else if (i == 0) res = pre - i + 1 + res + } + return res + + function abbrLen(mask) { + let count = n + for (let b = 3; b < bn; b <<= 1) if ((mask & b) == 0) count-- + return count + } + + function dfs(bit, mask) { + const len = abbrLen(mask) + if (len >= minlen) return + let match = true + for (let d of dict) { + if ((mask & d) == 0) { + match = false + break + } + } + if (match) { + minlen = len + minab = mask + } else + for (let b = bit; b < bn; b <<= 1) if (cand & b) dfs(b << 1, mask + b) + } +} diff --git a/41-add-strings.js b/415-add-strings.js similarity index 100% rename from 41-add-strings.js rename to 415-add-strings.js diff --git a/416-partition-equal-subset-sum.js b/416-partition-equal-subset-sum.js index 581d95df..7c79d633 100644 --- a/416-partition-equal-subset-sum.js +++ b/416-partition-equal-subset-sum.js @@ -1,3 +1,27 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +const canPartition = function(nums) { + const n = nums.length + const sum = nums.reduce((ac, e) => ac + e, 0) + if(sum % 2 === 1) return false + const target = sum / 2 + const dp = Array.from({length: n + 1}, () => Array(target + 101).fill(0)) + dp[0][0] = 1 + + for(let i = 1; i <= n ; i++) { + const e = nums[i - 1] + for(let s = 0; s < target + 101; s++) { + dp[i][s] = dp[i - 1][s] + if(s >= e) dp[i][s] += dp[i - 1][s - e] + } + } + return dp[n][target] > 0 +}; + +// another + /** * @param {number[]} nums * @return {boolean} @@ -92,3 +116,23 @@ const canPartition = function(nums) { return helper(nums, sum, 0) } + +// another + +/** + * @param {number[]} nums + * @return {boolean} + */ +const canPartition = function (nums) { + const sumA = nums.reduce((acc, curr) => acc + curr, 0) + if (sumA % 2) return false + let row = 1n << BigInt(sumA / 2) + for (const weight of nums) row = row | (row >> BigInt(weight)) + /* + check the the column corresponding to my target by bitwise ANDing + it with just 1,so if the first bit is 1, + it will return true, otherwise false + */ + return row & 1n +} + diff --git a/418-sentence-screen-fitting.js b/418-sentence-screen-fitting.js new file mode 100644 index 00000000..9f87bffa --- /dev/null +++ b/418-sentence-screen-fitting.js @@ -0,0 +1,17 @@ +/** + * @param {string[]} sentence + * @param {number} rows + * @param {number} cols + * @return {number} + */ +const wordsTyping = function(sentence, rows, cols) { + let start = 0 + const s = sentence.join(' ') + ' ' + const l = s.length + for (let i = 0; i < rows; i++) { + start += cols + while (start >= 0 && s[start % l] !== ' ') start-- + start++ + } + return Math.floor(start / l) +} diff --git a/42-trapping-rain-water.js b/42-trapping-rain-water.js index 4f6245b4..1b31b415 100644 --- a/42-trapping-rain-water.js +++ b/42-trapping-rain-water.js @@ -52,29 +52,68 @@ const trap = function(height) { * @return {number} */ const trap = function(height) { - const len = height.length - if(len === 0) return 0 - let left = 0 - let right = len - 1 - let leftMax = 0 - let rightMax = 0 - let res = 0 - while(left < right) { - if(height[left] < height[right]) { - if(height[left] <= leftMax) { - res += leftMax - height[left] - } else { - leftMax = height[left] - } - left++ + const n = height.length + let l = 0, r = n - 1, res = 0, leftMax = 0, rightMax = 0 + while(l <= r) { + if(height[l] <= height[r]) { + if(height[l] >= leftMax) leftMax = height[l] + else res += leftMax - height[l] + l++ } else { - if(height[right] <= rightMax) { - res += rightMax - height[right] + if(height[r] >= rightMax) rightMax = height[r] + else res += rightMax - height[r] + r-- + } + } + return res +}; + +// another + +/** + * @param {number[]} height + * @return {number} + */ +const trap = function(height) { + const n = height.length + if(n === 0) return 0 + let res = 0 + let l = 0, r = n - 1, leftMax = height[l], rightMax = height[r] + while(l < r) { + if(height[l] <= height[r]) { + l++ + leftMax = Math.max(leftMax, height[l]) + res += (leftMax - height[l]) } else { - rightMax = height[right] + r-- + rightMax = Math.max(rightMax, height[r]) + res += rightMax - height[r] } - right-- + } + + return res +}; + +// another + +/** + * @param {number[]} height + * @return {number} + */ +const trap = function(height) { + const n = height.length, { max } = Math + let res = 0, l = 0, r = n - 1, leftMax = height[0], rightMax = height[n - 1] + while(l <= r) { + if(leftMax < rightMax) { + leftMax = max(leftMax, height[l]) + res += leftMax - height[l] + l++ + } else { + rightMax = max(rightMax, height[r]) + res += rightMax - height[r] + r-- } } + return res -}; +}; diff --git a/421-maximum-xor-of-two-numbers-in-an-array.js b/421-maximum-xor-of-two-numbers-in-an-array.js index 9e0d9ceb..1e71476c 100644 --- a/421-maximum-xor-of-two-numbers-in-an-array.js +++ b/421-maximum-xor-of-two-numbers-in-an-array.js @@ -1,3 +1,40 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const findMaximumXOR = function(nums) { + let res = 0, mask = 0 + for(let i = 31; i >= 0; i--) { + mask = mask | (1 << i) + const set = new Set() + for(let e of nums) set.add(e & mask) + const tmp = res | (1 << i) + for(let e of set) { + if(set.has(e ^ tmp)) { + res = tmp + break + } + } + } + return res +}; + +// another + +/* + +This algorithm's idea is: +to iteratively determine what would be each bit of the final result from left to right. +And it narrows down the candidate group iteration by iteration. e.g. assume input are a,b,c,d,...z, 26 integers in total. +In first iteration, if you found that a, d, e, h, u differs on the MSB(most significant bit), +so you are sure your final result's MSB is set. Now in second iteration, +you try to see if among a, d, e, h, u there are at least two numbers make the 2nd MSB differs, +if yes, then definitely, the 2nd MSB will be set in the final result. +And maybe at this point the candidate group shinks from a,d,e,h,u to a, e, h. +Implicitly, every iteration, you are narrowing down the candidate group, +but you don't need to track how the group is shrinking, you only cares about the final result. + +*/ /* * @lc app=leetcode id=421 lang=javascript * @@ -51,3 +88,48 @@ const findMaximumXOR = function(nums) { } return maxResult } + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const findMaximumXOR = function (nums) { + if (nums == null || nums.length == 0) { + return 0 + } + const root = new Trie() + for (let num of nums) { + let curNode = root + for (let i = 31; i >= 0; i--) { + let curBit = (num >>> i) & 1 + if (curNode.children[curBit] == null) { + curNode.children[curBit] = new Trie() + } + curNode = curNode.children[curBit] + } + } + let max = Number.MIN_VALUE + for (let num of nums) { + let curNode = root + let curSum = 0 + for (let i = 31; i >= 0; i--) { + let curBit = (num >>> i) & 1 + if (curNode.children[curBit ^ 1] != null) { + curSum += 1 << i + curNode = curNode.children[curBit ^ 1] + } else { + curNode = curNode.children[curBit] + } + } + max = Math.max(curSum, max) + } + return max +} + +class Trie { + constructor() { + this.children = {} + } +} diff --git a/422-valid-word-square.js b/422-valid-word-square.js new file mode 100644 index 00000000..3e1475ca --- /dev/null +++ b/422-valid-word-square.js @@ -0,0 +1,19 @@ +/** + * @param {string[]} words + * @return {boolean} + */ +const validWordSquare = function(words) { + if (words == null || words.length === 0) return true + const n = words.length + for (let i = 0; i < n; i++) { + for (let j = 0; j < words[i].length; j++) { + if ( + j >= n || + words[j].length <= i || + words[j].charAt(i) !== words[i].charAt(j) + ) + return false + } + } + return true +} diff --git a/423-reconstruct-original-digits-from-english.js b/423-reconstruct-original-digits-from-english.js new file mode 100644 index 00000000..8a9c0db3 --- /dev/null +++ b/423-reconstruct-original-digits-from-english.js @@ -0,0 +1,30 @@ +/** + * @param {string} s + * @return {string} + */ +const originalDigits = function(s) { + const count = new Array(10).fill(0); + for (let i = 0; i < s.length; i++) { + let c = s.charAt(i); + if (c === "z") count[0]++; + if (c === "w") count[2]++; + if (c === "x") count[6]++; + if (c === "s") count[7]++; //7-6 + if (c === "g") count[8]++; + if (c === "u") count[4]++; + if (c === "f") count[5]++; //5-4 + if (c === "h") count[3]++; //3-8 + if (c === "i") count[9]++; //9-8-5-6 + if (c === "o") count[1]++; //1-0-2-4 + } + count[7] -= count[6]; + count[5] -= count[4]; + count[3] -= count[8]; + count[9] = count[9] - count[8] - count[5] - count[6]; + count[1] = count[1] - count[0] - count[2] - count[4]; + let ans = ""; + for (let i = 0; i <= 9; i++) { + ans += `${i}`.repeat(count[i]); + } + return ans; +}; diff --git a/424-longest-repeating-character-replacement.js b/424-longest-repeating-character-replacement.js index 8a17a9fa..7a49780e 100755 --- a/424-longest-repeating-character-replacement.js +++ b/424-longest-repeating-character-replacement.js @@ -23,3 +23,34 @@ const characterReplacement = function(s, k) { console.log(characterReplacement("ABAB", 2)); console.log(characterReplacement("AABABBA", 1)); + + +// another + +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +const characterReplacement = function (s, k) { + const freq = Array(26).fill(0), + n = s.length, + { max } = Math, + A = 'A'.charCodeAt(0) + let res = 0, + l = 0, + r = 0, + maxFreq = 0 + while (r < n) { + maxFreq = max(maxFreq, ++freq[s.charCodeAt(r) - A]) + if (r - l + 1 - maxFreq > k) { + freq[s.charCodeAt(l) - A]-- + l++ + } + res = max(res, r - l + 1) + r++ + } + + return res +} + diff --git a/425-word-squares.js b/425-word-squares.js new file mode 100644 index 00000000..66c6d9e8 --- /dev/null +++ b/425-word-squares.js @@ -0,0 +1,119 @@ +/** + * @param {string[]} words + * @return {string[][]} + */ +const wordSquares = function(words) { + const length = words[0].length + const createPrefixMap = function(words) { + const result = new Map() + for (let word of words) { + for (let i = 0; i < word.length - 1; ++i) { + const prefix = word.slice(0, i + 1) + const array = result.get(prefix) + if (array) { + array.push(word) + } else { + result.set(prefix, [word]) + } + } + } + return result + } + const backtracking = function(step, result, martix, wordsList) { + if (step === length) { + result.push([...martix]) + return + } + for (let word of wordsList) { + martix.push(word) + let prefix = '' + for (let i = 0; i < step + 1; ++i) { + prefix += martix[i][step + 1] + } + let newLists = dictMap.get(prefix) + newLists = newLists ? newLists : [] + backtracking(step + 1, result, martix, newLists) + martix.pop() + } + } + const result = [] + const dictMap = createPrefixMap(words) + backtracking(0, result, [], words) + return result +} + +// another + +/** + * @param {string[]} words + * @return {string[][]} + */ +const wordSquares = function(words) { + let result = [] + let trie = new Trie() + for (let word of words) { + trie.add(word) + } + + findWordSquare(result, [], trie) + return result +}; + +function findWordSquare (result, temp, trie) { + if (temp.length > 0 && temp.length === temp[0].length) { + result.push(temp) + return + } + + let prefix = '' + let j = temp.length + for (let i = 0; i < temp.length; i++) { + prefix += temp[i][j] + } + + let startWith = trie.startWith(prefix) + for (let word of startWith) { + findWordSquare(result, temp.concat([word]), trie) + } +} + +function Trie () { + this.isWord = false + this.children = new Map() +} + +Trie.prototype.add = function (word) { + let cur = this + for (let i = 0; i < word.length; i++) { + if (!cur.children.has(word[i])) { + cur.children.set(word[i], new Trie()) + } + cur = cur.children.get(word[i]) + } + cur.isWord = true +} + +Trie.prototype.startWith = function (prefix) { + let cur = this + for (let i = 0; i < prefix.length; i++) { + if (cur.children.has(prefix[i])) { + cur = cur.children.get(prefix[i]) + } else { + return [] + } + } + + let res = [] + const findWords = function (res, cur, str) { + if (!cur.isWord) { + for (let [key, val] of cur.children) { + findWords(res, val, str + key) + } + } else { + res.push(str) + } + } + + findWords(res, cur, prefix) + return res +} diff --git a/426-convert-binary-search-tree-to-sorted-doubly-linked-list.js b/426-convert-binary-search-tree-to-sorted-doubly-linked-list.js new file mode 100644 index 00000000..a75ad8a8 --- /dev/null +++ b/426-convert-binary-search-tree-to-sorted-doubly-linked-list.js @@ -0,0 +1,93 @@ +/** + * // Definition for a Node. + * function Node(val, left, right) { + * this.val = val; + * this.left = left; + * this.right = right; + * }; + */ +/** + * @param {Node} root + * @return {Node} + */ +const treeToDoublyList = function(root) { + let head = null, tail = null; + const helper = (node) => { + if(!node) return; + helper(node.left); + if(!head) head = node; + if(tail) tail.right = node; + node.left = tail; + tail = node; + helper(node.right); + }; + helper(root); + if(head) { + head.left = tail; + tail.right = head; + } + return head; +}; + +// another + +/** + * @param {Node} root + * @return {Node} + */ +const treeToDoublyList = function(root) { + if(root === null) return null + const left = treeToDoublyList(root.left) + const right = treeToDoublyList(root.right) + root.left = root + root.right = root + return connect(connect(left, root), right) +}; + +// n1 is the head of circular DLL as well as n2 +function connect(n1, n2) { + if(n1 === null) return n2 + if(n2 === null) return n1 + const t1 = n1.left + const t2 = n2.left + + t1.right = n2 + n2.left = t1 + t2.right = n1 + n1.left = t2 + + return n1 +} + +// another + +/** + * @param {Node} root + * @return {Node} + */ +const treeToDoublyList = function(root) { + if(root == null) return null + let cur = root + let start = root + while(start.left !== null) { + start = start.left + } + let prev = null + const stack = [] + while(stack.length !== 0 || cur !== null) { + while(cur !== null) { + stack.push(cur) + cur = cur.left + } + cur = stack.pop() + if(prev !== null) { + prev.right = cur + cur.left = prev + } + prev = cur + cur = cur.right + } + start.left = prev + prev.right = start + return start +}; diff --git a/427-construct-quad-tree.js b/427-construct-quad-tree.js new file mode 100644 index 00000000..5e84d5fe --- /dev/null +++ b/427-construct-quad-tree.js @@ -0,0 +1,41 @@ +/** + * // Definition for a QuadTree node. + * function Node(val,isLeaf,topLeft,topRight,bottomLeft,bottomRight) { + * this.val = val; + * this.isLeaf = isLeaf; + * this.topLeft = topLeft; + * this.topRight = topRight; + * this.bottomLeft = bottomLeft; + * this.bottomRight = bottomRight; + * }; + */ +/** + * @param {number[][]} grid + * @return {Node} + */ +const construct = function(grid) { + const tree = m => { + const node = new Node() + const isAllOne = m.every(r => r.every(v => v === 1)) + const isAllZero = m.every(r => r.every(v => v === 0)) + if (isAllOne) { + node.val = true + node.isLeaf = true + } else if (isAllZero) { + node.val = false + node.isLeaf = true + } else { + const len = m.length + let left = m.map(r => r.slice(0, len / 2)) + let right = m.map(r => r.slice(len / 2)) + node.topLeft = tree(left.slice(0, len / 2)) + node.topRight = tree(right.slice(0, len / 2)) + node.bottomLeft = tree(left.slice(len / 2)) + node.bottomRight = tree(right.slice(len / 2)) + node.isLeaf = false + node.val = true + } + return node + } + return tree(grid) +} diff --git a/428-serialize-and-deserialize-n-ary-tree.js b/428-serialize-and-deserialize-n-ary-tree.js new file mode 100644 index 00000000..edd89f55 --- /dev/null +++ b/428-serialize-and-deserialize-n-ary-tree.js @@ -0,0 +1,124 @@ +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ + +class Codec { + constructor() {} + /** + * @param {Node} root + * @return {string} + */ + // Encodes a tree to a single string. + serialize = function(root) { + if (root === null) return '' + let str = '' + function dfs(node) { + str += node.val + ',' + node.children.length + ',' + for (let child of node.children) dfs(child) + } + dfs(root) + return str + } + /** + * @param {string} data + * @return {Node} + */ + // Decodes your encoded data to tree. + deserialize = function(data) { + if (data === '') return null + let idx = 0 + function input() { + let j = data.indexOf(',', idx) + let n = Number(data.slice(idx, j)) + idx = j + 1 + return n + } + function dfs() { + let val = input(), + len = input() + let node = new Node(val, []) + while (len-- > 0) node.children.push(dfs()) + return node + } + return dfs() + } +} +// Your Codec object will be instantiated and called as such: +// Codec codec = new Codec(); +// codec.deserialize(codec.serialize(root)); + +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ + +// another + +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ + +class Codec { + constructor() {} + /** + * @param {Node} root + * @return {string} + */ + // Encodes a tree to a single string. + serialize = function(root) { + const ans = [] + const stack = root ? [root] : [] + while (stack.length) { + const cur = stack.pop() + ans.push(cur.val, cur.children.length) + for (let i = cur.children.length - 1; i >= 0; i--) { + stack.push(cur.children[i]) + } + } + return ans.join(',') + } + /** + * @param {string} data + * @return {Node} + */ + // Decodes your encoded data to tree. + deserialize = function(data) { + if (!data) return null + const arr = data.split(',') + const helper = (index = 0, parent) => { + const node = new Node(arr[index++], []) + parent.children.push(node) + let childCount = arr[index++] + while (childCount--) { + index = helper(index, node) + } + return index + } + const fakeRoot = new Node(null, []) + helper(0, fakeRoot) + return fakeRoot.children[0] + } +} +// Your Codec object will be instantiated and called as such: +// Codec codec = new Codec(); +// codec.deserialize(codec.serialize(root)); + +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ + diff --git a/429-n-ary-tree-level-order-traversal.js b/429-n-ary-tree-level-order-traversal.js new file mode 100644 index 00000000..413cc641 --- /dev/null +++ b/429-n-ary-tree-level-order-traversal.js @@ -0,0 +1,57 @@ +/** + * // Definition for a Node. + * function Node(val,children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[][]} + */ +const levelOrder = function(root) { + const res = [] + if(root == null) return res + helper(root, 0, res) + return res +}; + +function helper(node, index, res) { + if(node == null) return + if(res[index] == null) res[index] = [] + res[index].push(node.val) + for(let i = 0, len = node.children.length; i < len; i++) { + helper(node.children[i], index + 1, res) + } +} + +// another + +/** + * // Definition for a Node. + * function Node(val,children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * @param {Node} root + * @return {number[][]} + */ +const levelOrder = function(root) { + const res = [] + if(root == null) return res + const q = [] + q.push(root) + while(q.length) { + const size = q.length + const cur = [] + for(let i = 0; i < size; i++) { + const node = q.shift() + cur.push(node.val) + q.push(...node.children) + } + res.push(cur) + } + return res +}; diff --git a/431-encode-n-ary-tree-to-binary-tree.js b/431-encode-n-ary-tree-to-binary-tree.js new file mode 100644 index 00000000..85de1f54 --- /dev/null +++ b/431-encode-n-ary-tree-to-binary-tree.js @@ -0,0 +1,58 @@ +/** + * // Definition for a Node. + * function Node(val, children) { + * this.val = val; + * this.children = children; + * }; + */ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ + +class Codec { + constructor() {} + + /** + * @param {Node} root + * @return {TreeNode} + */ + // Encodes an n-ary tree to a binary tree. + encode = function(root) { + if (root == null) return null + let result = new TreeNode(root.val) + if (root.children.length > 0) { + result.left = this.encode(root.children[0]) + } + let cur = result.left + for (let i = 1; i < root.children.length; i++) { + cur.right = this.encode(root.children[i]) + cur = cur.right + } + return result + } + + /** + * @param {TreeNode} root + * @return {Node} + */ + // Decodes your binary tree to an n-ary tree. + decode = function(root) { + if (root == null) return null + let result = new Node(root.val, []) + let cur = root.left + while (cur != null) { + result.children.push(this.decode(cur)) + cur = cur.right + } + return result + } +} +/* + * Your Codec object will be instantiated and called as such: + * codec = Codec() + * codec.decode(codec.encode(root)) + */ diff --git a/433-minimum-genetic-mutation.js b/433-minimum-genetic-mutation.js new file mode 100644 index 00000000..8c5ab37c --- /dev/null +++ b/433-minimum-genetic-mutation.js @@ -0,0 +1,61 @@ +/** + * @param {string} start + * @param {string} end + * @param {string[]} bank + * @return {number} + */ +const minMutation = function(start, end, bank) { + const obj = { res: Number.MAX_VALUE } + dfs(start, end, bank, 0, obj, new Set()) + return obj.res === Number.MAX_VALUE ? -1 : obj.res +} + +function dfs(s, e, bank, num, obj, visited) { + if(s === e) { + obj.res = Math.min(obj.res, num) + return + } + for(let el of bank) { + let diff = 0 + for(let i = 0, len = s.length; i < len; i++) { + if(s[i] !== el[i]) { + diff++ + if(diff > 1) break + } + } + if(diff === 1 && !visited.has(el)) { + visited.add(el) + dfs(el, e, bank, num + 1, obj, visited) + visited.delete(el) + } + } +} + +// another + +/** + * @param {string} start + * @param {string} end + * @param {string[]} bank + * @return {number} + */ +const minMutation = function(start, end, bank) { + const bankSet = new Set(bank) + if (!bankSet.has(end)) return -1 + const queue = [[start, 0]] + const dna = ['A', 'C', 'G', 'T'] + while (queue.length) { + let [node, count] = queue.shift() + if (node === end) return count + for (let i = 0; i < node.length; i++) { + for (let j = 0; j < dna.length; j++) { + const d = node.slice(0, i) + dna[j] + node.slice(i + 1) + if (bankSet.has(d)) { + queue.push([d, count + 1]) + bankSet.delete(d) + } + } + } + } + return -1 +} diff --git a/435-non-overlapping-intervals.js b/435-non-overlapping-intervals.js index e85e0c68..7f4ffa45 100644 --- a/435-non-overlapping-intervals.js +++ b/435-non-overlapping-intervals.js @@ -1,3 +1,42 @@ +/** + * @param {number[][]} intervals + * @return {number} + */ +var eraseOverlapIntervals = function(intervals) { + intervals.sort((a, b) => a[1] - b[1]); + let res = 0 + let end = -Infinity + for(const [start, finish] of intervals) { + if(start < end) res++ + else end = finish + } + + return res +}; + +// another + +/** + * @param {number[][]} intervals + * @return {number} + */ +const eraseOverlapIntervals = function(intervals) { + if(intervals == null || intervals.length === 0) return 0 + intervals.sort((a, b) => a[1] - b[1]) + let res = 1, end = intervals[0][1] + const len = intervals.length + for(let i = 1; i < len; i++) { + if(intervals[i][0] >= end) { + end = intervals[i][1] + res++ + } + } + + return len - res +}; + +// another + /** * Definition for an interval. * function Interval(start, end) { diff --git a/436-find-right-interval.js b/436-find-right-interval.js new file mode 100644 index 00000000..6d1c3031 --- /dev/null +++ b/436-find-right-interval.js @@ -0,0 +1,29 @@ +/** + * @param {number[][]} intervals + * @return {number[]} + */ +const findRightInterval = function(intervals) { + const res = [] + const arrary = intervals + .map((interval, idx) => ({ interval, idx })) + .sort((obj1, obj2) => obj1.interval[0] - obj2.interval[0]) + for (let interval of intervals) { + const val = interval[interval.length - 1] + let left = 0, + right = intervals.length + while (left < right) { + const mid = Math.floor((left + right) / 2) + if (arrary[mid].interval[0] >= val) { + right = mid + } else { + left = mid + 1 + } + } + if (left >= intervals.length) { + res.push(-1) + } else { + res.push(arrary[left].idx) + } + } + return res +} diff --git a/438-find-all-anagrams-in-a-string.js b/438-find-all-anagrams-in-a-string.js index 6a171f8b..b0d5e49e 100644 --- a/438-find-all-anagrams-in-a-string.js +++ b/438-find-all-anagrams-in-a-string.js @@ -3,34 +3,26 @@ * @param {string} p * @return {number[]} */ -const findAnagrams = function(s, p) { - const slen = s.length - const plen = p.length - if( plen > slen ) { - return [] +const findAnagrams = function (s, p) { + const slen = s.length; + const plen = p.length; + if (plen > slen) return []; + const aCode = "a".charCodeAt(0); + const count = new Array(26).fill(0); + for (let i = 0; i < plen; i++) count[p.charCodeAt(i) - aCode] += 1; + const res = []; + for (let i = 0; i < slen; i++) { + count[s.charCodeAt(i) - aCode] -= 1; + if (i >= plen - 1) { + if (i - plen >= 0) count[s.charCodeAt(i - plen) - aCode] += 1; + if (allZero(count)) res.push(i - plen + 1); } - const aCode = ('a').charCodeAt(0) - const count = new Array(26).fill(0) - for(let i = 0; i < plen; i++) { - count[ p.charCodeAt(i) - aCode ] += 1 - } - const res = [] - for(let i = 0; i < slen; i++) { - count[ s.charCodeAt(i) - aCode ] -= 1 - if (i >= plen - 1) { - if(i - plen >= 0) count[ s.charCodeAt( i - plen ) - aCode ] += 1 - if (allZero(count)) { - res.push(i - plen + 1) - } - } - } - - return res + } + return res; }; - function allZero(count) { - for(let el of count) { - if(el !== 0) return false - } - return true + for (let el of count) { + if (el !== 0) return false; + } + return true; } diff --git a/439-ternary-expression-parser.js b/439-ternary-expression-parser.js new file mode 100644 index 00000000..e19fa880 --- /dev/null +++ b/439-ternary-expression-parser.js @@ -0,0 +1,22 @@ +/** + * @param {string} expression + * @return {string} + */ +const parseTernary = function(expression) { + const N = expression.length + const stack = [expression[N - 1]] + for (let i = N - 2; i >= 0; i -= 2) { + if (expression[i] === ':') { + stack.push(expression[i - 1]) + } else { + const l = stack.pop() + const r = stack.pop() + if (expression[i - 1] === 'T') { + stack.push(l) + } else { + stack.push(r) + } + } + } + return stack[0] +} diff --git a/44-wildcard-matching.js b/44-wildcard-matching.js new file mode 100644 index 00000000..12575854 --- /dev/null +++ b/44-wildcard-matching.js @@ -0,0 +1,34 @@ +/** + * @param {string} s + * @param {string} p + * @return {boolean} + */ +const isMatch = function(s, p) { + const M = s.length + const N = p.length + let i = 0, + j = 0, + lastMatchInS, + lastStarPos + while (i < M) { + if (j < N && (p[j] === s[i] || p[j] === '?')) { + i++ + j++ + } else if (j < N && p[j] === '*') { + lastStarPos = j + j++ + lastMatchInS = i + } else if (lastStarPos !== undefined) { + // back to previous step + j = lastStarPos + 1 + lastMatchInS++ + i = lastMatchInS + } else { + return false + } + } + while (j < N && p[j] === '*') { + j++ + } + return j === N +} diff --git a/440-k-th-smallest-in-lexicographical-order.js b/440-k-th-smallest-in-lexicographical-order.js index 0750acf5..00bb38fb 100644 --- a/440-k-th-smallest-in-lexicographical-order.js +++ b/440-k-th-smallest-in-lexicographical-order.js @@ -3,29 +3,63 @@ * @param {number} k * @return {number} */ -const findKthNumber = function(n, k) { +const findKthNumber = function (n, k) { + let cur = 1 + k = k - 1 + while(k > 0) { + const num = calc(cur) + if(num <= k) { + cur++ + k -= num + } else { + k-- + cur *= 10 + } + } + return cur + + function calc(cur) { + let total = 0 + let nxt = cur + 1 + while(cur <= n) { + total += Math.min(n - cur + 1, nxt - cur) + nxt *= 10 + cur *= 10 + } + + return total + } +} + +// another + +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const findKthNumber = function (n, k) { let curr = 1 k = k - 1 while (k > 0) { let steps = calSteps(n, curr, curr + 1) if (steps <= k) { - curr++ + curr += 1 k -= steps } else { curr *= 10 - k-- + k -= 1 } } return curr -} -//use long in case of overflow -function calSteps(n, n1, n2) { - let steps = 0 - while (n1 <= n) { - steps += Math.min(n + 1, n2) - n1 - n1 *= 10 - n2 *= 10 + function calSteps(n, n1, n2) { + let steps = 0 + while (n1 <= n) { + steps += Math.min(n + 1, n2) - n1 + n1 *= 10 + n2 *= 10 + } + return steps } - return steps } diff --git a/441-arranging-coins.js b/441-arranging-coins.js index 6c713105..605801fe 100644 --- a/441-arranging-coins.js +++ b/441-arranging-coins.js @@ -15,3 +15,13 @@ const arrangeCoins = function(n) { return num }; + +// another + +/** + * @param {number} n + * @return {number} + */ +const arrangeCoins = function(n) { + return (-1 + Math.sqrt(1+4*2*n)) >> 1 +}; diff --git a/442-find-all-duplicates-in-an-array.js b/442-find-all-duplicates-in-an-array.js index 2013b2a7..4d28baa9 100755 --- a/442-find-all-duplicates-in-an-array.js +++ b/442-find-all-duplicates-in-an-array.js @@ -19,3 +19,19 @@ const findDuplicates = function(nums) { console.log(findDuplicates([4, 3, 2, 7, 8, 2, 3, 1])); console.log(findDuplicates([10, 2, 5, 10, 9, 1, 1, 4, 3, 7])); + +// another + +/** + * @param {number[]} nums + * @return {number[]} + */ +const findDuplicates = function(nums) { + const res = [] + for(let i = 0, len = nums.length; i < len; i++) { + const idx = Math.abs(nums[i]) - 1 + if(nums[idx] < 0) res.push(idx + 1) + nums[idx] = -nums[idx] + } + return res; +}; diff --git a/444-sequence-reconstruction.js b/444-sequence-reconstruction.js new file mode 100644 index 00000000..d8fde009 --- /dev/null +++ b/444-sequence-reconstruction.js @@ -0,0 +1,65 @@ +/** + * @param {number[]} org + * @param {number[][]} seqs + * @return {boolean} + */ +const sequenceReconstruction = function(org, seqs) { + const pairs = {} + const idxs = {} + for (let i = 0; i < org.length; i++) idxs[org[i]] = i + for (let j = 0; j < seqs.length; j++) { + const s = seqs[j] + for (let i = 0; i < s.length; i++) { + if (idxs[s[i]] == null) return false + if (i > 0 && idxs[s[i - 1]] >= idxs[s[i]]) return false + pairs[`${s[i - 1]}_${s[i]}`] = 1 + } + } + + for (let i = 0; i < org.length; i++) + if (pairs[`${org[i - 1]}_${org[i]}`] == null) return false + + return true +} + +// another + +/** + * @param {number[]} org + * @param {number[][]} seqs + * @return {boolean} + */ +const sequenceReconstruction = function(org, seqs) { + const graph = new Map() + const indegree = new Map() + seqs.forEach(seq => { + for (let i = 0; i < seq.length; i++) { + if (!graph.has(seq[i])) graph.set(seq[i], []) + if (!indegree.has(seq[i])) indegree.set(seq[i], 0) + if (i > 0) { + graph.get(seq[i - 1]).push(seq[i]) + indegree.set(seq[i], indegree.get(seq[i]) + 1) + } + } + }) + if (org.length !== graph.size) return false + const array = [] + for (let [key, val] of indegree.entries()) { + if (val === 0) array.push(key) + } + let index = 0 + while (array.length > 0) { + if (array.length > 1) return false + const current = array.shift() + if (org[index] !== current) { + return false + } + index++ + graph.get(current).forEach(next => { + indegree.set(next, indegree.get(next) - 1) + if (indegree.get(next) === 0) array.push(next) + }) + } + return index === org.length +} + diff --git a/445-add-two-numbers-II.js b/445-add-two-numbers-II.js index 65a246ed..4800985a 100755 --- a/445-add-two-numbers-II.js +++ b/445-add-two-numbers-II.js @@ -1,3 +1,63 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +const addTwoNumbers = function(head1, head2) { + const r1 = reverse(head1), r2 = reverse(head2) + let l1 = r1, l2 = r2, inc = 0 + let dummy = new ListNode() + let pre = dummy + while(l1 || l2) { + let val = inc + if(l1) { + val += l1.val + l1 = l1.next + } + if(l2) { + val += l2.val + l2 = l2.next + } + if(val > 9) inc = 1 + else inc = 0 + const cur = new ListNode(val % 10) + pre.next = cur + pre = cur + } + if (inc) { + pre.next = new ListNode(1) + } + return reverse(dummy.next) +}; + +function reverse(head) { + const dummy = new ListNode() + dummy.next = head + let len = 0, cur = head + while(cur) { + len++ + cur = cur.next + } + let p = dummy, tail = head, tmp = null + for(let i = 0; i < len - 1; i++) { + tmp = p.next + p.next = tail.next + tail.next = tail.next.next + p.next.next = tmp + } + return dummy.next +} + + +// another + /** * Definition for singly-linked list. * function ListNode(val) { @@ -40,3 +100,55 @@ const addTwoNumbers = function(l1, l2) { return list.val === 0 ? list.next : list; }; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ +const addTwoNumbers = function(l1, l2) { + const s1 = [], s2 = [] + let h1 = l1, h2 = l2 + while(h1) { + s1.push(h1.val) + h1 = h1.next + } + while(h2) { + s2.push(h2.val) + h2 = h2.next + } + let inc = false + let tail = null + while(s1.length || s2.length) { + let tmp = 0 + if(s1.length) tmp += s1.pop() + if(s2.length) tmp += s2.pop() + if(inc) tmp++ + if(tmp > 9) { + inc = true + } else { + inc = false + } + tmp = tmp % 10 + const cur = new ListNode(tmp) + if(tail) cur.next = tail + tail = cur + } + + if(inc) { + const head = new ListNode(1) + head.next = tail + return head + } + return tail + +}; diff --git a/446-arithmetic-slices-ii-subsequence.js b/446-arithmetic-slices-ii-subsequence.js new file mode 100644 index 00000000..0eec4146 --- /dev/null +++ b/446-arithmetic-slices-ii-subsequence.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} A + * @return {number} + */ +const numberOfArithmeticSlices = function(A) { + if (!A || A.length < 3) return 0; + let res = 0; + const dp = Array(A.length); + for (let i = 0; i < A.length; i++) { + dp[i] = new Map(); + for (let j = 0; j < i; j++) { + const diff = A[i] - A[j]; + const prevCount = dp[j].get(diff) || 0; + res += prevCount; + const currCount = (dp[i].get(diff) || 0) + 1; + dp[i].set(diff, prevCount + currCount); + } + } + return res; +}; diff --git a/447-number-of-boomerangs.js b/447-number-of-boomerangs.js new file mode 100644 index 00000000..84f9081c --- /dev/null +++ b/447-number-of-boomerangs.js @@ -0,0 +1,26 @@ +/** + * @param {number[][]} points + * @return {number} + */ +const numberOfBoomerangs = function(points) { + const m = new Map() + const len = points.length + let res = 0 + for(let i = 0; i < len; i++) { + for(let j = 0; j < len; j++) { + if(i === j) continue + const d = dis(points[i], points[j]) + if(!m.has(d)) m.set(d, 0) + m.set(d, m.get(d) + 1) + } + for(let v of m.values()) { + res += v * (v - 1) + } + m.clear() + } + return res +}; + +function dis(a, b) { + return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2 +} diff --git a/448-find-all-numbers-disappeared-in-an-array.js b/448-find-all-numbers-disappeared-in-an-array.js index 40828515..bf3dd2da 100755 --- a/448-find-all-numbers-disappeared-in-an-array.js +++ b/448-find-all-numbers-disappeared-in-an-array.js @@ -15,3 +15,21 @@ const findDisappearedNumbers = function(nums) { } return arr; }; + +// another + +/** + * @param {number[]} nums + * @return {number[]} + */ +const findDisappearedNumbers = function(nums) { + for(let i = 0, len = nums.length; i < len; i++) { + const idx = Math.abs(nums[i]) - 1 + nums[idx] = - Math.abs(nums[idx]) + } + const res = [] + nums.forEach((e, i) => { + if(e > 0) res.push(i + 1) + }) + return res +}; diff --git a/450-delete-node-in-a-bst.js b/450-delete-node-in-a-bst.js index 8e6b80ef..51eee135 100644 --- a/450-delete-node-in-a-bst.js +++ b/450-delete-node-in-a-bst.js @@ -11,22 +11,65 @@ * @return {TreeNode} */ const deleteNode = function(root, key) { - if(root == null) return null - if (root.val > key) { - root.left = deleteNode(root.left, key) - } else if(root.val < key) { - root.right = deleteNode(root.right, key) + if(root == null) return null + if(key < root.val) { + root.left = deleteNode(root.left, key) + } else if(key > root.val) { + root.right = deleteNode(root.right, key) + } else { + if(root.left == null) { + return root.right + } else if(root.right == null) { + return root.left } else { - if (root.left == null) { - return root.right - } - if (root.right == null) { - return root.left - } - let rightSmallest = root.right - while(rightSmallest.left != null) rightSmallest = rightSmallest.left - rightSmallest.left = root.left - return root.right + let smallestRight = root.right + while(smallestRight.left !== null) smallestRight = smallestRight.left + smallestRight.left = root.left + return root.right } - return root + } + + return root }; + +// another + +/** + * 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 + * @param {number} key + * @return {TreeNode} + */ +const deleteNode = function(root, key) { + if(root == null) return root + + if(root.val < key) root.right = deleteNode(root.right, key) + else if(root.val > key) root.left = deleteNode(root.left, key) + else { + if(root.left == null && root.right === null) root = null + else if(root.left == null) root = root.right + else if(root.right == null) root = root.left + else { + const min = findMin(root.right) + root.val = min.val + root.right = deleteNode(root.right, root.val) + } + } + + return root +}; + +function findMin(node) { + let cur = node + while(cur.left) { + cur = cur.left + } + return cur +} diff --git a/452-minimum-number-of-arrows-to-burst-balloons.js b/452-minimum-number-of-arrows-to-burst-balloons.js new file mode 100644 index 00000000..ca8f8d45 --- /dev/null +++ b/452-minimum-number-of-arrows-to-burst-balloons.js @@ -0,0 +1,81 @@ +/** + * @param {number[][]} points + * @return {number} + */ +var findMinArrowShots = function(points) { + points.sort((a, b) => a[1] - b[1]); + if(points.length === 0) return 0 + let res = 1 + let end = points[0][1] + for(let i = 1; i < points.length; i++) { + const [s,e] = points[i] + if(s > end) { + res++ + end = e + } + } + + return res +}; + +// another + +/** + * @param {number[][]} points + * @return {number} + */ +const findMinArrowShots = function(points) { + const n = points.length + if(n === 0) return 0 + points.sort((a, b) => a[1] - b[1]) + let res = 1 + let end = points[0][1] + + for(let i = 1; i < n; i++) { + if(end >= points[i][0]) continue + res++ + end = points[i][1] + } + + return res +}; + +// another + +/** + * @param {number[][]} points + * @return {number} + */ +const findMinArrowShots = function(points) { + const sorted = points.sort((a, b) => a[0] - b[0]) + let ans = 0 + let lastX = null + for (let i = 0; i < sorted.length; i += 1) { + if (lastX && sorted[i][0] <= lastX) { + lastX = Math.min(sorted[i][1], lastX) + } else { + ans += 1 + lastX = sorted[i][1] + } + } + return ans +} + +// another + +/** + * @param {number[][]} points + * @return {number} + */ +const findMinArrowShots = function(points) { + if(points == null || points.length === 0) return 0 + points.sort((a, b) => a[1] - b[1]) + let end = points[0][1], res = 1 + for(let i = 1, len = points.length; i < len; i++) { + if(points[i][0] > end) { + end = points[i][1] + res++ + } + } + return res +}; diff --git a/454-4sum-ii.js b/454-4sum-ii.js new file mode 100644 index 00000000..708ea7c0 --- /dev/null +++ b/454-4sum-ii.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} A + * @param {number[]} B + * @param {number[]} C + * @param {number[]} D + * @return {number} + */ +const fourSumCount = function(A, B, C, D) { + const map = new Map() + let res = 0 + for (let i = 0, clen = C.length; i < clen; i++) { + for (let j = 0, dlen = D.length; j < dlen; j++) { + map.set( + C[i] + D[j], + typeof map.get(C[i] + D[j]) == 'undefined' + ? 1 + : map.get(C[i] + D[j]) + 1 + ) + } + } + for (let i = 0, alen = A.length; i < alen; i++) { + for (let j = 0, blen = B.length; j < blen; j++) { + res += + typeof map.get((A[i] + B[j]) * -1) == 'undefined' + ? 0 + : map.get((A[i] + B[j]) * -1) + } + } + return res +} diff --git a/456-132-pattern.js b/456-132-pattern.js new file mode 100644 index 00000000..e584d194 --- /dev/null +++ b/456-132-pattern.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +const find132pattern = function(nums) { + let [stack, s3] = [[], -Infinity] + for (let i = nums.length - 1; i >= 0; i--) { + if (nums[i] < s3) { + return true + } + while (stack[stack.length - 1] < nums[i]) { + s3 = stack.pop() + } + stack.push(nums[i]) + } + return false +} + +// another + +/** + * @param {number[]} nums + * @return {boolean} + */ +const find132pattern = function(nums) { + let idx = nums.length + let s3 = Number.NEGATIVE_INFINITY + for(let len = nums.length, i = len - 1; i >= 0; i--) { + if(nums[i] < s3) return true + while(idx < nums.length && nums[i] > nums[idx]) { + s3 = nums[idx++] + } + nums[--idx] = nums[i] + } + return false +} + diff --git a/458-poor-pigs.js b/458-poor-pigs.js new file mode 100644 index 00000000..da075dcc --- /dev/null +++ b/458-poor-pigs.js @@ -0,0 +1,26 @@ +/** + * @param {number} buckets + * @param {number} minutesToDie + * @param {number} minutesToTest + * @return {number} + */ +const poorPigs = function(buckets, minutesToDie, minutesToTest) { + const index = Math.ceil(minutesToTest / minutesToDie) + 1 + return Math.ceil(Math.log(buckets) / Math.log(index)) +} + +// another + +/** + * @param {number} buckets + * @param {number} minutesToDie + * @param {number} minutesToTest + * @return {number} + */ +const poorPigs = function(buckets, minutesToDie, minutesToTest) { + let pigs = 0 + while ((minutesToTest / minutesToDie + 1) ** pigs < buckets) { + pigs++ + } + return pigs +} diff --git a/459-repeated-substring-pattern.js b/459-repeated-substring-pattern.js index aae2ac4f..9debc498 100644 --- a/459-repeated-substring-pattern.js +++ b/459-repeated-substring-pattern.js @@ -1,3 +1,35 @@ +/** + * @param {string} s + * @return {boolean} + */ +const repeatedSubstringPattern = function(s) { + + const len = s.length + const table = build(s) + return table[len] && (table[len] % (len - table[len]) === 0) + + function build(str) { + const n = str.length + const table = Array(n + 1).fill(0) + let i = 1, j = 0 + table[0] = -1 + while(i < n) { + if(str[i] === str[j]) { + i++ + j++ + table[i] = j + } else { + if(j > 0) j = table[j] + else i++ + } + } + + return table + } +}; + +// another + /** * @param {string} s * @return {boolean} @@ -23,3 +55,51 @@ function genStr(sub, limit) { } return str } + +// another + +/** + * @param {string} s + * @return {boolean} + */ +const repeatedSubstringPattern = function (s) { + const l = s.length + const arr = DFA(s) + return arr[l] && arr[l] % (l - arr[l]) === 0 + function DFA(s) { + let i = 1 + let j = 0 + const len = s.length + const prefix = Array(len + 1).fill(0) + prefix[0] = -1 + prefix[1] = 0 + while (i < len) { + if (s[j] === s[i]) { + j++ + i++ + prefix[i] = j + } else { + if (j > 0) j = prefix[j] + else i++ + } + } + return prefix + } +} + +// another + +/** + * @param {string} s + * @return {boolean} + */ +const repeatedSubstringPattern = function(s) { + let i = 1, j = 0, n = s.length; + const dp = Array(n + 1).fill(0); + while( i < s.length ){ + if( s[i] === s[j] ) dp[++i] = ++j; + else if( j === 0 ) i++; + else j = dp[j]; + } + return dp[n] && (dp[n] % (n - dp[n]) === 0); +}; diff --git a/46-permutations.js b/46-permutations.js index 2a3486a0..82faf2f7 100755 --- a/46-permutations.js +++ b/46-permutations.js @@ -21,3 +21,28 @@ function backtrack(list, tempList, nums) { } } } + +// another + +/** + * @param {number[]} nums + * @return {number[][]} + */ +const permute = function(nums) { + const res = [] + bt(nums, 0, [], res) + return res +}; + +function bt(nums, idx, cur, res) { + if(idx === nums.length) { + res.push(cur.slice()) + return + } + for(let i = 0; i < nums.length; i++) { + if(cur.indexOf(nums[i]) !== -1) continue + cur.push(nums[i]) + bt(nums, idx + 1, cur, res) + cur.pop() + } +} diff --git a/461-hamming-distance.js b/461-hamming-distance.js new file mode 100644 index 00000000..8174de3f --- /dev/null +++ b/461-hamming-distance.js @@ -0,0 +1,43 @@ +/** + * @param {number} x + * @param {number} y + * @return {number} + */ +const hammingDistance = function (x, y) { + let d = 0 + let h = x ^ y + while (h > 0) { + d++ + h &= h - 1 + } + return d +} + +// another + +/** + * @param {number} x + * @param {number} y + * @return {number} + */ +const hammingDistance = function (x, y) { + let n = x ^ y + n = n - ((n >> 1) & 0x55555555) + n = (n & 0x33333333) + ((n >> 2) & 0x33333333) + return (((n + (n >> 4)) & 0xf0f0f0f) * 0x1010101) >> 24 +} + +// another + +/** + * @param {number} x + * @param {number} y + * @return {number} + */ +const hammingDistance = function (x, y) { + let n = x ^ y + let tmp = n - ((n >> 1) & 033333333333) - ((n >> 2) & 011111111111); + return ((tmp + (tmp >> 3)) & 030707070707) % 63; +} + +// https://tech.liuchao.me/2016/11/count-bits-of-integer/ diff --git a/462-minimum-moves-to-equal-array-elements-II.js b/462-minimum-moves-to-equal-array-elements-II.js index 4919debd..1695d55a 100755 --- a/462-minimum-moves-to-equal-array-elements-II.js +++ b/462-minimum-moves-to-equal-array-elements-II.js @@ -14,3 +14,63 @@ const minMoves2 = function(nums) { } return res; }; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const minMoves2 = function (nums) { + const n = nums.length + const mid = Math.floor(n / 2) + const nth = nthElement(nums, mid, (a, b) => a - b) + let res = 0 + for (let i = 0; i < n; i++) { + res += Math.abs(nums[i] - nth) + } + + return res +} + +function nthElement(arr, n, compareFn) { + if (n < 0 || n >= arr.length) { + throw new Error('Invalid index') + } + + const partition = (arr, left, right, pivotIndex) => { + const pivotValue = arr[pivotIndex] + ;[arr[pivotIndex], arr[right]] = [arr[right], arr[pivotIndex]] + let storeIndex = left + + for (let i = left; i < right; i++) { + if (compareFn(arr[i], pivotValue) < 0) { + ;[arr[i], arr[storeIndex]] = [arr[storeIndex], arr[i]] + storeIndex++ + } + } + + ;[arr[right], arr[storeIndex]] = [arr[storeIndex], arr[right]] + return storeIndex + } + + const select = (arr, left, right, k) => { + if (left === right) { + return arr[left] + } + + let pivotIndex = Math.floor(Math.random() * (right - left + 1)) + left + pivotIndex = partition(arr, left, right, pivotIndex) + + if (k === pivotIndex) { + return arr[k] + } else if (k < pivotIndex) { + return select(arr, left, pivotIndex - 1, k) + } else { + return select(arr, pivotIndex + 1, right, k) + } + } + + return select(arr, 0, arr.length - 1, n) +} + diff --git a/463-island-perimeter.js b/463-island-perimeter.js index d108382a..db888ecd 100755 --- a/463-island-perimeter.js +++ b/463-island-perimeter.js @@ -38,3 +38,33 @@ function cell(grid, r, c) { console.log( islandPerimeter([[0, 1, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0], [1, 1, 0, 0]]) ); + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const islandPerimeter = function(grid) { + const m = grid.length + const n = grid[0].length + const dirs = [[0, 1], [0, -1], [1, 0], [-1, 0]] + let r = 0 + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] === 1) r += h(i, j) + } + } + + return r + + function h(i, j) { + let res = 0 + for(let d of dirs) { + const nr = i + d[0] + const nc = j + d[1] + if(nr < 0 || nc < 0 || nr >= m || nc >= n || grid[nr][nc] === 0) res++ + } + return res + } +}; diff --git a/464-can-i-win.js b/464-can-i-win.js new file mode 100644 index 00000000..35423537 --- /dev/null +++ b/464-can-i-win.js @@ -0,0 +1,26 @@ +/** + * @param {number} maxChoosableInteger + * @param {number} desiredTotal + * @return {boolean} + */ +const canIWin = function(maxChoosableInteger, desiredTotal) { + if (desiredTotal <= 0) return true + if ((maxChoosableInteger * (1 + maxChoosableInteger)) / 2 < desiredTotal) + return false + const dp = new Array(1 << maxChoosableInteger).fill(0) + return dfs(dp, 0, maxChoosableInteger, desiredTotal) + + function dfs(dp, chs, max, target) { + if (target <= 0) return false + if (dp[chs] != 0) return dp[chs] === 1 + let win = false + for (let i = 0; i < max; i++) { + if ((chs & (1 << i)) === 0) { + //not used + win = win || !dfs(dp, chs ^ (1 << i), max, target - i - 1) + } + } + dp[chs] = win ? 1 : -1 + return win + } +} diff --git a/465-optimal-account-balancing.js b/465-optimal-account-balancing.js new file mode 100644 index 00000000..c3d21412 --- /dev/null +++ b/465-optimal-account-balancing.js @@ -0,0 +1,81 @@ +/** + +A group of friends went on holiday and sometimes lent each other money. +For example, Alice paid for Bill's lunch for $10. +Then later Chris gave Alice $5 for a taxi ride. +We can model each transaction as a tuple (x, y, z) which means person x gave person y $z. +Assuming Alice, Bill, and Chris are person 0, 1, and 2 respectively (0, 1, 2 are the person's ID), +the transactions can be represented as [[0, 1, 10], [2, 0, 5]]. + +Given a list of transactions between a group of people, +return the minimum number of transactions required to settle the debt. + +Note: + +A transaction will be given as a tuple (x, y, z). Note that x ≠ y and z > 0. +Person's IDs may not be linear, e.g. we could have the persons 0, 1, 2 or we could also have the persons 0, 2, 6. +Example 1: + +Input: +[[0,1,10], [2,0,5]] + +Output: +2 + +Explanation: +Person #0 gave person #1 $10. +Person #2 gave person #0 $5. + +Two transactions are needed. One way to settle the debt is person #1 pays person #0 and #2 $5 each. +Example 2: + +Input: +[[0,1,10], [1,0,1], [1,2,5], [2,0,5]] + +Output: +1 + +Explanation: +Person #0 gave person #1 $10. +Person #1 gave person #0 $1. +Person #1 gave person #2 $5. +Person #2 gave person #0 $5. + +Therefore, person #1 only need to give person #0 $4, and all debt is settled. + +*/ + +/** + * @param {number[][]} transactions + * @return {number} + */ +const minTransfers = function(transactions) { + if (transactions.length === 0) return 0; + const map = new Map(); + for (let [a, b, m] of transactions) { + if (!map.has(a)) map.set(a, 0); + if (!map.has(b)) map.set(b, 0); + map.set(a, map.get(a) - m); + map.set(b, map.get(b) + m); + } + const debts = [...map.values()].filter(debt => debt !== 0); + const len = debts.length; + const dfs = (id, d) => { + if (id >= d.length) return 0; + const cur = d[id]; + if (cur === 0) return dfs(id + 1, d); + + let res = Infinity; + for (let i = id + 1; i < len; i++) { + const next = d[i]; + if (cur * next < 0) { + d[i] = cur + next; + res = Math.min(res, 1 + dfs(id + 1, d)); + d[i] = next; + if (next + cur === 0) break; + } + } + return res; + }; + return dfs(0, debts); +}; diff --git a/468-validate-ip-address.js b/468-validate-ip-address.js new file mode 100644 index 00000000..d421c6c6 --- /dev/null +++ b/468-validate-ip-address.js @@ -0,0 +1,78 @@ +/** + * @param {string} IP + * @return {string} + */ +const validIPAddress = function (IP) { + if (IP.indexOf('.') > 0) return validIPv4(IP) ? 'IPv4' : 'Neither' + else return validIPv6(IP) ? 'IPv6' : 'Neither' +} + +const validIPv4 = function (IP) { + const strs = IP.split('.') + if (strs.length !== 4) return false + for (let str of strs) { + if (str.length === 0) return false + if (str.match(/[^0-9]/)) return false + if (str.length > 1 && str.charAt(0) === '0') return false + if (+str > 255) return false + } + return true +} + +const validIPv6 = function (IP) { + const strs = IP.split(':') + if (strs.length !== 8) return false + for (let str of strs) { + if (str.length === 0) return false + if (str.length > 4) return false + if (str.match(/[^0-9a-fA-F]/g)) return false + } + return true +} + +// another + +/** + * @param {string} IP + * @return {string} + */ +const validIPAddress = function(IP) { + const ipv4 = /^((\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.){4}$/ + const ipv6 = /^([\da-f]{1,4}:){8}$/i + return ipv4.test(IP + '.') ? 'IPv4' : ipv6.test(IP + ':') ? 'IPv6' : 'Neither' +} + +// another + +/** + * @param {string} IP + * @return {string} + */ +const validIPAddress = function(IP) { + if (IP.indexOf('.') != -1) { + const arr = IP.split('.') + if (arr.length !== 4) return 'Neither' + for (let i = 0; i < arr.length; i++) { + const numVal = parseInt(arr[i]) + if ( + numVal < 0 || + numVal >= 256 || + arr[i].length !== ('' + numVal).length + ) { + return 'Neither' + } + } + return 'IPv4' + } else if (IP.indexOf(':') != -1) { + const arr = IP.split(':') + if (arr.length !== 8) return 'Neither' + for (let i = 0; i < arr.length; i++) { + if (arr[i].length > 4 || arr[i].length === 0) return 'Neither' + const re = /[^0-9A-F]/i + if (re.test(arr[i])) return 'Neither' + } + return 'IPv6' + } else { + return 'Neither' + } +} diff --git a/469-convex-polygon.js b/469-convex-polygon.js new file mode 100644 index 00000000..bf2741be --- /dev/null +++ b/469-convex-polygon.js @@ -0,0 +1,32 @@ +/** + * @param {number[][]} points + * @return {boolean} + */ +const isConvex = function(points) { + let negative = false + let positive = false + const num = points.length + for (let p1 = 0; p1 < num; p1 += 1) { + const p2 = (p1 + 1) % num + const p3 = (p2 + 1) % num + const [Ax, Ay] = points[p1] + const [Bx, By] = points[p2] + const [Cx, Cy] = points[p3] + const crossProduct = CrossProductLength(Ax, Ay, Bx, By, Cx, Cy) + if (crossProduct < 0) { + negative = true + } else if (crossProduct > 0) { + positive = true + } + if (negative && positive) return false + } + return true +} + +function CrossProductLength(Ax, Ay, Bx, By, Cx, Cy) { + const BAx = Ax - Bx + const BAy = Ay - By + const BCx = Cx - Bx + const BCy = Cy - By + return BAx * BCy - BAy * BCx +} diff --git a/47-permutations-ii.js b/47-permutations-ii.js index 47d28267..02337a11 100644 --- a/47-permutations-ii.js +++ b/47-permutations-ii.js @@ -29,3 +29,36 @@ function permuteUniqueHelper(m, l, p, i, r) { } } } + + +// another + +/** + * @param {number[]} nums + * @return {number[][]} + */ +const permuteUnique = function(nums) { + const set = new Set() + const used = new Set() + bt(nums, 0, [], used, set) + const res = [] + for(let item of set) { + res.push(item.split(',')) + } + return res +}; + +function bt(nums, i, cur, used, set) { + if(i === nums.length) { + set.add(cur.slice().join(',')) + return + } + for(let idx = 0; idx < nums.length; idx++) { + if(used.has(idx)) continue + cur.push(nums[idx]) + used.add(idx) + bt(nums, i + 1, cur, used, set) + used.delete(idx) + cur.pop() + } +} diff --git a/470-implement-rand10-using-rand7.js b/470-implement-rand10-using-rand7.js new file mode 100644 index 00000000..eef7543c --- /dev/null +++ b/470-implement-rand10-using-rand7.js @@ -0,0 +1,26 @@ +/** + * The rand7() API is already defined for you. + * var rand7 = function() {} + * @return {number} a random integer in the range 1 to 7 + */ +const rand10 = function() { + let result = 40 + while (result >= 40) { + result = 7 * (rand7() - 1) + (rand7() - 1) + } + return (result % 10) + 1 +} + +// another + +/** + * The rand7() API is already defined for you. + * var rand7 = function() {} + * @return {number} a random integer in the range 1 to 7 + */ +const rand10 = function() { + let tmp = 40 + while(tmp >= 40) tmp = 7 * (rand7() - 1) + (rand7() - 1) + + return tmp % 10 + 1 +}; diff --git a/471-encode-string-with-shortest-length.js b/471-encode-string-with-shortest-length.js new file mode 100644 index 00000000..1c296b8d --- /dev/null +++ b/471-encode-string-with-shortest-length.js @@ -0,0 +1,36 @@ +/** + * @param {string} s + * @return {string} + */ +const encode = function(s) { + let N = s.length + let dp = Array(N) + .fill(0) + .map(() => Array(N)) + for (let len = 1; len <= N; len++) { + for (let i = 0; i <= N - len; i++) { + let j = i + len - 1 + dp[i][j] = s.slice(i, j + 1) + if (len > 4) { + for (let m = i; m < j; m++) { + if (dp[i][j].length > dp[i][m].length + dp[m + 1][j].length) { + dp[i][j] = dp[i][m] + dp[m + 1][j] + } + } + let substr = s.slice(i, j + 1) + for (let k = 1; k <= Math.floor(len / 2); k++) { + if (len % k === 0) { + let first = s.slice(i, i + k) + if (substr.split(first).join('') === '') { + let newStr = len / k + '[' + dp[i][i + k - 1] + ']' + if (newStr.length < dp[i][j].length) { + dp[i][j] = newStr + } + } + } + } + } + } + } + return dp[0][N - 1] +} diff --git a/472-concatenated-words.js b/472-concatenated-words.js index 31cf5996..096a4693 100644 --- a/472-concatenated-words.js +++ b/472-concatenated-words.js @@ -1,3 +1,119 @@ +/** + * @param {string[]} words + * @return {string[]} + */ + +const findAllConcatenatedWordsInADict = function (words) { + const pre = new Set() + words.sort((a, b) => a.length - b.length) + const res = [] + for(let i = 0; i < words.length; i++) { + if(valid(words[i], pre)) { + res.push(words[i]) + } + pre.add(words[i]) + } + + return res + + function valid(str, set) { + if(set.size === 0) return false + const dp = Array(str.length + 1).fill(false) + dp[0] = true + for(let i = 1; i <= str.length; i++) { + for(let j = 0; j < i; j++) { + if(!dp[j]) continue + if(set.has(str.slice(j, i))) { + dp[i] = true + break + } + } + } + + return dp[str.length] + } +} + + + + +// another + +/** + * @param {string[]} words + * @return {string[]} + */ + +const findAllConcatenatedWordsInADict = function (words) { + const set = new Set(words) + const res = [] + const map = new Map() + for (let w of words) { + if (w.length < 2) continue + if (dfs(w, set, map, 0)) res.push(w) + } + return res + + function dfs(word, set, map, pos) { + if (pos > 0 && map.get(word)) return map.get(word) + if (pos > 0 && set.has(word)) { + map.set(word, true) + return map.get(word) + } + for (let i = 1; i < word.length; i++) { + const left = word.slice(0, i) + const right = word.slice(i) + if (set.has(right) && dfs(left, set, map, pos + 1)) { + map.set(word, true) + return map.get(word) + } + } + + map.set(word, false) + return false + } +} + +// another + +/** + * @param {string[]} words + * @return {string[]} + */ + +const findAllConcatenatedWordsInADict = function (words) { + const set = new Set(words) + const res = [] + const map = new Map() + + for(let word of words) { + if(dfs(word, 0)) res.push(word) + } + return res + function dfs(word, idx) { + if(map.has(word)) return map.get(word) + if(idx > 0 && set.has(word)) return true + let tmp = false + for(let i = 1; i < word.length; i++) { + const prefix = word.slice(0, i), suffix = word.slice(i) + if(set.has(prefix) && set.has(suffix)) { + tmp = true + break + } + if(set.has(prefix) && dfs(suffix, idx + 1)) { + tmp = true + break + } + } + + map.set(word, tmp) + return tmp + } +} + + +// another + /** * @param {string[]} words * @return {string[]} diff --git a/473-matchsticks-to-square.js b/473-matchsticks-to-square.js new file mode 100644 index 00000000..101edd1d --- /dev/null +++ b/473-matchsticks-to-square.js @@ -0,0 +1,61 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +const makesquare = function(nums) { + if (nums == null || nums.length < 4) return false + const sum = nums.reduce((ac, el) => ac + el, 0) + if (sum % 4 !== 0) return false + nums.sort((a, b) => b - a) + return dfs(nums, new Array(4).fill(0), 0, sum / 4) +} + +function dfs(nums, arr, idx, target) { + if (idx === nums.length) { + return true + } + for (let i = 0; i < 4; i++) { + if (arr[i] + nums[idx] > target || (i > 0 && arr[i] === arr[i - 1])) + continue + arr[i] += nums[idx] + if (dfs(nums, arr, idx + 1, target)) return true + arr[i] -= nums[idx] + } + return false +} + + + +// another + +/** + * @param {number[]} nums + * @return {boolean} + */ +const makesquare = function(nums) { + if (nums.length == 0) return false + const edge = nums.reduce((accum, val) => accum + val) / 4 + nums.sort((val1, val2) => val2 - val1) + if (edge !== Math.floor(edge)) return false + const findEdge = function(target) { + if (target <= 0) return target === 0 + let newNums = [] + while (nums.length) { + let item = nums.shift() + if (findEdge(target - item)) { + nums = newNums.concat(nums) + return true + } + newNums.push(item) + } + nums = newNums + return false + } + let count = 4 + while (count) { + if (!findEdge(edge)) return false + count-- + } + return true +} + diff --git a/475-heaters.js b/475-heaters.js new file mode 100644 index 00000000..316c0f51 --- /dev/null +++ b/475-heaters.js @@ -0,0 +1,70 @@ +/** + * @param {number[]} houses + * @param {number[]} heaters + * @return {number} + */ +const findRadius = function(houses, heaters) { + heaters.sort((a, b) => a - b) + return Math.max(...houses.map(h => findMinDistance(h, heaters))) +} + +const findMinDistance = (house, heaters) => { + let left = 0 + let right = heaters.length - 1 + while (left <= right) { + const mid = left + ((right - left) >> 1) + if (heaters[mid] <= house && house <= heaters[mid + 1]) { + return Math.min(house - heaters[mid], heaters[mid + 1] - house) + } else if (heaters[mid] <= house) { + left = mid + 1 + } else { + right = mid - 1 + } + } + if (left === 0) return heaters[0] - house + if (left === heaters.length) return house - heaters[heaters.length - 1] +} + +// another + +/** + * @param {number[]} houses + * @param {number[]} heaters + * @return {number} + */ +const findRadius = function(houses, heaters) { + let res = 0 + let k = 0 + houses = houses.sort((a, b) => a - b) + heaters = heaters.sort((a, b) => a - b) + for (let i = 0; i < houses.length; i++) { + const curr = houses[i] + while ( + k < heaters.length && + Math.abs(heaters[k + 1] - curr) <= Math.abs(heaters[k] - curr) + ) { + k++ + } + res = Math.max(res, Math.abs(heaters[k] - curr)) + } + return res +} + +// another + +/** + * @param {number[]} houses + * @param {number[]} heaters + * @return {number} + */ +const findRadius = function(houses, heaters) { + heaters.sort((a, b) => a - b) + houses.sort((a, b) => a - b) + let res = 0, i = 0 + for(let h of houses) { + while(i < heaters.length - 1 && heaters[i] + heaters[i + 1] <= h * 2) i++ + res = Math.max(res, Math.abs(heaters[i] - h)) + } + return res +} + diff --git a/476-number-complement.js b/476-number-complement.js new file mode 100644 index 00000000..a41a0495 --- /dev/null +++ b/476-number-complement.js @@ -0,0 +1,13 @@ +/** + * @param {number} num + * @return {number} + */ +const findComplement = function(num) { + const toBin = num => (num >>> 0).toString(2) + const flip = str => { + let res = '' + for(let c of str) res += (c === '1' ? '0' : '1') + return res + } + return parseInt(flip(toBin(num)), 2) +}; diff --git a/478-generate-random-point-in-a-circle.js b/478-generate-random-point-in-a-circle.js new file mode 100644 index 00000000..65b17eb4 --- /dev/null +++ b/478-generate-random-point-in-a-circle.js @@ -0,0 +1,27 @@ +/** + * @param {number} radius + * @param {number} x_center + * @param {number} y_center + */ +const Solution = function(radius, x_center, y_center) { + this.radius = radius + this.x_center = x_center + this.y_center = y_center +} + +/** + * @return {number[]} + */ +Solution.prototype.randPoint = function() { + let len = Math.sqrt(Math.random()) * this.radius + let deg = Math.random() * 2 * Math.PI + let x = this.x_center + len * Math.cos(deg) + let y = this.y_center + len * Math.sin(deg) + return [x, y] +} + +/** + * Your Solution object will be instantiated and called as such: + * var obj = new Solution(radius, x_center, y_center) + * var param_1 = obj.randPoint() + */ diff --git a/479-largest-palindrome-product.js b/479-largest-palindrome-product.js new file mode 100644 index 00000000..429c8aa4 --- /dev/null +++ b/479-largest-palindrome-product.js @@ -0,0 +1,81 @@ +/** + * @param {number} n + * @return {number} + */ +function largestPalindrome(n) { + if(n === 1) return 9 + let max = BigInt(10 ** n - 1), min = max / 10n + 1n + for(let h = max; h >= min; h--) { + let left = h, right = 0n + for(let i = h; i !== 0n; ) { + right = right * 10n + i % 10n + i = i / 10n + left *= 10n + } + let pal = left + right + for(let i = max; i >= min; i--) { + let j = pal / i + if(j > i) break + if(pal % i === 0n) return pal % 1337n + } + } +} + +// another + +/** + * @param {number} n + * @return {number} + */ +const largestPalindrome = function (n) { + if (n === 1) return 9 + for (let i = 2, limit = 9 * 10 ** (n - 1); i < limit; i++) { + let left = 10 ** n - i + let right = +('' + left).split('').reverse().join('') + if (i ** 2 - 4 * right < 0) continue + const tmp = (i ** 2 - 4 * right) ** 0.5 + if (tmp === Math.floor(tmp)) { + return ( + (BigInt(right) + 10n ** BigInt(n) * (10n ** BigInt(n) - BigInt(i))) % + 1337n + ) + } + } +} + +// another + +/** + * @param {number} n + * @return {number} + */ +const largestPalindrome = function(n) { + if (n === 1) { + return 9 + } else if (n === 8) { + return 475 + } + let max = Math.pow(10, n) + let min = Math.pow(10, n - 1) + let ret = 0 + + for (let i = max - 1; i > 0; i--) { + ret = i * max + getReverse(i) + for (let factor = ~~Math.sqrt(ret); factor < max; factor++) { + if (ret % factor == 0 && ret / factor < max) { + return ret % 1337 + } + } + } + return -1 +} + +function getReverse(n) { + let result = 0 + let num = n + while (num > 0) { + result = result * 10 + (num % 10) + num = ~~(num / 10) + } + return result +} diff --git a/48-rotate-image.js b/48-rotate-image.js index 7274fa2d..83583d57 100644 --- a/48-rotate-image.js +++ b/48-rotate-image.js @@ -21,3 +21,46 @@ const rotate = function(matrix) { } } } + +// another + +/** + * @param {number[][]} matrix + * @return {void} Do not return anything, modify matrix in-place instead. + */ +const rotate = function (matrix) { + matrix.reverse() + for (let i = 0; i < matrix.length; ++i) { + for (let j = i + 1; j < matrix[i].length; ++j) swap(matrix, i, j) + } +} + +function swap(matrix, i, j) { + const tmp = matrix[j][i] + matrix[j][i] = matrix[i][j] + matrix[i][j] = tmp +} + +// another + +/** + * @param {number[][]} matrix + * @return {void} Do not return anything, modify matrix in-place instead. + */ +const rotate = function (matrix) { + matrix.reverse() + for (let i = 0; i < matrix.length; ++i) { + for (let j = matrix[i].length - 1; j > i; j--) swap(matrix, i, j) + } +} + +function swap(matrix, i, j) { + const tmp = matrix[j][i] + matrix[j][i] = matrix[i][j] + matrix[i][j] = tmp +} +/* +1 2 3 7 8 9 7 4 1 +4 5 6 ---> 4 5 6 --->8 5 2 +7 8 9 1 2 3 9 6 3 +*/ diff --git a/482-license-key-formatting.js b/482-license-key-formatting.js new file mode 100644 index 00000000..45f818c1 --- /dev/null +++ b/482-license-key-formatting.js @@ -0,0 +1,14 @@ +/** + * @param {string} S + * @param {number} K + * @return {string} + */ +const licenseKeyFormatting = function(S, K) { + if (S == null || S === "") return ""; + const newStr = S.replace(/-/g, "").toUpperCase(); + const arr = newStr.split(""); + for (let i = arr.length - 1 - K; i >= 0; i -= K) { + arr[i] = arr[i] + "-"; + } + return arr.join(""); +}; diff --git a/483-smallest-good-base.js b/483-smallest-good-base.js new file mode 100644 index 00000000..b47b275d --- /dev/null +++ b/483-smallest-good-base.js @@ -0,0 +1,44 @@ +/** + * @param {string} n + * @return {string} + */ +const smallestGoodBase = function(n) { + const N = BigInt(n), + bigint2 = BigInt(2), + bigint1 = BigInt(1), + bigint0 = BigInt(0) + let maxLen = countLength(N, bigint2) + for (let length = maxLen; length > 0; length--) { + let [found, base] = findMatchInHalf(length) + if (found) return '' + base + } + return '' + (N - 1) + function findMatchInHalf(length, smaller = bigint2, bigger = N) { + if (smaller > bigger) return [false] + if (smaller === bigger) { + return [valueOf1s(smaller, length) === N, smaller] + } + let mid = (smaller + bigger) / bigint2 + let val = valueOf1s(mid, length) + if (val === N) return [true, mid] + if (val > N) return findMatchInHalf(length, smaller, mid - bigint1) + return findMatchInHalf(length, mid + bigint1, bigger) + } + function valueOf1s(base, lengthOf1s) { + let t = bigint1 + for (let i = 1; i < lengthOf1s; i++) { + t *= base + t += bigint1 + } + return t + } + function countLength(N, base) { + let t = N, + len = 0 + while (t > bigint0) { + t /= base + len++ + } + return len + } +} diff --git a/484-find-permutation.js b/484-find-permutation.js new file mode 100644 index 00000000..18d3d441 --- /dev/null +++ b/484-find-permutation.js @@ -0,0 +1,72 @@ +/** + * @param {string} s + * @return {number[]} + */ +const findPermutation = function(s) { + const n = s.length + const res = Array(n + 1) + res[n] = n + 1 + for (let i = 0, len = n; i < len;) { + let j = i; + while (j < len && s.charAt(j) === 'D') { + j++; + } + for (let k = j - i; k >= 0; k--, j--) { + res[i++] = j + 1; + } + } + return res; +}; + +// another + +/** + * @param {string} s + * @return {number[]} + */ +const findPermutation = function(s) { + const n = s.length + const res = Array(n) + res[n] = n + 1 + for(let i = 0; i < n;) { + let j = i + while(j < n && s[j] === 'D') j++ + // console.log(j) + for(let k = j - i + 1; k > 0; k--) { + res[i] = j + 1 + i++ + j-- + } + } + + return res +}; + + +// another + +/** + * @param {string} s + * @return {number[]} + */ +const findPermutation = function(s) { + const n = s.length + const arr = Array.from({ length: n + 1 }, (el, idx) => idx + 1) + for(let h = 0; h < n; h++) { + if(s.charAt(h) === 'D') { + const l = h + while(h < n && s.charAt(h) === 'D') h++ + reverse(arr, l, h) + } + } + return arr +}; + +function reverse(arr, l, h) { + while(l < h) { + arr[l] ^= arr[h] + arr[h] ^= arr[l] + arr[l] ^= arr[h] + l++, h-- + } +} diff --git a/487-max-consecutive-ones-ii.js b/487-max-consecutive-ones-ii.js new file mode 100644 index 00000000..e200962d --- /dev/null +++ b/487-max-consecutive-ones-ii.js @@ -0,0 +1,35 @@ +/** + +Given a binary array, find the maximum number of consecutive 1s in this array if you can flip at most one 0. + +Example 1: +Input: [1,0,1,1,0] +Output: 4 +Explanation: Flip the first zero will get the the maximum number of consecutive 1s. + After flipping, the maximum number of consecutive 1s is 4. +Note: + +The input array will only contain 0 and 1. +The length of input array is a positive integer and will not exceed 10,000 +Follow up: +What if the input numbers come in one by one as an infinite stream? +In other words, you can't store all numbers coming from the stream as it's too large to hold in memory. +Could you solve it efficiently? + +*/ + +/** + * @param {number[]} nums + * @return {number} + */ +const findMaxConsecutiveOnes = function(nums) { + let max = 0, + k = 1 + const zeroIndex = [] + for (let l = 0, h = 0; h < nums.length; h++) { + if (nums[h] === 0) zeroIndex.push(h) + if (zeroIndex.length > k) l = zeroIndex.shift() + 1 + max = Math.max(max, h - l + 1) + } + return max +} diff --git a/488-zuma-game.js b/488-zuma-game.js new file mode 100644 index 00000000..9a0ca829 --- /dev/null +++ b/488-zuma-game.js @@ -0,0 +1,89 @@ +/** + +Think about Zuma Game. You have a row of balls on the table, colored red(R), yellow(Y), blue(B), green(G), and white(W). +You also have several balls in your hand. + +Each time, you may choose a ball in your hand, and insert it into the row (including the leftmost place and rightmost place). +Then, if there is a group of 3 or more balls in the same color touching, remove these balls. +Keep doing this until no more balls can be removed. + +Find the minimal balls you have to insert to remove all the balls on the table. +If you cannot remove all the balls, output -1. + +Example 1: + +Input: board = "WRRBBW", hand = "RB" +Output: -1 +Explanation: WRRBBW -> WRR[R]BBW -> WBBW -> WBB[B]W -> WW +Example 2: + +Input: board = "WWRRBBWW", hand = "WRBRW" +Output: 2 +Explanation: WWRRBBWW -> WWRR[R]BBWW -> WWBBWW -> WWBB[B]WW -> WWWW -> empty +Example 3: + +Input: board = "G", hand = "GGGGG" +Output: 2 +Explanation: G -> G[G] -> GG[G] -> empty +Example 4: + +Input: board = "RBYYBBRRB", hand = "YRBGB" +Output: 3 +Explanation: RBYYBBRRB -> RBYY[Y]BBRRB -> RBBBRRB -> RRRB -> B -> B[B] -> BB[B] -> empty + + +Constraints: + +You may assume that the initial row of balls on the table won’t have any 3 or more consecutive balls with the same color. +The number of balls on the table won't exceed 16, and the string represents these balls is called "board" in the input. +The number of balls in your hand won't exceed 5, and the string represents these balls is called "hand" in the input. +Both input strings will be non-empty and only contain characters 'R','Y','B','G','W'. + +*/ + +/** + * @param {string} board + * @param {string} hand + * @return {number} + */ +const findMinStep = function(board, hand) { + const map = {} + for (let c of hand) map[c] = (map[c] || 0) + 1 + const res = helper(board, map) + return res === Number.MAX_VALUE ? -1 : res +} + +function helper(s, m) { + const str = reduce(s) + if (str.length === 0) return 0 + let res = Number.MAX_VALUE + let i = 0 + while (i < str.length) { + const beg = i + while (i < str.length && str[i] === str[beg]) { + i++ + } + if (m[str[beg]] >= 3 - (i - beg)) { + const dval = 3 - i + beg + m[str[beg]] -= dval + const tmp = helper(s.slice(0, beg) + s.slice(i), m) + m[str[beg]] += dval + if (tmp !== Number.MAX_VALUE) res = res < tmp + dval ? res : tmp + dval + } + } + return res +} +function reduce(str) { + let res = '' + let i = 0 + while (i < str.length) { + const beg = i + while (i < str.length && str[beg] === str[i]) { + i++ + } + if (i - beg >= 3) { + return reduce(str.slice(0, beg) + str.slice(i)) + } + } + return str +} diff --git a/489-robot-room-cleaner.js b/489-robot-room-cleaner.js new file mode 100644 index 00000000..b1c55cef --- /dev/null +++ b/489-robot-room-cleaner.js @@ -0,0 +1,101 @@ +/** + * // This is the robot's control interface. + * // You should not implement it, or speculate about its implementation + * function Robot() { + * + * // Returns true if the cell in front is open and robot moves into the cell. + * // Returns false if the cell in front is blocked and robot stays in the current cell. + * @return {boolean} + * this.move = function() { + * ... + * }; + * + * // Robot will stay in the same cell after calling turnLeft/turnRight. + * // Each turn will be 90 degrees. + * @return {void} + * this.turnLeft = function() { + * ... + * }; + * + * // Robot will stay in the same cell after calling turnLeft/turnRight. + * // Each turn will be 90 degrees. + * @return {void} + * this.turnRight = function() { + * ... + * }; + * + * // Clean the current cell. + * @return {void} + * this.clean = function() { + * ... + * }; + * }; + */ +/** + * @param {Robot} robot + * @return {void} + */ +const cleanRoom = function(robot) { + const visited = new Set() + const shift = [ + [-1, 0], + [0, 1], + [1, 0], + [0, -1] + ] + dfs(0, 0, 0) + function dfs(r, c, dir) { + visited.add(r + ',' + c) + robot.clean() + for (let i = 0; i < 4; i++) { + const newDir = (dir + i) % 4 + const x = shift[newDir][0] + r + const y = shift[newDir][1] + c + if (!visited.has(x + ',' + y) && robot.move()) { + dfs(x, y, newDir) + robot.turnRight() + robot.turnRight() + robot.move() + robot.turnRight() + robot.turnRight() + } + robot.turnRight() + } + } +} + +// another + +/** + * @param {Robot} robot + * @return {void} + */ +const cleanRoom = function(robot) { + const dirs = [ + [-1, 0], + [0, 1], + [1, 0], + [0, -1] + ] + const visited = new Set() + clean(0, 0, 0) + function clean( x, y, curDirection) { + robot.clean() + visited.add(`${x},${y}`) + for(let i = curDirection; i < curDirection + 4; i++) { + const nx = dirs[i % 4][0] + x + const ny = dirs[i % 4][1] + y + if(!visited.has(`${nx},${ny}`) && robot.move()) { + clean(nx, ny, i % 4) + } + robot.turnRight() + } + robot.turnRight() + robot.turnRight() + robot.move() + robot.turnRight() + robot.turnRight() + + } +}; + diff --git a/49-group-anagrams.js b/49-group-anagrams.js index f5baeff2..dfffbb2f 100755 --- a/49-group-anagrams.js +++ b/49-group-anagrams.js @@ -1,3 +1,32 @@ +/** + * @param {string[]} strs + * @return {string[][]} + */ +const groupAnagrams = (strs) => { + const resp = new Array(), + termsGrouped = new Map() + strs.forEach((term) => { + const hashed = hash(term) + if (!termsGrouped.has(hashed)) termsGrouped.set(hashed, new Array()) + termsGrouped.get(hashed).push(term) + }) + termsGrouped.forEach((terms) => { + resp.push(terms) + }) + return resp +} + +const hash = (term) => { + const arr = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for(let i = 0, len = term.length; i < len; i++) { + arr[term[i].charCodeAt(0) - a]++ + } + return arr.join('-') +} + +// another + /** * @param {string[]} strs * @return {string[][]} @@ -19,6 +48,5 @@ const groupAnagrams = function(strs) { hash[sel] = [el]; } } - return Object.values(hash); }; diff --git a/490-the-maze.js b/490-the-maze.js new file mode 100644 index 00000000..a19f6cb2 --- /dev/null +++ b/490-the-maze.js @@ -0,0 +1,215 @@ +/** + +There is a ball in a maze with empty spaces and walls. +The ball can go through empty spaces by rolling up, down, left or right, +but it won't stop rolling until hitting a wall. When the ball stops, it could choose the next direction. +Given the ball's start position, the destination and the maze, determine whether the ball could stop at the destination. + +The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty space. +You may assume that the borders of the maze are all walls. +The start and destination coordinates are represented by row and column indexes. + +Example 1: + +Input 1: a maze represented by a 2D array + +0 0 1 0 0 +0 0 0 0 0 +0 0 0 1 0 +1 1 0 1 1 +0 0 0 0 0 + +Input 2: start coordinate (rowStart, colStart) = (0, 4) +Input 3: destination coordinate (rowDest, colDest) = (4, 4) + +Output: true + +Explanation: One possible way is : left -> down -> left -> down -> right -> down -> right. + +Example 2: + +Input 1: a maze represented by a 2D array + +0 0 1 0 0 +0 0 0 0 0 +0 0 0 1 0 +1 1 0 1 1 +0 0 0 0 0 + +Input 2: start coordinate (rowStart, colStart) = (0, 4) +Input 3: destination coordinate (rowDest, colDest) = (3, 2) + +Output: false + +Explanation: There is no way for the ball to stop at the destination. + +Note: + +There is only one ball and one destination in the maze. +Both the ball and the destination exist on an empty space, and they will not be at the same position initially. +The given maze does not contain border (like the red rectangle in the example pictures), +but you could assume the border of the maze are all walls. +The maze contains at least 2 empty spaces, and both the width and height of the maze won't exceed 100. + +*/ + +/** + * @param {number[][]} maze + * @param {number[]} start + * @param {number[]} destination + * @return {boolean} + */ +const hasPath = function(maze, start, destination) { + const m = maze.length + const n = maze[0].length + const queue = [] + const visited = Array.from({ length: m }, () => new Array(n).fill(false)) + queue.push(start) + const dirs = [ + [-1, 0], + [0, -1], + [0, 1], + [1, 0] + ] + while (queue.length) { + const cur = queue.shift() + if (cur[0] === destination[0] && cur[1] === destination[1]) return true + if (visited[cur[0]][cur[1]]) continue + visited[cur[0]][cur[1]] = true + for (let dir of dirs) { + let x = cur[0], + y = cur[1] + while (x >= 0 && x < m && y >= 0 && y < n && maze[x][y] === 0) { + x += dir[0] + y += dir[1] + } + x -= dir[0] + y -= dir[1] + queue.push([x, y]) + } + } + return false +} + +// another + +/** + * @param {number[][]} maze + * @param {number[]} start + * @param {number[]} destination + * @return {boolean} + */ +const hasPath = function(maze, start, destination) { + const visited = Array.from({ length: maze.length }, () => + new Array(maze[0].length).fill(false) + ) + const dirs = [ + [-1, 0], + [0, -1], + [0, 1], + [1, 0] + ] + return dfs(maze, start, destination, visited, dirs) +} + +function dfs(maze, start, destination, visited, dirs) { + if (visited[start[0]][start[1]]) return false + if (start[0] === destination[0] && start[1] === destination[1]) return true + visited[start[0]][start[1]] = true + for (let i = 0; i < dirs.length; i++) { + const d = dirs[i] + let row = start[0] + let col = start[1] + while (isValid(maze, row + d[0], col + d[1])) { + row += d[0] + col += d[1] + } + if (dfs(maze, [row, col], destination, visited, dirs)) return true + } + return false +} + +function isValid(maze, row, col) { + return ( + row >= 0 && + row < maze.length && + col >= 0 && + col < maze[0].length && + maze[row][col] !== 1 + ) +} + +// another + +/** + * @param {number[][]} maze + * @param {number[]} start + * @param {number[]} destination + * @return {boolean} + */ +const hasPath = function(maze, start, destination) { + const m = maze.length, n = maze[0].length + const dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]] + const visited = new Set() + let res = false + dfs(start[0], start[1]) + return res + + function dfs(i, j) { + if(i < 0 || i >= m || j < 0 || j >= n || maze[i][j] === 1 || visited.has(`${i},${j}`)) return + if(i === destination[0] && j === destination[1]) { + res = true + return + } + visited.add(`${i},${j}`) + const ib = i, jb = j + for(const [dx, dy] of dirs) { + let ii = i, jj = j + while( + ii + dx >= 0 && + ii + dx < m && + jj + dy >= 0 && + jj + dy < n && + maze[ii + dx][jj + dy] === 0 + ) { + ii += dx + jj += dy + } + dfs(ii, jj) + } + } +}; + +// another + +/** + * @param {number[][]} maze + * @param {number[]} start + * @param {number[]} destination + * @return {boolean} + */ +const hasPath = function(maze, start, destination) { + const m = maze.length, n = maze[0].length + const dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]] + const visited = new Set() + const q = [start] + while(q.length) { + const [i, j] = q.pop() + if(i === destination[0] && j === destination[1]) return true + visited.add(`${i},${j}`) + for(const [dx, dy] of dirs) { + let ni = i, nj = j + while(valid(ni + dx, nj + dy)) { + ni += dx + nj += dy + } + if(!visited.has(`${ni},${nj}`)) q.push([ni, nj]) + } + } + + return false + + function valid(i, j) { + return i >= 0 && i < m && j >= 0 && j < n && maze[i][j] === 0 + } +}; diff --git a/492-construct-the-rectangle.js b/492-construct-the-rectangle.js new file mode 100644 index 00000000..59e6e663 --- /dev/null +++ b/492-construct-the-rectangle.js @@ -0,0 +1,9 @@ +/** + * @param {number} area + * @return {number[]} + */ +const constructRectangle = function(area) { + let w = Math.sqrt(area) >> 0; + while (area % w != 0) w--; + return [(area / w) >> 0, w]; +}; diff --git a/493-reverse-pairs.js b/493-reverse-pairs.js index 2f0bab92..1ad26aa2 100644 --- a/493-reverse-pairs.js +++ b/493-reverse-pairs.js @@ -1,3 +1,52 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const reversePairs = function(nums) { + return mergeSort(nums, [], 0, nums.length-1); +}; + +function mergeSort(arr, temp, left, right){ + let mid = Math.floor((left+right)/2), count = 0; + if(left2*a[j])){ + j++; + } + count+= (j-(mid)); + } + i=left; + j=mid; + while(i<=(mid-1) && j<=right){ + if (a[i]>(a[j])) { + temp[k++] = a[j++]; + } else { + temp[k++] = a[i++]; + } + } + while(i<=(mid-1)){ + temp[k++] = a[i++]; + } + while(j<=right){ + temp[k++] = a[j++]; + } + for(let x=left; x<=right; x++){ + a[x] = temp[x]; + } + return count; +} + +// another + /** * @param {number[]} nums * @return {number} @@ -48,7 +97,7 @@ function merge(A, start, mid, end) { function mergesort_and_count(A, start, end) { if (start < end) { - let mid = ((start + end) >> 1) + let mid = start + ((end - start) >> 1) let count = mergesort_and_count(A, start, mid) + mergesort_and_count(A, mid + 1, end) let j = mid + 1 diff --git a/494-target-sum.js b/494-target-sum.js index 8fe84b51..2a414a41 100755 --- a/494-target-sum.js +++ b/494-target-sum.js @@ -1,3 +1,59 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const findTargetSumWays = function(nums, target) { + const n = nums.length + let res = 0 + for(let i = 0, limit = Math.pow(2, n); i < limit; i++) { + if(helper(i)) res++ + } + + return res + + function helper(mask) { + let sum = 0 + for(let i = 0; i < nums.length; i++) { + if(mask & (1 << i)) { + sum += nums[i] + } else sum -= nums[i] + } + + return sum === target + } +}; + +// another + +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +const findTargetSumWays = function(nums, target) { + const sum = nums.reduce((a, b) => a+b); + if(Math.abs(target) > sum) { + return 0; + } + if((target + sum) % 2) { + return 0; + } + const newTarget = (target + sum) / 2; + let dp = new Array(newTarget+1).fill(0); + dp[0] = 1; + for(let i = 0; i < nums.length; i++) { + for(let j = newTarget; j >= nums[i]; j--) { + dp[j] += dp[j - nums[i]]; + } + } + return dp[newTarget]; +}; + + + +// another + /** * @param {number[]} nums * @param {number} S diff --git a/495-teemo-attacking.js b/495-teemo-attacking.js new file mode 100644 index 00000000..47876b5a --- /dev/null +++ b/495-teemo-attacking.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} timeSeries + * @param {number} duration + * @return {number} + */ +const findPoisonedDuration = function(timeSeries, duration) { + if (timeSeries == null || timeSeries.length === 0) return 0 + let res = 0 + for (let i = 1, len = timeSeries.length; i < len; i++) { + const tmp = + timeSeries[i - 1] + duration > timeSeries[i] + ? timeSeries[i] - timeSeries[i - 1] + : duration + res += tmp + } + return res + duration +} diff --git a/496-next-greater-element-I.js b/496-next-greater-element-I.js index 663ef13e..e3b281bb 100755 --- a/496-next-greater-element-I.js +++ b/496-next-greater-element-I.js @@ -1,3 +1,35 @@ +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number[]} + */ +const nextGreaterElement = function(nums1, nums2) { + const map = new Map() + const stk = [] + + for(let i = 0, n = nums2.length; i < n; i++) { + const e = nums2[i] + while(stk.length && stk.at(-1) < e) { + const tmp = stk.pop() + map.set(tmp, e) + } + stk.push(e) + } + + const res = [] + for(const e of nums1) { + if(map.has(e)) { + res.push(map.get(e)) + } else { + res.push(-1) + } + } + + return res +}; + +// another + /** * @param {number[]} findNums * @param {number[]} nums diff --git a/497-random-point-in-non-overlapping-rectangles.js b/497-random-point-in-non-overlapping-rectangles.js new file mode 100644 index 00000000..1dc372ac --- /dev/null +++ b/497-random-point-in-non-overlapping-rectangles.js @@ -0,0 +1,78 @@ +/** + * @param {number[][]} rects + */ +const Solution = function(rects) { + this.rects = rects + this.areas = rects.map(([x1, y1, x2, y2]) => (x2 - x1 + 1) * (y2 - y1 + 1)) +} + +/** + * @return {number[]} + */ +Solution.prototype.pick = function() { + const { rects, areas } = this + let areaSum = 0 + let selected + for (let i = 0; i < rects.length; i++) { + const area = areas[i] + areaSum += area + const p = area / areaSum + if (Math.random() < p) { + selected = rects[i] + } + } + const [x1, y1, x2, y2] = selected + return [ + ((Math.random() * (x2 - x1 + 1)) | 0) + x1, + ((Math.random() * (y2 - y1 + 1)) | 0) + y1 + ] +} +/** + * Your Solution object will be instantiated and called as such: + * var obj = new Solution(rects) + * var param_1 = obj.pick() + */ + +// another + +/** + * @param {number[][]} rects + */ +const Solution = function(rects) { + const xywhs = [] + const acc_sums = [0] + let sum = 0 + for (const [x, y, x2, y2] of rects) { + const w = x2 - x + 1 + const h = y2 - y + 1 + xywhs.push({ x, y, w, h }) + sum += w * h + acc_sums.push(sum) + } + this.xywhs = xywhs + this.acc_sums = acc_sums +} + +/** + * @return {number[]} + */ +Solution.prototype.pick = function() { + const picked = Math.floor( + Math.random() * this.acc_sums[this.acc_sums.length - 1] + ) + let i = 0 + for (; i < this.acc_sums.length - 2; i++) { + if (picked >= this.acc_sums[i] && picked < this.acc_sums[i + 1]) { + break + } + } + const { x, y, w, h } = this.xywhs[i] + return [x + Math.floor(Math.random() * w), y + Math.floor(Math.random() * h)] +} + +/** + * Your Solution object will be instantiated and called as such: + * var obj = new Solution(rects) + * var param_1 = obj.pick() + */ + diff --git a/498-diagonal-traverse.js b/498-diagonal-traverse.js new file mode 100644 index 00000000..214b065b --- /dev/null +++ b/498-diagonal-traverse.js @@ -0,0 +1,81 @@ +/** + * @param {number[][]} matrix + * @return {number[]} + */ +const findDiagonalOrder = function(matrix) { + if (!matrix.length || !matrix[0].length) { + return [] + } + const m = matrix.length + const n = matrix[0].length + const output = [] + for (let sum = 0; sum <= m + n - 2; sum++) { + for ( + let i = Math.min(m - 1, sum); + sum % 2 === 0 && isValid(i, sum - i, m, n); + i-- + ) { + const j = sum - i + output.push(matrix[i][j]) + } + for ( + let j = Math.min(n - 1, sum); + sum % 2 === 1 && isValid(sum - j, j, m, n); + j-- + ) { + const i = sum - j + output.push(matrix[i][j]) + } + } + return output +} + +function isValid(i, j, m, n) { + if (i < 0 || i >= m || j < 0 || j >= n) { + return false + } + return true +} + +// another + +/** + * @param {number[][]} matrix + * @return {number[]} + */ +const findDiagonalOrder = function(matrix) { + if (matrix.length == 0) return [] + let r = 0, + c = 0, + m = matrix.length, + n = matrix[0].length, + arr = new Array(m * n) + for (let i = 0; i < arr.length; i++) { + arr[i] = matrix[r][c] + if ((r + c) % 2 === 0) { + // moving up + if (c === n - 1) { + r++ + } else if (r === 0) { + c++ + } else { + r-- + c++ + } + } else { + // moving down + if (r === m - 1) { + c++ + } else if (c === 0) { + r++ + } else { + r++ + c-- + } + } + } + return arr +} + + + diff --git a/499-the-maze-iii.js b/499-the-maze-iii.js new file mode 100644 index 00000000..f7543ea1 --- /dev/null +++ b/499-the-maze-iii.js @@ -0,0 +1,230 @@ +/** + +There is a ball in a maze with empty spaces and walls. +The ball can go through empty spaces by rolling up (u), down (d), left (l) or right (r), +but it won't stop rolling until hitting a wall. When the ball stops, it could choose the next direction. +There is also a hole in this maze. The ball will drop into the hole if it rolls on to the hole. + +Given the ball position, the hole position and the maze, +find out how the ball could drop into the hole by moving the shortest distance. +The distance is defined by the number of empty spaces traveled by the ball from +the start position (excluded) to the hole (included). +Output the moving directions by using 'u', 'd', 'l' and 'r'. +Since there could be several different shortest ways, you should output the lexicographically smallest way. +If the ball cannot reach the hole, output "impossible". + +The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty space. +You may assume that the borders of the maze are all walls. +The ball and the hole coordinates are represented by row and column indexes. + +Example 1: + +Input 1: a maze represented by a 2D array + +0 0 0 0 0 +1 1 0 0 1 +0 0 0 0 0 +0 1 0 0 1 +0 1 0 0 0 + +Input 2: ball coordinate (rowBall, colBall) = (4, 3) +Input 3: hole coordinate (rowHole, colHole) = (0, 1) + +Output: "lul" + +Explanation: There are two shortest ways for the ball to drop into the hole. +The first way is left -> up -> left, represented by "lul". +The second way is up -> left, represented by 'ul'. +Both ways have shortest distance 6, but the first way is lexicographically smaller because 'l' < 'u'. So the output is "lul". + +Example 2: + +Input 1: a maze represented by a 2D array + +0 0 0 0 0 +1 1 0 0 1 +0 0 0 0 0 +0 1 0 0 1 +0 1 0 0 0 + +Input 2: ball coordinate (rowBall, colBall) = (4, 3) +Input 3: hole coordinate (rowHole, colHole) = (3, 0) + +Output: "impossible" + +Note: + +There is only one ball and one hole in the maze. +Both the ball and hole exist on an empty space, and they will not be at the same position initially. +The given maze does not contain border (like the red rectangle in the example pictures), +but you could assume the border of the maze are all walls. +The maze contains at least 2 empty spaces, and the width and the height of the maze won't exceed 30. + +*/ + +/** + * @param {number[][]} maze + * @param {number[]} ball + * @param {number[]} hole + * @return {string} + */ +function findShortestWay(maze, ball, hole) { + const H = maze.length + const W = maze[0].length + const costs = [...Array(H)].map(r => Array(W).fill(Number.MAX_VALUE)) + let minRoute = '' + dfs(ball[0], ball[1], 0, '') + return minRoute || 'impossible' + + function dfs(r, c, cost, route) { + if (cost >= costs[r][c]) return + costs[r][c] = cost + for (let [dr, dc, d] of [ + [1, 0, 'd'], + [0, -1, 'l'], + [0, 1, 'r'], + [-1, 0, 'u'] + ]) { + let rr = r + let cc = c + let steps = 0 + for ( + ; + rr + dr >= 0 && + rr + dr < H && + cc + dc >= 0 && + cc + dc < W && + maze[rr + dr][cc + dc] !== 1; + + ) { + rr += dr + cc += dc + steps++ + if (rr === hole[0] && cc === hole[1]) { + if (cost + steps < costs[hole[0]][hole[1]]) { + costs[hole[0]][hole[1]] = cost + steps + minRoute = route + d + } + return + } + } + dfs(rr, cc, cost + steps, route + d) + } + } +} + +// another + +const dirs = [ + [1, 0, 'd'], + [0, -1, 'l'], + [0, 1, 'r'], + [-1, 0, 'u'] +] + +/** + * @param {number[][]} maze + * @param {number[]} ball + * @param {number[]} hole + * @return {string} + */ +const findShortestWay = function(maze, ball, hole) { + const m = maze.length + const n = maze[0].length + const dist = [...new Array(m)].map(() => new Array(n).fill(Infinity)) + dist[ball[0]][ball[1]] = 0 + const pq = new PriorityQueue({ + comparator: (a, b) => { + if (dist[a[0][0]][a[0][1]] !== dist[b[0][0]][b[0][1]]) { + return dist[a[0][0]][a[0][1]] < dist[b[0][0]][b[0][1]] + } + return a[1] < b[1] + } + }) + pq.enqueue([ball, '']) + while (pq.length) { + const [[x, y], path] = pq.dequeue() + if (x === hole[0] && y === hole[1]) { + return path + } + for (const [di, dj, dir] of dirs) { + if (isValidPosition(x + di, y + dj, m, n) && maze[x + di][y + dj] === 0) { + const [i, j] = walk(maze, x + di, y + dj, di, dj, m, n, hole) + const deltaDist = Math.abs(x - i) + Math.abs(y - j) + if (dist[x][y] + deltaDist <= dist[i][j]) { + dist[i][j] = dist[x][y] + deltaDist + pq.enqueue([[i, j], path + dir]) + } + } + } + } + return 'impossible' +} + +function walk(maze, x, y, di, dj, m, n, [hi, hj]) { + let i = x + let j = y + while ( + isValidPosition(i + di, j + dj, m, n) && + maze[i + di][j + dj] === 0 && + !(hi === i && hj === j) + ) { + i += di + j += dj + } + return [i, j] +} + +function isValidPosition(i, j, m, n) { + if (i < 0 || i >= m || j < 0 || j >= n) { + return false + } + return true +} + +class PriorityQueue { + constructor({ comparator }) { + this.comparator = comparator + this.arr = [] + } + + enqueue(element) { + this.arr.push(element) + moveUp(this.arr, this.arr.length - 1, this.comparator) + } + + dequeue() { + const output = this.arr[0] + this.arr[0] = this.arr[this.arr.length - 1] + this.arr.pop() + moveDown(this.arr, 0, this.comparator) + return output + } + + get length() { + return this.arr.length + } +} + +function moveUp(arr, i, comparator) { + const p = Math.floor((i - 1) / 2) + const isValid = p < 0 || comparator(arr[p], arr[i]) + if (!isValid) { + ;[arr[i], arr[p]] = [arr[p], arr[i]] + moveUp(arr, p, comparator) + } +} + +function moveDown(arr, i, comparator) { + const left = 2 * i + 1 + const right = 2 * i + 2 + const isValid = + (left >= arr.length || comparator(arr[i], arr[left])) && + (right >= arr.length || comparator(arr[i], arr[right])) + if (!isValid) { + const next = + right >= arr.length || comparator(arr[left], arr[right]) ? left : right + ;[arr[i], arr[next]] = [arr[next], arr[i]] + moveDown(arr, next, comparator) + } +} diff --git a/5-longest-palindromic-substring.js b/5-longest-palindromic-substring.js index 1c460a1f..76afe7f4 100755 --- a/5-longest-palindromic-substring.js +++ b/5-longest-palindromic-substring.js @@ -70,3 +70,40 @@ function preProcess(s) { ret += "#$"; return ret; } + +// another + +/** + * @param {string} s + * @return {string} + */ +const longestPalindrome = function(s) { + const n = s.length + let res = '' + for(let i = 0; i < n; i++) { + const first = chk(s, i, i, n) + if(first.length > res.length) res = first + const second = chk(s, i, i + 1, n) + if(second.length > res.length) res = second + } + return res +}; + +function chk(str, i, j, n) { + if(j >= n) return str[i] + let l = i, r = j + while(l >= 0 && r < n) { + if(str[l] === str[r]) { + l-- + r++ + } else { + return str.slice(l + 1, r) + } + } + if(l < 0) { + return str.slice(0, r) + } else { + return str.slice(l + 1, n) + } +} + diff --git a/50-powx-n.js b/50-powx-n.js index e589e8ff..36c6619e 100644 --- a/50-powx-n.js +++ b/50-powx-n.js @@ -14,3 +14,68 @@ const myPow = function(x, n) { return myPow(1 / x, -n); } }; + +// another + +/** + * @param {number} x + * @param {number} n + * @return {number} + */ +const myPow = function(x, n) { + if(n === 0) return 1 + if(n === 1) return x + if(n < 0) { + x = 1 / x + n = -n + } + return n % 2 === 1 ? myPow(x, ~~(n / 2)) ** 2 * x : myPow(x, ~~(n / 2)) ** 2 +}; + +// another + +/** + * @param {number} x + * @param {number} n + * @return {number} + */ +const myPow = function (x, n) { + if (n === 0) return 1 + if (n < 0) { + if (n === -(2 ** 31)) { + ++n + n = -n + x = 1 / x + return x * x * myPow(x * x, n / 2) + } + n = -n + x = 1 / x + } + return n % 2 == 0 ? myPow(x * x, n / 2) : x * myPow(x * x, (n / 2) >> 0) +} + +// another + +/** + * @param {number} x + * @param {number} n + * @return {number} + */ +const myPow = function (x, n) { + if (n === 0) return 1 + if (n < 0) { + n = -n + x = 1 / x + } + let res = 1 + while (n > 0) { + if (n & 1) { + res *= x + --n + } + x *= x + n /= 2 + } + return res +} + diff --git a/502-ipo.js b/502-ipo.js index 95219ee7..9938088e 100644 --- a/502-ipo.js +++ b/502-ipo.js @@ -6,9 +6,104 @@ * @return {number} */ const findMaximizedCapital = function(k, W, Profits, Capital) { - let idxArr = Profits.map((_, i) => i).sort((ia, ib) => Profits[ib] - Profits[ia]); + const capPQ = new PriorityQueue((a, b) => a.cap < b.cap) + const proPQ = new PriorityQueue((a, b) => a.pro > b.pro) + for(let i = 0, len = Profits.length; i < len; i++) { + capPQ.push({ cap: Capital[i], pro: Profits[i] }) + } + while(k) { + while(!capPQ.isEmpty() && capPQ.peek().cap <= W) { + proPQ.push(capPQ.pop()) + } + if(proPQ.isEmpty()) break + + W += proPQ.pop().pro + k-- + } + return W +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number} k + * @param {number} W + * @param {number[]} Profits + * @param {number[]} Capital + * @return {number} + */ +const findMaximizedCapital = function(k, W, Profits, Capital) { + const idxArr = Profits.map((_, i) => i).sort((ia, ib) => Profits[ib] - Profits[ia]); while (k) { - let choose = idxArr.findIndex(i => Capital[i] <= W); + const choose = idxArr.findIndex(i => Capital[i] <= W); if (choose == -1) return W; W += Profits[idxArr[choose]]; idxArr.splice(choose, 1); @@ -16,3 +111,105 @@ const findMaximizedCapital = function(k, W, Profits, Capital) { } return W; }; + +// another + +/** + * @param {number} k + * @param {number} w + * @param {number[]} profits + * @param {number[]} capital + * @return {number} + */ +const findMaximizedCapital = function(k, w, profits, capital) { + const capPQ = new PQ((a, b) => a.cap < b.cap) + const proPQ = new PQ((a, b) => a.pro > b.pro) + const n = profits.length + + for(let i = 0; i < n; i++) { + capPQ.push({ cap: capital[i], pro: profits[i] }) + } + + while(k) { + + while(!capPQ.isEmpty() && capPQ.peek().cap <= w) { + proPQ.push(capPQ.pop()) + } + + if(proPQ.isEmpty()) break + + w += proPQ.pop().pro + k-- + } + + + return w +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/503-next-greater-element-II.js b/503-next-greater-element-II.js index 6d180376..37a4898e 100755 --- a/503-next-greater-element-II.js +++ b/503-next-greater-element-II.js @@ -1,3 +1,28 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const nextGreaterElements = function(nums) { + const arr = [] + const n = nums.length + const res = Array(n).fill(-1) + nums.push(...nums) + const stk = [] + for(let i = 0; i < 2 * n; i++) { + const e = nums[i] + while(stk.length && nums[stk.at(-1)] < e) { + const idx = stk.pop() + res[idx] = e + } + if(i < n) stk.push(i) + } + + return res +}; + +// another + + /** * @param {number[]} nums * @return {number[]} @@ -20,3 +45,23 @@ function single(idx, arr) { } return -1; } + +// another + +/** + * @param {number[]} nums + * @return {number[]} + */ + const nextGreaterElements = function(nums) { + const res = [], n = nums.length + const stack = [] + for(let i = 2 * n - 1; i >= 0; i--) { + while(stack.length && nums[stack[stack.length - 1]] <= nums[i % n]) { + stack.pop() + } + res[i % n] = stack.length ? nums[stack[stack.length - 1]] : -1 + stack.push(i % n) + } + + return res +}; diff --git a/504-base-7.js b/504-base-7.js new file mode 100644 index 00000000..56cc8352 --- /dev/null +++ b/504-base-7.js @@ -0,0 +1,23 @@ +/** + * @param {number} num + * @return {string} + */ +const convertToBase7 = function(num) { + if(num == null) return '' + const sign = num >= 0 ? '+' : '-' + let res = '' + let remain = Math.abs(num) + if(num === 0) return '0' + while(remain > 0) { + res = remain % 7 + res + remain = Math.floor(remain / 7) + } + + return sign === '+' ? res : '-' + res +}; + +// another + +const convertToBase7 = function(num) { + return num.toString(7) +}; diff --git a/505-the-maze-ii.js b/505-the-maze-ii.js new file mode 100644 index 00000000..b63952bd --- /dev/null +++ b/505-the-maze-ii.js @@ -0,0 +1,110 @@ +/** + +There is a ball in a maze with empty spaces and walls. +The ball can go through empty spaces by rolling up, down, left or right, +but it won't stop rolling until hitting a wall. When the ball stops, it could choose the next direction. + +Given the ball's start position, the destination and the maze, +find the shortest distance for the ball to stop at the destination. +The distance is defined by the number of empty spaces traveled by the ball from the start position (excluded) to +the destination (included). If the ball cannot stop at the destination, return -1. + +The maze is represented by a binary 2D array. 1 means the wall and 0 means the empty space. +You may assume that the borders of the maze are all walls. +The start and destination coordinates are represented by row and column indexes. + +Example 1: + +Input 1: a maze represented by a 2D array + +0 0 1 0 0 +0 0 0 0 0 +0 0 0 1 0 +1 1 0 1 1 +0 0 0 0 0 + +Input 2: start coordinate (rowStart, colStart) = (0, 4) +Input 3: destination coordinate (rowDest, colDest) = (4, 4) + +Output: 12 + +Explanation: One shortest way is : left -> down -> left -> down -> right -> down -> right. + The total distance is 1 + 1 + 3 + 1 + 2 + 2 + 2 = 12. + +Example 2: + +Input 1: a maze represented by a 2D array + +0 0 1 0 0 +0 0 0 0 0 +0 0 0 1 0 +1 1 0 1 1 +0 0 0 0 0 + +Input 2: start coordinate (rowStart, colStart) = (0, 4) +Input 3: destination coordinate (rowDest, colDest) = (3, 2) + +Output: -1 + +Explanation: There is no way for the ball to stop at the destination. + +Note: + +There is only one ball and one destination in the maze. +Both the ball and the destination exist on an empty space, and they will not be at the same position initially. +The given maze does not contain border (like the red rectangle in the example pictures), +but you could assume the border of the maze are all walls. +The maze contains at least 2 empty spaces, and both the width and height of the maze won't exceed 100. + +*/ + +/** + * @param {number[][]} maze + * @param {number[]} start + * @param {number[]} destination + * @return {number} + */ +const shortestDistance = function(maze, start, destination) { + const dirs = [ + [-1, 0], + [1, 0], + [0, 1], + [0, -1] + ] + if (maze == null || maze.length === 0 || maze[0].length === 0) return -1 + const m = maze.length + const n = maze[0].length + const d = Array.from({ length: m }, () => new Array(n).fill(Infinity)) + const q = [[start[0], start[1], 0]] + + while (q.length) { + const cur = q.shift() + for (let dir of dirs) { + let nextX = cur[0] + let nextY = cur[1] + let len = cur[2] + while ( + nextX >= 0 && + nextX < m && + nextY >= 0 && + nextY < n && + maze[nextX][nextY] === 0 + ) { + nextX += dir[0] + nextY += dir[1] + len++ + } + nextX -= dir[0] + nextY -= dir[1] + len-- + if (len > d[destination[0]][destination[1]]) continue + if (len < d[nextX][nextY]) { + d[nextX][nextY] = len + q.push([nextX, nextY, len]) + } + } + } + return d[destination[0]][destination[1]] === Infinity + ? -1 + : d[destination[0]][destination[1]] +} diff --git a/506-relative-ranks.js b/506-relative-ranks.js new file mode 100644 index 00000000..a89e02a4 --- /dev/null +++ b/506-relative-ranks.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} nums + * @return {string[]} + */ +const findRelativeRanks = function(nums) { + const numIndexMapping = {} + for (let index = 0; index < nums.length; ++index) { + numIndexMapping[nums[index]] = index + } + let rank = nums.length + for (let num in numIndexMapping) { + const index = numIndexMapping[num] + if (3 < rank) { + nums[index] = '' + rank + } else if (3 == rank) { + nums[index] = 'Bronze Medal' + } else if (2 == rank) { + nums[index] = 'Silver Medal' + } else { + nums[index] = 'Gold Medal' + } + --rank + } + + return nums +} diff --git a/510-inorder-successor-in-bst-ii.js b/510-inorder-successor-in-bst-ii.js new file mode 100644 index 00000000..1f9a4ef1 --- /dev/null +++ b/510-inorder-successor-in-bst-ii.js @@ -0,0 +1,27 @@ +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * }; + */ +/** + * @param {Node} node + * @return {Node} + */ +const inorderSuccessor = function(node) { + if (node.right == null) { + let cur = node + while (cur.parent !== null && cur.parent.right === cur) { + cur = cur.parent + } + return cur.parent + } + let cur = node.right + while (cur.left !== null) { + cur = cur.left + } + return cur +} diff --git a/511-game-play-analysis-i.sql b/511-game-play-analysis-i.sql new file mode 100644 index 00000000..1c31ac33 --- /dev/null +++ b/511-game-play-analysis-i.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +select player_id, min(event_date) as first_login +from Activity +group by player_id; diff --git a/512-game-play-analysis-ii.sql b/512-game-play-analysis-ii.sql new file mode 100644 index 00000000..023a9cb7 --- /dev/null +++ b/512-game-play-analysis-ii.sql @@ -0,0 +1,8 @@ +# Write your MySQL query statement below +select player_id, device_id +from activity +where (player_id, event_date) in ( +select player_id, min(event_date) +from activity +group by player_id +); diff --git a/514-freedom-trail.js b/514-freedom-trail.js new file mode 100644 index 00000000..cd42d63d --- /dev/null +++ b/514-freedom-trail.js @@ -0,0 +1,39 @@ +/** + * @param {string} ring + * @param {string} key + * @return {number} + */ +const findRotateSteps = function(ring, key) { + function findLeft(i, j) { + let k = i + let count = 0 + while (ring[k] !== key[j]) { + k-- + count++ + if (k === -1) k += ring.length + } + return [k, count] + } + function findRight(i, j) { + let k = i + let count = 0 + while (ring[k] !== key[j]) { + k++ + count++ + if (k === ring.length) k -= ring.length + } + return [k, count] + } + const dp = [] + for (let i = 0; i < ring.length; i++) { + dp[i] = [] + } + function f(i, j) { + if (dp[i][j] !== undefined) return dp[i][j] + if (j === key.length) return (dp[i][j] = 0) + const [i1, c1] = findLeft(i, j) + const [i2, c2] = findRight(i, j) + return (dp[i][j] = Math.min(c1 + 1 + f(i1, j + 1), c2 + 1 + f(i2, j + 1))) + } + return f(0, 0) +} diff --git a/516-longest-palindromic-subsequence.js b/516-longest-palindromic-subsequence.js index cdb115ef..7eaeefe0 100644 --- a/516-longest-palindromic-subsequence.js +++ b/516-longest-palindromic-subsequence.js @@ -1,3 +1,48 @@ +// 区间DP + +/** + * @param {string} s + * @return {number} + */ +const longestPalindromeSubseq = function(s) { + const n = s.length + const dp = Array.from({ length: n }, () => Array(n).fill(0)) + for(let i = 0; i < n; i++) dp[i][i] = 1 + for(let len = 2; len <= n; len++) { + for(let i = 0; i + len - 1 < n; i++) { + const j = i + len - 1 + if(s[i] === s[j]) dp[i][j] = 2 + dp[i + 1][j - 1] + else dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]) + } + } + return dp[0][n - 1] +}; + +// another + +/** + * @param {string} s + * @return {number} + */ +const longestPalindromeSubseq = function(s) { + const n = s.length + const dp = Array.from({ length: n }, () => Array(n).fill(0)) + for(let i = 0; i < n; i++) { + dp[i][i] = 1 + for(let j = i - 1; j >= 0; j--) { + if(s[i] === s[j]) { + dp[i][j] = dp[i - 1][j + 1] + 2 + } else { + dp[i][j] = Math.max(dp[i - 1][j], dp[i][j + 1]) + } + } + } + + return dp[n - 1][0] +}; + +// another + /** * @param {string} s * @return {number} diff --git a/517-super-washing-machines.js b/517-super-washing-machines.js new file mode 100644 index 00000000..1b5dbf17 --- /dev/null +++ b/517-super-washing-machines.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} machines + * @return {number} + */ +const findMinMoves = function(machines) { + let total = 0 + for (let i of machines) total += i + if (total % machines.length !== 0) return -1 + let avg = (total / machines.length) >> 0, + cnt = 0, + max = 0 + for (let load of machines) { + cnt += load - avg + max = Math.max(Math.max(max, Math.abs(cnt)), load - avg) + } + return max +} diff --git a/518-coin-change-2.js b/518-coin-change-2.js index 51a5db3c..92577234 100644 --- a/518-coin-change-2.js +++ b/518-coin-change-2.js @@ -1,17 +1,90 @@ +/** + * @param {number} amount + * @param {number[]} coins + * @return {number} + */ +const change = function(amount, coins) { + const n = coins.length + const dp = Array.from({length: n + 1}, () => Array(amount + 1).fill(0)) + for(let i = 0; i <= n; i++) { + dp[i][0] = 1 + } + + for(let j = 1; j <= amount; j++) { + for(let i = 1; i <= n; i++) { + const e = coins[i - 1] + dp[i][j] = dp[i - 1][j] + (j >= e ? dp[i][j - e]: 0) + } + } + // console.log(dp) + return dp[n][amount] +}; + +// another + + + /** * @param {number} amount * @param {number[]} coins * @return {number} */ function change(amount, coins) { - const dp = Array.from(new Array(coins.length+1), () => new Array(amount + 1).fill(0)) - dp[0][0] = 1; - - for (let i = 1; i <= coins.length; i++) { - dp[i][0] = 1; - for (let j = 1; j <= amount; j++) { - dp[i][j] = dp[i-1][j] + (j >= coins[i-1] ? dp[i][j-coins[i-1]] : 0); - } + const dp = Array.from(new Array(coins.length + 1), () => + new Array(amount + 1).fill(0) + ) + dp[0][0] = 1 + for (let i = 1; i <= coins.length; i++) { + dp[i][0] = 1 + for (let j = 1; j <= amount; j++) { + dp[i][j] = + dp[i - 1][j] + (j >= coins[i - 1] ? dp[i][j - coins[i - 1]] : 0) } - return dp[coins.length][amount]; + } + return dp[coins.length][amount] +} + + +// another + +/** + * @param {number} amount + * @param {number[]} coins + * @return {number} + */ +const change = function (amount, coins) { + const dp = Array(amount + 1).fill(0) + dp[0] = 1 + for (let coin of coins) { + for (let i = coin; i < amount + 1; i++) dp[i] += dp[i - coin] + } + return dp[amount] +} + +// another + +// another + +const change = function(amount,coins) { + const n = coins.length + const dp = Array.from({ length: n + 1 }, () => Array(amount + 1)) + dp[0][0] = 1 + for(let i = 0; i < n; i++) dp[i][0] = 1 + helper(0, amount) + return dp[0][amount] === undefined ? 0 : dp[0][amount] + + function helper(i, rem) { + if(dp[i][rem] != null) return dp[i][rem] + if(rem < 0) return 0 + if(rem === 0) return 1 + if(i >= coins.length) return 0 + let res = 0 + + res += helper(i, rem - coins[i]) + res += helper(i + 1, rem) + + dp[i][rem] = res + + return res + } } diff --git a/519-random-flip-matrix.js b/519-random-flip-matrix.js new file mode 100644 index 00000000..2cbbf632 --- /dev/null +++ b/519-random-flip-matrix.js @@ -0,0 +1,35 @@ +/** + * @param {number} n_rows + * @param {number} n_cols + */ +const Solution = function(n_rows, n_cols) { + this.r = n_rows + this.c = n_cols + this.total = n_rows * n_cols + this.m = new Map() +} + +/** + * @return {number[]} + */ +Solution.prototype.flip = function() { + const r = (Math.random() * this.total--) >> 0 + const i = this.m.get(r) || r + this.m.set(r, this.m.get(this.total) || this.total) + return [(i / this.c) >> 0, i % this.c] +} + +/** + * @return {void} + */ +Solution.prototype.reset = function() { + this.m.clear() + this.total = this.c * this.r +} + +/** + * Your Solution object will be instantiated and called as such: + * var obj = Object.create(Solution).createNew(n_rows, n_cols) + * var param_1 = obj.flip() + * obj.reset() + */ diff --git a/522-longest-uncommon-subsequence-ii.js b/522-longest-uncommon-subsequence-ii.js new file mode 100644 index 00000000..cf62c60b --- /dev/null +++ b/522-longest-uncommon-subsequence-ii.js @@ -0,0 +1,38 @@ +/** + * @param {string[]} strs + * @return {number} + */ +const findLUSlength = function(strs) { + strs.sort((a, b) => b.length - a.length) + const dup = getDuplicates(strs) + for(let i = 0; i < strs.length; i++) { + if(!dup.has(strs[i])) { + if(i === 0) return strs[0].length + for(let j = 0; j < i; j++) { + if(isSubsequence(strs[j], strs[i])) break + if(j === i - 1) return strs[i].length + } + } + } + return -1 +}; + +function isSubsequence(a, b) { + let i = 0, j = 0 + while(i < a.length && j < b.length) { + if(a.charAt(i) === b.charAt(j)) j++ + i++ + } + return j === b.length +} + +function getDuplicates(arr) { + const set = new Set() + const dup = new Set() + for(let el of arr) { + if(set.has(el)) dup.add(el) + else set.add(el) + } + return dup +} + diff --git a/524-longest-word-in-dictionary-through-deleting.js b/524-longest-word-in-dictionary-through-deleting.js new file mode 100644 index 00000000..bfe2742f --- /dev/null +++ b/524-longest-word-in-dictionary-through-deleting.js @@ -0,0 +1,138 @@ +/** + * @param {string} s + * @param {string[]} dictionary + * @return {string} + */ + const findLongestWord = function(s, dictionary) { + let res = '' + for (const word of dictionary) { + let j = 0 + for (let i = 0, len = s.length; i < len; i++) { + if(word[j] === s[i]) j++ + if(j === word.length) { + if(word.length > res.length) res = word + else if(word.length === res.length && word < res) res = word + break + } + } + } + return res +}; + +// another + +/** + * @param {string} s + * @param {string[]} dictionary + * @return {string} + */ +const findLongestWord = function (s, dictionary) { + const n = dictionary.length + const idxArr = Array(n).fill(0) + let res = '' + for (const ch of s) { + for (let i = 0; i < n; i++) { + const idx = idxArr[i] + if (idx >= dictionary[i].length) continue + if (ch === dictionary[i][idx]) { + idxArr[i]++ + } + + if ( + idxArr[i] === dictionary[i].length && + (dictionary[i].length > res.length || + (dictionary[i].length === res.length && dictionary[i] < res)) + ) { + res = dictionary[i] + } + } + } + return res +} + + +// another + +/** + * @param {string} s + * @param {string[]} dictionary + * @return {string} + */ +const findLongestWord = function(s, dictionary) { + let res = '' + for(let d of dictionary) { + let j = 0 + for(let i = 0, n = s.length; i < n; i++) { + if(d[j] === s[i]) j++ + if(j === d.length && j >= res.length) { + if(j > res.length || d < res) { + res = d + } + break + } + } + } + return res +}; + +// another + +/** + * @param {string} s + * @param {string[]} dictionary + * @return {string} + */ +const findLongestWord = function(s, dictionary) { + dictionary.sort((a, b) => a.length === b.length ? cmp(a, b) : b.length - a.length) + let res = '' + for(let d of dictionary) { + let j = 0 + for(let i = 0, n = s.length; i < n; i++) { + if(d[j] === s[i]) j++ + if(j === d.length) return d + } + } + return '' + function cmp(s1, s2) { + for(let i = 0, n = s1.length; i < n; i++) { + if(s1[i] < s2[i]) return -1 + else if(s1[i] > s2[i]) return 1 + } + return 0 + } +}; + +// another + + +/** + * @param {string} s + * @param {string[]} d + * @return {string} + */ +const findLongestWord = function(s, d) { + let results = []; + let maxLen = 0; + for (const word of d) { + let j = 0; + for (let i = 0; i < s.length; i++) { + if (s[i] === word[j]) { + j++; + if (j === word.length) break; + } + } + if (j === word.length && word.length >= maxLen) { + if (word.length > maxLen) { + maxLen = word.length; + results = []; + } + results.push(word); + } + } + + let result = results[0]; + for (let i = 1; i < results.length; i++) { + if (results[i] < result) result = results[i]; + } + return result || ''; +} diff --git a/525-contiguous-array.js b/525-contiguous-array.js index 7b12241c..9b0da1ea 100644 --- a/525-contiguous-array.js +++ b/525-contiguous-array.js @@ -2,4 +2,48 @@ * @param {number[]} nums * @return {number} */ -const findMaxLength = function(nums) {} +const findMaxLength = function(nums) { + let res = 0, sum = 0 + const hash = {0: -1}, n = nums.length + + for(let i = 0; i < n; i++) { + const cur = nums[i] + sum += cur === 0 ? -1 : 1 + if(hash[sum] != null) { + res = Math.max(res, i - hash[sum]) + } else { + hash[sum] = i + } + + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const findMaxLength = function (nums) { + const map = new Map() + map.set(0, -1) + let count = 0 + let max = 0 + for (let i = 0; i < nums.length; i++) { + let num = nums[i] + if (num === 0) { + count -= 1 + } + if (num === 1) { + count += 1 + } + if (map.has(count)) { + max = Math.max(max, i - map.get(count)) + } else { + map.set(count, i) + } + } + return max +} diff --git a/527-word-abbreviation.js b/527-word-abbreviation.js new file mode 100644 index 00000000..3cdbcaac --- /dev/null +++ b/527-word-abbreviation.js @@ -0,0 +1,40 @@ +/** + * @param {string[]} dict + * @return {string[]} + */ +const wordsAbbreviation = function(dict) { + const result = [] + const prefixLen = new Array(dict.length).fill(1) + for (let i = 0; i < dict.length; i++) { + result[i] = makeAbbr(dict[i], 1) + } + for (let i = 0; i < dict.length; i++) { + while (true) { + const set = new Set() + for (let j = i + 1; j < dict.length; j++) { + if (result[i] === result[j]) { + set.add(j) + } + } + if (set.size === 0) { + break + } + set.add(i) + for (let val of set.values()) { + result[val] = makeAbbr(dict[val], ++prefixLen[val]) + } + } + } + return result +} + +function makeAbbr(s, prefixLen) { + if (prefixLen >= s.length - 2) { + return s + } + let str = '' + str += s.slice(0, prefixLen) + str += s.length - 1 - prefixLen + str += s[s.length - 1] + return str +} diff --git a/528-random-pick-with-weight.js b/528-random-pick-with-weight.js new file mode 100644 index 00000000..e33a3904 --- /dev/null +++ b/528-random-pick-with-weight.js @@ -0,0 +1,108 @@ +/** + * @param {number[]} w + */ +const Solution = function(w) { + this.a = [] + let sum = 0 + for (let i = 0, len = w.length; i < len; i++) { + sum += w[i] + this.a[i] = sum + } +} + +/** + * @return {number} + */ +Solution.prototype.pickIndex = function() { + const len = this.a.length + const sum = this.a[len - 1] + const rand = ((Math.random() * sum) >> 0) + 1 + let l = 0, + h = len - 1 + while (l < h) { + const mid = (l + h) >> 1 + if (this.a[mid] === rand) return mid + else if (this.a[mid] < rand) l = mid + 1 + else h = mid + } + return l +} + +/** + * Your Solution object will be instantiated and called as such: + * var obj = new Solution(w) + * var param_1 = obj.pickIndex() + */ + +// another + +/** + * @param {number[]} w + */ +const Solution = function(w) { + this.a = [] + let sum = 0 + for(let i = 0, len = w.length; i < len; i++) { + sum += w[i] + this.a[i] = sum + } +}; + +/** + * @return {number} + */ +Solution.prototype.pickIndex = function() { + const len = this.a.length + const sum = this.a[len - 1] + const rand = ((Math.random() * sum) >> 0) + 1 + let l = 0, h = len - 1 + while(l <= h) { + const mid = (l + h) >> 1 + if(this.a[mid] === rand) return mid + else if(this.a[mid] < rand) l = mid + 1 + else h = mid - 1 + } + return l +}; + +/** + * Your Solution object will be instantiated and called as such: + * var obj = new Solution(w) + * var param_1 = obj.pickIndex() + */ + +// another + +/** + * @param {number[]} w + */ +const Solution = function(w) { + this.a = [] + let sum = 0 + for(let i = 0, len = w.length; i < len; i++) { + sum += w[i] + this.a[i] = sum + } +}; + +/** + * @return {number} + */ +Solution.prototype.pickIndex = function() { + const len = this.a.length + const sum = this.a[len - 1] + const rand = ((Math.random() * sum) >> 0) + 1 + let l = 0, h = len - 1 + while(l < h) { + const mid = (l + h) >> 1 + if(this.a[mid] < rand) l = mid + 1 + else h = mid + } + return l +}; + +/** + * Your Solution object will be instantiated and called as such: + * var obj = new Solution(w) + * var param_1 = obj.pickIndex() + */ diff --git a/529-minesweeper.js b/529-minesweeper.js new file mode 100644 index 00000000..7e772c49 --- /dev/null +++ b/529-minesweeper.js @@ -0,0 +1,58 @@ +/** + * @param {character[][]} board + * @param {number[]} click + * @return {character[][]} + */ +const updateBoard = function(board, click) { + const visited = new Set(); + const [clickRow, clickCol] = click; + if (board[clickRow][clickCol] === "M") { + board[clickRow][clickCol] = "X"; + return board; + } + const directions = [ + [-1, 0], // top + [1, 0], // down + [0, -1], // left + [0, 1], // right + [-1, -1], // top left + [1, 1], // bottom right + [-1, 1], // top right + [1, -1] // bottom left + ]; + + function dfs(row, col) { + visited.add(`${row},${col}`); + if (board[row][col] === "M") return; + let numBombs = 0; + for (let dir of directions) { + if ( + board[row + dir[0]] === undefined || + board[row + dir[0]][col + dir[1]] === undefined + ) + continue; + if (board[row + dir[0]][col + dir[1]] === "M") { + numBombs += 1; + } + } + if (numBombs) { + board[row][col] = `${numBombs}`; + return; + } + board[row][col] = "B"; + for (let dir of directions) { + if ( + board[row + dir[0]] === undefined || + board[row + dir[0]][col + dir[1]] === undefined || + board[row + dir[0]][col + dir[1]] !== "E" + ) + continue; + if (!visited.has(`${row + dir[0]},${col + dir[1]}`)) { + dfs(row + dir[0], col + dir[1]); + } + } + } + dfs(clickRow, clickCol); + return board; +}; + diff --git a/53-maximum-subarray.js b/53-maximum-subarray.js index 15725003..dde9daa9 100755 --- a/53-maximum-subarray.js +++ b/53-maximum-subarray.js @@ -1,3 +1,19 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxSubArray = function (nums) { + let res = -1e9, sum = 0 + for(const e of nums) { + sum += e + res = Math.max(res, sum) + if(sum < 0) sum = 0 + } + return res +} + +// another + /** * @param {number[]} nums * @return {number} @@ -11,3 +27,50 @@ const maxSubArray = function(nums) { } return maxSum; }; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxSubArray = function(nums) { + const n = nums.length, dp = Array(n).fill(0) + dp[0] = nums[0] + let res = dp[0] + for(let i = 1; i < n; i++) { + dp[i] = Math.max(dp[i - 1], 0) + nums[i] + res = Math.max(res, dp[i]) + } + return res +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maxSubArray = function(nums) { + return helper(nums, 0, nums.length - 1) +}; + +function helper(arr, l, r) { + if(l > r) return -Infinity + const mid = l + ((r - l) >> 1) + let cur = 0, leftMax = 0, rightMax = 0 + for(let i = mid - 1; i >= l; i--) { + cur += arr[i] + leftMax = Math.max(leftMax, cur) + } + cur = 0 + for(let i = mid + 1; i <= r; i++) { + cur += arr[i] + rightMax = Math.max(rightMax, cur) + } + const res = arr[mid] + leftMax + rightMax + const leftRes = helper(arr, l, mid - 1) + const rightRes = helper(arr, mid + 1, r) + + return Math.max(res, leftRes, rightRes) +} diff --git a/531-lonely-pixel-i.js b/531-lonely-pixel-i.js new file mode 100644 index 00000000..c56dd1ea --- /dev/null +++ b/531-lonely-pixel-i.js @@ -0,0 +1,60 @@ +/** + * @param {character[][]} picture + * @return {number} + */ +const findLonelyPixel = function(picture) { + if(picture == null || picture[0].length === 0) return 0 + const rows = picture.length + const cols = picture[0].length + const r = new Array(rows).fill(0) + const c = new Array(cols).fill(0) + for(let i = 0; i < rows; i++) { + for(let j = 0; j < cols; j++) { + if(picture[i][j] === 'B') { + r[i]++ + c[j]++ + } + } + } + let res = 0 + for(let i = 0; i < rows; i++) { + if(r[i] === 1) { + for(let j = 0; j < cols; j++) { + if(picture[i][j] === 'B') { + if(c[j] === 1)res++ + break + } + } + } + } + return res +}; + +// another + +/** + * @param {character[][]} picture + * @return {number} + */ +const findLonelyPixel = function(picture) { + if(picture == null || picture[0].length === 0) return 0 + const rows = picture.length + const cols = picture[0].length + const c = new Array(cols).fill(0) + for(let i = 0; i < rows; i++) { + for(let j = 0; j < cols; j++) { + if(picture[i][j] === 'B') c[j]++ + } + } + let res = 0 + for(let i = 0; i < rows; i++) { + let cnt = 0, pos = -1 + for(let j = 0; j < cols; j++) { + if(picture[i][j] !== 'B') continue + if(++cnt === 1) pos = j + else break + } + if(cnt === 1 && c[pos] === 1) res++ + } + return res +}; diff --git a/533-lonely-pixel-ii.js b/533-lonely-pixel-ii.js new file mode 100644 index 00000000..f4de89c9 --- /dev/null +++ b/533-lonely-pixel-ii.js @@ -0,0 +1,81 @@ +/** + * @param {character[][]} picture + * @param {number} N + * @return {number} + */ +const findBlackPixel = function(picture, N) { + let m = [] + for (let i = 0; i < picture.length; i++) { + let cnt = 0 + let str = '' + for (let j = 0; j < picture[0].length; j++) { + if (picture[i][j] === 'W') continue + cnt++ + if (cnt > N) break + str += j + ',' + } + if (cnt === N) m[i] = str + } + let ans = 0 + for (let j = 0; j < picture[0].length; j++) { + let cnt = 0 + let rowStr = '' + for (let i = 0; i < picture.length; i++) { + if (picture[i][j] === 'W') continue + cnt++ + if (cnt === 1) rowStr = m[i] + else if (cnt > N || m[i] !== rowStr) { + rowStr = '' + break + } + } + if (cnt === N && rowStr) ans += N + } + return ans +} + +// another + +/** + * @param {character[][]} picture + * @param {number} N + * @return {number} + */ +const findBlackPixel = function(picture, N) { + const rows = picture.length + if(rows === 0) return 0 + const cols = picture[0].length + if(cols === 0) return 0 + const m = new Map() + const colCnt = new Array(cols).fill(0) + for(let i = 0; i < rows; i++) { + const k = scanRow(picture, i, cols, N, colCnt) + if(k) { + m.set(k, (m.get(k) || 0) + 1) + } + } + let res = 0 + for(let [k, v] of m) { + if(v === N) { + for(let i = 0; i < cols; i++) { + if(k[i] === 'B' && colCnt[i] === N) res += N + } + } + } + return res +} + +function scanRow(p, r, cols, N, arr) { + let str = '' + let cnt = 0 + for(let i = 0; i < cols; i++) { + if(p[r][i] === 'B') { + cnt++ + arr[i] += 1 + } + str += p[r][i] + } + if(cnt === N) return str + return '' +} + diff --git a/534-game-play-analysis-iii.sql b/534-game-play-analysis-iii.sql new file mode 100644 index 00000000..d6e0dbf6 --- /dev/null +++ b/534-game-play-analysis-iii.sql @@ -0,0 +1,10 @@ +# Write your MySQL query statement below +select player_id, event_date, sum(games_played) as games_played_so_far +from (select a.player_id, a.event_date, b.games_played +from ( +select player_id, event_date +from activity +group by player_id, event_date) a +join activity b +on a.player_id = b.player_id and a.event_date >=b.event_date) as tb +group by player_id, event_date; diff --git a/536-construct-binary-tree-from-string.js b/536-construct-binary-tree-from-string.js new file mode 100644 index 00000000..4fb1ea18 --- /dev/null +++ b/536-construct-binary-tree-from-string.js @@ -0,0 +1,34 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {string} s + * @return {TreeNode} + */ +const str2tree = function(s) { + const stack = [] + for (let i = 0, j = i; i < s.length; i++, j = i) { + const c = s.charAt(i) + if (c === ')') stack.pop() + else if ((c >= '0' && c <= '9') || c === '-') { + while ( + i + 1 < s.length && + s.charAt(i + 1) >= '0' && + s.charAt(i + 1) <= '9' + ) + i++ + const currentNode = new TreeNode(+s.slice(j, i + 1)) + if (stack.length) { + const parent = stack[stack.length - 1] + if (parent.left !== null) parent.right = currentNode + else parent.left = currentNode + } + stack.push(currentNode) + } + } + return stack.length === 0 ? null : stack[0] +} diff --git a/54-spiral-matrix.js b/54-spiral-matrix.js index 2c9eebcf..fbbb5aff 100644 --- a/54-spiral-matrix.js +++ b/54-spiral-matrix.js @@ -39,3 +39,48 @@ const spiralOrder = function(matrix) { } return res }; + +// another + +/** + * @param {number[][]} matrix + * @return {number[]} + */ +const spiralOrder = function(matrix) { + const res = [], m = matrix.length, n = matrix[0].length + const dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]] + let di = 0, i = 0, j = 0, nx = 0, ny = 1 + while(true) { + res.push(matrix[i][j]) + matrix[i][j] = Infinity + if(chk(i, j)) { + if(di === 0 && (j + 1 >= n || matrix[i][j + 1] === Infinity)) { + i++ + di = 1 + } else if(di === 1 && (i + 1 >= m || matrix[i + 1][j] === Infinity)) { + j-- + di = 2 + } else if(di === 2 && (j - 1 < 0 || matrix[i][j - 1] === Infinity)) { + i-- + di = 3 + } else if(di === 3 && (i - 1 < 0 || matrix[i - 1][j] === Infinity)) { + j++ + di = 0 + } else { + i += dirs[di][0] + j += dirs[di][1] + } + } else break + } + return res + + function chk(i, j) { + for(let dir of dirs) { + const nx = i + dir[0], ny = j + dir[1] + if(nx >= 0 && nx < matrix.length && ny >= 0 && ny < matrix[0].length && matrix[nx][ny] !== Infinity) return true + } + return false + } +}; + + diff --git a/540-single-element-in-a-sorted-array.js b/540-single-element-in-a-sorted-array.js index b2c7dcff..a840caa3 100755 --- a/540-single-element-in-a-sorted-array.js +++ b/540-single-element-in-a-sorted-array.js @@ -12,3 +12,54 @@ const singleNonDuplicate = function(nums) { } } }; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const singleNonDuplicate = function(nums) { + const n = nums.length + let left = 0, right = n - 1 + while(left < right) { + const mid = left + ((right - left) >> 1) + if(nums[mid] === nums[mid ^ 1]) left = mid + 1 + else right = mid + } + + return nums[left] +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const singleNonDuplicate = function(nums) { + const n = nums.length + let left = 0, right = n - 1 + while(left < right) { + const mid = ~~((left + right) / 2) + if((mid % 2 === 0 && nums[mid] === nums[mid + 1]) || (mid % 2 === 1 && nums[mid] === nums[mid - 1])) left = mid + 1 + else right = mid + } + + return nums[left] +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const singleNonDuplicate = function(nums) { + if(nums.length === 0) return 0 + let res = nums[0] + for(let i = 1, len = nums.length; i < len; i++) { + res ^= nums[i] + } + return res +}; diff --git a/541-reverse-string-ii.js b/541-reverse-string-ii.js new file mode 100644 index 00000000..7486e7a1 --- /dev/null +++ b/541-reverse-string-ii.js @@ -0,0 +1,28 @@ +/** + * @param {string} s + * @param {number} k + * @return {string} + */ +const reverseStr = function(s, k) { + const arr = s.split('') + for(let i = 0, len = s.length; i < len; i += 2 * k) { + helper(arr, i, k) + } + return arr.join('') +}; + +function helper(arr, start, k) { + let s = start + let e = arr.length > start + k - 1 ? start + k - 1 : arr.length + while(s < e) { + swap(arr, s, e) + s++ + e-- + } +} + +function swap(arr, s, e) { + const tmp = arr[s] + arr[s] = arr[e] + arr[e] = tmp +} diff --git a/543-diameter-of-binary-tree.js b/543-diameter-of-binary-tree.js index c428ae2c..acf2deac 100755 --- a/543-diameter-of-binary-tree.js +++ b/543-diameter-of-binary-tree.js @@ -9,16 +9,71 @@ * @param {TreeNode} root * @return {number} */ -let ans; +const diameterOfBinaryTree = function (root) { + if (root === null) return 0 + let longest = 0 + function dfs(node) { + if (node === null) return 0 + let leftmax = dfs(node.left) + let rightmax = dfs(node.right) + longest = Math.max(longest, leftmax + 1 + rightmax) + return Math.max(leftmax, rightmax) + 1 + } + dfs(root) + return longest - 1 +} + +// another + +/** + * 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 {number} + */ const diameterOfBinaryTree = function(root) { - ans = 1; - depth(root); - return ans - 1; + let res = 0 + dfs(root) + return res + + function dfs(node) { + if(node == null) return 0 + const left = dfs(node.left), right = dfs(node.right) + res = Math.max(res, left + right) + return Math.max(left, right) + 1 + } }; -function depth(node) { - if (node == null) return 0; - let L = depth(node.left); - let R = depth(node.right); - ans = Math.max(ans, L + R + 1); - return Math.max(L, R) + 1; -} + +// another + +/** + * 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 {number} + */ +const diameterOfBinaryTree = function(root) { + let res = -Infinity + dfs(root) + return res + function dfs(node) { + if(node == null) return -1 + const left = dfs(node.left) + const right = dfs(node.right) + res = Math.max(res, left + right + 2) + return Math.max(left, right) + 1 + } +}; + diff --git a/544-output-contest-matches.js b/544-output-contest-matches.js new file mode 100644 index 00000000..e81f6d0f --- /dev/null +++ b/544-output-contest-matches.js @@ -0,0 +1,82 @@ +/** + +During the NBA playoffs, we always arrange the rather strong team to play with the rather weak team, +like make the rank 1 team play with the rank nth team, which is a good strategy to make the contest more interesting. +Now, you're given n teams, you need to output their final contest matches in the form of a string. + +The n teams are given in the form of positive integers from 1 to n, which represents their initial rank. +(Rank 1 is the strongest team and Rank n is the weakest team.) +We'll use parentheses('(', ')') and commas(',') to represent the contest team pairing - parentheses('(' , ')') for +pairing and commas(',') for partition. During the pairing process in each round, +you always need to follow the strategy of making the rather strong one pair with the rather weak one. + +Example 1: +Input: 2 +Output: (1,2) +Explanation: +Initially, we have the team 1 and the team 2, placed like: 1,2. +Then we pair the team (1,2) together with '(', ')' and ',', which is the final answer. +Example 2: +Input: 4 +Output: ((1,4),(2,3)) +Explanation: +In the first round, we pair the team 1 and 4, the team 2 and 3 together, as we need to make the strong team and weak team together. +And we got (1,4),(2,3). +In the second round, the winners of (1,4) and (2,3) need to play again to generate the final winner, +so you need to add the paratheses outside them. +And we got the final answer ((1,4),(2,3)). +Example 3: +Input: 8 +Output: (((1,8),(4,5)),((2,7),(3,6))) +Explanation: +First round: (1,8),(2,7),(3,6),(4,5) +Second round: ((1,8),(4,5)),((2,7),(3,6)) +Third round: (((1,8),(4,5)),((2,7),(3,6))) +Since the third round will generate the final winner, you need to output the answer (((1,8),(4,5)),((2,7),(3,6))). +Note: +The n is in range [2, 212]. +We ensure that the input n can be converted into the form 2k, where k is a positive integer. + +*/ + +/** + * @param {number} n + * @return {string} + */ +const findContestMatch = function(n) { + const arr = [] + for(let i = 0; i < n; i++) { + arr[i] = i + 1 + } + while(n > 1) { + for(let i = 0; i < (n >> 1); i++) { + arr[i] = `(${arr[i]},${arr[n - 1 - i]})` + } + n = n >> 1 + } + return arr[0] +}; + +// another + +/** + * @param {number} n + * @return {string} + */ +const findContestMatch = function(n) { + const arr = [] + for(let i = 0; i < n; i++) { + arr[i] = i + 1 + } + let l = 0 + let r = n - 1 + while(l < r) { + while(l < r) { + arr[l] = `(${arr[l]},${arr[r]})` + l++ + r-- + } + l = 0 + } + return arr[0] +}; diff --git a/545-boundary-of-binary-tree.js b/545-boundary-of-binary-tree.js new file mode 100644 index 00000000..79a2985e --- /dev/null +++ b/545-boundary-of-binary-tree.js @@ -0,0 +1,35 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ +const boundaryOfBinaryTree = function (root) { + if (!root) return [] + if (!root.left && !root.right) return [root.val] + const res = [root.val] + buildSide(root.left, 'left', res) + buildBottom(root, res) + const right = [] + buildSide(root.right, 'right', right) + return [...res, ...right.reverse()] +} + +function buildSide(root, side, res) { + if (!root) return + if (root.left || root.right) res.push(root.val) + if (root[side]) buildSide(root[side], side, res) + else buildSide(root[side === 'left' ? 'right' : 'left'], side, res) +} + +function buildBottom(root, res) { + if (!root) return + if (!root.left && !root.right) res.push(root.val) + buildBottom(root.left, res) + buildBottom(root.right, res) +} diff --git a/547-friend-circles.js b/547-friend-circles.js new file mode 100644 index 00000000..48f88ce0 --- /dev/null +++ b/547-friend-circles.js @@ -0,0 +1,23 @@ +/** + * @param {number[][]} M + * @return {number} + */ +const findCircleNum = function(M) { + let count = 0 + const visited = {} + const dfs = function(M, i) { + for (let j = 0; j < M[i].length; j++) { + if (M[i][j] == 1 && !visited[j]) { + visited[j] = true + dfs(M, j) + } + } + } + for (let i = 0; i < M.length; i++) { + if (!visited[i]) { + dfs(M, i) + count++ + } + } + return count +} diff --git a/548-split-array-with-equal-sum.js b/548-split-array-with-equal-sum.js new file mode 100644 index 00000000..57036340 --- /dev/null +++ b/548-split-array-with-equal-sum.js @@ -0,0 +1,52 @@ +/** + +Given an array with n integers, you need to find if there are triplets (i, j, k) which satisfies following conditions: +0 < i, i + 1 < j, j + 1 < k < n - 1 +Sum of subarrays (0, i - 1), (i + 1, j - 1), (j + 1, k - 1) and (k + 1, n - 1) should be equal. +where we define that subarray (L, R) represents a slice of the original array starting +from the element indexed L to the element indexed R. + +Example: + +Input: [1,2,1,2,1,2,1] +Output: True +Explanation: +i = 1, j = 3, k = 5. +sum(0, i - 1) = sum(0, 0) = 1 +sum(i + 1, j - 1) = sum(2, 2) = 1 +sum(j + 1, k - 1) = sum(4, 4) = 1 +sum(k + 1, n - 1) = sum(6, 6) = 1 + +Note: +1 <= n <= 2000. +Elements in the given array will be in range [-1,000,000, 1,000,000]. + +*/ + +/** + * @param {number[]} nums + * @return {boolean} + */ +const splitArray = function(nums) { + if (nums.length < 7) return false + const len = nums.lenght + const sum = new Array(len.length).fill(0) + sum[0] = nums[0] + for (let i = 1; i < len; i++) { + sum[i] = sum[i - 1] + nums[i] + } + for (let j = 3; j < len - 3; j++) { + const set = new Set() + for (let i = 1; i < j - 1; i++) { + if (sum[i - 1] === sum[j - 1] - sum[i]) set.add(sum[i - 1]) + } + for (let k = j + 2; k < len - 1; k++) { + if ( + sum[len - 1] - sum[k] === sum[k - 1] - sum[j] && + set.has(sum[k - 1] - sum[j]) + ) + return true + } + } + return false +} diff --git a/549-binary-tree-longest-consecutive-sequence-ii.js b/549-binary-tree-longest-consecutive-sequence-ii.js new file mode 100644 index 00000000..af61208a --- /dev/null +++ b/549-binary-tree-longest-consecutive-sequence-ii.js @@ -0,0 +1,30 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const longestConsecutive = function (root, res = { val: 0 }) { + if (root === null) return 0; + let ans = 0; + function f(node) { + let inc = 1, + dec = 1; + const child = [node.left, node.right]; + for (let c of child) { + if (c === null) continue; + let r = f(c); + if (node.val + 1 === c.val) inc = Math.max(inc, r[0] + 1); + else if (node.val - 1 === c.val) dec = Math.max(dec, r[1] + 1); + } + ans = Math.max(ans, inc + dec - 1); + return [inc, dec]; + } + f(root); + return ans; +}; diff --git a/55-jump-game.js b/55-jump-game.js index 500c4e63..4bf6ebf6 100644 --- a/55-jump-game.js +++ b/55-jump-game.js @@ -3,14 +3,27 @@ * @return {boolean} */ const canJump = function(nums) { - const len = nums.length - let maxIdx = 0 - for(let i = 0; i < len; i++) { - if (i <= maxIdx) { - maxIdx = Math.max(maxIdx, i + nums[i]) - } else { - break - } + let max = 0 + for(let i = 0, len = nums.length; i < len; i++) { + if(i <= max && nums[i] > 0) { + max = Math.max(max, i + nums[i]) } - return maxIdx >= len - 1 ? true : false + } + return max >= nums.length - 1 +}; + +// another + +/** + * @param {number[]} nums + * @return {boolean} + */ +const canJump = function(nums) { + let max = 0 + const n = nums.length + for(let i = 0; i < n; i++) { + if(max < i) return false + max = Math.max(max, i + nums[i]) + if(max >= n - 1) return true + } }; diff --git a/550-game-play-analysis-iv.sql b/550-game-play-analysis-iv.sql new file mode 100644 index 00000000..ac439a25 --- /dev/null +++ b/550-game-play-analysis-iv.sql @@ -0,0 +1,10 @@ +# Write your MySQL query statement below +select +round((select count(distinct a.player_id) from Activity a +inner join +(select player_id, min(event_date) as first_logged + from Activity + group by player_id) b on datediff(a.event_date, b.first_logged)=1 + and a.player_id = b.player_id) + / + (select count(distinct player_id) from Activity),2) as fraction; diff --git a/555-split-concatenated-strings.js b/555-split-concatenated-strings.js new file mode 100644 index 00000000..fb16ff4d --- /dev/null +++ b/555-split-concatenated-strings.js @@ -0,0 +1,36 @@ +/** + * @param {string[]} strs + * @return {string} + */ +const splitLoopedString = function (strs) { + let ans = '' + const n = strs.length + if (n === 0) return '' + findMaxStrings(strs) + for (let i = 0; i < n; ++i) { + solve(strs, i, true) + solve(strs, i, false) + } + return ans + function findMaxStrings(strs) { + for (let i = 0; i < n; ++i) { + const temp = strs[i].split('').reverse().join('') + strs[i] = strs[i] > temp ? strs[i] : temp + } + } + function solve(strs, i, flag) { + let temp = strs[i] + if (flag) { + temp = temp.split('').reverse().join('') + } + let size = temp.length + let str1 = '', + str2 = '' + for (let j = i + 1; j < n; ++j) str1 += strs[j] + for (let j = 0; j < i; ++j) str2 += strs[j] + for (let k = 0; k < size; ++k) { + let newOne = temp.substr(k) + str1 + str2 + temp.substr(0, k) + ans = ans === '' ? newOne : ans > newOne ? ans : newOne + } + } +} diff --git a/558-logical-or-of-two-binary-grids-represented-as-quad-trees.js b/558-logical-or-of-two-binary-grids-represented-as-quad-trees.js new file mode 100644 index 00000000..e9d1533a --- /dev/null +++ b/558-logical-or-of-two-binary-grids-represented-as-quad-trees.js @@ -0,0 +1,44 @@ +/** + * // Definition for a QuadTree node. + * function Node(val,isLeaf,topLeft,topRight,bottomLeft,bottomRight) { + * this.val = val; + * this.isLeaf = isLeaf; + * this.topLeft = topLeft; + * this.topRight = topRight; + * this.bottomLeft = bottomLeft; + * this.bottomRight = bottomRight; + * }; + */ +/** + * @param {Node} quadTree1 + * @param {Node} quadTree2 + * @return {Node} + */ +const intersect = function (quadTree1, quadTree2) { + if (quadTree1.isLeaf) { + return quadTree1.val ? quadTree1 : quadTree2; + } + + if (quadTree2.isLeaf) { + return quadTree2.val ? quadTree2 : quadTree1; + } + + const topLeft = intersect(quadTree1.topLeft, quadTree2.topLeft); + const topRight = intersect(quadTree1.topRight, quadTree2.topRight); + const bottomLeft = intersect(quadTree1.bottomLeft, quadTree2.bottomLeft); + const bottomRight = intersect(quadTree1.bottomRight, quadTree2.bottomRight); + + if ( + topLeft.isLeaf && + topRight.isLeaf && + bottomLeft.isLeaf && + bottomRight.isLeaf && + topLeft.val == topRight.val && + topRight.val == bottomLeft.val && + bottomLeft.val == bottomRight.val + ) { + return new Node(topLeft.val, true, null, null, null, null); + } else { + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +}; diff --git a/56-merge-intervals.js b/56-merge-intervals.js index 3be10e04..244a9fad 100644 --- a/56-merge-intervals.js +++ b/56-merge-intervals.js @@ -1,3 +1,73 @@ +/** + * @param {number[][]} intervals + * @return {number[][]} + */ +const merge = function(intervals) { + intervals.sort((a, b) => a[0] - b[0]) + const res = [] + let cur = intervals[0] + const n = intervals.length + res.push(cur) + for(let i = 1; i < n; i++) { + const e = intervals[i] + if(e[0] <= cur[1]) { + cur[1] = Math.max(e[1], cur[1]) + } else { + res.push(e) + cur = e + } + } + + return res +}; + +// another + +/** + * @param {number[][]} intervals + * @return {number[][]} + */ +const merge = function(intervals) { + intervals.sort((a, b) => a[0] - b[0] || a[1] - b[1]) + const res = [intervals[0]] + for(let i = 1, n = intervals.length; i < n; i++) { + const [s, e] = intervals[i] + const pre = res[res.length - 1] + if(s <= pre[1]) { + pre[1] = Math.max(pre[1], e) + } else { + res.push(intervals[i]) + } + } + return res +}; + +// another + + +/** + * @param {number[][]} intervals + * @return {number[][]} + */ +const merge = function(intervals) { + if(intervals == null || intervals.length === 0) return [] + intervals.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) + const res = [intervals[0]] + for(let i = 1, n = intervals.length; i < n; i++) { + const last = res[res.length - 1] + const lastEnd = last[1] + const [s, e] = intervals[i] + if(s > lastEnd) { + res.push(intervals[i]) + } else { + last[1] = Math.max(last[1], e) + } + } + return res +}; + +// another + /** * Definition for an interval. * function Interval(start, end) { diff --git a/560-subarray-sum-equals-k.js b/560-subarray-sum-equals-k.js index cbce19c3..c81bff23 100644 --- a/560-subarray-sum-equals-k.js +++ b/560-subarray-sum-equals-k.js @@ -5,10 +5,10 @@ */ const subarraySum = function(nums, k) { let totalNum = 0 - let map = new Map() + const map = new Map() let cumulativeSum = 0 map.set(0, 1) - for (let i = 0; i < nums.length; i++) { + for (let i = 0, len = nums.length; i < len; i++) { cumulativeSum += nums[i] if (map.get(cumulativeSum - k)) { totalNum += map.get(cumulativeSum - k) @@ -21,3 +21,23 @@ const subarraySum = function(nums, k) { } return totalNum } + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const subarraySum = function (nums, k) { + const n = nums.length, hash = { 0: 1 } + let pre = 0 + let res = 0 + for (let i = 0; i < n; i++) { + const cur = pre + nums[i] + if (hash[cur - k] != null) res += hash[cur - k] + hash[cur] = (hash[cur] || 0) + 1 + pre = cur + } + return res +} diff --git a/562-longest-line-of-consecutive-one-in-matrix.js b/562-longest-line-of-consecutive-one-in-matrix.js new file mode 100644 index 00000000..1fead0e2 --- /dev/null +++ b/562-longest-line-of-consecutive-one-in-matrix.js @@ -0,0 +1,25 @@ +/** + * @param {number[][]} M + * @return {number} + */ +const longestLine = function (M) { + const m = M.length + if (!m) return 0 + const n = M[0].length + if (!n) return 0 + + const DP = [...Array(m)].map(() => [...Array(n)].map(() => [0, 0, 0, 0])) + let max = 0 + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (M[i][j]) { + DP[i][j][0] = (i ? DP[i - 1][j][0] : 0) + 1 + DP[i][j][1] = (j < n - 1 && i ? DP[i - 1][j + 1][1] : 0) + 1 + DP[i][j][2] = (j && i ? DP[i - 1][j - 1][2] : 0) + 1 + DP[i][j][3] = (j ? DP[i][j - 1][3] : 0) + 1 + max = Math.max(max, ...DP[i][j]) + } + } + } + return max +} diff --git a/563-binary-tree-tilt.js b/563-binary-tree-tilt.js new file mode 100644 index 00000000..802a0037 --- /dev/null +++ b/563-binary-tree-tilt.js @@ -0,0 +1,23 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const findTilt = function(root) { + const tilt = { val: 0 } + dfs(root, tilt) + function dfs(root, tilt) { + if (!root) return 0 + let left = dfs(root.left, tilt) + let right = dfs(root.right, tilt) + tilt.val += Math.abs(left - right) + return root.val + left + right + } + return tilt.val +} diff --git a/564-find-the-closest-palindrome.js b/564-find-the-closest-palindrome.js index 8c12f73c..54db51cb 100644 --- a/564-find-the-closest-palindrome.js +++ b/564-find-the-closest-palindrome.js @@ -1,3 +1,85 @@ +/** + * @param {string} n + * @return {string} + */ +const nearestPalindromic = function(n) { + const {floor} = Math + const str = num => `${num}` + const a = makeSmaller(n), b = makeGreater(n) + // console.log(a, b) + if(delta(b, n) >= delta(n, a)) { + return a + } + return b + + function makeGreater(num) { + const n = num.length + const arr = num.split('') + for(let i = 0, j = n - 1; i <= j;) { + arr[j] = arr[i] + i++ + j-- + } + const tmp = arr.join('') + // console.log(tmp) + if(tmp > num) return tmp + let carry = 1 + + for(let i = floor((n - 1) / 2); i >= 0; i--) { + const cur = +arr[i] + carry + if(cur <= 9) { + arr[i] = str(cur) + carry = 0 + } else { + arr[i] = '0' + carry = 1 + } + arr[n - 1 - i] = arr[i] + } + if(carry) { + const ta = Array(n + 1).fill('0') + ta[0] = '1' + ta[ta.length - 1] = '1' + return ta.join('') + } + return arr.join('') + } + + function makeSmaller(num) { + const n = num.length + const arr = num.split('') + for(let i = 0, j = n - 1; i <= j;) { + arr[j] = arr[i] + i++ + j-- + } + const tmp = arr.join('') + if(tmp < num) return tmp + let carry = 1 + for(let i = floor((n - 1) / 2); i >= 0; i--) { + const cur = +arr[i] - carry + if(cur >= 0) { + arr[i] = str(cur) + carry = 0 + } else { + arr[i] = '9' + carry = 1 + } + arr[n - 1 - i] = arr[i] + } + if(arr[0] === '0' && n > 1) { + return '9'.repeat(n - 1) + } + return arr.join('') + } + function delta(a, b) { + return BigInt(a) - BigInt(b) + } +}; + +// another + + /** * @param {bigint | string} n * @return {string} diff --git a/567-permutation-in-string.js b/567-permutation-in-string.js index 96cf95e0..9a36f675 100644 --- a/567-permutation-in-string.js +++ b/567-permutation-in-string.js @@ -31,3 +31,36 @@ function matches(s1map, s2map) { } return true } + + +// another + +/** + * @param {string} s1 + * @param {string} s2 + * @return {boolean} + */ +const checkInclusion = function(s1, s2) { + const arr = Array(26).fill(0) + const a = 'a'.charCodeAt(0) + const s1l = s1.length + for(let c of s1) arr[c.charCodeAt(0) - a] += 1 + for(let i = 0, len = s2.length; i < len; i++) { + const tmp = s2[i] + arr[tmp.charCodeAt(0) - a]-- + if(i >= s1l - 1) { + if(allZeros(arr)) return true + arr[s2.charCodeAt(i - s1l + 1) - a]++ + } + + } + + return false +}; + +function allZeros(arr) { + for(let e of arr) { + if(e !== 0) return false + } + return true +} diff --git a/568-maximum-vacation-days.js b/568-maximum-vacation-days.js new file mode 100644 index 00000000..ffc8508b --- /dev/null +++ b/568-maximum-vacation-days.js @@ -0,0 +1,21 @@ +/** + * @param {number[][]} flights + * @param {number[][]} days + * @return {number} + */ +const maxVacationDays = function (flights, days) { + const N = flights.length + let dp = new Array(N).fill(0) + for (let k = days[0].length - 1; k >= 0; k--) { + const tmp = new Array(N) + for (let i = 0; i < N; i++) { + tmp[i] = days[i][k] + dp[i] + for (let j = 0; j < N; j++) { + if (flights[i][j] === 0) continue + tmp[i] = Math.max(tmp[i], days[j][k] + dp[j]) + } + } + dp = tmp + } + return dp[0] +} diff --git a/569-median-employee-salary.sql b/569-median-employee-salary.sql new file mode 100644 index 00000000..d92fb3c3 --- /dev/null +++ b/569-median-employee-salary.sql @@ -0,0 +1,14 @@ +# Write your MySQL query statement below +SELECT a.Id, a.Company, a.Salary +FROM ( + SELECT e.Id, e.Company, e.Salary, + IF(@prev = e.Company, @rank := @rank+1, @rank := 1) AS Ranking, + @prev := e.Company + FROM Employee e, (SELECT @rank := 0, @prev := 0) AS t + ORDER BY e.Company, e.Salary #, e.Id +) AS a, ( + SELECT Company, COUNT(*) AS cnt + FROM Employee + GROUP BY Company +) AS b +WHERE a.Company = b.Company AND Ranking IN (FLOOR((cnt+1)/2), FLOOR((cnt+2)/2)); diff --git a/57-insert-interval.js b/57-insert-interval.js index 60d4663b..d7611a1c 100644 --- a/57-insert-interval.js +++ b/57-insert-interval.js @@ -1,3 +1,30 @@ +/** + * @param {number[][]} intervals + * @param {number[]} newInterval + * @return {number[][]} + */ +const insert = function(intervals, newInterval) { + const res = [], n = intervals.length + let i = 0 + while(i < n && intervals[i][1] < newInterval[0]) { + res.push(intervals[i]) + i++ + } + while(i < n && intervals[i][0] <= newInterval[1]) { + newInterval[0] = Math.min(newInterval[0], intervals[i][0]) + newInterval[1] = Math.max(newInterval[1], intervals[i][1]) + i++ + } + res.push(newInterval) + while(i < n) { + res.push(intervals[i]) + i++ + } + + return res +}; + +// another /** * @param {number[][]} intervals * @param {number[]} newInterval diff --git a/570-managers-with-at-least-5-direct-reports.sql b/570-managers-with-at-least-5-direct-reports.sql new file mode 100644 index 00000000..641b9df0 --- /dev/null +++ b/570-managers-with-at-least-5-direct-reports.sql @@ -0,0 +1,10 @@ +# Write your MySQL query statement below +SELECT e1.Name +FROM Employee e1 +JOIN ( + SELECT ManagerId + FROM Employee + GROUP BY ManagerId + HAVING COUNT(ManagerId) >= 5 +) e2 +ON e1.Id = e2.ManagerId; diff --git a/571-find-median-given-frequency-of-numbers.sql b/571-find-median-given-frequency-of-numbers.sql new file mode 100644 index 00000000..c563c8e0 --- /dev/null +++ b/571-find-median-given-frequency-of-numbers.sql @@ -0,0 +1,7 @@ +# Write your MySQL query statement below +SELECT AVG(Number) AS median +FROM + (SELECT * FROM Numbers ORDER BY Number) a, + (SELECT @i:=0) init +WHERE + Frequency >= ABS(@i+(@i:=@i+Frequency) - (SELECT SUM(Frequency) FROM Numbers)); diff --git a/573-squirrel-simulation.js b/573-squirrel-simulation.js new file mode 100644 index 00000000..6d9f5cd5 --- /dev/null +++ b/573-squirrel-simulation.js @@ -0,0 +1,46 @@ +/** + * @param {number} height + * @param {number} width + * @param {number[]} tree + * @param {number[]} squirrel + * @param {number[][]} nuts + * @return {number} + */ +const minDistance = function(height, width, tree, squirrel, nuts) { + const arr = nuts.map(el => 2 * distance(el, tree)) + const sum = arr.reduce((ac, el) => ac + el, 0) + let res = Number.MAX_VALUE + for(let i = 0, len = arr.length; i < len; i++) { + let tmp = sum - arr[i] + distance(squirrel, nuts[i]) + distance(nuts[i], tree) + res = Math.min(res, tmp) + } + return res +}; + +function distance(p1, p2) { + return Math.abs(p1[0] - p2[0]) + Math.abs(p1[1] - p2[1]) +} + +// another + +/** + * @param {number} height + * @param {number} width + * @param {number[]} tree + * @param {number[]} squirrel + * @param {number[][]} nuts + * @return {number} + */ +const minDistance = function (height, width, tree, squirrel, nuts) { + let sum = 0, + maxDiff = -Number.MAX_VALUE + for (let nut of nuts) { + const dist = Math.abs(tree[0] - nut[0]) + Math.abs(tree[1] - nut[1]) + sum += 2 * dist + maxDiff = Math.max( + maxDiff, + dist - Math.abs(squirrel[0] - nut[0]) - Math.abs(squirrel[1] - nut[1]) + ) + } + return sum - maxDiff +} diff --git a/574-winning-candidate.sql b/574-winning-candidate.sql new file mode 100644 index 00000000..352f0ce6 --- /dev/null +++ b/574-winning-candidate.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +SELECT Name +FROM Candidate c +INNER JOIN (SELECT CandidateId + FROM Vote + GROUP BY CandidateId + ORDER BY COUNT(CandidateId) DESC + LIMIT 0,1) v +ON c.id = v.CandidateId; diff --git a/5745-last-day-where-you-can-still-cross.js b/5745-last-day-where-you-can-still-cross.js new file mode 100644 index 00000000..93911f4f --- /dev/null +++ b/5745-last-day-where-you-can-still-cross.js @@ -0,0 +1,76 @@ +/** + * @param {number} row + * @param {number} col + * @param {number[][]} cells + * @return {number} + */ +const latestDayToCross = function (row, col, cells) { + const d = [ + [-1, 0], + [1, 0], + [0, 1], + [0, -1], + ] + + let a = Array.from({ length: row }, () => Array(col).fill(0)) + let visited = Array.from({ length: row }, () => Array(col).fill(false)) + + for (let i = 0; i < cells.length; i++) { + a[cells[i][0] - 1][cells[i][1] - 1] = i + } + + let l = 0 + let r = row * col + while (l + 1 < r) { + let w = ~~((l + r) / 2) + if (canCross(w)) { + l = w + } else { + r = w + } + } + + return l + + function canReachBottom(i, j, day) { + if (i == row - 1) { + return true + } + visited[i][j] = true + + for (let diff of d) { + let newI = i + diff[0] + let newJ = j + diff[1] + + if (newI < 0 || newI >= row || newJ < 0 || newJ >= col) { + continue + } + + if (visited[newI][newJ] || a[newI][newJ] < day) { + continue + } + + if (canReachBottom(newI, newJ, day)) { + return true + } + } + + return false + } + + function canCross(day) { + for (let layer of visited) { + layer.forEach((e, idx) => (layer[idx] = false)) + } + + for (let j = 0; j < col; j++) { + if (a[0][j] >= day && canReachBottom(0, j, day)) { + return true + } + } + + return false + } +} + + diff --git a/576-out-of-boundary-paths.js b/576-out-of-boundary-paths.js new file mode 100644 index 00000000..78472acd --- /dev/null +++ b/576-out-of-boundary-paths.js @@ -0,0 +1,95 @@ +/** + * @param {number} m + * @param {number} n + * @param {number} N + * @param {number} i + * @param {number} j + * @return {number} + */ +const findPaths = function (m, n, N, i, j) { + const dp = [...Array(2)].map((_) => + [...Array(50)].map((_) => Array(50).fill(0)) + ) + while (N-- > 0) { + for (let i = 0; i < m; i++) { + for (let j = 0, nc = (N + 1) % 2, np = N % 2; j < n; j++) { + dp[nc][i][j] = + ((i === 0 ? 1 : dp[np][i - 1][j]) + + (i === m - 1 ? 1 : dp[np][i + 1][j]) + + (j === 0 ? 1 : dp[np][i][j - 1]) + + (j === n - 1 ? 1 : dp[np][i][j + 1])) % + 1000000007 + } + } + } + return dp[1][i][j] +} + +// another + +/** + * @param {number} m + * @param {number} n + * @param {number} N + * @param {number} i + * @param {number} j + * @return {number} + */ +const findPaths = function (m, n, N, i, j) { + if (N <= 0) return 0; + const MOD = 1000000007; + let count = Array.from({ length: m }, () => new Array(n).fill(0)); + count[i][j] = 1; + let result = 0; + const dirs = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ]; + for (let step = 0; step < N; step++) { + const temp = Array.from({ length: m }, () => new Array(n).fill(0)); + for (let r = 0; r < m; r++) { + for (let c = 0; c < n; c++) { + for (let d of dirs) { + const nr = r + d[0]; + const nc = c + d[1]; + if (nr < 0 || nr >= m || nc < 0 || nc >= n) { + result = (result + count[r][c]) % MOD; + } else { + temp[nr][nc] = (temp[nr][nc] + count[r][c]) % MOD; + } + } + } + } + count = temp; + } + return result; +}; + +// another + +/** + * @param {number} m + * @param {number} n + * @param {number} N + * @param {number} i + * @param {number} j + * @return {number} + */ +const findPaths = function (m, n, N, i, j, memo = new Map()) { + const key = N + ',' + i + ',' + j; + if (memo.has(key)) return memo.get(key); + const isOutside = i === -1 || i === m || j === -1 || j === n; + if (N === 0 || isOutside) return +isOutside; + memo.set(key, ( + findPaths(m, n, N - 1, i - 1, j, memo) + + findPaths(m, n, N - 1, i + 1, j, memo) + + findPaths(m, n, N - 1, i, j + 1, memo) + + findPaths(m, n, N - 1, i, j - 1, memo) + ) % 1000000007); + return memo.get(key); +} + + + diff --git a/577-employee-bonus.sql b/577-employee-bonus.sql new file mode 100644 index 00000000..74d8825a --- /dev/null +++ b/577-employee-bonus.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +SELECT Employee.name, Bonus.bonus +from Employee LEFT JOIN Bonus ON +Employee.empid = Bonus.empid +WHERE bonus is null or bonus<1000; diff --git a/578-get-highest-answer-rate-question.sql b/578-get-highest-answer-rate-question.sql new file mode 100644 index 00000000..6a376996 --- /dev/null +++ b/578-get-highest-answer-rate-question.sql @@ -0,0 +1,8 @@ +# Write your MySQL query statement below +select question_id as survey_log +from ( + select question_id, count(answer_id)/count(*) as count + from survey_log group by question_id + order by count desc + limit 1 +) as p; diff --git a/579-find-cumulative-salary-of-an-employee.sql b/579-find-cumulative-salary-of-an-employee.sql new file mode 100644 index 00000000..b7f187b9 --- /dev/null +++ b/579-find-cumulative-salary-of-an-employee.sql @@ -0,0 +1,6 @@ +# Write your MySQL query statement below +SELECT A.Id, MAX(B.Month) as Month, SUM(B.Salary) as Salary +FROM Employee A, Employee B +WHERE A.Id = B.Id AND B.Month BETWEEN (A.Month-3) AND (A.Month-1) +GROUP BY A.Id, A.Month +ORDER BY Id, Month DESC; diff --git a/580-count-student-number-in-departments.sql b/580-count-student-number-in-departments.sql new file mode 100644 index 00000000..03a2b52f --- /dev/null +++ b/580-count-student-number-in-departments.sql @@ -0,0 +1,7 @@ +# Write your MySQL query statement below +SELECT dept_name, IFNULL(COUNT(student_id),0) as student_number +FROM department +LEFT JOIN student +USING (dept_id) +GROUP BY dept_name +ORDER BY student_number DESC, dept_name; diff --git a/582-kill-process.js b/582-kill-process.js new file mode 100644 index 00000000..d5c5c502 --- /dev/null +++ b/582-kill-process.js @@ -0,0 +1,60 @@ +/** + * @param {number[]} pid + * @param {number[]} ppid + * @param {number} kill + * @return {number[]} + */ +const killProcess = function(pid, ppid, kill) { + const pm = new Map() + for(let i = 0, len = pid.length; i < len; i++) { + const c = pid[i] + const p = ppid[i] + let tmp = pm.get(p) + if(!tmp) tmp = new Set() + tmp.add(c) + pm.set(p, tmp) + } + const res = [] + const q = [kill] + while(q.length) { + const size = q.length + for(let i = 0; i < size; i++) { + const el = q.shift() + res.push(el) + if(pm.get(el)) { + q.push(...Array.from(pm.get(el))) + } + } + } + return res +}; + +// another + +/** + * @param {number[]} pid + * @param {number[]} ppid + * @param {number} kill + * @return {number[]} + */ +const killProcess = function(pid, ppid, kill) { + const pm = new Map() + for(let i = 0, len = pid.length; i < len; i++) { + const p = ppid[i] + let tmp = pm.get(p) + if(!tmp) tmp = new Set() + tmp.add(pid[i]) + pm.set(p, tmp) + } + const res = [] + function dfs(k) { + res.push(k) + if(pm.get(k)) { + for(let e of pm.get(k)) { + dfs(e) + } + } + } + dfs(kill) + return res +}; diff --git a/583-delete-operation-for-two-strings.js b/583-delete-operation-for-two-strings.js new file mode 100644 index 00000000..66821d18 --- /dev/null +++ b/583-delete-operation-for-two-strings.js @@ -0,0 +1,71 @@ +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const minDistance = function (word1, word2, memo = new Map()) { + if (word1 === word2) return 0 + if (word1 === '' || word2 === '') return Math.max(word1.length, word2.length) + const len1 = word1.length + const len2 = word2.length + if (memo.has(`${word1}-${word2}`)) return memo.get(`${word1}-${word2}`) + let res + if (word1[len1 - 1] === word2[len2 - 1]) { + res = minDistance(word1.slice(0, len1 - 1), word2.slice(0, len2 - 1), memo) + } else { + res = + 1 + + Math.min( + minDistance(word1.slice(0, len1 - 1), word2, memo), + minDistance(word1, word2.slice(0, len2 - 1), memo) + ) + } + memo.set(`${word1}-${word2}`, res) + return res +} + +// another + +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const minDistance = function (word1, word2) { + const len1 = word1.length + const len2 = word2.length + const dp = Array.from({ length: len1 + 1 }, () => new Array(len2 + 1).fill(0)) + for(let i = 1; i <= len1; i++) { + for(let j = 1; j<= len2; j++) { + if(word1[i - 1] === word2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1 + else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]) + } + } + return len1 + len2 - dp[len1][len2] * 2 +} + +// another + +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const minDistance = function (word1, word2) { + const len1 = word1.length + const len2 = word2.length + const dp = Array.from({ length: len1 + 1 }, () => new Array(len2 + 1).fill(0)) + for(let i = 1; i <= len2; i++) { + dp[0][i] = i + } + for(let j = 1; j <= len1; j++) { + dp[j][0] = j + } + for(let i = 1; i <= len1; i++) { + for(let j = 1; j<= len2; j++) { + if(word1[i - 1] === word2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + else dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1 + } + } + return dp[len1][len2] +} diff --git a/5832-array-with-elements-not-equal-to-average-of-neighbors.js b/5832-array-with-elements-not-equal-to-average-of-neighbors.js new file mode 100644 index 00000000..ef33751a --- /dev/null +++ b/5832-array-with-elements-not-equal-to-average-of-neighbors.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +const rearrangeArray = function(nums) { + nums.sort((a, b) => a - b) + const res = [] + let idx = 0, i = 0 + const n = ~~((nums.length + 1) / 2) + while(i < nums.length) { + if(idx >= nums.length) idx = 1 + // console.log(idx,i) + res[idx] = nums[i] + + idx += 2 + i++ + } + + return res +}; diff --git a/584-find-customer-referee.sql b/584-find-customer-referee.sql new file mode 100644 index 00000000..7378efcb --- /dev/null +++ b/584-find-customer-referee.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +select name +from customer +where referee_id <> 2 or referee_id is NULL; diff --git a/5843-number-of-strings-that-appear-as-substrings-in-word.js b/5843-number-of-strings-that-appear-as-substrings-in-word.js new file mode 100644 index 00000000..3c87e656 --- /dev/null +++ b/5843-number-of-strings-that-appear-as-substrings-in-word.js @@ -0,0 +1,12 @@ +/** + * @param {string[]} patterns + * @param {string} word + * @return {number} + */ +const numOfStrings = function(patterns, word) { + let res = 0 + for(let e of patterns) { + if(word.indexOf(e) !== -1) res++ + } + return res +}; diff --git a/5844-minimum-non-zero-product-of-the-array-elements.js b/5844-minimum-non-zero-product-of-the-array-elements.js new file mode 100644 index 00000000..067d8260 --- /dev/null +++ b/5844-minimum-non-zero-product-of-the-array-elements.js @@ -0,0 +1,21 @@ +/** + * @param {number} p + * @return {number} + */ +const minNonZeroProduct = function(p) { + const b = BigInt(p) + const mod = BigInt(10 ** 9 + 7) + + return (BigInt(1n << b) - 1n) % mod * pow(BigInt(1n << b) - 2n, BigInt(1n << (b - 1n)) - 1n) % mod; + + function pow(a, n) { + let r = 1n; + a %= mod; + while (n > 0n) { + r = r * a % mod; + a = a * a % mod; + n /= 2n; + } + return r; + } +}; diff --git a/585-investments-in-2016.sql b/585-investments-in-2016.sql new file mode 100644 index 00000000..26c97210 --- /dev/null +++ b/585-investments-in-2016.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +select sum(TIV_2016) TIV_2016 +from insurance a +where 1 = (select count(*) from insurance b where a.LAT = b.LAT and a.LON = b.LON) +and 1 < (select count(*) from insurance c where a.TIV_2015 = c.TIV_2015); diff --git a/587-erect-the-fence.js b/587-erect-the-fence.js new file mode 100644 index 00000000..61a73a70 --- /dev/null +++ b/587-erect-the-fence.js @@ -0,0 +1,33 @@ +/** + * @param {number[][]} points + * @return {number[][]} + */ +const outerTrees = function (points) { + const orientation = (p1, p2, p3) => { + return (p2[1] - p1[1]) * (p3[0] - p2[0]) - (p2[0] - p1[0]) * (p3[1] - p2[1]) + } + points.sort((a, b) => { + return a[0] === b[0] ? a[1] - b[1] : a[0] - b[0] + }) + const stack = [] + for (let i = 0; i < points.length; i++) { + while ( + stack.length >= 2 && + orientation(stack[stack.length - 2], stack[stack.length - 1], points[i]) > + 0 + ) + stack.pop() + stack.push(points[i]) + } + stack.pop() + for (let i = points.length - 1; i >= 0; i--) { + while ( + stack.length >= 2 && + orientation(stack[stack.length - 2], stack[stack.length - 1], points[i]) > + 0 + ) + stack.pop() + stack.push(points[i]) + } + return [...new Set(stack)] +} diff --git a/588-design-in-memory-file-system.js b/588-design-in-memory-file-system.js new file mode 100644 index 00000000..e23ea7dd --- /dev/null +++ b/588-design-in-memory-file-system.js @@ -0,0 +1,149 @@ +const FileSystem = function () { + this.items = new Map() +} + +/** + * @param {string} path + * @return {string[]} + */ +FileSystem.prototype.ls = function (path) { + const paths = path.split('/').filter((p) => !!p.length) + let curr = this.items + let last = '' + + for (const p of paths) { + curr = curr.get(p) + last = p + } + const list = Array.from(curr.keys()).filter((e) => e !== 'content') + if (curr.has('content')) list.push(last) + return list.sort() +} + +/** + * @param {string} path + * @return {void} + */ +FileSystem.prototype.mkdir = function (path) { + const paths = path.split('/').filter((p) => !!p.length) + let curr = this.items + for (const p of paths) { + if (!curr.has(p)) { + curr.set(p, new Map()) + } + curr = curr.get(p) + } +} + +/** + * @param {string} filePath + * @param {string} content + * @return {void} + */ +FileSystem.prototype.addContentToFile = function (filePath, content) { + const paths = filePath.split('/').filter((p) => !!p.length) + let curr = this.items + for (const p of paths) { + if (!curr.has(p)) { + curr.set(p, new Map()) + } + curr = curr.get(p) + } + curr.set('content', (curr.get('content') || '') + content) +} + +/** + * @param {string} filePath + * @return {string} + */ +FileSystem.prototype.readContentFromFile = function (filePath) { + const paths = filePath.split('/').filter((p) => !!p.length) + let curr = this.items + for (const p of paths) { + curr = curr.get(p) + } + return curr.get('content') +} + +/** + * Your FileSystem object will be instantiated and called as such: + * var obj = new FileSystem() + * var param_1 = obj.ls(path) + * obj.mkdir(path) + * obj.addContentToFile(filePath,content) + * var param_4 = obj.readContentFromFile(filePath) + */ + +// another + +const FileSystem = function () { + this.root = new Node() +} + +/** + * @param {string} path + * @return {string[]} + */ +FileSystem.prototype.ls = function (path) { + const cur = this.find(path) + if(cur.content) { + const arr = path.split('/') + return [arr[arr.length - 1]] + } + return Object.keys(cur.children).sort() +} + +/** + * @param {string} path + * @return {void} + */ +FileSystem.prototype.mkdir = function (path) { + this.find(path) +} + +/** + * @param {string} filePath + * @param {string} content + * @return {void} + */ +FileSystem.prototype.addContentToFile = function (filePath, content) { + const cur = this.find(filePath) + cur.content += content +} + +/** + * @param {string} filePath + * @return {string} + */ +FileSystem.prototype.readContentFromFile = function (filePath) { + const cur = this.find(filePath) + return cur.content +} + +FileSystem.prototype.find = function (filePath) { + if(filePath.length === 1) return this.root + const arr = filePath.split('/').slice(1) + let cur = this.root + for(let e of arr) { + if (cur.children[e] == null) cur.children[e] = new Node() + cur = cur.children[e] + } + return cur +} + +/** + * Your FileSystem object will be instantiated and called as such: + * var obj = new FileSystem() + * var param_1 = obj.ls(path) + * obj.mkdir(path) + * obj.addContentToFile(filePath,content) + * var param_4 = obj.readContentFromFile(filePath) + */ + +class Node { + constructor() { + this.children = {} + this.content = '' + } +} + diff --git a/591-tag-validator.js b/591-tag-validator.js new file mode 100644 index 00000000..ead25315 --- /dev/null +++ b/591-tag-validator.js @@ -0,0 +1,205 @@ +/** + * @param {string} code + * @return {boolean} + */ +const isValid = function (code) { + const stack = [] + const [A, Z] = ['A', 'Z'].map((e) => e.charCodeAt(0)) + for (let i = 0; i < code.length; ) { + if (i > 0 && stack.length === 0) return false + if (code.startsWith('', j) + if (i < 0) return false + i += 3 + } else if (code.startsWith('', j) + if (i < 0 || i === j || i - j > 9) return false + for (let k = j; k < i; k++) { + if ( + code.charAt(k) !== code[k].toUpperCase() || + !(code.charCodeAt(k) >= A && code.charCodeAt(k) <= Z) + ) + return false + } + let s = code.slice(j, i++) + if (stack.length === 0 || stack.pop() !== s) return false + } else if (code.startsWith('<', i)) { + let j = i + 1 + i = code.indexOf('>', j) + if (i < 0 || i === j || i - j > 9) return false + for (let k = j; k < i; k++) { + if ( + code.charAt(k) !== code[k].toUpperCase() || + !(code.charCodeAt(k) >= A && code.charCodeAt(k) <= Z) + ) + return false + } + let s = code.slice(j, i++) + stack.push(s) + } else { + i++ + } + } + return stack.length === 0 +} + +// another + +/** + * @param {string} code + * @return {boolean} + */ +const isValid = function (code) { + code = code.replace(/|t/g, '-') + let prev + while (code !== prev) { + prev = code + code = code.replace(/<([A-Z]{1,9})>[^<]*<\/\1>/g, 't') + } + return code === 't' +} + + +// another + +/** + * @param {string} code + * @return {boolean} + */ +const isValid = function (code) { + const STATES = { + lt: 1, // < + tagOrData: 2, // uppercase=tag, '!'=data + tagName: 3, // uppercase, '>'=end + dataContent: 4, // any, ']'=wait-for-end + dataEnd: 5, // any, ']'=end + tagContent: 6, // any, '<'=tag-or-data + } + class Validator { + constructor(str) { + this.state = STATES.lt + this.str = str + this.stack = [] + this.i = 0 + // this ensure it doesnt start with cdata + this.isValid = this.isUpperCase(this.str[1]) + // check through code + while (this.isValid && this.i < this.str.length) { + this.isValid = this.validate() + } + // check if there is unclosed tags + this.isValid = this.isValid && !this.stack.length + } + + /** + * check and move on + */ + validate() { + let char = this.str[this.i] + switch (this.state) { + // expect '<', only used at start + case STATES.lt: + this.i++ + if (char == '<') { + this.state = STATES.tagOrData + return true + } + return false + // expect (end-)tag-name or cdata + case STATES.tagOrData: + // data + if (char == '!') { + this.i = this.findStrEnd(this.i + 1, '[CDATA[') + if (this.i == -1) { + return false + } + this.state = STATES.dataContent + return true + } + // end tag + if (char == '/') { + let name = this.stack.pop() + if (!name) { + return false + } + this.i = this.findStrEnd(this.i + 1, name + '>') + if (this.i == -1) { + return false + } + if (!this.stack.length & (this.i < this.str.length)) { + // more than one top level tags + return false + } + this.state = STATES.tagContent + return true + } + // tag name + { + let name = this.findTagName(this.i) + if (!name) { + return false + } + if (name.length > 9) { + return false + } + this.i += name.length + 1 + this.stack.push(name) + this.state = STATES.tagContent + return true + } + case STATES.dataContent: // you can try replace these code with indexOf + { + let end = this.findStrEnd(this.i, ']]>') + if (end != -1) { + // found end + this.i = end + this.state = STATES.tagContent + return true + } + // not yet + this.i++ + return true + } + case STATES.tagContent: + if (char == '<') { + this.state = STATES.tagOrData + this.i++ + return true + } + this.i++ + return true + } + } + + isUpperCase(char) { + return /[A-Z]/.test(char) + } + + findStrEnd(from, toFind = '') { + let end = from + toFind.length + for (let i = 0; i < toFind.length; i++) { + if (toFind[i] != this.str[i + from]) return -1 + } + return end + } + + findTagName(from) { + let tagName = '' + for (let i = from; i < this.str.length; i++) { + if (this.isUpperCase(this.str[i])) { + tagName += this.str[i] + continue + } + if (this.str[i] == '>') { + return tagName + } + return '' + } + return '' + } + } + let v = new Validator(code) + return v.isValid +} diff --git a/592-fraction-addition-and-subtraction.js b/592-fraction-addition-and-subtraction.js new file mode 100644 index 00000000..323df6c3 --- /dev/null +++ b/592-fraction-addition-and-subtraction.js @@ -0,0 +1,36 @@ +/** + * @param {string} expression + * @return {string} + */ +const fractionAddition = function (expression) { + if (expression[0] === '-') expression = '0/1' + expression + const terms = expression.split(/[+-]/g) + const ops = '+' + expression.replace(/[^+-]/g, '') + const nums = [], + dens = [] + for (let term of terms) { + let t = term.split('/') + nums.push(parseInt(t[0])) + dens.push(parseInt(t[1])) + } + const lcm = LCM(dens) + const numSum = nums.reduce( + (sum, num, i) => sum + ((+(ops[i] === '+') || -1) * num * lcm) / dens[i], + 0 + ) + const gcd = Math.abs(GCD(numSum, lcm)) + return numSum / gcd + '/' + lcm / gcd +} + +function LCM(arr) { + let res = arr[0] + for (let i = 1; i < arr.length; i++) { + res = (arr[i] * res) / GCD(arr[i], res) + } + return res +} + +function GCD(a, b) { + if (b === 0) return a + return GCD(b, a % b) +} diff --git a/5956-find-first-palindromic-string-in-the-array.js b/5956-find-first-palindromic-string-in-the-array.js new file mode 100644 index 00000000..b496507a --- /dev/null +++ b/5956-find-first-palindromic-string-in-the-array.js @@ -0,0 +1,23 @@ +/** + * @param {string[]} words + * @return {string} + */ +const firstPalindrome = function(words) { + for(let str of words) { + if(isPa(str)) return str + } + + return '' +}; + +function isPa(str) { + let l = 0, r = str.length - 1 + while(l < r) { + if(str[l] !== str[r]) return false + l++ + r-- + } + + + return true +} diff --git a/5957-adding-spaces-to-a-string.js b/5957-adding-spaces-to-a-string.js new file mode 100644 index 00000000..1696b3b6 --- /dev/null +++ b/5957-adding-spaces-to-a-string.js @@ -0,0 +1,18 @@ +/** + * @param {string} s + * @param {number[]} spaces + * @return {string} + */ +var addSpaces = function(s, spaces) { + let res = '', j = 0, idx = spaces[j] + for(let i = 0, n = s.length; i < n; i++) { + if(i === idx) { + res += ' ' + j++ + idx = spaces[j] + } + res += s[i] + } + + return res +}; diff --git a/5958-number-of-smooth-descent-periods-of-a-stock.js b/5958-number-of-smooth-descent-periods-of-a-stock.js new file mode 100644 index 00000000..d797df08 --- /dev/null +++ b/5958-number-of-smooth-descent-periods-of-a-stock.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} prices + * @return {number} + */ +const getDescentPeriods = function(prices) { + if(prices.length === 1) return 1 + let res = 0, idx = 0 + + for (let i = 1, n = prices.length; i < n ; i++) { + if(prices[i - 1] - prices[i] === 1) { + if (i === n - 1) { + const len = i - idx + 1 + res += (len + 1) * len / 2 + } + } else { + const len = i - 1 - idx + 1 + res += (len + 1) * len / 2 + idx = i + if(i === n - 1) { + res += 1 + } + } + + } + + return res +}; diff --git a/596-customer-placing-the-largest-number-of-orders.sql b/596-customer-placing-the-largest-number-of-orders.sql new file mode 100644 index 00000000..088b10cc --- /dev/null +++ b/596-customer-placing-the-largest-number-of-orders.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +select customer_number +from orders +group by customer_number +order by count(*) desc limit 1; diff --git a/597-friend-requests-i-overall-acceptance-rate.sql b/597-friend-requests-i-overall-acceptance-rate.sql new file mode 100644 index 00000000..8f0e1e47 --- /dev/null +++ b/597-friend-requests-i-overall-acceptance-rate.sql @@ -0,0 +1,6 @@ +# Write your MySQL query statement below +select round(ifnull( + (select count(*) from (select distinct requester_id, accepter_id from request_accepted) as a) + / + (select count(*) from (select distinct sender_id, send_to_id from friend_request) as b) + ,0),2) as accept_rate; diff --git a/5976-check-if-every-row-and-column-contains-all-numbers.js b/5976-check-if-every-row-and-column-contains-all-numbers.js new file mode 100644 index 00000000..fe00e653 --- /dev/null +++ b/5976-check-if-every-row-and-column-contains-all-numbers.js @@ -0,0 +1,34 @@ +/** + * @param {number[][]} matrix + * @return {boolean} + */ +var checkValid = function(matrix) { + const n = matrix.length + let res = true + for(let i = 0; i < n; i++) { + if(!chkRow(i) || !chkCol(i)) { + res = false + break + } + } + + + return res + + function chkRow(i) { + const row = matrix[i], set = new Set() + for(let i = 0; i < n; i++) { + set.add(row[i]) + } + return set.size === n + } + + function chkCol(j) { + const set = new Set() + for(let i = 0; i < n; i++) { + set.add(matrix[i][j]) + } + + return set.size === n + } +}; diff --git a/5977-minimum-swaps-to-group-all-1s-together-ii.js b/5977-minimum-swaps-to-group-all-1s-together-ii.js new file mode 100644 index 00000000..a143e4b3 --- /dev/null +++ b/5977-minimum-swaps-to-group-all-1s-together-ii.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var minSwaps = function(nums) { + let one = 0; + for (let i = 0; i < nums.length; i++) { + if (nums[i] == 1) + one++; + } + let maxOne = 0; + for (let i = 0; i < one; i++) { + if (nums[i] == 1) + maxOne++; + } + let max = maxOne; + for (let i = 1; i < nums.length; i++) { + if (nums[i - 1] == 1) + maxOne--; + if (nums[(i + one - 1) % nums.length] == 1) + maxOne++; + if (maxOne > max) + max = maxOne; + } + return one - max; + +}; diff --git a/5978-count-words-obtained-after-adding-a-letter.js b/5978-count-words-obtained-after-adding-a-letter.js new file mode 100644 index 00000000..9136ea31 --- /dev/null +++ b/5978-count-words-obtained-after-adding-a-letter.js @@ -0,0 +1,28 @@ +/** + * @param {string[]} startWords + * @param {string[]} targetWords + * @return {number} + */ +var wordCount = function(startWords, targetWords) { + const set = new Set(); + for (let startWord of startWords) { + const chars = startWord.split(''); + chars.sort(); + set.add(chars.join('')); + } + let res = 0; + for (let targetWord of targetWords) { + let chars = targetWord.split(''); + chars.sort() + + let word = chars.join(''); + for (let i = 0; i < chars.length; i++) { + let subWord = word.substring(0, i) + word.substring(i + 1, chars.length); + if (set.has(subWord)) { + res++; + break; + } + } + } + return res; +}; diff --git a/598-range-addition-ii.js b/598-range-addition-ii.js new file mode 100644 index 00000000..7d95a8a1 --- /dev/null +++ b/598-range-addition-ii.js @@ -0,0 +1,13 @@ +/** + * @param {number} m + * @param {number} n + * @param {number[][]} ops + * @return {number} + */ +const maxCount = function (m, n, ops) { + for (let i = 0, len = ops.length; i < len; i++) { + if (ops[i][0] < m) m = ops[i][0] + if (ops[i][1] < n) n = ops[i][1] + } + return m * n +} diff --git a/60-permutation-sequence.js b/60-permutation-sequence.js index 979dfdc9..ea812807 100644 --- a/60-permutation-sequence.js +++ b/60-permutation-sequence.js @@ -4,18 +4,142 @@ * @return {string} */ const getPermutation = function(n, k) { - let sb = '' - const num = [] - let fact = 1 - for (let i = 1; i <= n; i++) { - fact *= i - num.push(i) + const factorial = Array(n + 1).fill(0) + factorial[0] = 1 + for(let i = 1; i <= n; i++) { + factorial[i] = factorial[i - 1] * i + } + let res = '' + const visited = Array(n + 1).fill(0) + dfs(0) + return res + + function dfs(idx) { + if(idx === n) return + + const cnt = factorial[n - idx - 1] + for(let i = 1; i <= n; i++) { + if(visited[i]) continue + if(cnt < k) { + k -= cnt + continue + } + res += i + visited[i] = 1 + dfs(idx + 1) + return } - for(let i = 0, l = k - 1; i < n; i++ ) { - fact = Math.floor( fact / (n - i) ) - let index = Math.floor( l / fact ) - sb += num.splice(index, 1)[0] - l -= index * fact - } - return sb + } +}; + +// another + +/** + * @param {number} n + * @param {number} k + * @return {string} + */ +const getPermutation = function(n, k) { + const factorial = Array(n + 1).fill(0) + factorial[0] = 1 + for(let i = 1, pre = 1; i <= n; i++) { + factorial[i] = pre * i + pre = factorial[i] + } + const nums = Array.from({length: n}, (_, i) => i + 1) + + let res = '' + k-- + for(let i = 1; i <= n; i++) { + const idx = ~~(k / factorial[n - i]) + res += nums[idx] + nums.splice(idx, 1) + k -= idx * factorial[n - i] + } + + return res +}; + +// another + +/** + * @param {number} n + * @param {number} k + * @return {string} + */ +const getPermutation = function(n, k) { + const fact = [] + const nums = [] + for(let i = 1; i <= n; i++) { + nums.push(i) + } + fact[0] = 1 + for(let i = 1, tmp = 1; i <= n; i++) { + tmp *= i + fact[i] = tmp + } + let res = '' + k-- + for(let i = 1; i <= n; i++) { + const idx = ~~(k / fact[n - i]) + res += nums[idx] + nums.splice(idx, 1) + k -= idx * fact[n - i] + } + + return res +}; + +// another + +/** + * @param {number} n + * @param {number} k + * @return {string} + */ +const getPermutation = function (n, k) { + let sb = '' + const num = [] + let fact = 1 + for (let i = 1; i <= n; i++) { + fact *= i + num.push(i) + } + for (let i = 0, l = k - 1; i < n; i++) { + fact = Math.floor(fact / (n - i)) + const index = Math.floor(l / fact) + sb += num.splice(index, 1)[0] + l -= index * fact + } + return sb +} + +// another + +/** + * @param {number} n + * @param {number} k + * @return {string} + */ +const getPermutation = function(n, k) { + const factorial = [] + const nums = [] + let res = '' + factorial[0] = 1 + for(let i = 1, sum = 1; i <= n; i++) { + sum *= i + factorial[i] = sum + } + for(let i = 1; i <= n; i++) { + nums.push(i) + } + k-- + for(let i = 0; i <= n; i++) { + const idx = ~~(k / factorial[n - i]) + res += nums[idx] + nums.splice(idx, 1) + k -= idx * factorial[n - i] + } + + return res }; diff --git a/600-non-negative-integers-without-consecutive-ones.js b/600-non-negative-integers-without-consecutive-ones.js new file mode 100644 index 00000000..36c61434 --- /dev/null +++ b/600-non-negative-integers-without-consecutive-ones.js @@ -0,0 +1,21 @@ +/** + * @param {number} num + * @return {number} + */ +const findIntegers = function (num) { + const binary = num.toString(2) + const fibonacci = [1, 2] + for (let i = 2; i < binary.length; ++i) { + fibonacci.push(fibonacci[i - 2] + fibonacci[i - 1]) + } + let answer = binary.indexOf('11') === -1 ? 1 : 0 + for (let i = 0; i < binary.length; ++i) { + if (binary[i] === '1') { + answer += fibonacci[binary.length - 1 - i] + if (binary[i - 1] === '1') { + break + } + } + } + return answer +} diff --git a/601-human-traffic-of-stadium.sql b/601-human-traffic-of-stadium.sql new file mode 100644 index 00000000..628b0024 --- /dev/null +++ b/601-human-traffic-of-stadium.sql @@ -0,0 +1,8 @@ +# Write your MySQL query statement below +select distinct s1.* from stadium as s1, stadium as s2, stadium as s3 +where + ((s1.id + 1 = s2.id and s1.id + 2 = s3.id) + or (s1.id - 1 = s2.id and s1.id + 1 = s3.id) + or (s1.id - 2 = s2.id and s1.id - 1 = s3.id)) + and s1.people >= 100 and s2.people >= 100 and s3.people >= 100 +order by s1.id; diff --git a/602-friend-requests-ii-who-has-the-most-friends.sql b/602-friend-requests-ii-who-has-the-most-friends.sql new file mode 100644 index 00000000..06ee877f --- /dev/null +++ b/602-friend-requests-ii-who-has-the-most-friends.sql @@ -0,0 +1,11 @@ +# Write your MySQL query statement below +select id1 as id, count(id2) as num +from +(select requester_id as id1, accepter_id as id2 +from request_accepted +union +select accepter_id as id1, requester_id as id2 +from request_accepted) tmp1 +group by id1 +order by num desc +limit 1; diff --git a/603-consecutive-available-seats.sql b/603-consecutive-available-seats.sql new file mode 100644 index 00000000..0f06e5e3 --- /dev/null +++ b/603-consecutive-available-seats.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +select distinct a.seat_id +from cinema a +left join cinema b on a.seat_id = b.seat_id - 1 or a.seat_id = b.seat_id + 1 +where a.free = 1 and b.free = 1; diff --git a/604-design-compressed-string-iterator.js b/604-design-compressed-string-iterator.js new file mode 100644 index 00000000..3cbe0a42 --- /dev/null +++ b/604-design-compressed-string-iterator.js @@ -0,0 +1,38 @@ +/** + * @param {string} compressedString + */ +const StringIterator = function(compressedString) { + const s = compressedString.replace(/[a-zA-Z]/g,'-') + const ss = compressedString.replace(/[0-9]+/g, '-') + const sa = s.split('-').filter(e => !!e).map(e => +e) + const ssa = ss.split('-').filter(e => !!e) + this.idx = 0 + this.charArr = ssa + this.numArr = sa +}; + +/** + * @return {character} + */ +StringIterator.prototype.next = function() { + let res = ' ' + if(this.idx >= this.numArr.length) return res + if(this.numArr[this.idx]) res = this.charArr[this.idx] + this.numArr[this.idx]-- + if(this.numArr[this.idx] === 0) this.idx++ + return res +}; + +/** + * @return {boolean} + */ +StringIterator.prototype.hasNext = function() { + return this.numArr[this.idx] > 0 +}; + +/** + * Your StringIterator object will be instantiated and called as such: + * var obj = new StringIterator(compressedString) + * var param_1 = obj.next() + * var param_2 = obj.hasNext() + */ diff --git a/606-construct-string-from-binary-tree.js b/606-construct-string-from-binary-tree.js new file mode 100644 index 00000000..7e2f1a4a --- /dev/null +++ b/606-construct-string-from-binary-tree.js @@ -0,0 +1,19 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} t + * @return {string} + */ +const tree2str = function(t) { + if (!t) return '' + const left = tree2str(t.left) + const right = tree2str(t.right) + if (right) return `${t.val}(${left})(${right})` + else if (left) return `${t.val}(${left})` + else return `${t.val}` +}; diff --git a/607-sales-person.sql b/607-sales-person.sql new file mode 100644 index 00000000..7b2051eb --- /dev/null +++ b/607-sales-person.sql @@ -0,0 +1,7 @@ +# Write your MySQL query statement below +select name +from salesperson +where sales_id not in (select sales_id from +orders left join company +on orders.com_id = company.com_id +where company.name = 'red'); diff --git a/608-tree-node.sql b/608-tree-node.sql new file mode 100644 index 00000000..c7ec6a9e --- /dev/null +++ b/608-tree-node.sql @@ -0,0 +1,8 @@ +# Write your MySQL query statement below +select distinct + t1.id, + case when t1.p_id is NULL then 'Root' + when t2.id is NULL then 'Leaf' + else 'Inner' + end as Type +from tree t1 left join tree t2 on t1.id = t2.p_id; diff --git a/609-find-duplicate-file-in-system.js b/609-find-duplicate-file-in-system.js new file mode 100644 index 00000000..0f8bcbac --- /dev/null +++ b/609-find-duplicate-file-in-system.js @@ -0,0 +1,16 @@ +/** + * @param {string[]} paths + * @return {string[][]} + */ +const findDuplicate = function (paths) { + const map = {} + for (let text of paths) { + for (let i = 1, files = text.split(' '); i < files.length; i++) { + const paren = files[i].indexOf('(') + const content = files[i].substring(paren + 1, files[i].length - 1) + map[content] = map[content] || [] + map[content].push(files[0] + '/' + files[i].substr(0, paren)) + } + } + return Object.values(map).filter((dups) => dups.length > 1) +} diff --git a/61-rotate-list.js b/61-rotate-list.js index cbd51513..5f97560e 100644 --- a/61-rotate-list.js +++ b/61-rotate-list.js @@ -29,3 +29,37 @@ const rotateRight = function(head, k) { return dummy.next; }; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ +const rotateRight = function(head, k) { + if(head == null) return null + let len = 1 + let tmp = head + while(tmp.next) { + len++ + tmp = tmp.next + } + k = k % len + if(k === 0) return head + let tail = head + for(let i = 1; i < len - k; i++) { + tail = tail.next + } + const newHead = tail.next + tmp.next = head + tail.next = null + return newHead +}; diff --git a/610-triangle-judgement.sql b/610-triangle-judgement.sql new file mode 100644 index 00000000..9c5c9cf6 --- /dev/null +++ b/610-triangle-judgement.sql @@ -0,0 +1,9 @@ +# Write your MySQL query statement below +SELECT x + , y + , z + , CASE WHEN + x + y > z AND x + z > y AND y + z > x THEN 'Yes' + ELSE 'No' + END AS triangle + FROM triangle; diff --git a/612-shortest-distance-in-a-plane.sql b/612-shortest-distance-in-a-plane.sql new file mode 100644 index 00000000..8cedcf8f --- /dev/null +++ b/612-shortest-distance-in-a-plane.sql @@ -0,0 +1,4 @@ +# Write your MySQL query statement below +select round(sqrt(min(pow(a.x-b.x,2) + pow(a.y-b.y,2))), 2) shortest +from point_2d a, point_2d b +where (a.x,a.y) != (b.x,b.y); diff --git a/613-shortest-distance-in-a-line.sql b/613-shortest-distance-in-a-line.sql new file mode 100644 index 00000000..c6a56425 --- /dev/null +++ b/613-shortest-distance-in-a-line.sql @@ -0,0 +1,5 @@ +# Write your MySQL query statement below +select min(abs(t1.x-t2.x)) as shortest +from point as t1 +join point as t2 +on t1.x != t2.x; diff --git a/614-second-degree-follower.sql b/614-second-degree-follower.sql new file mode 100644 index 00000000..191777de --- /dev/null +++ b/614-second-degree-follower.sql @@ -0,0 +1,17 @@ +# Write your MySQL query statement below +SELECT + followee AS follower, + COUNT(DISTINCT follower) AS num +FROM follow +WHERE followee IN (SELECT follower FROM follow) +GROUP BY followee +ORDER BY followee; + +# another + +select distinct follower, num +from follow, +(select followee, count(distinct follower) as num from follow +group by followee) as t +where follower = t.followee +order by follower; diff --git a/615-average-salary-departments-vs-company.sql b/615-average-salary-departments-vs-company.sql new file mode 100644 index 00000000..28a8a6c8 --- /dev/null +++ b/615-average-salary-departments-vs-company.sql @@ -0,0 +1,14 @@ +# Write your MySQL query statement below +SELECT d1.pay_month, d1.department_id, +CASE WHEN d1.department_avg > c1.company_avg THEN 'higher' + WHEN d1.department_avg < c1.company_avg THEN 'lower' + ELSE 'same' +END AS 'comparison' +FROM ((SELECT LEFT(s1.pay_date, 7) pay_month, e1.department_id, AVG(s1.amount) department_avg +FROM salary s1 +JOIN employee e1 ON s1.employee_id = e1.employee_id +GROUP BY pay_month, e1.department_id) d1 +LEFT JOIN (SELECT LEFT(pay_date, 7) pay_month, AVG(amount) company_avg +FROM salary +GROUP BY pay_month) c1 ON d1.pay_month = c1.pay_month) +ORDER BY pay_month DESC, department_id; diff --git a/616-add-bold-tag-in-string.js b/616-add-bold-tag-in-string.js new file mode 100644 index 00000000..c06d70ac --- /dev/null +++ b/616-add-bold-tag-in-string.js @@ -0,0 +1,31 @@ +/** + * @param {string} s + * @param {string[]} dict + * @return {string} + */ +const addBoldTag = function (s, dict) { + const bold = new Array(s.length) + for (let sub of dict) { + let found = -1 + let prevBold = 0 + while ((found = s.indexOf(sub, found + 1)) !== -1) { + for (let i = Math.max(prevBold, found); i < found + sub.length; i++) { + bold[i] = 1 + } + prevBold = found + sub.length + } + } + let res = '' + let open = false + for (let i = 0; i < s.length; i++) { + if (bold[i] && !open) { + open = true + res += '' + } else if (!bold[i] && open) { + open = false + res += '' + } + res += s[i] + } + return open ? res + '' : res +} diff --git a/618-students-report-by-geography.sql b/618-students-report-by-geography.sql new file mode 100644 index 00000000..252089ee --- /dev/null +++ b/618-students-report-by-geography.sql @@ -0,0 +1,14 @@ +# Write your MySQL query statement below +SELECT MAX(America) AS America, MAX(Asia) as Asia, MAX(Europe) AS Europe +FROM ( + SELECT + CASE WHEN continent = 'America' THEN @r1 := @r1 + 1 + WHEN continent = 'Asia' THEN @r2 := @r2 + 1 + WHEN continent = 'Europe' THEN @r3 := @r3 + 1 END row_id, + CASE WHEN continent = 'America' THEN name END America, + CASE WHEN continent = 'Asia' THEN name END Asia, + CASE WHEN continent = 'Europe' THEN name END Europe + FROM student, (SELECT @r1 := 0, @r2 := 0, @r3 := 0) AS row_id + ORDER BY name +) t +GROUP BY row_id; diff --git a/619-biggest-single-number.sql b/619-biggest-single-number.sql new file mode 100644 index 00000000..978912d9 --- /dev/null +++ b/619-biggest-single-number.sql @@ -0,0 +1,8 @@ +# Write your MySQL query statement below +select( + select num + from my_numbers + group by num + having count(*) = 1 + order by num desc limit 1 +) as num; diff --git a/62-unique-paths.js b/62-unique-paths.js index 7372e320..6abde1b3 100644 --- a/62-unique-paths.js +++ b/62-unique-paths.js @@ -17,6 +17,24 @@ const uniquePaths = function(m, n) { // another +/** + * @param {number} m + * @param {number} n + * @return {number} + */ +const uniquePaths = function(m, n) { + const dp = Array(m).fill(0) + for(let i = 0; i < n; i++) { + dp[0] = 1 + for(let j = 1; j < m; j++) { + dp[j] += dp[j - 1] + } + } + return dp[m - 1] +}; + +// another + /** * @param {number} m * @param {number} n diff --git a/621-task-scheduler.js b/621-task-scheduler.js index 0b69d503..1c07d12c 100755 --- a/621-task-scheduler.js +++ b/621-task-scheduler.js @@ -1,3 +1,36 @@ +/** + * @param {character[]} tasks + * @param {number} n + * @return {number} + */ +const leastInterval = function (tasks, n) { + const len = tasks.length + const cnt = Array(26).fill(0) + + const A = 'A'.charCodeAt(0) + let maxFreq = 0, + maxFreqCnt = 0 + for (const ch of tasks) { + const idx = ch.charCodeAt(0) - A + cnt[idx]++ + if (maxFreq === cnt[idx]) { + maxFreqCnt++ + } else if (maxFreq < cnt[idx]) { + maxFreqCnt = 1 + maxFreq = cnt[idx] + } + } + + const slot = maxFreq - 1 + const numOfPerSlot = n - (maxFreqCnt - 1) + const available = len - maxFreq * maxFreqCnt + const idles = Math.max(0, slot * numOfPerSlot - available) + return len + idles +} + + +// another + /** * @param {character[]} tasks * @param {number} n @@ -15,3 +48,56 @@ const leastInterval = function(tasks, n) { } return idle_slots > 0 ? idle_slots + tasks.length : tasks.length; }; + +// another + +/** + * @param {character[]} tasks + * @param {number} n + * @return {number} + */ +const leastInterval = function(tasks, n) { + const hash = {}; + for(let task of tasks) { + hash[task] = hash[task] + 1 || 1 + } + let max = 0, count = 0; + for(let el in hash) { + if(hash[el] > max) { + max = hash[el]; + count = 1 + } else if(hash[el] === max) { + count++; + } + } + return Math.max((max - 1) * (n + 1) + count, tasks.length) +}; + +// another + +/** + * @param {character[]} tasks + * @param {number} n + * @return {number} + */ +const leastInterval = function(tasks, n) { + let max = 0, maxCnt = 0 + const len = tasks.length, cnt = Array(26).fill(0), A = 'A'.charCodeAt(0) + + for(let ch of tasks) { + const idx = ch.charCodeAt(0) - A + cnt[idx]++ + if(max === cnt[idx]) maxCnt++ + else if(max < cnt[idx]) { + max = cnt[idx] + maxCnt = 1 + } + } + + const maxSlots = max * maxCnt + const avaiSlots = (max - 1) * (n - (maxCnt - 1)) + const rem = len - maxSlots + const emptySlots = Math.max(0, avaiSlots - rem) + + return len + emptySlots +}; diff --git a/622-design-circular-queue.js b/622-design-circular-queue.js new file mode 100644 index 00000000..668cd4ff --- /dev/null +++ b/622-design-circular-queue.js @@ -0,0 +1,79 @@ +/** + * Initialize your data structure here. Set the size of the queue to be k. + * @param {number} k + */ +const MyCircularQueue = function (k) { + this.a = new Array(k).fill(0) + this.front = 0 + this.rear = -1 + this.len = 0 +} + +/** + * Insert an element into the circular queue. Return true if the operation is successful. + * @param {number} value + * @return {boolean} + */ +MyCircularQueue.prototype.enQueue = function (value) { + if (!this.isFull()) { + this.rear = (this.rear + 1) % this.a.length + this.a[this.rear] = value + this.len++ + return true + } else return false +} + +/** + * Delete an element from the circular queue. Return true if the operation is successful. + * @return {boolean} + */ +MyCircularQueue.prototype.deQueue = function () { + if (!this.isEmpty()) { + this.front = (this.front + 1) % this.a.length + this.len-- + return true + } else return false +} + +/** + * Get the front item from the queue. + * @return {number} + */ +MyCircularQueue.prototype.Front = function () { + return this.isEmpty() ? -1 : this.a[this.front] +} + +/** + * Get the last item from the queue. + * @return {number} + */ +MyCircularQueue.prototype.Rear = function () { + return this.isEmpty() ? -1 : this.a[this.rear] +} + +/** + * Checks whether the circular queue is empty or not. + * @return {boolean} + */ +MyCircularQueue.prototype.isEmpty = function () { + return this.len === 0 +} + +/** + * Checks whether the circular queue is full or not. + * @return {boolean} + */ +MyCircularQueue.prototype.isFull = function () { + return this.len == this.a.length +} + +/** + * Your MyCircularQueue object will be instantiated and called as such: + * var obj = new MyCircularQueue(k) + * var param_1 = obj.enQueue(value) + * var param_2 = obj.deQueue() + * var param_3 = obj.Front() + * var param_4 = obj.Rear() + * var param_5 = obj.isEmpty() + * var param_6 = obj.isFull() + */ diff --git a/623-add-one-row-to-tree.js b/623-add-one-row-to-tree.js new file mode 100644 index 00000000..1ce663de --- /dev/null +++ b/623-add-one-row-to-tree.js @@ -0,0 +1,81 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {number} v + * @param {number} d + * @return {TreeNode} + */ +const addOneRow = function (root, v, d, level = 1) { + if (d === 1) { + const node = new TreeNode(v) + node.left = root + return node + } + const queue = [] + queue.push(root) + let depth = 1 + while (queue.length) { + const size = queue.length + for (let i = 0; i < size; i++) { + const cur = queue.shift() + if (depth === d - 1) { + let left = new TreeNode(v) + let right = new TreeNode(v) + left.left = cur.left + right.right = cur.right + cur.left = left + cur.right = right + } else { + if (cur.left !== null) { + queue.push(cur.left) + } + if (cur.right !== null) { + queue.push(cur.right) + } + } + } + depth++ + } + return root +} + +// another + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {number} v + * @param {number} d + * @return {TreeNode} + */ +const addOneRow = function (root, v, d, level = 1) { + if (!root) return + if (d === 1) { + const newRoot = new TreeNode(v) + newRoot.left = root + return newRoot + } else if (d === level + 1) { + const oldLeft = root.left + const oldRight = root.right + root.left = new TreeNode(v) + root.right = new TreeNode(v) + root.left.left = oldLeft + root.right.right = oldRight + } else { + addOneRow(root.left, v, d, level + 1) + addOneRow(root.right, v, d, level + 1) + } + return root +} diff --git a/624-maximum-distance-in-arrays.js b/624-maximum-distance-in-arrays.js new file mode 100644 index 00000000..020fad88 --- /dev/null +++ b/624-maximum-distance-in-arrays.js @@ -0,0 +1,47 @@ +/** + +Given m arrays, and each array is sorted in ascending order. +Now you can pick up two integers from two different arrays (each array picks one) +and calculate the distance. +We define the distance between two integers a and b to be their absolute difference |a-b|. +Your task is to find the maximum distance. + +Example 1: + +Input: +[[1,2,3], + [4,5], + [1,2,3]] + +Output: 4 + +Explanation: +One way to reach the maximum distance 4 is to pick 1 in the first or third array and pick 5 in the second array. + +Note: +Each given array will have at least 1 number. There will be at least two non-empty arrays. +The total number of the integers in all the m arrays will be in the range of [2, 10000]. +The integers in the m arrays will be in the range of [-10000, 10000]. + +*/ + +/** + * @param {number[][]} arrays + * @return {number} + */ +const maxDistance = function(arrays) { + if (arrays == null) return 0 + let result = 0 + let min = arrays[0][0] + let max = arrays[0][arrays[0].length - 1] + for (let i = 1; i < arrays.length; i++) { + result = Math.max( + result, + Math.abs(arrays[i][arrays[i].length - 1] - min), + Math.abs(arrays[i][0] - max) + ) + max = Math.max(max, arrays[i][arrays[i].length - 1]) + min = Math.min(min, arrays[i][0]) + } + return result +} diff --git a/625-minimum-factorization.js b/625-minimum-factorization.js new file mode 100644 index 00000000..95df687e --- /dev/null +++ b/625-minimum-factorization.js @@ -0,0 +1,18 @@ +/** + * @param {number} a + * @return {number} + */ +const smallestFactorization = function (a) { + if (a < 2) return a + let MAX_INT = 2 ** 31 - 1, + res = 0, + mul = 1 + for (let i = 9; i >= 2; i--) { + while (a % i === 0) { + a /= i + res = mul * i + res + mul *= 10 + } + } + return a < 2 && res <= MAX_INT ? res : 0 +} diff --git a/627-swap-salary.sql b/627-swap-salary.sql new file mode 100644 index 00000000..317dd008 --- /dev/null +++ b/627-swap-salary.sql @@ -0,0 +1,2 @@ +# Write your MySQL query statement below +UPDATE salary SET sex = IF(sex='m','f','m'); diff --git a/628-maximum-product-of-three-numbers.js b/628-maximum-product-of-three-numbers.js new file mode 100644 index 00000000..d801ee9f --- /dev/null +++ b/628-maximum-product-of-three-numbers.js @@ -0,0 +1,45 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maximumProduct = function (nums) { + nums.sort((a, b) => a - b) + return Math.max( + nums[0] * nums[1] * nums[nums.length - 1], + nums[nums.length - 1] * nums[nums.length - 2] * nums[nums.length - 3] + ) +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const maximumProduct = function (nums) { + let max1 = -Infinity + let max2 = -Infinity + let max3 = -Infinity + let min1 = Infinity + let min2 = Infinity + for (let num of nums) { + if (num > max1) { + max3 = max2 + max2 = max1 + max1 = num + } else if (num > max2) { + max3 = max2 + max2 = num + } else if (num > max3) { + max3 = num + } + + if (num < min1) { + min2 = min1 + min1 = num + } else if (num < min2) { + min2 = num + } + } + return Math.max(max1 * max2 * max3, max1 * min1 * min2) +} diff --git a/629-k-inverse-pairs-array.js b/629-k-inverse-pairs-array.js index 4ea54181..e653e9b5 100644 --- a/629-k-inverse-pairs-array.js +++ b/629-k-inverse-pairs-array.js @@ -1,3 +1,27 @@ +/** + * @param {number} n + * @param {number} k + * @return {number} + */ +const kInversePairs = function(n, k) { + const mod = 1e9 + 7 + const dp = Array.from({ length: n + 1 }, () => Array(k + 1).fill(0)) + for(let i = 0; i <= n; i++) dp[i][0] = 1 + for(let i = 2; i <= n; i++) { + for(let j = 1; j <= k; j++) { + if(j >= i) dp[i][j] = (dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - i]) % mod + else dp[i][j] = (dp[i - 1][j] + dp[i][j - 1]) % mod + + if(dp[i][j] < 0) dp[i][j] += mod + } + } + + return dp[n][k] +}; + +// another + + /** * @param {number} n * @param {number} k diff --git a/630-course-schedule-iii.js b/630-course-schedule-iii.js new file mode 100644 index 00000000..b2f0f289 --- /dev/null +++ b/630-course-schedule-iii.js @@ -0,0 +1,252 @@ +/** + * @param {number[][]} courses + * @return {number} + */ +const scheduleCourse = function (courses) { + const compare = (a, b) => a[0] === b[0] ? 0 : (a[0] > b[0] ? -1 : 1) + const queue = new PriorityQueue({ compare }) + courses.sort((a, b) => a[1] - b[1]) + let time = 0 + for(let e of courses) { + time += e[0] + queue.enqueue(e) + if(time > e[1]) { + const tmp = queue.dequeue() + time -= tmp[0] + } + } + return queue.size() +} + +// another + +/** + * @param {number[][]} courses + * @return {number} + */ +const scheduleCourse = function(courses) { + const pq = new PQ((a, b) => a[0] === b[0] ? a[1] < b[1] : a[0] > b[0]) + const n = courses.length + courses.sort((a, b) => a[1] === b[1] ? a[0] - b[0] : a[1] - b[1]) + + let time = 0 + for(const e of courses) { + const [dur, end] = e + time += dur + pq.push(e) + if(time > end) { + const tmp = pq.pop() + time -= tmp[0] + } + } + + return pq.size() +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + + +/** + * @param {number[][]} courses + * @return {number} + */ +const scheduleCourse = function (courses) { + const queue = new MaxPriorityQueue({ + priority: e => e[0] + }) + courses.sort((a, b) => a[1] - b[1]) + let time = 0 + for(let e of courses) { + time += e[0] + queue.enqueue(e) + if(time > e[1]) { + const tmp = queue.dequeue().element + time -= tmp[0] + } + } + return queue.size() +} + +// another + +/** + * @param {number[][]} courses + * @return {number} + */ +const scheduleCourse = function (courses) { + courses.sort((c1, c2) => c1[1] - c2[1]) + let count = 0 + let time = 0 + const queue = [] + const inQueue = (val) => { + let i = 0 + while (i < queue.length && queue[i] > val) i += 1 + queue.splice(i, 0, val) + } + for (let i = 0; i < courses.length; i += 1) { + const [dur, end] = courses[i] + if (time <= end - dur) { + count += 1 + time += dur + inQueue(dur) + } else if (queue.length && queue[0] > dur) { + time = time - queue.shift() + dur + inQueue(dur) + } + } + return count +} + +// another + +/** + * @param {number[][]} courses + * @return {number} + */ +const scheduleCourse = function (courses) { + courses.sort((a, b) => +a[1] - +b[1]) + let queue = new Heap() + let time = 0 + for (let c of courses) { + if (c[0] + time <= c[1]) { + time += c[0] + queue.push(c[0]) + } else if (queue.size() > 0) { + let top = queue.peek() + if (top > c[0]) { + queue.pop() + queue.push(c[0]) + time += c[0] - top + } + } + } + return queue.size() +} + +const parent = (i) => Math.floor((i - 1) / 2) +const left = (i) => 2 * i + 1 +const right = (i) => 2 * i + 2 +class Heap { + constructor() { + this.compare = (a, b) => +b - +a + this._heap = [] + } + size() { + return this._heap.length + } + _upper(i, j) { + return this.compare(this._heap[i], this._heap[j]) < 0 + } + _swap(i, j) { + let tmp = this._heap[i] + this._heap[i] = this._heap[j] + this._heap[j] = tmp + } + push(item) { + this._heap.push(item) + this._siftUp() + return this.size() + } + _siftUp() { + let node = this._heap.length - 1 + while (node > 0 && this._upper(node, parent(node))) { + this._swap(node, parent(node)) + node = parent(node) + } + } + peek() { + return this._heap[0] + } + pop() { + let ret = this._heap[0] + if (this.size() > 1) { + this._swap(0, this._heap.length - 1) + } + this._heap.pop() + this._siftDown() + return ret + } + _siftDown() { + let node = 0 + while ( + (right(node) < this.size() && this._upper(right(node), node)) || + (left(node) < this.size() && this._upper(left(node), node)) + ) { + let upperChild = + right(node) < this.size() && this._upper(right(node), left(node)) + ? right(node) + : left(node) + this._swap(upperChild, node) + node = upperChild + } + } +} + diff --git a/631-design-excel-sum-formula.js b/631-design-excel-sum-formula.js new file mode 100644 index 00000000..ad7db1f9 --- /dev/null +++ b/631-design-excel-sum-formula.js @@ -0,0 +1,169 @@ +/** + * @param {number} H + * @param {character} W + */ +const Excel = function (H, W) { + this.W = W.charCodeAt(0) - 'A'.charCodeAt(0) + 1 + this.H = H + this.map = {} + this.mat = [] + for (let i = 0; i < this.H; i++) { + this.mat[i] = new Array(this.W).fill(0) + } + return +} + +/** + * @param {number} r + * @param {character} c + * @param {number} v + * @return {void} + */ +Excel.prototype.set = function (r, c, v) { + let row = r - 1 + let col = c.charCodeAt(0) - 'A'.charCodeAt(0) + if (this.map[r + ':' + c]) delete this.map[r + ':' + c] + this.mat[row][col] = v +} +/** + * @param {number} r + * @param {character} c + * @return {number} + */ +Excel.prototype.get = function (r, c) { + let row = r - 1 + let col = c.charCodeAt(0) - 'A'.charCodeAt(0) + if (this.map[r + ':' + c] !== undefined) + return this.sum(r, c, this.map[r + ':' + c]) + return this.mat[row][col] +} + +/** + * @param {number} r + * @param {character} c + * @param {string[]} strs + * @return {number} + */ +Excel.prototype.sum = function (r, c, strs) { + let sum = 0 + for (let str of strs) { + if (str.indexOf(':') < 0) { + sum += this.get(+str.substring(1), str[0]) + } else { + let [r1, c1, r2, c2] = this.getRange(str.split(':')) + for (let i = r1; i <= r2; i++) { + for (let j = c1; j <= c2; j++) { + sum += this.get(i + 1, String.fromCharCode(j + 'A'.charCodeAt(0))) + } + } + } + } + this.map[r + ':' + c] = strs + return sum +} + +Excel.prototype.getRange = function (arr) { + let p1 = arr[0], + p2 = arr[1] + let c1 = p1[0].charCodeAt(0) - 'A'.charCodeAt(0) + let r1 = +p1.substring(1) - 1 + let c2 = p2[0].charCodeAt(0) - 'A'.charCodeAt(0) + let r2 = +p2.substring(1) - 1 + return [r1, c1, r2, c2] +} + +/** + * Your Excel object will be instantiated and called as such: + * var obj = Object.create(Excel).createNew(H, W) + * obj.set(r,c,v) + * var param_2 = obj.get(r,c) + * var param_3 = obj.sum(r,c,strs) + */ + + +// another + +/** + * @param {number} H + * @param {character} W + */ +const Excel = function (H, W) { + this.data = [] + for (let i = 1; i <= H; i++) { + this.data[i] = [] + for (let j = 1; j <= this.col(W); j++) { + this.data[i][j] = 0 + } + } +} + +Excel.prototype.col = function (c) { + return c.charCodeAt() - 'A'.charCodeAt() + 1 +} + +Excel.prototype.parse = function (str) { + let idx = str.indexOf(':') + if (idx === -1) return { r: Number(str.slice(1)), c: str[0] } + let topLeft = str.slice(0, idx), + bottomRight = str.slice(idx + 1) + return [ + { r: Number(topLeft.slice(1)), c: topLeft[0] }, + { r: Number(bottomRight.slice(1)), c: bottomRight[0] }, + ] +} + +/** + * @param {number} r + * @param {character} c + * @param {number} v + * @return {void} + */ +Excel.prototype.set = function (r, c, v) { + this.data[r][this.col(c)] = v +} + +/** + * @param {number} r + * @param {character} c + * @return {number} + */ +Excel.prototype.get = function (r, c) { + if (Array.isArray(this.data[r][this.col(c)])) { + let sum = 0 + for (let str of this.data[r][this.col(c)]) { + let parsed = this.parse(str) + if (Array.isArray(parsed)) { + for (let i = parsed[0].r; i <= parsed[1].r; i++) { + for ( + let jc = parsed[0].c; + jc <= parsed[1].c; + jc = String.fromCharCode(jc.charCodeAt() + 1) + ) { + sum += this.get(i, jc) + } + } + } else sum += this.get(parsed.r, parsed.c) + } + return sum + } + return this.data[r][this.col(c)] +} + +/** + * @param {number} r + * @param {character} c + * @param {string[]} strs + * @return {number} + */ +Excel.prototype.sum = function (r, c, strs) { + this.set(r, c, strs) + return this.get(r, c) +} + +/** + * Your Excel object will be instantiated and called as such: + * var obj = new Excel(H, W) + * obj.set(r,c,v) + * var param_2 = obj.get(r,c) + * var param_3 = obj.sum(r,c,strs) + */ diff --git a/632-smallest-range.js b/632-smallest-range.js index 1083fdd0..0dcca794 100644 --- a/632-smallest-range.js +++ b/632-smallest-range.js @@ -184,3 +184,99 @@ var smallestRange = function(nums) { return ans } + + +// another + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} +/** + * @param {number[][]} nums + * @return {number[]} + */ +const smallestRange = function (nums) { + const pq = new PQ((a, b) => a[0] < b[0]) + const limit = 10 ** 5, + n = nums.length, + { max } = Math + let right = -1e5, + res = [-limit, limit] + for (let i = 0; i < n; i++) { + pq.push([nums[i][0], i, 0]) + right = max(right, nums[i][0]) + } + while (pq.size()) { + const cur = pq.pop() + const [left, list, indice] = cur + if (right - left < res[1] - res[0]) res = [left, right] + if (indice + 1 === nums[list].length) return res + right = max(right, nums[list][indice + 1]) + pq.push([nums[list][indice + 1], list, indice + 1]) + } + return [] +} diff --git a/634-find-the-derangement-of-an-array.js b/634-find-the-derangement-of-an-array.js new file mode 100644 index 00000000..ae7c4945 --- /dev/null +++ b/634-find-the-derangement-of-an-array.js @@ -0,0 +1,33 @@ +/** + * @param {number} n + * @return {number} + */ +const findDerangement = function (n) { + if ([0, 1].includes(n)) return 0 + if (n === 2) return 1 + let prev = 1 + const MOD = 10 ** 9 + 7 + let result = 0 + for (let i = 3; i <= n; i++) { + result = (prev * i + (i % 2 === 1 ? -1 : 1)) % MOD + prev = result + } + return result +} + +// another + +/** + * @param {number} n + * @return {number} + */ +const findDerangement = function (n) { + if (n === 0) return 0 + const MOD = 10 ** 9 + 7 + const dp = [1, 0] + for (let i = 2; i <= n; i++) { + dp[i] = ((i - 1) * (dp[i - 2] + dp[i - 1])) % MOD + } + return dp[n] +} + diff --git a/635-design-log-storage-system.js b/635-design-log-storage-system.js new file mode 100644 index 00000000..32fb33aa --- /dev/null +++ b/635-design-log-storage-system.js @@ -0,0 +1,79 @@ +/** + +You are given several logs that 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. + +Design a log storage system to implement the following functions: + +void Put(int id, string timestamp): Given a log's unique id and timestamp, +store the log in your storage system. + +int[] Retrieve(String start, String end, String granularity): Return the id of logs whose +timestamps are within the range from start to end. Start and end all have the same format as timestamp. +However, granularity means the time level for consideration. For example, start = "2017:01:01:23:59:59", +end = "2017:01:02:23:59:59", granularity = "Day", it means that we need to find the logs within the range +from Jan. 1st 2017 to Jan. 2nd 2017. + +Example 1: +put(1, "2017:01:01:23:59:59"); +put(2, "2017:01:01:22:59:59"); +put(3, "2016:01:01:00:00:00"); +retrieve("2016:01:01:01:01:01","2017:01:01:23:00:00","Year"); // return [1,2,3], because you need to return all logs within 2016 and 2017. +retrieve("2016:01:01:01:01:01","2017:01:01:23:00:00","Hour"); // return [1,2], because you need to return all logs start from 2016:01:01:01 to 2017:01:01:23, where log 3 is left outside the range. + +Note: +There will be at most 300 operations of Put or Retrieve. +Year ranges from [2000,2017]. Hour ranges from [00,23]. +Output for Retrieve has no order required. + +*/ + +const Log = function(id, timeArgs) { + this.id = id; + this.timeArgs = timeArgs; +}; +const LogSystem = function() { + this.logs = []; +}; + +/** + * @param {number} id + * @param {string} timestamp + * @return {void} + */ +LogSystem.prototype.put = function(id, timestamp) { + const args = timestamp.split(":"); + this.logs.push(new Log(id, args)); +}; + +/** + * @param {string} s + * @param {string} e + * @param {string} gra + * @return {number[]} + */ +LogSystem.prototype.retrieve = function(s, e, gra) { + const gransarr = ["Year", "Month", "Day", "Hour", "Minute", "Second"]; + const idx = gransarr.indexOf(gra); + const sargs = s.split(":").slice(0, idx + 1); + const eargs = e.split(":").slice(0, idx + 1); + const sdate = new Date(...sargs).getTime(); + const edate = new Date(...eargs).getTime(); + const set = []; + this.logs.forEach(function(item) { + const itemArgs = item.timeArgs.slice(0, idx + 1); + const itemTime = new Date(...itemArgs).getTime(); + if (itemTime >= sdate && itemTime <= edate) { + set.push(item.id); + } + }); + return set; +}; + +/** + * Your LogSystem object will be instantiated and called as such: + * var obj = new LogSystem() + * obj.put(id,timestamp) + * var param_2 = obj.retrieve(s,e,gra) + */ diff --git a/636-exclusive-time-of-functions.js b/636-exclusive-time-of-functions.js new file mode 100644 index 00000000..81663d95 --- /dev/null +++ b/636-exclusive-time-of-functions.js @@ -0,0 +1,22 @@ +/** + * @param {number} n + * @param {string[]} logs + * @return {number[]} + */ +const exclusiveTime = function (n, logs) { + const res = [...Array(n)].fill(0) + const stack = [] + let pre = 0 + for (let i = 0; i < logs.length; i++) { + const log = logs[i].split(':') + if (log[1] === 'start') { + if(stack.length !== 0) res[stack[stack.length - 1]] += +log[2] - pre + stack.push(log[0]) + pre = log[2] + } else { + res[stack.pop()] += +log[2] - pre + 1 + pre = +log[2] + 1 + } + } + return res +} diff --git a/638-shopping-offers.js b/638-shopping-offers.js new file mode 100644 index 00000000..49747e60 --- /dev/null +++ b/638-shopping-offers.js @@ -0,0 +1,89 @@ +/** + * @param {number[]} price + * @param {number[][]} special + * @param {number[]} needs + * @return {number} + */ +const shoppingOffers = function (price, special, needs) { + return helper(price, special, needs, 0) +} + +function helper(price, special, needs, pos) { + let local_min = directPurchase(price, needs) + for (let i = pos; i < special.length; i++) { + let offer = special[i] + let temp = [] + for (let j = 0; j < needs.length; j++) { + if (needs[j] < offer[j]) { + // check if the current offer is valid + temp = null + break + } + temp.push(needs[j] - offer[j]) + } + + if (temp !== null) { + // use the current offer and try next + local_min = Math.min( + local_min, + offer[offer.length - 1] + helper(price, special, temp, i), + ) + } + } + + return local_min +} + +function directPurchase(price, needs) { + let total = 0 + for (let i = 0; i < needs.length; i++) { + total += price[i] * needs[i] + } + + return total +} + + +// another + +/** + * @param {number[]} price + * @param {number[][]} special + * @param {number[]} needs + * @return {number} + */ +const shoppingOffers = function (price, special, needs) { + const directBuy = function (price, needs) { + let res = 0 + for (let i = 0; i < price.length; i++) { + res += price[i] * needs[i] + } + return res + } + const isValid = function (offer, needs) { + for (let i = 0; i < offer.length; i++) { + if (offer[i] > needs[i]) return false + } + return true + } + const help = (price, special, needs) => { + let curMin = directBuy(price, needs) + for (let i = 0; i < special.length; i++) { + let curOf = special[i] + if (isValid(curOf, needs)) { + let tem = [] + for (let j = 0; j < needs.length; j++) { + tem.push(needs[j] - curOf[j]) + } + if (tem.length > 0) { + curMin = Math.min( + curMin, + curOf[curOf.length - 1] + help(price, special, tem) + ) + } + } + } + return curMin + } + return help(price, special, needs) +} diff --git a/641-design-circular-deque.js b/641-design-circular-deque.js new file mode 100644 index 00000000..2689aa20 --- /dev/null +++ b/641-design-circular-deque.js @@ -0,0 +1,103 @@ +/** + * Initialize your data structure here. Set the size of the deque to be k. + * @param {number} k + */ +const MyCircularDeque = function(k) { + this.q = [] + this.k = k +}; + +/** + * Adds an item at the front of Deque. Return true if the operation is successful. + * @param {number} value + * @return {boolean} + */ +MyCircularDeque.prototype.insertFront = function(value) { + if(this.q.length < this.k) { + this.q.unshift(value) + return true + } + return false +}; + +/** + * Adds an item at the rear of Deque. Return true if the operation is successful. + * @param {number} value + * @return {boolean} + */ +MyCircularDeque.prototype.insertLast = function(value) { + if(this.q.length < this.k) { + this.q.push(value) + return true + } + return false +}; + +/** + * Deletes an item from the front of Deque. Return true if the operation is successful. + * @return {boolean} + */ +MyCircularDeque.prototype.deleteFront = function() { + if(this.q.length) { + this.q.shift() + return true + } + return false +}; + +/** + * Deletes an item from the rear of Deque. Return true if the operation is successful. + * @return {boolean} + */ +MyCircularDeque.prototype.deleteLast = function() { + if(this.q.length) { + this.q.pop() + return true + } + return false +}; + +/** + * Get the front item from the deque. + * @return {number} + */ +MyCircularDeque.prototype.getFront = function() { + return this.q[0] === undefined ? -1 : this.q[0] +}; + +/** + * Get the last item from the deque. + * @return {number} + */ +MyCircularDeque.prototype.getRear = function() { + return this.q[this.q.length - 1] === undefined ? -1 : this.q[this.q.length - 1] +}; + +/** + * Checks whether the circular deque is empty or not. + * @return {boolean} + */ +MyCircularDeque.prototype.isEmpty = function() { + return this.q.length === 0 +}; + +/** + * Checks whether the circular deque is full or not. + * @return {boolean} + */ +MyCircularDeque.prototype.isFull = function() { + return this.q.length === this.k +}; + +/** + * Your MyCircularDeque object will be instantiated and called as such: + * var obj = new MyCircularDeque(k) + * var param_1 = obj.insertFront(value) + * var param_2 = obj.insertLast(value) + * var param_3 = obj.deleteFront() + * var param_4 = obj.deleteLast() + * var param_5 = obj.getFront() + * var param_6 = obj.getRear() + * var param_7 = obj.isEmpty() + * var param_8 = obj.isFull() + */ diff --git a/642-design-search-autocomplete-system.js b/642-design-search-autocomplete-system.js new file mode 100644 index 00000000..1f4a5657 --- /dev/null +++ b/642-design-search-autocomplete-system.js @@ -0,0 +1,258 @@ +/** + * @param {string[]} sentences + * @param {number[]} times + */ +const AutocompleteSystem = function (sentences, times) { + this.trie = new Trie() + this.inputString = '' + this.MAX_RESULTS = 3 + for (let i = 0, len = times.length; i < len; i++) { + this.trie.insert(sentences[i], times[i]) + } +} + +/** + * @param {character} c + * @return {string[]} + */ +AutocompleteSystem.prototype.input = function (c) { + if (c === '#') { + this.trie.insert(this.inputString) + this.inputString = '' + return [] + } + this.inputString += c + const strings = this.trie.stringsStartingWith(this.inputString) + const results = Object.keys(strings) + results.sort((a, b) => { + const aFreq = strings[a] + const bFreq = strings[b] + return aFreq !== bFreq ? bFreq - aFreq : a > b ? 1 : -1 + }) + return results.slice(0, this.MAX_RESULTS) +} + +/** + * Your AutocompleteSystem object will be instantiated and called as such: + * var obj = new AutocompleteSystem(sentences, times) + * var param_1 = obj.input(c) + */ + +// Using a Trie (Prefix tree). +/** + * Initialize your data structure here. + */ +const Trie = function () { + this._trie = {} +} + +/** + * Inserts a string into the trie a number of times. + * @param {string} word + * @param {number} [count=1] + * @return {void} + */ +Trie.prototype.insert = function (word, count = 1) { + if (!word.length || count < 1) { + return + } + let curr = this._trie + for (let i = 0; i < word.length; i++) { + const char = word[i] + if (!curr.hasOwnProperty(char)) { + curr[char] = {} + } + curr = curr[char] + } + if (!curr.hasOwnProperty('#')) { + curr['#'] = 0 + } + curr['#'] += count +} + +/** + * Returns if there is any string in the trie that starts with the given prefix. + * @param {string} prefix + * @return {Object} + */ +// Time: O(n), where n is the number of different strings in the Trie. +// Space: O(1) +Trie.prototype.stringsStartingWith = function (prefix) { + if (!prefix.length) { + return false + } + let curr = this._trie + for (let i = 0; i < prefix.length; i++) { + const char = prefix[i] + if (!curr.hasOwnProperty(char)) { + return false + } + curr = curr[char] + } + const results = {} + function traverse(node, chars) { + if (!node) { + return + } + Object.keys(node).forEach((char) => { + if (char === '#') { + results[chars] = node[char] + return + } + traverse(node[char], chars + char) + }) + } + traverse(curr, prefix) + return results +} + +// another + +class TrieNode { + constructor() { + this.children = new Map() + this.counts = new Map() + this.isWord = false + } +} + +class Pair { + constructor(s, c) { + this.str = s + this.cnt = c + } +} + +/** + * @param {string[]} sentences + * @param {number[]} times + */ +const AutocompleteSystem = function (sentences, times) { + this.root = new TrieNode() + this.prefix = '' + for (let i = 0, n = sentences.length; i < n; i++) { + this.add(sentences[i], times[i]) + } +} + +AutocompleteSystem.prototype.add = function (str, cnt) { + let cur = this.root + for (const ch of str) { + let next = cur.children.get(ch) + if (next == null) { + next = new TrieNode() + cur.children.set(ch, next) + } + cur = next + cur.counts.set(str, (cur.counts.get(str) || 0) + cnt) + } + cur.isWord = true +} + +/** + * @param {character} c + * @return {string[]} + */ +AutocompleteSystem.prototype.input = function (c) { + if (c === '#') { + this.add(this.prefix, 1) + this.prefix = '' + return [] + } + this.prefix += c + let cur = this.root + for (const ch of this.prefix) { + const next = cur.children.get(ch) + if (next == null) { + return [] + } + cur = next + } + const pq = new PriorityQueue((a, b) => + a.cnt === b.cnt ? a.str.localeCompare(b.str) < 0 : a.cnt > b.cnt + ) + + for(const s of cur.counts.keys()) { + pq.push(new Pair(s, cur.counts.get(s))) + } + const res = [] + for(let i = 0; i < 3 && pq.size(); i++) { + res.push(pq.pop().str) + } + + return res +} + +/** + * Your AutocompleteSystem object will be instantiated and called as such: + * var obj = new AutocompleteSystem(sentences, times) + * var param_1 = obj.input(c) + */ + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/644-maximum-average-subarray-ii.js b/644-maximum-average-subarray-ii.js new file mode 100644 index 00000000..f9c70e0b --- /dev/null +++ b/644-maximum-average-subarray-ii.js @@ -0,0 +1,62 @@ +/** + +Given an array consisting of n integers, +find the contiguous subarray whose length is greater than or +equal to k that has the maximum average value. +And you need to output the maximum average value. + +Example 1: +Input: [1,12,-5,-6,50,3], k = 4 +Output: 12.75 +Explanation: +when length is 5, maximum average value is 10.8, +when length is 6, maximum average value is 9.16667. +Thus return 12.75. +Note: +1 <= k <= n <= 10,000. +Elements of the given array will be in range [-10,000, 10,000]. +The answer with the calculation error less than 10-5 will be accepted. + +*/ + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const findMaxAverage = function(nums, k) { + let left = nums[0] + let right = nums[0] + nums.forEach(num => { + left = Math.min(left, num) + right = Math.max(right, num) + }) + const check = average => { + let rightSum = 0 + let leftSum = 0 + let minLeftSum = 0 + for (let i = 0; i < k; i++) { + rightSum += nums[i] - average + } + for (let i = k; i <= nums.length; i++) { + if (rightSum - minLeftSum >= 0) { + return true + } + if (i < nums.length) { + rightSum += nums[i] - average + leftSum += nums[i - k] - average + minLeftSum = Math.min(leftSum, minLeftSum) + } + } + return false + } + while (left + 1e-5 < right) { + let mid = (left + right) / 2 + if (check(mid)) { + left = mid + } else { + right = mid + } + } + return left +} diff --git a/645-set-mismatch.js b/645-set-mismatch.js new file mode 100644 index 00000000..c3f0a6a7 --- /dev/null +++ b/645-set-mismatch.js @@ -0,0 +1,62 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var findErrorNums = function(nums) { + const res = [] + for(let i=0; i 0) nums[idx] = -nums[idx]; + else res[0] = idx+1; + } + for(let i=0; i 0) res[1] = i + 1; + } + return res; +}; + diff --git a/646-maximum-length-of-pair-chain.js b/646-maximum-length-of-pair-chain.js index 39a7e71e..3a0661cd 100755 --- a/646-maximum-length-of-pair-chain.js +++ b/646-maximum-length-of-pair-chain.js @@ -1,3 +1,64 @@ +/** + * @param {number[][]} pairs + * @return {number} + */ +var findLongestChain = function(pairs) { + pairs.sort((a, b) => a[1] - b[1]); + if(pairs.length === 0) return 0 + let res = 1 + let end = pairs[0][1] + for(let i = 1; i < pairs.length; i++) { + if(pairs[i][0] > end) { + res++ + end = pairs[i][1] + } + } + return res +}; + +// another + +/** + * @param {number[][]} pairs + * @return {number} + */ +const findLongestChain = function(pairs) { + let res = 0 + const n = pairs.length + if(n === 0) return res + pairs.sort((a, b) => a[1] - b[1]) + let end = pairs[0][1] + res++ + for(let i = 1; i < n; i++) { + const e = pairs[i] + if(e[0] <= end) continue + res++ + end = e[1] + } + + return res +}; + +// another + +/** + * @param {number[][]} pairs + * @return {number} + */ +const findLongestChain = function(pairs) { + pairs.sort((a, b) => a[1] - b[1]) + let end = pairs[0][1], res = 1 + for(let i = 1, len = pairs.length; i < len; i++) { + if(pairs[i][0] > end) { + res++ + end = pairs[i][1] + } + } + return res +}; + +// another + /** * @param {number[][]} pairs * @return {number} @@ -14,3 +75,25 @@ const findLongestChain = function(pairs) { } return res; }; + +// another + +/** + * @param {number[][]} pairs + * @return {number} + */ +const findLongestChain = function (pairs) { + pairs.sort((a, b) => a[0] - b[0]) + let out = 0 + let prevEnd = Number.MIN_SAFE_INTEGER + for (let i = 0; i < pairs.length; i++) { + const cur = pairs[i] + if (prevEnd < cur[0]) { + prevEnd = cur[1] + out += 1 + } else { + prevEnd = Math.min(cur[1], prevEnd) + } + } + return out +} diff --git a/647-palindromic-substrings.js b/647-palindromic-substrings.js index 177cd7b5..ebf640e7 100755 --- a/647-palindromic-substrings.js +++ b/647-palindromic-substrings.js @@ -30,3 +30,35 @@ const countSubstrings = function(s) { console.log(countSubstrings("abc")); console.log(countSubstrings("aaa")); + +// another + +/** + * @param {string} s + * @return {number} + */ +const countSubstrings = function(s) { + const arr = manachers(s) + return arr.map(e => ~~((e + 1) / 2)).reduce((ac, e) => ac + e, 0) +}; + +function manachers(s) { + const str = `@#${s.split('').join('#')}#$` + const arr = Array(str.length).fill(0) + + let center = right = 0 + for(let i = 1, n = str.length; i < n - 1; i++) { + if(i < right) { + arr[i] = Math.min(right - i, arr[2 * center - i]) + } + while(str[i + arr[i] + 1] === str[i - arr[i] - 1]) { + arr[i] += 1 + } + if(i + arr[i] > right) { + center = i + right = i + arr[i] + } + } + + return arr +} diff --git a/649-dota2-senate.js b/649-dota2-senate.js new file mode 100644 index 00000000..eb15ae80 --- /dev/null +++ b/649-dota2-senate.js @@ -0,0 +1,27 @@ +/** + * @param {string} senate + * @return {string} + */ +const predictPartyVictory = function (senate) { + const m = senate.length, + radiant = [], + dire = [] + for (let i = 0; i < m; i++) { + if (senate[i] === 'R') { + radiant.push(i) + } else { + dire.push(i) + } + } + + while (radiant.length && dire.length) { + let r = radiant.shift(), + d = dire.shift() + if (r < d) { + radiant.push(r + m) + } else { + dire.push(d + m) + } + } + return radiant.length > dire.length ? 'Radiant' : 'Dire' +} diff --git a/651-4-keys-keyboard.js b/651-4-keys-keyboard.js new file mode 100644 index 00000000..b20bcd6f --- /dev/null +++ b/651-4-keys-keyboard.js @@ -0,0 +1,54 @@ +/** + * @param {number} N + * @return {number} + */ +const maxA = function (N) { + const dp = [0, 1, 2, 3, 4, 5, 6] + const recurse = function (n) { + if (dp[n]) return dp[n] + const max = Math.max( + recurse(n - 3) * 2, + recurse(n - 4) * 3, + recurse(n - 5) * 4 + ) + return (dp[n] = max) + } + return recurse(N) +} + +// another + +/** + * @param {number} N + * @return {number} + */ +const maxA = function (N) { + const dp = [...new Array(N + 1)].map((_, i) => i) + for (let i = 4; i <= N; i++) { + for (let j = 1; j <= i - 3; j++) { + dp[i] = Math.max(dp[i], dp[j] * (i - j - 1)) + } + } + return dp[N] +} + +// another + +/** + * @param {number} N + * @return {number} + */ +const maxA = function (N) { + const dp = new Array(7).fill(0) + for (let i = 1; i <= N; i++) { + dp[0] = i + for (let k = 6; k > 2; k--) { + dp[0] = Math.max(dp[0], dp[k] * (k - 1)) + } + for (let k = 6; k > 0; k--) { + dp[k] = dp[k - 1] + } + } + return dp[0] +} + diff --git a/652-find-duplicate-subtrees.js b/652-find-duplicate-subtrees.js new file mode 100644 index 00000000..8a1a84da --- /dev/null +++ b/652-find-duplicate-subtrees.js @@ -0,0 +1,58 @@ +/** + * 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 {TreeNode[]} + */ +const findDuplicateSubtrees = function(root) { + const hash = {}, res = [] + pre(root, hash, res) + return res +}; + +function pre(node, hash, res) { + if(node == null) return '#' + const str = `${node.val},${pre(node.left, hash, res)},${pre(node.right, hash, res)}` + if(hash[str] == null) hash[str] = 0 + hash[str]++ + if(hash[str] === 2) res.push(node) + return str +} + +// another + +/** + * 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 {TreeNode[]} + */ +const findDuplicateSubtrees = function(root) { + const serId = {}, cntId = {}, res = [] + let id = 1 + post(root) + return res + + function post(node) { + if(node == null) return 0 + const curId = `${post(node.left)},${node.val},${post(node.right)}` + serId[curId] = serId[curId] || id + if(serId[curId] === id) id++ + cntId[curId] = (cntId[curId] || 0) + 1 + if(cntId[curId] === 2) res.push(node) + return serId[curId] + } +}; + diff --git a/653-two-sum-iv-input-is-a-bst.js b/653-two-sum-iv-input-is-a-bst.js new file mode 100644 index 00000000..ba7dc1e9 --- /dev/null +++ b/653-two-sum-iv-input-is-a-bst.js @@ -0,0 +1,23 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {number} k + * @return {boolean} + */ +const findTarget = function(root, k) { + const m = new Map() + return traverse(root, k, m) +}; + +function traverse(node, k, m) { + if(node == null) return false + if(m.has(k - node.val)) return true + m.set(node.val, node) + return traverse(node.left,k,m) || traverse(node.right,k,m) +} diff --git a/655-print-binary-tree.js b/655-print-binary-tree.js new file mode 100644 index 00000000..a3ef06f5 --- /dev/null +++ b/655-print-binary-tree.js @@ -0,0 +1,29 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {string[][]} + */ +const printTree = function (root) { + const h = getH(root) + const w = Math.pow(2, h) - 1 + const matrix = new Array(h).fill(0).map((_) => new Array(w).fill('')) + fill(root, 0, 0, w - 1) + return matrix + function getH(root) { + if (!root) return 0 + return Math.max(getH(root.left), getH(root.right)) + 1 + } + function fill(root, level, start, end) { + if (!root) return + let mid = (start + end) / 2 + matrix[level][mid] = root.val + '' + fill(root.left, level + 1, start, mid - 1) + fill(root.right, level + 1, mid + 1, end) + } +} diff --git a/656-coin-path.js b/656-coin-path.js new file mode 100644 index 00000000..93debc6b --- /dev/null +++ b/656-coin-path.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} A + * @param {number} B + * @return {number[]} + */ +const cheapestJump = function (A, B) { + if (A[A.length - 1] < 0) return [] + let dp = [] + let nextTo = [] + dp[A.length - 1] = A[A.length - 1] + nextTo[A.length - 1] = -1 + for (let i = A.length - 2; i >= 0; i--) { + dp[i] = -1 + if (A[i] === -1) continue + let cost = Infinity + for (let j = i + 1; j <= Math.min(i + B, A.length - 1); j++) { + if (dp[j] !== -1 && dp[j] < cost) { + cost = dp[j] + nextTo[i] = j + } + } + if (cost < Infinity) dp[i] = cost + A[i] + } + let ans = [] + if (dp[0] >= 0) { + let p = 0 + while (p >= 0) { + ans.push(p + 1) + p = nextTo[p] + } + } + return ans +} diff --git a/659-split-array-into-consecutive-subsequences.js b/659-split-array-into-consecutive-subsequences.js index 2dd9f95d..af5bb0fc 100644 --- a/659-split-array-into-consecutive-subsequences.js +++ b/659-split-array-into-consecutive-subsequences.js @@ -26,3 +26,32 @@ const isPossible = function(nums) { function getOrDefault(map, key) { return map.get(key) || 0 } + + +// another + +/** + * @param {number[]} nums + * @return {boolean} + */ +const isPossible = function(nums) { + let prev = -Infinity, p1 = 0, p2 = 0, p3 = 0 + let i = 0 + const n = nums.length + while (i < n) { + let curr = nums[i], c1 = 0, c2 = 0, c3 = 0 + let cnt = 0 + while (i < n && nums[i] === curr) { cnt++; i++ } + if (curr !== prev+1) { + if (p1 > 0 || p2 > 0) { return false } + c1 = cnt; c2 = 0; c3 = 0 + } else { + if (cnt < p1 + p2) { return false } + c2 = p1 + c3 = p2 + Math.min(p3, cnt - p1 - p2) + c1 = Math.max(0, cnt - p1 - p2 - p3) + } + prev = curr; p1 = c1; p2 = c2; p3 = c3; + } + return p1 === 0 && p2 === 0 +}; diff --git a/66-plus-one.js b/66-plus-one.js new file mode 100644 index 00000000..d786bf40 --- /dev/null +++ b/66-plus-one.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} digits + * @return {number[]} + */ +const plusOne = function (digits) { + for (let i = digits.length - 1; i >= 0; i--) { + if (digits[i] !== 9) { + digits[i]++ + return digits + } else { + digits[i] = 0 + } + } + digits.unshift(1) + return digits +} diff --git a/660-remove-9.js b/660-remove-9.js new file mode 100644 index 00000000..c9fc656b --- /dev/null +++ b/660-remove-9.js @@ -0,0 +1,22 @@ +/** + * @param {number} n + * @return {number} + */ +const newInteger = function (n) { + let res = '' + while (n > 0) { + res = (n % 9) + res + n = Math.floor(n / 9) + } + return parseInt(res, 10) +} + +// another + +/** + * @param {number} n + * @return {number} + */ +const newInteger = function (n) { + return +(n).toString(9) +} diff --git a/661-image-smoother.js b/661-image-smoother.js new file mode 100644 index 00000000..c55f98fd --- /dev/null +++ b/661-image-smoother.js @@ -0,0 +1,41 @@ +/** + * @param {number[][]} M + * @return {number[][]} + */ +const imageSmoother = function (M) { + const r = M.length + if (r === 0) return 0 + const c = M[0].length + if (c === 0) return 0 + const res = Array.from({ length: r }, () => Array(c).fill(0)) + for (let i = 0; i < r; i++) { + for (let j = 0; j < c; j++) { + res[i][j] = helper(M, i, j, res) + } + } + return res +} + +function helper(M, i, j, res) { + let val = M[i][j] + let num = 1 + const dirs = [ + [-1, -1], + [-1, 0], + [-1, 1], + [0, -1], + [0, 1], + [1, -1], + [1, 0], + [1, 1], + ] + for (let [dr, dc] of dirs) { + const ii = i + dr + const jj = j + dc + if (M[ii] != null && M[ii][jj] != null) { + val += M[ii][jj] + num++ + } + } + return (val / num) >> 0 +} diff --git a/662-maximum-width-of-binary-tree.js b/662-maximum-width-of-binary-tree.js index 7f457617..9c8f8874 100644 --- a/662-maximum-width-of-binary-tree.js +++ b/662-maximum-width-of-binary-tree.js @@ -1,3 +1,37 @@ +/** + * 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 {number} + */ +const widthOfBinaryTree = function (root) { + let max = 1n + const stack = [] + const bi = BigInt + const width = (root, level, pos) => { + if (root == null) return + if (level >= stack.length) stack.push(pos) + else { + // console.log(stack) + const tmp = pos - stack[level] + 1n + if(tmp > max) max = tmp + } + width(root.left, level + 1, 2n * pos) + width(root.right, level + 1, 2n * pos + 1n) + } + width(root, 0, 1n) + return Number(max) +} + + +// another + /** * Definition for a binary tree node. * function TreeNode(val) { diff --git a/663-equal-tree-partition.js b/663-equal-tree-partition.js new file mode 100644 index 00000000..e7f7b9c6 --- /dev/null +++ b/663-equal-tree-partition.js @@ -0,0 +1,25 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {boolean} + */ +const checkEqualTree = function (root) { + const s = new Set() + const visit = (node, k = 1) => { + if (!node) return 0 + const l = visit(node.left) + const r = visit(node.right) + const ret = l + r + node.val + if (k) s.add(ret) + return ret + } + const sum = visit(root, 0) + if (sum % 2) return false + return s.has(sum / 2) +} diff --git a/664-strange-printer.js b/664-strange-printer.js index 2cfa9a33..deb5a1fe 100644 --- a/664-strange-printer.js +++ b/664-strange-printer.js @@ -29,3 +29,26 @@ const strangePrinter = function(s) { return help(s, 0, n - 1) } + +// another + +/** + * @param {string} s + * @return {number} + */ +const strangePrinter = function(s) { + const n = s.length + const dp = Array.from({ length: n }, () => Array(n).fill(n)) + for(let i = 0; i < n; i++) dp[i][i] = 1 + for(let len = 2; len <= n; len++) { + for(let i = 0; i < n - len + 1; i++) { + let j = i + len - 1 + dp[i][j] = 1 + dp[i + 1][j] + for(let k = i + 1; k < j; k++) { + if(s[i] === s[k]) dp[i][j] = Math.min(dp[i][j], dp[i][k - 1] + dp[k + 1][j]) + } + if(s[i] === s[j]) dp[i][j] = Math.min(dp[i][j - 1], dp[i][j]) + } + } + return dp[0][n - 1] +}; diff --git a/666-path-sum-iv.js b/666-path-sum-iv.js new file mode 100644 index 00000000..a223b42f --- /dev/null +++ b/666-path-sum-iv.js @@ -0,0 +1,89 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const pathSum = function (nums) { + if (nums == null || nums.length === 0) return 0 + const tree = Array(2 ** 5).fill(null) + for (let num of nums) { + const r = ((num / 100) >> 0) - 1 + const pos = (((num % 100) / 10) >> 0) - 1 + const v = num % 10 + tree[Math.pow(2, r) + pos] = v + } + let res = 0 + const q = [1] + while (q.length) { + const cur = q.shift() + const left = cur * 2 + const right = cur * 2 + 1 + if (left >= tree.length || (tree[left] == null && tree[right] == null)) + res += tree[cur] + else { + if (tree[left] != null) { + q.push(left) + tree[left] += tree[cur] + } + if (tree[right] != null) { + q.push(right) + tree[right] += tree[cur] + } + } + } + return res +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const pathSum = function (nums) { + if (nums == null || nums.length === 0) return 0 + const tree = new Map() + for (let num of nums) { + tree.set((num / 10) >> 0, num % 10) + } + return traverse((nums[0] / 10) >> 0, 0) + + function traverse(node, prev) { + if (!tree.has(node)) return 0 + const level = (node / 10) >> 0 + const pos = node % 10 + const val = tree.get(node) + const left = (level + 1) * 10 + pos * 2 - 1 + const right = (level + 1) * 10 + pos * 2 + const cur = prev + val + if (!tree.has(left) && !tree.has(right)) return cur + return traverse(left, cur) + traverse(right, cur) + } +} + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const pathSum = function (nums) { + const arr = Array(1 << 5).fill(-1) + for (let num of nums) { + let [lvl, pos, val] = [ + parseInt(num / 100), + parseInt((num % 100) / 10), + num % 10, + ] + arr[(1 << (lvl - 1)) - 1 + pos - 1] = val + } + let sum = 0 + for (let i = 0; i < 1 << 4; i++) { + if (arr[i] !== -1) { + arr[i] += i > 0 ? arr[parseInt((i - 1) >> 1)] : 0 + if (arr[i * 2 + 1] === -1 && arr[i * 2 + 2] === -1) { + sum += arr[i] + } + } + } + return sum +} diff --git a/667-beautiful-arrangement-ii.js b/667-beautiful-arrangement-ii.js new file mode 100644 index 00000000..a8f665c1 --- /dev/null +++ b/667-beautiful-arrangement-ii.js @@ -0,0 +1,23 @@ +/** + * @param {number} n + * @param {number} k + * @return {number[]} + */ +const constructArray = function (n, k) { + const res = [1] + while (k) { + const index = res.length + if (index % 2 === 1) { + res.push(res[index - 1] + k) + } else { + res.push(res[index - 1] - k) + } + k -= 1 + } + if (res.length < n) { + for (let i = res.length + 1; i <= n; i += 1) { + res.push(i) + } + } + return res +} diff --git a/668-kth-smallest-number-in-multiplication-table.js b/668-kth-smallest-number-in-multiplication-table.js index 41128049..6e15d6e4 100644 --- a/668-kth-smallest-number-in-multiplication-table.js +++ b/668-kth-smallest-number-in-multiplication-table.js @@ -30,3 +30,33 @@ function count(m, n, target) { } return nSmaller; } + +// another + +/** + * @param {number} m + * @param {number} n + * @param {number} k + * @return {number} + */ +const findKthNumber = function(m, n, k) { + let left = 1; + let right = m * n; + while (left < right) { + const mid = Math.floor((left + right) / 2); + const num = count(m, n, mid); + if (num < k) left = mid + 1; + else right = mid; + } + return left; +}; + +function count(m, n, target) { + let res = 0; + let j = n; + for (let i = 1; i <= m; i++) { + while (i * j > target) j-- + res += j; + } + return res; +} diff --git a/67-add-binary.js b/67-add-binary.js index 5017f4ab..1e6c437f 100644 --- a/67-add-binary.js +++ b/67-add-binary.js @@ -16,3 +16,28 @@ const addBinary = function(a, b) { } return s }; + +// another + +/** + * @param {string} a + * @param {string} b + * @return {string} + */ +const addBinary = function(a, b) { + let next = false + let res = [] + let ai = a.length - 1 + let bi = b.length - 1 + while((ai >= 0 && bi >=0) || next) { + const tmp = (ai >= 0 ? +a[ai--] : 0) + (bi >= 0 ? +b[bi--] : 0) + (next ? 1 : 0) + if(tmp > 1) next = true + else next = false + res.unshift('' + (tmp % 2)) + } + + while(ai >= 0) res.unshift(a[ai--]) + while(bi >= 0) res.unshift(b[bi--]) + + return res.join('') +}; diff --git a/671-second-minimum-node-in-a-binary-tree.js b/671-second-minimum-node-in-a-binary-tree.js new file mode 100644 index 00000000..12bd486a --- /dev/null +++ b/671-second-minimum-node-in-a-binary-tree.js @@ -0,0 +1,66 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const findSecondMinimumValue = function(root) { + if(root == null) return -1 + const q = [root] + let min = Number.MAX_VALUE + let min2nd = Number.MAX_VALUE + while(q.length) { + const len = q.length + for(let i = 0; i < len; i++) { + const cur = q.shift() + if(cur.val <= min) { + min = cur.val + } else if(cur.val > min && cur.val < min2nd) { + min2nd = cur.val + } + if(cur.left) q.push(cur.left) + if(cur.right) q.push(cur.right) + } + } + return min2nd === Number.MAX_VALUE ? -1 : min2nd +}; + +// another + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +const findSecondMinimumValue = function (root) { + if (root === null) return -1; + if (root.left === null && root.right === null) return -1; + let left = root.left.val; + let right = root.right.val; + if (left === root.val) { + left = findSecondMinimumValue(root.left); + } + if (right === root.val) { + right = findSecondMinimumValue(root.right); + } + if (right !== -1 && left !== -1) { + return Math.min(left, right); + } + if (right === -1) { + return left; + } + if (left === -1) { + return right; + } +}; diff --git a/672-bulb-switcher-ii.js b/672-bulb-switcher-ii.js new file mode 100644 index 00000000..9e3bb96e --- /dev/null +++ b/672-bulb-switcher-ii.js @@ -0,0 +1,12 @@ +/** + * @param {number} n + * @param {number} m + * @return {number} + */ +const flipLights = function (n, m) { + n = Math.min(n, 3) + if (m === 0) return 1 + if (m === 1) return n === 1 ? 2 : n === 2 ? 3 : 4 + if (m === 2) return n === 1 ? 2 : n === 2 ? 4 : 7 + return n === 1 ? 2 : n === 2 ? 4 : 8 +} diff --git a/675-cut-off-trees-for-golf-event.js b/675-cut-off-trees-for-golf-event.js new file mode 100644 index 00000000..8e370aa8 --- /dev/null +++ b/675-cut-off-trees-for-golf-event.js @@ -0,0 +1,69 @@ +/** + * @param {number[][]} forest + * @return {number} + */ +const cutOffTree = function (forest) { + const n = forest.length + if (n === 0) return 0 + const m = forest[0].length + if (m === 0) return 0 + const entries = [] + for (let i = 0; i < n; i += 1) { + for (let j = 0; j < m; j += 1) { + if (forest[i][j] > 0) { + entries.push([forest[i][j], i, j]) + } + } + } + entries.sort((e1, e2) => e1[0] - e2[0]) + const direct = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ] + const visited = Array(n) + .fill(null) + .map(() => Array(m).fill(0)) + const bfs = function (start, end) { + for (let i = 0; i < n; i += 1) + for (let j = 0; j < m; j += 1) visited[i][j] = 0 + let cur = [start], + next = [], + step = 0 + visited[start[0]][start[1]] = 1 + while (cur.length > 0) { + next = [] + for (const [x, y] of cur) { + if (x === end[0] && y === end[1]) return step + for (const [dx, dy] of direct) { + const p = x + dx, + q = y + dy + if ( + p < 0 || + q < 0 || + p >= n || + q >= m || + visited[p][q] === 1 || + forest[p][q] === 0 + ) + continue + visited[p][q] = 1 + next.push([p, q]) + } + } + step += 1 + cur = next + } + return -1 + } + let pre = [0, 0], + totalCnt = 0 + for (const entry of entries) { + const step = bfs(pre, entry.slice(1)) + if (step === -1) return -1 + totalCnt += step + pre = entry.slice(1) + } + return totalCnt +} diff --git a/678-valid-parenthesis-string.js b/678-valid-parenthesis-string.js index bfac5df3..443a9a4d 100644 --- a/678-valid-parenthesis-string.js +++ b/678-valid-parenthesis-string.js @@ -12,3 +12,26 @@ const checkValidString = function(s) { } return lo === 0; }; + +// another + +/** + * @param {string} s + * @return {boolean} + */ + const checkValidString = function (s) { + let lo = 0, hi = 0 // 可能多余的‘(’ + for(let ch of s) { + if(ch === '(') lo++, hi++ + if(ch === ')') { + if(lo > 0) lo-- + hi-- + } + if(ch === '*') { + if(lo > 0) lo-- + hi++ + } + if(hi < 0) return false + } + return lo === 0 +} diff --git a/68-text-justification.js b/68-text-justification.js index a629c398..3f26e4a1 100755 --- a/68-text-justification.js +++ b/68-text-justification.js @@ -1,3 +1,40 @@ +/** + * @param {string[]} words + * @param {number} maxWidth + * @return {string[]} + */ +const fullJustify = function(words, maxWidth) { + const res = [] + let curRow = [] + let numOfChars = 0 + + for (let w of words) { + if (numOfChars + w.length + curRow.length > maxWidth) { + for(let i = 0; i < maxWidth - numOfChars; i++) { + if(curRow.length === 1) { + curRow[0] += ' ' + } else { + curRow[i % (curRow.length - 1)] += ' ' + } + } + res.push(curRow.join('')) + curRow = [] + numOfChars = 0 + } + curRow.push(w) + numOfChars += w.length + } + + const numOfSpace = maxWidth - numOfChars - (curRow.length - 1) + let tail = '' + for(let i = 0; i < numOfSpace; i++) tail += ' ' + res.push(curRow.join(' ') + tail) + + return res +}; + +// another + /** * @param {string[]} words * @param {number} L diff --git a/681-next-closest-time.js b/681-next-closest-time.js new file mode 100644 index 00000000..3dcecc92 --- /dev/null +++ b/681-next-closest-time.js @@ -0,0 +1,43 @@ +/** + * @param {string} time + * @return {string} + */ +const nextClosestTime = function (time) { + const digits = time.split('') + const orderedDigits = [...digits].sort() + for (let i = digits.length - 1; i >= 0; i--) { + const current = digits[i] + switch (i) { + case 4: + digits[i] = findSmallest(digits[i], '9', orderedDigits) + if (digits[i] > current) return digits.join('') + break + case 3: + digits[i] = findSmallest(digits[i], '5', orderedDigits) + if (digits[i] > current) return digits.join('') + break + case 1: + digits[i] = findSmallest( + digits[i], + digits[i - 1] == '2' ? '4' : '9', + orderedDigits + ) + if (digits[i] > current) return digits.join('') + break + case 0: + digits[i] = findSmallest(digits[i], '2', orderedDigits) + if (digits[i] > current) return digits.join('') + break + } + } + return digits.join('') +} + +const findSmallest = (low, high, order) => { + for (let d = 0; d < order.length; d++) { + if (order[d] != ':' && order[d] > low && order[d] <= high) { + return order[d] + } + } + return order[0] +} diff --git a/683-k-empty-slots.js b/683-k-empty-slots.js new file mode 100644 index 00000000..edffbf4f --- /dev/null +++ b/683-k-empty-slots.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} bulbs + * @param {number} K + * @return {number} + */ +const kEmptySlots = function (bulbs, K) { + const days = new Array(bulbs.length) + for (let i = 0; i < bulbs.length; i++) days[bulbs[i] - 1] = i + 1 + let left = 0, + right = K + 1, + res = Number.MAX_VALUE + for (let i = 0; right < days.length; i++) { + if (days[i] < days[left] || days[i] <= days[right]) { + if (i === right) res = Math.min(res, Math.max(days[left], days[right])) + left = i + right = K + 1 + i + } + } + return res === Number.MAX_VALUE ? -1 : res +} diff --git a/684-redundant-connection.js b/684-redundant-connection.js new file mode 100644 index 00000000..23df8832 --- /dev/null +++ b/684-redundant-connection.js @@ -0,0 +1,24 @@ +/** + * @param {number[][]} edges + * @return {number[]} + */ +const findRedundantConnection = function (edges) { + const uf = {} + for (let edge of edges) { + let u = edge[0] + let v = edge[1] + if (find(u) === find(v)) { + return edge + } else { + union(u, v) + } + } + function union(a, b) { + uf[find(a)] = uf[find(b)] + } + function find(x) { + if (!uf[x]) uf[x] = x + if (uf[x] === x) return x + return find(uf[x]) + } +} diff --git a/685-redundant-connection-ii.js b/685-redundant-connection-ii.js new file mode 100644 index 00000000..012a084d --- /dev/null +++ b/685-redundant-connection-ii.js @@ -0,0 +1,39 @@ +/** + * @param {number[][]} edges + * @return {number[]} + */ +const findRedundantDirectedConnection = function (edges) { + const parent = [] + //detect circle + for (let i = 1; i <= edges.length; i++) { + parent[i] = i + } + let circleEdge, removedEdge, candidateEdge + for (let i = 0; i < edges.length; i++) { + const [u, v] = edges[i] + const pu = findParent(parent, u) + const pv = findParent(parent, v) + if (pv !== v) { + removedEdge = [u, v] // node with 2 parents + } else { + if (pv === pu) { + circleEdge = [u, v] // circle edge + } + parent[v] = pu + } + } + if (!removedEdge) { + return circleEdge + } + if (circleEdge) { + return edges.find((d) => d[1] === removedEdge[1] && d[0] !== removedEdge[0]) + } else { + return removedEdge + } +} +const findParent = function (parent, i) { + if (parent[i] !== i) { + parent[i] = findParent(parent, parent[i]) + } + return parent[i] +} diff --git a/687-longest-univalue-path.js b/687-longest-univalue-path.js index baa86b5f..123bfd54 100644 --- a/687-longest-univalue-path.js +++ b/687-longest-univalue-path.js @@ -1,3 +1,37 @@ + +/** + * 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 {number} + */ +const longestUnivaluePath = function(root) { + let res = 0 + dfs(root) + return res + + function dfs(node) { + if(node == null) return 0 + let left = dfs(node.left), right = dfs(node.right) + if(node.left && node.left.val === node.val) left++ + else left = 0 + + if(node.right && node.right.val === node.val) right++ + else right = 0 + + res = Math.max(res, left + right) + return Math.max(left, right) + } +}; + +// another + /** * Definition for a binary tree node. * function TreeNode(val) { diff --git a/688-knight-probability-in-chessboard.js b/688-knight-probability-in-chessboard.js new file mode 100644 index 00000000..546677d2 --- /dev/null +++ b/688-knight-probability-in-chessboard.js @@ -0,0 +1,43 @@ +/** + * @param {number} N + * @param {number} K + * @param {number} r + * @param {number} c + * @return {number} + */ +const knightProbability = function (N, K, r, c) { + const moves = [ + [1, 2], + [1, -2], + [2, 1], + [2, -1], + [-1, 2], + [-1, -2], + [-2, 1], + [-2, -1], + ] + const dp = [...Array(K + 1)].map(() => + [...Array(N)].map(() => Array(N).fill(0)) + ) + dp[0][r][c] = 1 + for (let step = 1; step <= K; step++) { + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + for (let move of moves) { + let row = i + move[0], + col = j + move[1] + if (row >= 0 && row < N && col >= 0 && col < N) + dp[step][i][j] += dp[step - 1][row][col] / 8 + } + } + } + } + let res = 0 + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + res += dp[K][i][j] + } + } + return res +} + diff --git a/69-sqrt(x).js b/69-sqrt(x).js index a27d2f3b..3e3da29d 100755 --- a/69-sqrt(x).js +++ b/69-sqrt(x).js @@ -1,3 +1,22 @@ +/** + * @param {number} x + * @return {number} + */ +const mySqrt = function(x) { + let left = 0, right = x; + while (left < right) { + let mid = right - ((right - left) >> 1); + if (mid * mid > x) { + right = mid - 1; + } else { + left = mid; + } + } + return left; +}; + +// another + /** * @param {number} x * @return {number} @@ -7,3 +26,22 @@ const mySqrt = function(x) { while (r * r > x) r = ((r + x / r) / 2) | 0; return r; }; + +// another + +/** + * @param {number} x + * @return {number} + */ +const mySqrt = function(x) { + let l = 1, r = x + if(x === 0) return 0 + while(true) { + let mid = l + ((r - l) >> 1) + if(mid * mid > x) r = mid - 1 + else { + if((mid + 1) * (mid + 1) > x) return mid + l = mid + 1 + } + } +}; diff --git a/690-employee-importance.js b/690-employee-importance.js new file mode 100644 index 00000000..a958653e --- /dev/null +++ b/690-employee-importance.js @@ -0,0 +1,34 @@ +/** + * Definition for Employee. + * function Employee(id, importance, subordinates) { + * // It's the unique id of each node + * // unique id of this employee + * this.id = id; + * // the importance value of this employee + * this.importance = importance; + * // the id of direct subordinates + * this.subordinates = subordinates; + * } + */ + +/** + * @param {Employee[]} employees + * @param {number} id + * @return {number} + */ +const GetImportance = function (employees, id) { + const map = {} + employees.forEach((employee) => { + map[employee.id] = employee + }) + const s = [id] + let importance = 0 + while (s.length) { + let current = map[s.pop()] + importance += current.importance + if (current.subordinates.length) { + s.push(...current.subordinates.reverse()) + } + } + return importance +} diff --git a/691-stickers-to-spell-word.js b/691-stickers-to-spell-word.js index ac5b4f16..b81b80ea 100644 --- a/691-stickers-to-spell-word.js +++ b/691-stickers-to-spell-word.js @@ -1,3 +1,76 @@ +/** + * @param {string[]} stickers + * @param {string} target + * @return {number} + */ +const minStickers = function(stickers, target) { + const n = target.length + const limit = 1 << n + const dp = Array(limit).fill(Infinity) + dp[0] = 0 + for(let state = 0; state < limit; state++) { + if(dp[state] === Infinity) continue + for(let s of stickers) { + const ns = helper(state, target, s) + dp[ns] = Math.min(dp[ns], dp[state] + 1) + } + + } + + return dp[limit - 1] === Infinity ? -1 : dp[limit - 1] + + function helper(state, target, s) { + const n = target.length + for(const ch of s) { + for(let i = 0; i < n; i++) { + if(target[i] === ch && ((state >> i) & 1) === 0) { + state |= (1 << i) + break + } + } + } + + return state + } +}; + +// another + + +/** + * @param {string[]} stickers + * @param {string} target + * @return {number} + */ +const minStickers = function (stickers, target) { + const n = stickers.length + const m = target.length + const limit = 1 << m + const dp = Array(limit).fill(Infinity) + dp[0] = 0 + for (let i = 0; i < limit; i++) { + if (dp[i] === Infinity) continue + for (const sticker of stickers) { + let stat = i + for (const ch of sticker) { + for (let j = 0; j < m; j++) { + if (target[j] === ch && ((stat >> j) & 1) === 0) { + stat |= (1 << j) + break + } + } + } + dp[stat] = Math.min(dp[stat], dp[i] + 1) + } + } + + return dp[limit - 1] === Infinity ? -1 : dp[limit - 1] +} + + +// another + + /** * @param {string[]} stickers * @param {string} target diff --git a/694-number-of-distinct-islands.js b/694-number-of-distinct-islands.js new file mode 100644 index 00000000..1472a640 --- /dev/null +++ b/694-number-of-distinct-islands.js @@ -0,0 +1,105 @@ +/** + +Given a non-empty 2D array grid of 0's and 1's, +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. + +Count the number of distinct islands. 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. + +Example 1: +11000 +11000 +00011 +00011 + +Given the above grid map, return 1. + +Example 2: +11011 +10000 +00001 +11011 + +Given the above grid map, return 3. + +Notice that: +11 +1 +and + 1 +11 +are considered different island shapes, because we do not consider reflection / rotation. +Note: The length of each dimension in the given grid does not exceed 50. + +*/ + +/** + * @param {number[][]} grid + * @return {number} + */ +const numDistinctIslands = function(grid) { + const set = new Set() + for (let i = 0; i < grid.length; i++) { + for (let j = 0; j < grid[0].length; j++) { + if (grid[i][j] === 1) { + const tempArr = [] + helper(i, j, grid, tempArr) + const x = tempArr[0][0] - 0 + const y = tempArr[0][1] - 0 + let str = '' + for (let k = 0; k < tempArr.length; k++) { + str += '#' + (tempArr[k][0] - x) + '#' + (tempArr[k][1] - y) + } + set.add(str) + } + } + } + return set.size +} + +function helper(i, j, arr, tempArr) { + tempArr.push([i, j]) + arr[i][j] = 0 + + if (arr[i][j - 1] === 1) helper(i, j - 1, arr, tempArr) + if (arr[i][j + 1] === 1) helper(i, j + 1, arr, tempArr) + if (arr[i - 1]) { + if (arr[i - 1][j] === 1) helper(i - 1, j, arr, tempArr) + } + if (arr[i + 1]) { + if (arr[i + 1][j] === 1) helper(i + 1, j, arr, tempArr) + } +} + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const numDistinctIslands = function(grid) { + if (!grid.length) return 0; + const pattern = new Set(); + grid.forEach((rows, row) => { + rows.forEach((val, col) => { + if (val === 1) pattern.add(depthFirst(grid, row, col, "o")); + }); + }); + return pattern.size; +}; + +function depthFirst(graph, row, col, di) { + if (graph[row] && graph[row][col]) { + graph[row][col] = 0; + let p = + di + + depthFirst(graph, row + 1, col, "d") + + depthFirst(graph, row - 1, col, "u") + + depthFirst(graph, row, col + 1, "r") + + depthFirst(graph, row, col - 1, "l") + + "b"; + return p; + } else return ""; +} diff --git a/699-falling-squares.js b/699-falling-squares.js index 5438e80a..f0d08104 100644 --- a/699-falling-squares.js +++ b/699-falling-squares.js @@ -1,33 +1,93 @@ +class Interval { + constructor(s,e,h) { + this.start = s + this.end = e + this.height = h + } +} /** * @param {number[][]} positions * @return {number[]} */ -class Interval { - constructor(start, end, height) { - this.start = start - this.end = end - this.height = height - } -} -function fallingSquares(positions) { - const intervals = [] +const fallingSquares = function(positions) { + const n = positions.length const res = [] - let h = 0 - for (let pos of positions) { - let cur = new Interval(pos[0], pos[0] + pos[1] - 1, pos[1]) - h = Math.max(h, getHeight(intervals, cur)) - res.push(h) + const intervals = [] + let curMax = 0 + for(let i = 0; i < n; i++) { + const [s, len] = positions[i] + const ins = new Interval(s, s + len, len) + curMax = Math.max(curMax, getHeight(intervals, ins)) + res.push(curMax) } + return res -} -function getHeight(intervals, cur) { - let preMaxHeight = 0 - for (let i of intervals) { - if (i.end < cur.start) continue - if (i.start > cur.end) continue - preMaxHeight = Math.max(preMaxHeight, i.height) +}; + +function getHeight(intervals, ins) { + let preMax = 0 + for(const e of intervals) { + if(ins.start >= e.end) continue + if(ins.end <= e.start) continue + preMax = Math.max(preMax, e.height) } - cur.height += preMaxHeight - intervals.push(cur) - return cur.height + + ins.height += preMax + intervals.push(ins) + return ins.height } + +// another + +/** + * @param {number[][]} positions + * @return {number[]} + */ +var fallingSquares = function (positions) { + let ranges = [{ left: 0, height: 0, right: 1e8 + 1e6 }], rtn = [], max = 0 + + outer: + for (let [left, length] of positions) { + let curHeight = 0, startI = -1, right = left + length, newRanges = [] + for (let i = 0; i < ranges.length; i++) { + let range = ranges[i] + if (left < range.right && startI == -1) { + startI = i + // left part + if (left != range.left) { + newRanges.push({ + left: range.left, + height: range.height, + right: left + }) + } + } + if (startI != -1) { + curHeight = Math.max(curHeight, range.height) + } + if (right <= range.right) { + // added part + let newHeight = length + curHeight + newRanges.push({ + left, + height: newHeight, + right, + }) + // right part + if (right != range.right) { + newRanges.push({ + left: right, + height: range.height, + right: range.right, + }) + } + max = Math.max(newHeight, max) + rtn.push(max) + // replace + ranges.splice(startI, i - startI + 1, ...newRanges) + continue outer + } + } + } + return rtn +}; diff --git a/7-reverse-integer.js b/7-reverse-integer.js index f6f83c2a..1048c8cf 100755 --- a/7-reverse-integer.js +++ b/7-reverse-integer.js @@ -1,3 +1,25 @@ +/** + * @param {number} x + * @return {number} + */ +const reverse = function (x) { + let res = 0, tail, newResult + const low = -Math.pow(2, 31), high = Math.pow(2, 31) + while(x !== 0) { + tail = x % 10 + newResult = res * 10 + tail + // if((newResult - tail) / 10 !== res) return 0 + if(newResult < low || newResult >= high) return 0 + res = newResult + x = ~~(x / 10) + } + + return res +}; + +// another + + /** * @param {number} x * @return {number} @@ -18,3 +40,22 @@ const reverse = function(num) { if (negative) return result * -1; return result; }; + +// another + +/** + * @param {number} n + * @return {number} + */ +const reverse = (n) => { + if (typeof n !== 'number') { + throw new Error('n must be a number'); + } + let sign = Math.sign(n); + n = Math.abs(n); + if (n < 0) { + return -reverse(-n); + } + let reversed = Number([...n.toString()].reverse().join('')); + return sign * reversed; +} diff --git a/70-climbing-stairs.js b/70-climbing-stairs.js index 71cb4942..a52c4c63 100755 --- a/70-climbing-stairs.js +++ b/70-climbing-stairs.js @@ -22,3 +22,26 @@ function single(i, hash) { hash[i] = single(i - 1, hash) + single(i - 2, hash); return hash[i]; } + +// another + +/** + * @param {number} n + * @return {number} + */ +const climbStairs = function (n) { + const dp = new Array(n + 1).fill(0) + if (n === 1) { + return 1 + } + if (n === 2) { + return 2 + } + dp[0] = 0 + dp[1] = 1 + dp[2] = 2 + for (let i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2] + } + return dp[n] +} diff --git a/700-search-in-a-binary-search-tree.js b/700-search-in-a-binary-search-tree.js index f7a9d42f..7b4b24df 100755 --- a/700-search-in-a-binary-search-tree.js +++ b/700-search-in-a-binary-search-tree.js @@ -1,8 +1,9 @@ /** * Definition for a binary tree node. - * function TreeNode(val) { - * this.val = val; - * this.left = this.right = null; + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) * } */ /** @@ -10,14 +11,9 @@ * @param {number} val * @return {TreeNode} */ -const searchBST = function(root, val) { - if (root === null) return []; - - if (root.val === val) { - return root; - } else if (root.val < val) { - return searchBST(root.right, val); - } else { - return searchBST(root.left, val); +const searchBST = function (root, val) { + if (!root || root.val === val) { + return root } -}; + return root.val < val ? searchBST(root.right, val) : searchBST(root.left, val) +} diff --git a/701-insert-into-a-binary-search-tree.js b/701-insert-into-a-binary-search-tree.js index 7cb0ac51..f6b8a655 100644 --- a/701-insert-into-a-binary-search-tree.js +++ b/701-insert-into-a-binary-search-tree.js @@ -44,3 +44,25 @@ const insertIntoBST = function(root, val) { } return root; }; + +// another + +/** + * 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 + * @param {number} val + * @return {TreeNode} + */ +const insertIntoBST = function(root, val) { + if(root == null) return new TreeNode(val) + if(val < root.val) root.left = insertIntoBST(root.left, val) + else if(val > root.val) root.right = insertIntoBST(root.right, val) + return root +}; diff --git a/702-search-in-a-sorted-array-of-unknown-size.js b/702-search-in-a-sorted-array-of-unknown-size.js new file mode 100644 index 00000000..2b884a65 --- /dev/null +++ b/702-search-in-a-sorted-array-of-unknown-size.js @@ -0,0 +1,33 @@ +/** + * // This is the ArrayReader's API interface. + * // You should not implement it, or speculate about its implementation + * function ArrayReader() { + * + * @param {number} index + * @return {number} + * this.get = function(index) { + * ... + * }; + * }; + */ + +/** + * @param {ArrayReader} reader + * @param {number} target + * @return {number} + */ +const search = function (reader, target) { + let left = 0, + right = 1 + while (reader.get(right) < target) { + left = right + right <<= 1 + } + while (left <= right) { + const mid = left + Math.floor((right - left) / 2) + if (reader.get(mid) === target) return mid + if (reader.get(mid) > target) right = mid - 1 + else left = mid + 1 + } + return -1 +} diff --git a/703-kth-largest-element-in-a-stream.js b/703-kth-largest-element-in-a-stream.js new file mode 100644 index 00000000..0c1fc313 --- /dev/null +++ b/703-kth-largest-element-in-a-stream.js @@ -0,0 +1,39 @@ +/** + * @param {number} k + * @param {number[]} nums + */ +const KthLargest = function(k, nums) { + this.sorted = nums.sort((a, b) => a - b); + this.k = k; +}; + +/** + * @param {number} val + * @return {number} + */ +KthLargest.prototype.add = function(val) { + let left = 0; + let right = this.sorted.length - 1; + let insertIndex = left; + while (left <= right) { + let mid = left + Math.floor((right - left) / 2); + if (val > this.sorted[mid]) { + left = mid + 1; + insertIndex = mid + 1; + } else if (val < this.sorted[mid]) { + right = mid - 1; + insertIndex = mid; + } else { + insertIndex = mid; + break; + } + } + this.sorted.splice(insertIndex, 0, val); + return this.sorted[this.sorted.length - this.k]; +}; + +/** + * Your KthLargest object will be instantiated and called as such: + * var obj = new KthLargest(k, nums) + * var param_1 = obj.add(val) + */ diff --git a/707-design-linked-list.js b/707-design-linked-list.js new file mode 100644 index 00000000..081e9b95 --- /dev/null +++ b/707-design-linked-list.js @@ -0,0 +1,200 @@ +/** + * Initialize your data structure here. + */ +var MyLinkedList = function() { + this.arr = [] +} + +/** + * Get the value of the index-th node in the linked list. If the index is invalid, return -1. + * @param {number} index + * @return {number} + */ +MyLinkedList.prototype.get = function(index) { + if (this.arr[index] !== undefined) { + return this.arr[index] + } else { + return -1 + } +} + +/** + * Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. + * @param {number} val + * @return {void} + */ +MyLinkedList.prototype.addAtHead = function(val) { + this.arr.unshift(val) +} + +/** + * Append a node of value val to the last element of the linked list. + * @param {number} val + * @return {void} + */ +MyLinkedList.prototype.addAtTail = function(val) { + this.arr.push(val) +} + +/** + * Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. + * @param {number} index + * @param {number} val + * @return {void} + */ +MyLinkedList.prototype.addAtIndex = function(index, val) { + if (this.arr.length >= index) { + this.arr.splice(index, 0, val) + } + if (index < 0) { + this.arr.unshift(val) + } +} + +/** + * Delete the index-th node in the linked list, if the index is valid. + * @param {number} index + * @return {void} + */ +MyLinkedList.prototype.deleteAtIndex = function(index) { + if (index >= 0 && index < this.arr.length) { + this.arr.splice(index, 1) + } +} + +/** + * Your MyLinkedList object will be instantiated and called as such: + * var obj = new MyLinkedList() + * var param_1 = obj.get(index) + * obj.addAtHead(val) + * obj.addAtTail(val) + * obj.addAtIndex(index,val) + * obj.deleteAtIndex(index) + */ + +// another + +/** + * Initialize your data structure here. + */ +var MyLinkedList = function(val) { + this.head = null + this.tail = null + this.size = 0 +} + +// Create Node class to store node data as an 'object' +var Node = function(val) { + this.val = val + this.next = null +} + +/** + * Get the value of the index-th node in the linked list. If the index is invalid, return -1. + * @param {number} index + * @return {number} + */ +MyLinkedList.prototype.get = function(index) { + if (index < 0 || this.size === 0 || index > this.size - 1) return -1 + let curr = this.head + let i = 0 + while (i < index) { + curr = curr.next + i += 1 + } + return curr.val +} + +/** + * Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. + * @param {number} val + * @return {void} + */ +MyLinkedList.prototype.addAtHead = function(val) { + let newNode = new Node(val) + if (this.head === null) { + this.head = newNode + this.tail = newNode + } else { + newNode.next = this.head + this.head = newNode + } + this.size++ + return this +} + +/** + * Append a node of value val to the last element of the linked list. + * @param {number} val + * @return {void} + */ +MyLinkedList.prototype.addAtTail = function(val) { + const newNode = new Node(val) + if (this.head === null) { + this.head = newNode + this.tail = newNode + } else { + this.tail.next = newNode + this.tail = newNode + } + this.size++ + return this +} + +/** + * Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. + * @param {number} index + * @param {number} val + * @return {void} + */ +MyLinkedList.prototype.addAtIndex = function(index, val) { + if (index > this.size) return + if (index <= 0) return this.addAtHead(val) + if (index === this.size) return this.addAtTail(val) + let newNode = new Node(val) + let i = 0 + let curr = this.head + while (i < index - 1) { + curr = curr.next + i++ + } + newNode.next = curr.next ? curr.next : null + curr.next = newNode + this.size++ + return this +} + +/** + * Delete the index-th node in the linked list, if the index is valid. + * @param {number} index + * @return {void} + */ +MyLinkedList.prototype.deleteAtIndex = function(index) { + if (index >= this.size || index < 0) return + if (index === 0) { + this.head = this.head.next + this.size-- + return this + } + let curr = this.head + let i = 0 + while (i < index - 1) { + i++ + curr = curr.next + } + curr.next = curr.next.next ? curr.next.next : null + if (!curr.next) this.tail = curr + this.size-- + return this +} + +/** + * Your MyLinkedList object will be instantiated and called as such: + * var obj = new MyLinkedList() + * var param_1 = obj.get(index) + * obj.addAtHead(val) + * obj.addAtTail(val) + * obj.addAtIndex(index,val) + * obj.deleteAtIndex(index) + */ + diff --git a/708-insert-into-a-sorted-circular-linked-list.js b/708-insert-into-a-sorted-circular-linked-list.js new file mode 100644 index 00000000..6714c100 --- /dev/null +++ b/708-insert-into-a-sorted-circular-linked-list.js @@ -0,0 +1,32 @@ +/** + * // Definition for a Node. + * function Node(val, next) { + * this.val = val; + * this.next = next; + * }; + */ + +/** + * @param {Node} head + * @param {number} insertVal + * @return {Node} + */ +const insert = function (head, insertVal) { + if (head === null) { + const node = new Node(insertVal) + node.next = node + return node + } + let prev = head, + cur = prev.next + while (cur != head) { + if (prev.val > cur.val) { + if (insertVal >= prev.val || insertVal <= cur.val) break + } + if (prev.val <= insertVal && insertVal <= cur.val) break + prev = cur + cur = cur.next + } + prev.next = new Node(insertVal, cur) + return head +} diff --git a/71-simplify-path.js b/71-simplify-path.js new file mode 100644 index 00000000..e9bb4497 --- /dev/null +++ b/71-simplify-path.js @@ -0,0 +1,14 @@ +/** + * @param {string} path + * @return {string} + */ +const simplifyPath = function(path) { + path = path.split('/').filter(s => !!s && s !== '.') + while (path[0] === '..') path = path.slice(1) + let result = [] + for (let val of path) { + if (val === '..') result.pop() + else result.push(val) + } + return '/' + result.join('/') +} diff --git a/710-random-pick-with-blacklist.js b/710-random-pick-with-blacklist.js new file mode 100644 index 00000000..700d339b --- /dev/null +++ b/710-random-pick-with-blacklist.js @@ -0,0 +1,31 @@ +/** + * @param {number} N + * @param {number[]} blacklist + */ +const Solution = function (N, blacklist) { + this.map = new Map() + for (let b of blacklist) this.map.set(b, -1) + this.M = N - this.map.size + for (let b of blacklist) { + if (b < this.M) { + while (this.map.has(N - 1)) N-- + this.map.set(b, N - 1) + N-- + } + } +} + +/** + * @return {number} + */ +Solution.prototype.pick = function () { + const p = Math.floor(Math.random() * this.M) + if (this.map.has(p)) return this.map.get(p) + return p +} + +/** + * Your Solution object will be instantiated and called as such: + * var obj = new Solution(N, blacklist) + * var param_1 = obj.pick() + */ diff --git a/711-number-of-distinct-islands-ii.js b/711-number-of-distinct-islands-ii.js new file mode 100644 index 00000000..1a6e9bfe --- /dev/null +++ b/711-number-of-distinct-islands-ii.js @@ -0,0 +1,58 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const numDistinctIslands2 = function (grid) { + const dirs = [ + [0, 1], + [0, -1], + [-1, 0], + [1, 0], + ] + const rowSize = grid.length + const colSize = grid[0].length + const seen = Array.from({ length: rowSize }, () => Array(colSize).fill(false)) + const islands = new Set() + for (let r = 0; r < rowSize; r++) { + for (let c = 0; c < colSize; c++) { + const shape = [] + dfs(r, c, shape) + if (shape.length > 0) islands.add(canonical(shape)) + } + } + return islands.size + function dfs(r, c, shape = []) { + if (!inBound(r, c) || grid[r][c] !== 1 || seen[r][c]) return + seen[r][c] = true + shape.push(r * colSize + c) + dirs.forEach(([dr, dc]) => dfs(r + dr, c + dc, shape)) + } + function canonical(shape) { + let ans = '' + const lift = rowSize + colSize + const n = shape.length + const out = Array(n).fill(0) + const xs = Array(n).fill(0) + const ys = Array(n).fill(0) + for (let rotate = 0; rotate < 8; rotate++) { + for (let i = 0; i < n; i++) { + const x = ~~(shape[i] / colSize) + const y = shape[i] % colSize + xs[i] = rotate <= 1 ? x : rotate <= 3 ? -x : rotate <= 5 ? y : -y + ys[i] = + rotate <= 3 ? (rotate % 2 === 0 ? y : -y) : rotate % 2 === 0 ? x : -x + } + const mx = Math.min(...xs) + const my = Math.min(...ys) + for (let i = 0; i < n; i++) { + out[i] = (xs[i] - mx) * lift + (ys[i] - my) + } + const candidate = out.sort((a, b) => a - b).join(',') + if (ans < candidate) ans = candidate + } + return ans + } + function inBound(r, c) { + return r >= 0 && r < rowSize && c >= 0 && c < colSize + } +} diff --git a/713-subarray-product-less-than-k.js b/713-subarray-product-less-than-k.js new file mode 100644 index 00000000..33400b8d --- /dev/null +++ b/713-subarray-product-less-than-k.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const numSubarrayProductLessThanK = function(nums, k) { + if (k == 0) return 0 + let cnt = 0 + let pro = 1 + for (let i = 0, j = 0, len = nums.length; j < len; j++) { + pro *= nums[j] + while (i <= j && pro >= k) { + pro /= nums[i++] + } + cnt += j - i + 1 + } + return cnt +} diff --git a/715-range-module.js b/715-range-module.js index 65f77cd2..4c193227 100644 --- a/715-range-module.js +++ b/715-range-module.js @@ -1,3 +1,99 @@ + +const RangeModule = function() { + this.st = new SegmentTree(); +}; + +/** + * @param {number} left + * @param {number} right + * @return {void} + */ +RangeModule.prototype.addRange = function(left, right) { + this.st.add(left, right); +}; + +/** + * @param {number} left + * @param {number} right + * @return {boolean} + */ +RangeModule.prototype.queryRange = function(left, right) { + return this.st.query(left, right); +}; + +/** + * @param {number} left + * @param {number} right + * @return {void} + */ +RangeModule.prototype.removeRange = function(left, right) { + this.st.remove(left, right); +}; + +/** + * Your RangeModule object will be instantiated and called as such: + * var obj = new RangeModule() + * obj.addRange(left,right) + * var param_2 = obj.queryRange(left,right) + * obj.removeRange(left,right) + */ +class SegNode { + constructor(l, r, state) { + this.l = l; + this.r = r; + this.state = state; + this.left = null; + this.right = null; + } +} + +function SegmentTree() { + let root = new SegNode(0, 1e9, false); + return { update, query, add, remove } + function update(node, l, r, state) { + if (l <= node.l && r >= node.r) { + node.state = state; + node.left = null; + node.right = null; + return node.state; + } + if (l >= node.r || r <= node.l) return node.state; + let mid = node.l + parseInt((node.r - node.l) / 2); + if (node.left == null) { + node.left = new SegNode(node.l, mid, node.state); + node.right = new SegNode(mid, node.r, node.state); + } + let left = update(node.left, l, r, state); + let right = update(node.right, l, r, state); + node.state = left && right; + return node.state; + } + function query(l, r) { + return dfs(root, l, r); + } + function dfs(node, l, r) { + if (l >= node.r || r <= node.l) return true; + if ((l <= node.l && r >= node.r) || (node.left == null)) return node.state; + let mid = node.l + parseInt((node.r - node.l) / 2); + if (r <= mid) { + return dfs(node.left, l, r); + } else if (l >= mid) { + return dfs(node.right, l, r); + } else { + return dfs(node.left, l, r) && dfs(node.right, l, r); + } + } + function add(l, r) { + update(root, l, r, true); + } + function remove(l, r) { + update(root, l, r, false); + } +} + + +// another + const RangeModule = function() { this.range = [] } @@ -123,3 +219,162 @@ RangeModule.prototype.removeRange = function(left, right) { * var param_2 = obj.queryRange(left,right) * obj.removeRange(left,right) */ + + +// another + +const RangeModule = function () { + this.intervals = [] +} + +/** + * @param {number} left + * @param {number} right + * @return {void} + */ +RangeModule.prototype.addRange = function (left, right) { + const n = this.intervals.length + const tmp = [] + for (let i = 0; i <= n; i++) { + const cur = this.intervals[i] + + if (i == n || cur[0] > right) { + tmp.push([left, right]) + while (i < n) tmp.push(this.intervals[i++]) + } else if (cur[1] < left) tmp.push(cur) + else { + left = Math.min(left, cur[0]) + right = Math.max(right, cur[1]) + } + } + this.intervals = tmp +} + +/** + * @param {number} left + * @param {number} right + * @return {boolean} + */ +RangeModule.prototype.queryRange = function (left, right) { + const n = this.intervals.length + let l = 0, + r = n - 1 + while (l <= r) { + let m = ~~(l + (r - l) / 2) + if (this.intervals[m][0] >= right) r = m - 1 + else if (this.intervals[m][1] <= left) l = m + 1 + else return this.intervals[m][0] <= left && this.intervals[m][1] >= right + } + return false +} + +/** + * @param {number} left + * @param {number} right + * @return {void} + */ +RangeModule.prototype.removeRange = function (left, right) { + const n = this.intervals.length + const tmp = [] + for (let i = 0; i < n; i++) { + const cur = this.intervals[i] + if (cur[1] <= left || cur[0] >= right) tmp.push(cur) + else { + if (cur[0] < left) tmp.push([cur[0], left]) + if (cur[1] > right) tmp.push([right, cur[1]]) + } + } + this.intervals = tmp +} + +/** + * Your RangeModule object will be instantiated and called as such: + * var obj = new RangeModule() + * obj.addRange(left,right) + * var param_2 = obj.queryRange(left,right) + * obj.removeRange(left,right) + */ + +// another + +const RangeModule = function () { + this.intervals = [] +} + +/** + * @param {number} left + * @param {number} right + * @return {void} + */ +RangeModule.prototype.addRange = function (left, right) { + const tmp = [] + const n = this.intervals.length + for(let i = 0; i <= n; i++) { + const cur = this.intervals[i] + if(i === n || cur[0] > right) { + tmp.push([left, right]) + while(i < n) tmp.push(this.intervals[i++]) + }else if(cur[1] < left) { + tmp.push(cur) + }else { + // cur[0] <= right + // left <= cur[1] + left = Math.min(left, cur[0]) + right = Math.max(right, cur[1]) + } + } + // console.log(tmp) + this.intervals = tmp +} + +/** + * @param {number} left + * @param {number} right + * @return {boolean} + */ +RangeModule.prototype.queryRange = function (left, right) { + const n = this.intervals.length, arr = this.intervals + let l = 0, r = n - 1 + while(l <= r) { + const mid = ~~(l + (r - l) / 2) + if(arr[mid][0] >= right) r = mid - 1 + else if(arr[mid][1] <= left) l = mid + 1 + else return arr[mid][0] <= left && arr[mid][1] >= right + } + + return false +} + +/** + * @param {number} left + * @param {number} right + * @return {void} + */ +RangeModule.prototype.removeRange = function (left, right) { + const tmp = [] + const n = this.intervals.length + + for(let i = 0; i < n; i++) { + const cur = this.intervals[i] + if(cur[1] < left) { + tmp.push(cur) + }else if(cur[0] > right) tmp.push(cur) + else { + // left <= cur[1] + // cur[0] <= right + if(left > cur[0]) tmp.push([cur[0], left]) + if(right < cur[1]) tmp.push([right, cur[1]]) + } + } + // console.log(tmp) + this.intervals = tmp +} + +/** + * Your RangeModule object will be instantiated and called as such: + * var obj = new RangeModule() + * obj.addRange(left,right) + * var param_2 = obj.queryRange(left,right) + * obj.removeRange(left,right) + */ + diff --git a/716-max-stack.js b/716-max-stack.js new file mode 100644 index 00000000..5fbe1b18 --- /dev/null +++ b/716-max-stack.js @@ -0,0 +1,54 @@ +/** + * initialize your data structure here. + */ +const MaxStack = function() { + this.stack = [] +} + +/** + * @param {number} x + * @return {void} + */ +MaxStack.prototype.push = function(x) { + this.stack.push(x) +} + +/** + * @return {number} + */ +MaxStack.prototype.pop = function() { + return this.stack.pop() +} + +/** + * @return {number} + */ +MaxStack.prototype.top = function() { + return this.stack[this.stack.length - 1] +} + +/** + * @return {number} + */ +MaxStack.prototype.peekMax = function() { + return Math.max(...this.stack) +} + +/** + * @return {number} + */ +MaxStack.prototype.popMax = function() { + const elem = Math.max(...this.stack) + const index = this.stack.lastIndexOf(elem) + return this.stack.splice(index, 1)[0] +} + +/** + * Your MaxStack object will be instantiated and called as such: + * var obj = new MaxStack() + * obj.push(x) + * var param_2 = obj.pop() + * var param_3 = obj.top() + * var param_4 = obj.peekMax() + * var param_5 = obj.popMax() + */ diff --git a/719-find-k-th-smallest-pair-distance.js b/719-find-k-th-smallest-pair-distance.js index 1ef7c937..63e8a619 100644 --- a/719-find-k-th-smallest-pair-distance.js +++ b/719-find-k-th-smallest-pair-distance.js @@ -1,3 +1,28 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +function smallestDistancePair(nums, k) { + nums.sort((a, b) => a - b) + let l = 0, n = nums.length, r = nums[n - 1] - nums[0] + + let res = 0 + while(l < r) { + let cnt = 0, mid = l + ((r - l) >> 1) + for(let i = 0, j = 0; i < n; i++) { + while(j < n && nums[j] <= nums[i] + mid) j++ + cnt += j - 1 - i + } + if(cnt < k) l = mid + 1 + else r = mid + } + + return l +} + +// another + /** * @param {number[]} nums * @param {number} k diff --git a/72-edit-distance.js b/72-edit-distance.js index a9a30af8..f9e41c89 100644 --- a/72-edit-distance.js +++ b/72-edit-distance.js @@ -23,3 +23,32 @@ const minDistance = function(word1, word2) { } return dp[m][n]; }; + +// another + +/** + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +const minDistance = function(word1, word2) { + const m = word1.length, n = word2.length + const dp = Array(n + 1).fill(0) + for(let i = 1; i <= n; i++) dp[i] = i + let pre = 0 + for(let i = 1; i <= m; i++) { + pre = dp[0] + dp[0] = i + for(let j = 1; j <= n; j++) { + let tmp = dp[j] + if(word1[i - 1] === word2[j - 1]) { + dp[j] = pre + } else { + dp[j] = Math.min(pre, dp[j], dp[j - 1]) + 1 + } + pre = tmp + } + } + + return dp[n] +}; diff --git a/720-longest-word-in-dictionary.js b/720-longest-word-in-dictionary.js new file mode 100644 index 00000000..d1dce3a4 --- /dev/null +++ b/720-longest-word-in-dictionary.js @@ -0,0 +1,18 @@ +/** + * @param {string[]} words + * @return {string} + */ +const longestWord = function(words) { + if(words == null || words.length === 0) return '' + words.sort() + const s = new Set() + let res = '' + for(let i = 0, len = words.length; i < len; i++) { + const w = words[i] + if(w.length === 1 || s.has(w.slice(0, w.length - 1))) { + res = w.length > res.length ? w : res + s.add(w) + } + } + return res +}; diff --git a/721-accounts-merge.js b/721-accounts-merge.js new file mode 100644 index 00000000..f4a0be07 --- /dev/null +++ b/721-accounts-merge.js @@ -0,0 +1,35 @@ +/** + * @param {string[][]} accounts + * @return {string[][]} + */ +const accountsMerge = function (accounts) { + const roots = new Set() + const owner = {} + const parent = {} + const children = {} + + for (let account of accounts) { + let [user, root, ...emails] = account + let r1 = find(root) + owner[root] = user + children[r1] = children[r1] || [root] + roots.add(r1) + + for (let email of emails) { + let r2 = find(email) + if (r2 !== r1) { + parent[r2] = r1 + children[r1].push(...(children[r2] ? children[r2] : [email])) + roots.delete(r2) + delete children[r2] + } + } + } + + return [...roots].map((r) => [owner[r], ...children[r].sort()]) + + function find(a) { + parent[a] = parent[a] || a + return a === parent[a] ? a : find(parent[a]) + } +} diff --git a/722-remove-comments.js b/722-remove-comments.js new file mode 100644 index 00000000..901cc15d --- /dev/null +++ b/722-remove-comments.js @@ -0,0 +1,28 @@ +/** + * @param {string[]} source + * @return {string[]} + */ +const removeComments = function (source) { + const code = source.join('\n') + const isBlockStart = (c, i) => c[i] === '/' && c[i + 1] === '*' + const isBlockEnd = (c, i) => c[i] === '*' && c[i + 1] === '/' + const isLineStart = (c, i) => c[i] === '/' && c[i + 1] === '/' + const isNewLine = (c, i) => c[i] === '\n' + let i = 0, + output = '' + + while (i < code.length) { + if (isBlockStart(code, i)) { + i += 2 + while (!isBlockEnd(code, i) && i < code.length) i++ + i += 2 + } else if (isLineStart(code, i)) { + i += 2 + while (!isNewLine(code, i) && i < code.length) i++ + } else { + output += code[i++] + } + } + + return output.split('\n').filter((l) => l.length) +} diff --git a/723-candy-crush.js b/723-candy-crush.js new file mode 100644 index 00000000..1d5f7f56 --- /dev/null +++ b/723-candy-crush.js @@ -0,0 +1,139 @@ +/** + * @param {number[][]} board + * @return {number[][]} + */ +const candyCrush = function (board) { + while (true) { + let moreToCrush = false + for (let i = 0; i < board.length; i++) { + for (let j = 0; j < board[0].length; j++) { + if (board[i][j] > 0) { + moreToCrush = + flagForCrush(board, i, j, board[i][j], 0, true, false) || + moreToCrush + moreToCrush = + flagForCrush(board, i, j, board[i][j], 0, false, true) || + moreToCrush + } + } + } + if (!moreToCrush) break + crush(board) + inflictGravity(board) + } + return board +} +const flagForCrush = function (board, i, j, target, count, right, down) { + if ( + j === board[0].length || + i === board.length || + Math.abs(board[i][j]) !== Math.abs(target) + ) { + return count >= 3 + } + + let shouldFlagIndexRight = flagForCrush( + board, + i, + j + 1, + target, + right ? count + 1 : 1, + true, + false + ) + let shouldFlagIndexDown = flagForCrush( + board, + i + 1, + j, + target, + down ? count + 1 : 1, + false, + true + ) + + if ((shouldFlagIndexRight && right) || (shouldFlagIndexDown && down)) { + board[i][j] = -Math.abs(board[i][j]) + return true + } + + return false +} +const crush = function (board) { + for (let i = 0; i < board.length; i++) { + for (let j = 0; j < board[0].length; j++) { + if (board[i][j] < 0) board[i][j] = 0 + } + } +} +const inflictGravity = function (board) { + for (let j = 0; j < board[0].length; j++) { + let st = board.length - 1 + let end = board.length - 2 + while (end >= 0) { + if (board[st][j] === 0 && board[end][j] !== 0) { + let temp = board[st][j] + board[st][j] = board[end][j] + board[end][j] = temp + st-- + } else if (board[st][j] !== 0) { + st-- + } + end-- + } + } +} + +// another + +/** + * @param {number[][]} board + * @return {number[][]} + */ +const candyCrush = function (board) { + const N = board.length, + M = board[0].length + let found = true + while (found) { + found = false + for (let i = 0; i < N; i++) { + for (let j = 0; j < M; j++) { + const val = Math.abs(board[i][j]) + if (val === 0) continue + if ( + j < M - 2 && + Math.abs(board[i][j + 1]) === val && + Math.abs(board[i][j + 2]) === val + ) { + found = true + let ind = j + while (ind < Math.min(M, j + 3) && Math.abs(board[i][ind]) === val) + board[i][ind++] = -val + } + if ( + i < N - 2 && + Math.abs(board[i + 1][j]) === val && + Math.abs(board[i + 2][j]) === val + ) { + found = true + let ind = i + while (ind < Math.min(N, i + 3) && Math.abs(board[ind][j]) === val) + board[ind++][j] = -val + } + } + } + if (found) { + // move positive values to the bottom, then set the rest to 0 + for (let j = 0; j < M; j++) { + let storeInd = N - 1 + for (let i = N - 1; i >= 0; i--) { + if (board[i][j] > 0) { + board[storeInd--][j] = board[i][j] + } + } + for (let k = storeInd; k >= 0; k--) board[k][j] = 0 + } + } + } + return board +} + diff --git a/727-minimum-window-subsequence.js b/727-minimum-window-subsequence.js new file mode 100644 index 00000000..635bc00f --- /dev/null +++ b/727-minimum-window-subsequence.js @@ -0,0 +1,162 @@ +/** + * @param {string} s1 + * @param {string} s2 + * @return {string} + */ +const minWindow = function (s1, s2) { + const S = s1,T=s2 + let m = T.length, n = S.length; + let dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); + for (let j = 0; j <= n; j++) { + dp[0][j] = j + 1; + } + for (let i = 1; i <= m; i++) { + for (let j = 1; j <= n; j++) { + if (T.charAt(i - 1) == S.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1]; + } else { + dp[i][j] = dp[i][j - 1]; + } + } + } + + let start = 0, len = n + 1; + for (let j = 1; j <= n; j++) { + if (dp[m][j] != 0) { + if (j - dp[m][j] + 1 < len) { + start = dp[m][j] - 1; + len = j - dp[m][j] + 1; + } + } + } + return len == n + 1 ? "" : S.substring(start, start + len); +} + +// another + +/** + * @param {string} s1 + * @param {string} s2 + * @return {string} + */ +const minWindow = function (s1, s2) { + let n1 = s1.length, + n2 = s2.length, + s1Idx = 0, + s2Idx = 0, + start = -1, + len = n1 + 1 + while (s1Idx < n1) { + if (s1[s1Idx] === s2[s2Idx]) { + if (s2Idx === n2 - 1) { + const end = s1Idx + while (s2Idx >= 0) { + while (s1[s1Idx] !== s2[s2Idx]) s1Idx-- + s2Idx-- + s1Idx-- + } + const tmp = end - s1Idx + if (tmp < len) { + len = tmp + start = s1Idx + 1 + } + s2Idx++ + s1Idx += 2 + } else { + s2Idx++ + s1Idx++ + } + } else s1Idx++ + } + return start === -1 ? '' : s1.slice(start, start + len) +} + +// another + +/** + * @param {string} s1 + * @param {string} s2 + * @return {string} + */ +const minWindow = function(s1, s2) { + let res = '', n = s1.length, m = s2.length + if(s1 === '' || s2 === '') return res + let minLen = Infinity + let right = 0 + while(right < n) { + let tIndex = 0 + while(right < n) { + if(s1[right] === s2[tIndex]) tIndex++ + if(tIndex === m) break + right++ + } + if(right === n) break + let left = right + tIndex = m - 1 + while(left >= 0) { + if(s1[left] === s2[tIndex]) { + tIndex-- + } + if(tIndex < 0) break + left-- + } + + if(right - left + 1 < minLen) { + minLen = right - left + 1 + res = s1.slice(left, right + 1) + } + right = left + 1 + } + + return res +}; + +// another + +/** + * @param {string} S + * @param {string} T + * @return {string} + */ +const minWindow = function (S, T) { + if (S.length === 0 || T.length === 0) { + return '' + } + let right = 0 + let minLen = Number.MAX_VALUE + let result = '' + while (right < S.length) { + let tIndex = 0 + while (right < S.length) { + if (S.charAt(right) === T.charAt(tIndex)) { + tIndex++ + } + if (tIndex === T.length) { + break + } + right++ + } + if (right === S.length) { + break + } + let left = right + tIndex = T.length - 1 + while (left >= 0) { + if (S.charAt(left) === T.charAt(tIndex)) { + tIndex-- + } + if (tIndex < 0) { + break + } + left-- + } + if (right - left + 1 < minLen) { + minLen = right - left + 1 + result = S.slice(left, right + 1) + } + // we have to move right pointer to the next position of left pointer, NOT the next position + // of right pointer + right = left + 1 + } + return result +} diff --git a/729-my-calendar-i.js b/729-my-calendar-i.js new file mode 100644 index 00000000..22425c94 --- /dev/null +++ b/729-my-calendar-i.js @@ -0,0 +1,74 @@ +const MyCalendar = function () { + this.root = null +} + +const Node = function (start, end) { + this.start = start + this.end = end + this.left = null + this.right = null +} + +Node.prototype.insert = function (node) { + if (node.start >= this.end) { + if (this.right === null) { + this.right = node + return true + } + return this.right.insert(node) + } else if (node.end <= this.start) { + if (this.left === null) { + this.left = node + return true + } + return this.left.insert(node) + } else { + return false + } +} + +/** + * @param {number} start + * @param {number} end + * @return {boolean} + */ +MyCalendar.prototype.book = function (start, end) { + const newNode = new Node(start, end) + if (this.root === null) { + this.root = newNode + return true + } else { + return this.root.insert(newNode) + } +} + +/** + * Your MyCalendar object will be instantiated and called as such: + * var obj = new MyCalendar() + * var param_1 = obj.book(start,end) + */ + +// another + +const MyCalendar = function() { + this.s = new Set() +}; + +/** + * @param {number} start + * @param {number} end + * @return {boolean} + */ +MyCalendar.prototype.book = function(start, end) { + for(let e of this.s) { + if(Math.max(start, e[0]) < Math.min(end, e[1])) return false + } + this.s.add([start, end]) + return true +}; + +/** + * Your MyCalendar object will be instantiated and called as such: + * var obj = new MyCalendar() + * var param_1 = obj.book(start,end) + */ diff --git a/731-my-calendar-ii.js b/731-my-calendar-ii.js new file mode 100644 index 00000000..056a06cc --- /dev/null +++ b/731-my-calendar-ii.js @@ -0,0 +1,32 @@ +const MyCalendarTwo = function () { + this.calendar = [] + this.overlaps = [] +} + +/** + * @param {number} start + * @param {number} end + * @return {boolean} + */ +MyCalendarTwo.prototype.book = function (start, end) { + for (let i = 0; i < this.overlaps.length; i++) { + if (start < this.overlaps[i].end && end > this.overlaps[i].start) + return false + } + + for (let i = 0; i < this.calendar.length; i++) { + if (start < this.calendar[i].end && end > this.calendar[i].start) + this.overlaps.push({ + start: Math.max(start, this.calendar[i].start), + end: Math.min(end, this.calendar[i].end), + }) + } + this.calendar.push({ start: start, end: end }) + return true +} + +/** + * Your MyCalendarTwo object will be instantiated and called as such: + * var obj = new MyCalendarTwo() + * var param_1 = obj.book(start,end) + */ diff --git a/732-my-calendar-iii.js b/732-my-calendar-iii.js index 952ba97d..ad5f21cc 100644 --- a/732-my-calendar-iii.js +++ b/732-my-calendar-iii.js @@ -41,3 +41,80 @@ MyCalendarThree.prototype.book = function(start, end) { * var obj = new MyCalendarThree() * var param_1 = obj.book(start,end) */ + +// another + + +var MyCalendarThree = function() { + this.st = new SegmentTree(0, 10 ** 9); +}; + +/** + * @param {number} start + * @param {number} end + * @return {number} + */ +MyCalendarThree.prototype.book = function(start, end) { + this.st.add(start, end); + return this.st.getMax(); +}; + +/** + * Your MyCalendarThree object will be instantiated and called as such: + * var obj = new MyCalendarThree() + * var param_1 = obj.book(start,end) + */ + +class SegmentTree { + constructor(start, end) { + this.root = new TreeNode(start, end); + } + + add(qs, qe, node=this.root) { + + // completely outside of query range + if(qs > node.end || qe <= node.start) { + return node.val; + } + + // completely covered by query range + if(qs <= node.start && qe > node.end) { + node.booked += 1; + node.val += 1; + return node.val; + } + + let mid = (node.start + node.end)/2 >> 0; + + if(!node.left) { + node.left = new TreeNode(node.start, mid); + } + + if(!node.right) { + node.right = new TreeNode(mid+1, node.end); + } + + node.val = Math.max( + this.add(qs, qe, node.left), + this.add(qs, qe, node.right), + ) + node.booked; + + return node.val; + + } + + getMax() { + return this.root.val; + } + +} + +class TreeNode { + constructor(start, end) { + this.start = start; + this.end = end; + this.val = 0; + this.booked = 0; + this.left = this.right = null; + } +} diff --git a/733-flood-fill.js b/733-flood-fill.js new file mode 100644 index 00000000..528c5f6e --- /dev/null +++ b/733-flood-fill.js @@ -0,0 +1,72 @@ +/** + * @param {number[][]} image + * @param {number} sr + * @param {number} sc + * @param {number} newColor + * @return {number[][]} + */ +const floodFill = function(image, sr, sc, newColor, firstColor = image[sr][sc]) { + if ( + sr < 0 || + sc < 0 || + sr >= image.length || + sc >= image[sr].length || + image[sr][sc] !== firstColor || + image[sr][sc] === newColor + ) { + return image + } + + image[sr][sc] = newColor + + floodFill(image, sr + 1, sc, newColor, firstColor) + floodFill(image, sr - 1, sc, newColor, firstColor) + floodFill(image, sr, sc + 1, newColor, firstColor) + floodFill(image, sr, sc - 1, newColor, firstColor) + + return image +} + +// another + +/** + * @param {number[][]} image + * @param {number} sr + * @param {number} sc + * @param {number} newColor + * @return {number[][]} + */ +const floodFill = function ( + image, + sr, + sc, + newColor, + firstColor = image[sr][sc] +) { + const dirs = [0, -1, 0, 1, 0] + const rows = image.length + const cols = image[0].length + const q = [[sr, sc]] + while (q.length) { + const len = q.length + for (let i = 0; i < len; i++) { + const cur = q.shift() + image[cur[0]][cur[1]] = newColor + for (let j = 0; j < 4; j++) { + const [nr, nc] = [cur[0] + dirs[j], cur[1] + dirs[j + 1]] + if ( + nr >= 0 && + nr < rows && + nc >= 0 && + nc < cols && + image[nr][nc] === firstColor && + image[nr][nc] !== newColor + ) { + q.push([nr, nc]) + } + } + } + } + return image +} + diff --git a/734-sentence-similarity.js b/734-sentence-similarity.js new file mode 100644 index 00000000..af0b37d5 --- /dev/null +++ b/734-sentence-similarity.js @@ -0,0 +1,26 @@ +/** + * @param {string[]} words1 + * @param {string[]} words2 + * @param {string[][]} pairs + * @return {boolean} + */ +const areSentencesSimilar = function(words1, words2, pairs) { + if(pairs == null || pairs.length === 0) { + if(words1.length === words2.length) return true + return false + } + const m = new Map() + for(let p of pairs) { + if(!m.has(p[0])) m.set(p[0], new Set()) + m.get(p[0]).add(p[1]) + if(!m.has(p[1])) m.set(p[1], new Set()) + m.get(p[1]).add(p[0]) + } + for(let i = 0, len = Math.max(words1.length, words2.length); i < len; i++) { + const c1 = words1[i] + const c2 = words2[i] + if( c1 === c2 ) continue + if( !(m.has(c1) && m.get(c1).has(c2)) ) return false + } + return true +}; diff --git a/735-asteroid-collision.js b/735-asteroid-collision.js index 35b768f7..f48a26b0 100644 --- a/735-asteroid-collision.js +++ b/735-asteroid-collision.js @@ -1,3 +1,25 @@ +/** + * @param {number[]} asteroids + * @return {number[]} + */ +const asteroidCollision = function(asteroids) { + const stk = [], n = asteroids.length, {abs} = Math + for(const e of asteroids) { + while(stk.length && stk.at(-1) > 0 && e < 0 && -e > stk.at(-1)) { + stk.pop() + } + if(stk.length && stk.at(-1) > 0 && e < 0 && -e === stk.at(-1)) { + stk.pop() + }else if(stk.length && stk.at(-1) > 0 && e < 0 && -e < stk.at(-1)) { + + }else stk.push(e) + } + return stk +}; + +// another + + /** * @param {number[]} asteroids * @return {number[]} diff --git a/736-parse-lisp-expression.js b/736-parse-lisp-expression.js new file mode 100644 index 00000000..71dd2132 --- /dev/null +++ b/736-parse-lisp-expression.js @@ -0,0 +1,119 @@ +/** + * @param {string} expression + * @return {number} + */ +const evaluate = (x) => + e( + JSON.parse( + x.replace(/[() ]|([a-z][a-z0-9]*)/g, (m) => + m === '(' ? '[' : m === ')' ? ']' : m === ' ' ? ',' : `"${m}"` + ) + ) + ) +const e = (x, v = []) => + ({ + string: () => v.find((y) => y[0] === x)[1], + number: () => x, + object: () => + ({ + add: () => e(x[1], v) + e(x[2], v), + mult: () => e(x[1], v) * e(x[2], v), + let: () => + e( + x[x.length - 1], + x + .slice(1, -1) + .reduce( + ({ v, t }, z) => + t ? { v: [[t, e(z, v)], ...v] } : { v, t: z }, + { v } + ).v + ), + }[x[0]]()), + }[typeof x]()) + +// another + +/** + * @param {string} expression + * @return {number} + */ +const evaluate = function (expression) { + const tokens = tokenizer(expression) + let i = 0 + function exec(scope) { + let value = null + const next = tokens[i++] + if (next === '(') { + scope = enter(scope) + switch (tokens[i++]) { + case 'add': + const a = exec(scope) + const b = exec(scope) + value = a + b + break + case 'mult': + const x = exec(scope) + const y = exec(scope) + value = x * y + break + case 'let': + while (tokens[i] !== '(' && tokens[i + 1] !== ')') { + scope.variables[tokens[i++]] = exec(scope) + } + value = exec(scope) + break + } + scope = exit(scope) + i++ + } else if (isNumber(next)) { + value = Number(next) + } else { + // Find variable in current scope otherwise go to parent + let t = scope + while (t) { + if (next in t.variables) { + value = t.variables[next] + break + } + t = t.parent + } + } + return value + } + return exec(newScope()) +} +function tokenizer(expression) { + const tokens = [] + let token = '' + for (const c of expression) { + if (c === '(' || c === ')') { + if (token) tokens.push(token) + tokens.push(c) + token = '' + } else if (c === ' ') { + if (token) tokens.push(token) + token = '' + } else { + token += c + } + } + if (token) { + tokens.push(token) + } + return tokens +} +function isNumber(n) { + return !isNaN(n) +} +function newScope() { + return { parent: null, variables: {} } +} +function enter(scope) { + const next = newScope() + next.parent = scope + return next +} +function exit(scope) { + return scope.parent +} diff --git a/737-sentence-similarity-ii.js b/737-sentence-similarity-ii.js new file mode 100644 index 00000000..e0448540 --- /dev/null +++ b/737-sentence-similarity-ii.js @@ -0,0 +1,27 @@ +/** + * @param {string[]} words1 + * @param {string[]} words2 + * @param {string[][]} pairs + * @return {boolean} + */ +const areSentencesSimilarTwo = function (words1, words2, pairs) { + if (words1.length !== words2.length) return false + const parent = {} + + function getParent(word) { + if (parent[word] === undefined || parent[word] === word) return word + return getParent(parent[word]) + } + for (let [w1, w2] of pairs) { + if (w1 > w2) [w1, w2] = [w2, w1] + parent[w1] = getParent(w1) + if (parent[w2] !== undefined) parent[getParent(w2)] = parent[w1] + parent[w2] = parent[w1] + } + for (let i = 0; i < words1.length; i++) { + let w1 = words1[i] + let w2 = words2[i] + if (getParent(w1) !== getParent(w2)) return false + } + return true +} diff --git a/740-delete-and-earn.js b/740-delete-and-earn.js new file mode 100644 index 00000000..eab5407a --- /dev/null +++ b/740-delete-and-earn.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const deleteAndEarn = function (nums) { + const n = 10001 + const values = new Array(n).fill(0) + for (let num of nums) values[num] += num + + let take = 0, + skip = 0 + for (let i = 0; i < n; i++) { + const takei = skip + values[i] + const skipi = Math.max(skip, take) + take = takei + skip = skipi + } + return Math.max(take, skip) +} diff --git a/741-cherry-pickup.js b/741-cherry-pickup.js new file mode 100644 index 00000000..7bb78790 --- /dev/null +++ b/741-cherry-pickup.js @@ -0,0 +1,66 @@ +/** + +In a N x N grid representing a field of cherries, each cell is one of three possible integers. + +0 means the cell is empty, so you can pass through; +1 means the cell contains a cherry, that you can pick up and pass through; +-1 means the cell contains a thorn that blocks your way. + +Your task is to collect maximum number of cherries possible by following the rules below: + +Starting at the position (0, 0) and reaching (N-1, N-1) by moving right or down through valid +path cells (cells with value 0 or 1); +After reaching (N-1, N-1), returning to (0, 0) by moving left or up through valid path cells; +When passing through a path cell containing a cherry, you pick it up and the cell becomes an empty cell (0); +If there is no valid path between (0, 0) and (N-1, N-1), then no cherries can be collected. + +Example 1: + +Input: grid = +[[0, 1, -1], + [1, 0, -1], + [1, 1, 1]] +Output: 5 +Explanation: +The player started at (0, 0) and went down, down, right right to reach (2, 2). +4 cherries were picked up during this single trip, and the matrix becomes [[0,1,-1],[0,0,-1],[0,0,0]]. +Then, the player went left, up, up, left to return home, picking up one more cherry. +The total number of cherries picked up is 5, and this is the maximum possible. + +Note: + +grid is an N by N 2D array, with 1 <= N <= 50. +Each grid[i][j] is an integer in the set {-1, 0, 1}. +It is guaranteed that grid[0][0] and grid[N-1][N-1] are not -1. + +*/ + +/** + * @param {number[][]} grid + * @return {number} + */ +const cherryPickup = grid => { + const n = grid.length + const dp = [...new Array(n)].map(() => + [...new Array(n)].map(() => Array(n).fill(-Infinity)) + ) + dp[0][0][0] = grid[0][0] + const go = (x1, y1, x2) => { + const y2 = x1 + y1 - x2 + if (x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0) return -1 + if (grid[y1][x1] === -1 || grid[y2][x2] === -1) return -1 + if (dp[y1][x1][x2] !== -Infinity) return dp[y1][x1][x2] + dp[y1][x1][x2] = Math.max( + go(x1 - 1, y1, x2 - 1), + go(x1, y1 - 1, x2), + go(x1, y1 - 1, x2 - 1), + go(x1 - 1, y1, x2) + ) + if (dp[y1][x1][x2] >= 0) { + dp[y1][x1][x2] += grid[y1][x1] + if (x1 !== x2) dp[y1][x1][x2] += grid[y2][x2] + } + return dp[y1][x1][x2] + } + return Math.max(0, go(n - 1, n - 1, n - 1)) +} diff --git a/742-closest-leaf-in-a-binary-tree.js b/742-closest-leaf-in-a-binary-tree.js new file mode 100644 index 00000000..8d39ab62 --- /dev/null +++ b/742-closest-leaf-in-a-binary-tree.js @@ -0,0 +1,103 @@ +/** + +Given a binary tree where every node has a unique value, and a target key k, +find the value of the nearest leaf node to target k in the tree. + +Here, nearest to a leaf means the least number of edges travelled on the binary +tree to reach any leaf of the tree. Also, a node is called a leaf if it has no children. + +In the following examples, the input tree is represented in flattened form +row by row. The actual root tree given will be a TreeNode object. + +Example 1: + +Input: +root = [1, 3, 2], k = 1 +Diagram of binary tree: + 1 + / \ + 3 2 + +Output: 2 (or 3) + +Explanation: Either 2 or 3 is the nearest leaf node to the target of 1. +Example 2: + +Input: +root = [1], k = 1 +Output: 1 + +Explanation: The nearest leaf node is the root node itself. +Example 3: + +Input: +root = [1,2,3,4,null,null,null,5,null,6], k = 2 +Diagram of binary tree: + 1 + / \ + 2 3 + / + 4 + / + 5 + / + 6 + +Output: 3 +Explanation: The leaf node with value 3 (and not the leaf node with value 6) +is nearest to the node with value 2. + +Note: +root represents a binary tree with at least 1 node and at most 1000 nodes. +Every node has a unique node.val in range [1, 1000]. +There exists some node in the given binary tree for which node.val == k. + +*/ + + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {number} k + * @return {number} + */ +const findClosestLeaf = function(root, k) { + if (root == null) return -1 + const g = new Map() + dfs(root, null, g) + const q = [] + for (let [key, value] of g) { + if (key.val === k) { + q.push(key, ...g.get(key)) + break + } + } + const s = new Set() + while (q.length) { + const size = q.length + for (let i = 0; i < size; i++) { + const node = q.shift() + if (node.left === null && node.right === null) return node.val + if (!s.has(node)) q.push(...g.get(node)) + s.add(node) + } + } +} + +function dfs(node, parent, g) { + if (node == null) return + if (g.get(node) == null) g.set(node, new Set()) + if (parent) { + g.get(node).add(parent) + if (g.get(parent) == null) g.set(parent, new Set()) + g.get(parent).add(node) + } + dfs(node.left, node, g) + dfs(node.right, node, g) +} diff --git a/743-network-delay-time.js b/743-network-delay-time.js new file mode 100644 index 00000000..893d1432 --- /dev/null +++ b/743-network-delay-time.js @@ -0,0 +1,306 @@ +/** + * @param {number[][]} times + * @param {number} n + * @param {number} k + * @return {number} + */ +const networkDelayTime = function(times, n, k) { + const g = Array.from({ length: n + 1 }, () => Array(n + 1).fill(Infinity)) + const graph = {} + for(const [u,v,w] of times) { + if(graph[u] == null) graph[u] = {} + graph[u][v] = w + g[u][v] = w + } + for(let k = 1; k <= n; k++) { + for(let i = 1; i <= n; i++) { + for(let j = 1; j <= n; j++) { + g[i][j] = Math.min(g[i][j], g[i][k] + g[k][j]) + } + } + } + + let q = [k] + const visited = new Set() + const dis = Array(n + 1).fill(Infinity) + let res = 0 + dis[k] = 0 + // console.log(g) + while(q.length) { + const size = q.length, tmp = [] + for(let i = 0; i < size; i++) { + const e = q[i] + visited.add(e) + for(let nxt of (Object.keys(graph[e] || {}) || [])) { + nxt = +nxt + if(!visited.has(nxt)) { + tmp.push(nxt) + } + if(g[e][nxt]) dis[nxt] = Math.min(dis[nxt], dis[e] + g[e][nxt]) + } + } + + q = tmp + } + // console.log(dis) + for(let i = 1; i <= n; i++) { + if(i === k) continue + res = Math.max(res, dis[i]) + } + + return visited.size === n ? res : -1 +}; + +// another + +/** + * @param {number[][]} times + * @param {number} n + * @param {number} k + * @return {number} + */ +const networkDelayTime = function(times, n, k) { + const graph = {} + for(const [u, v, w] of times) { + if(graph[u] == null) graph[u] = [] + graph[u][v] = w + } + const visited = new Array(n + 1).fill(false) + const pq = new PQ((a, b) => a[0] < b[0]) + pq.push([0, k]) + let res = 0 + while(!pq.isEmpty()) { + const [dist, cur] = pq.pop() + if(visited[cur]) continue + visited[cur] = true + n-- + res = dist + if(graph[cur]) { + for(const nxt of Object.keys(graph[cur])) { + pq.push([res + graph[cur][nxt], nxt]) + } + } + } + return n === 0 ? res : -1 +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number[][]} times + * @param {number} N + * @param {number} K + * @return {number} + */ +const networkDelayTime = function (times, N, K) { + const mins = new Array(N).fill(Infinity) + mins[K - 1] = 0 + for (let i = 0; i < N; i++) { + for (let [u, v, t] of times) { + if (mins[u - 1] === Infinity) continue + if (mins[v - 1] > mins[u - 1] + t) { + mins[v - 1] = mins[u - 1] + t + } + } + } + return mins.includes(Infinity) ? -1 : Math.max(...mins) +} + +// another + +/** + * @param {number[][]} times + * @param {number} N + * @param {number} K + * @return {number} + */ +const networkDelayTime = function(times, N, K) { + const distances = new Array(N).fill(Infinity); + distances[K - 1] = 0; + + for(let i = 0 ; i < N -1 ; i++){ + let counter = 0; + for(let j = 0 ; j < times.length ; j++){ + const source = times[j][0]; + const target = times[j][1]; + const weight = times[j][2]; + if(distances[source - 1] + weight < distances[target - 1]){ + distances[target - 1] = distances[source - 1] + weight; + counter++ + } + } + if(counter === 0) break + } + + const res = Math.max(...distances); + return res === Infinity ? -1 : res; +}; + +// another + +/** + * @param {number[][]} times + * @param {number} N + * @param {number} K + * @return {number} + */ +const networkDelayTime = function (times, N, K) { + const hash = {} + for(const [u, v, t] of times) { + if(hash[u] == null) hash[u] = {} + hash[u][v] = t + } + const pq = new PriorityQueue((a, b) => a[0] < b[0]) + pq.push([0, K]) + const visited = Array.from(N + 1) + let res = 0 + while(!pq.isEmpty()) { + const [dist, cur] = pq.pop() + if(visited[cur]) continue + visited[cur] = true + res = dist + N-- + if(hash[cur]) { + for(let next of Object.keys(hash[cur])) { + pq.push([dist + hash[cur][next], next]) + } + } + } + return N === 0 ? res : -1 +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/744-find-smallest-letter-greater-than-target.js b/744-find-smallest-letter-greater-than-target.js new file mode 100644 index 00000000..a6980a51 --- /dev/null +++ b/744-find-smallest-letter-greater-than-target.js @@ -0,0 +1,17 @@ +/** + * @param {character[]} letters + * @param {character} target + * @return {character} + */ +const nextGreatestLetter = function (letters, target) { + const n = letters.length + if (target < letters[0] || target >= letters[n - 1]) return letters[0] + let left = 0 + let right = n - 1 + while (left < right) { + let mid = left + ((right - left) >> 1) + if (letters[mid] <= target) left = mid + 1 + else right = mid + } + return letters[right] +} diff --git a/745-prefix-and-suffix-search.js b/745-prefix-and-suffix-search.js new file mode 100644 index 00000000..cd283984 --- /dev/null +++ b/745-prefix-and-suffix-search.js @@ -0,0 +1,61 @@ +/** + * @param {string[]} words + */ +const WordFilter = function (words) { + this.trie = new trie() + let val = 0 + for (let word of words) { + /* suffix # prefix */ + let temp = '' + this.trie.insert('#' + word, val) + this.trie.insert(word + '#', val) + for (let i = 0; i < word.length; i++) { + temp = word.substring(i) + temp += '#' + word + this.trie.insert(temp, val) + } + val++ + } +} +/** + * @param {string} prefix + * @param {string} suffix + * @return {number} + */ +WordFilter.prototype.f = function (prefix, suffix) { + return this.trie.startsWith(suffix + '#' + prefix) +} +/** + * Your WordFilter object will be instantiated and called as such: + * var obj = new WordFilter(words) + * var param_1 = obj.f(prefix,suffix) + */ +const trie = function () { + this.map = new Map() + this.isEnd = false + this.val = -1 +} +trie.prototype.insert = function (word, val) { + let temp = this + let i = 0 + while (i < word.length && temp.map.has(word[i])) { + temp.val = Math.max(temp.val, val) + temp = temp.map.get(word[i++]) + } + while (i < word.length) { + let t2 = new trie() + temp.map.set(word[i++], t2) + temp.val = Math.max(temp.val, val) + temp = t2 + } + temp.isEnd = true + temp.val = Math.max(temp.val, val) + return true +} +trie.prototype.startsWith = function (prefix) { + let temp = this + let i = 0 + while (i < prefix.length && temp.map.has(prefix[i])) + temp = temp.map.get(prefix[i++]) + return i >= prefix.length ? temp.val : -1 +} diff --git a/747-largest-number-at-least-twice-of-others.js b/747-largest-number-at-least-twice-of-others.js new file mode 100644 index 00000000..d78a10ef --- /dev/null +++ b/747-largest-number-at-least-twice-of-others.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const dominantIndex = function(nums) { + let max = -Infinity + let idx = -1 + for(let i = 0, len = nums.length; i < len; i++) { + if(nums[i] > max) { + max = nums[i] + idx = i + } + } + for(let i = 0, len = nums.length; i < len; i++) { + if(nums[i] !== max && max < nums[i] * 2) return -1 + } + return idx +}; diff --git a/748-shortest-completing-word.js b/748-shortest-completing-word.js new file mode 100644 index 00000000..b791dcc9 --- /dev/null +++ b/748-shortest-completing-word.js @@ -0,0 +1,65 @@ +/** + * @param {string} licensePlate + * @param {string[]} words + * @return {string} + */ +const shortestCompletingWord = function(licensePlate, words) { + const letters = licensePlate + .replace(/\d/g, '') + .replace(/ /g, '') + .toLowerCase() + .split('') + let matchingWords = words.filter(word => { + let completingWord = true + letters.forEach(letter => { + let letterIndex = word.indexOf(letter) + if (letterIndex > -1) { + let re = new RegExp(letter) + word = word.replace(re, '') + } else { + completingWord = false + } + }) + return completingWord + }) + const wordLengths = matchingWords.map(word => word.length) + return matchingWords[wordLengths.indexOf(Math.min.apply(Math, wordLengths))] +} + +// another + +/** + * @param {string} licensePlate + * @param {string[]} words + * @return {string} + */ +const shortestCompletingWord = function(licensePlate, words) { + licensePlate = licensePlate.toLowerCase() + const plateCount = Array(26).fill(0) + let plateLength = 0 + for (let i = 0; i < licensePlate.length; i += 1) { + const code = licensePlate.charCodeAt(i) + if (code < 97 || code > 122) { + continue + } + plateCount[code - 97] += 1 + plateLength += 1 + } + const longerOrEqualWords = words.filter(word => word.length >= plateLength) + return longerOrEqualWords.reduce((shortest, word) => { + if (shortest && shortest.length <= word.length) { + return shortest + } + const wordCount = Array(26).fill(0) + for (let i = 0; i < word.length; i += 1) { + const code = word.charCodeAt(i) + wordCount[code - 97] += 1 + } + for (let i = 0; i < 26; i += 1) { + if (wordCount[i] - plateCount[i] < 0) { + return shortest + } + } + return word + }, null) +} diff --git a/749-contain-virus.js b/749-contain-virus.js new file mode 100644 index 00000000..7a6bec2c --- /dev/null +++ b/749-contain-virus.js @@ -0,0 +1,261 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const containVirus = function (grid) { + let ans = 0 + while (true) { + const walls = model(grid) + if (walls === 0) break + ans += walls + } + return ans + function model(grid) { + const m = grid.length, + n = grid[0].length + const virus = [], + toInfect = [] + const visited = Array.from({ length: m }, () => Array(n).fill(0)) + const walls = [] + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] === 1 && visited[i][j] === 0) { + virus.push(new Set()) + toInfect.push(new Set()) + walls.push([0]) + dfs( + grid, + visited, + virus[virus.length - 1], + toInfect[toInfect.length - 1], + walls[walls.length - 1], + i, + j + ) + } + } + } + let maxArea = 0, + idx = -1 + for (let i = 0; i < toInfect.length; i++) { + if (toInfect[i].size > maxArea) { + maxArea = toInfect[i].size + idx = i + } + } + if (idx === -1) return 0 + for (let i = 0; i < toInfect.length; i++) { + if (i !== idx) { + for (let key of toInfect[i]) grid[(key / n) >> 0][key % n] = 1 + } else { + for (let key of virus[i]) grid[(key / n) >> 0][key % n] = -1 + } + } + return walls[idx][0] + } + function dfs(grid, visited, virus, toInfect, wall, row, col) { + const m = grid.length, + n = grid[0].length + if (row < 0 || row >= m || col < 0 || col >= n || visited[row][col] === 1) + return + if (grid[row][col] === 1) { + visited[row][col] = 1 + virus.add(row * n + col) + const dir = [0, -1, 0, 1, 0] + for (let i = 0; i < 4; i++) + dfs( + grid, + visited, + virus, + toInfect, + wall, + row + dir[i], + col + dir[i + 1] + ) + } else if (grid[row][col] === 0) { + wall[0]++ + toInfect.add(row * n + col) + } + } +} + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const containVirus = (grid) => { + const m = grid.length; + const n = grid[0].length; + let ans = 0; + while (true) { + // list of regions can spread virus + const regions = []; + const visited = Array.from({ length: m }, () => Array(n).fill(false)); + for (let i = 0; i < m; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] === 1 && !visited[i][j]) { + const region = new Region(); + dfs(grid, i, j, region, visited); + if (region.uninfected.size > 0) regions.push(region); + } + } + } + + if (regions.length === 0) break; + regions.sort((a, b) => a.uninfected.size - b.uninfected.size); + let idx = -1, wall = -Infinity + for(let i = 0, len = regions.length; i < len; i++) { + if(regions[i].uninfected.size > wall) { + wall = regions[i].uninfected.size + idx = i + } + } + const mostToBeInfected = regions[idx] + ans += mostToBeInfected.wallNeeded + regions.splice(idx, 1) + for (let x of mostToBeInfected.infected) { + let i = (x / n) >> 0, + j = x % n; + grid[i][j] = 2; + } + + for (let region of regions) { + for (let x of region.uninfected) { + let i = (x / n) >> 0, + j = x % n; + grid[i][j] = 1; + } + } + } + + return ans; + function dfs(grid, i, j, region, visited) { + if (i < 0 || i == m || j < 0 || j == n) return; + + if (grid[i][j] === 1 && !visited[i][j]) { + visited[i][j] = true; + region.infected.add(i * n + j); + dfs(grid, i - 1, j, region, visited); + dfs(grid, i + 1, j, region, visited); + dfs(grid, i, j - 1, region, visited); + dfs(grid, i, j + 1, region, visited); + } else if (grid[i][j] === 0) { + region.wallNeeded += 1; + region.uninfected.add(i * n + j); + } + } +}; +class Region { + constructor() { + this.wallNeeded = 0; + this.infected = new Set(); + this.uninfected = new Set(); + } +} + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const containVirus = function (grid) { + const infected = 1 + const healthy = 0 + const quarantined = 2 + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ] + const mod = 100 + const encode = (row, col) => row + col * mod + const decode = (num) => [num % mod, Math.floor(num / mod)] + const disjointSet = {} + for (let row = 0; row < grid.length; row++) { + for (let col = 0; col < grid[row].length; col++) { + const coord = encode(row, col) + disjointSet[coord] = coord + if (grid[row][col] === 0) continue + if (grid[row][col - 1] === 1) union(coord, encode(row, col - 1)) + if (row > 0 && grid[row - 1][col] === 1) + union(coord, encode(row - 1, col)) + } + } + let numWalls = 0 + while (true) { + const impact = quarantineAndContaminate() + if (impact === 0) return numWalls + numWalls += impact + spreadVirus() + } + function find(coord) { + return (disjointSet[coord] = + disjointSet[coord] === coord ? coord : find(disjointSet[coord])) + } + function union(coord, toCoord) { + return (disjointSet[find(coord)] = find(toCoord)) + } + function quarantineAndContaminate() { + const impact = new Map() + for (let row = 0; row < grid.length; row++) { + for (let col = 0; col < grid[row].length; col++) { + if (grid[row][col] !== infected) continue + const root = find(encode(row, col)) + if (!impact.has(root)) impact.set(root, new Set()) + for (let [down, right] of directions) { + if (grid[row + down] && grid[row + down][col + right] === healthy) { + impact.get(root).add(encode(row + down, col + right)) + } + } + } + } + let impactedCoords = new Set() + let root = null + for (let [node, coords] of impact) { + if (impactedCoords.size < coords.size) { + impactedCoords = coords + root = node + } + } + if (impactedCoords.size === 0) return 0 + return quarantine(...decode(root)) + } + function quarantine(row, col) { + if (row < 0 || row >= grid.length || col < 0 || col >= grid[0].length) + return 0 + if (grid[row][col] === 2) return 0 + if (grid[row][col] === 0) return 1 + let totalWalls = 0 + grid[row][col] = 2 + for (let [down, right] of directions) { + totalWalls += quarantine(row + down, col + right) + } + return totalWalls + } + function spreadVirus() { + const infectedCoords = new Set() + for (let row = 0; row < grid.length; row++) { + for (let col = 0; col < grid[row].length; col++) { + if (grid[row][col] !== healthy) continue + for (let [down, right] of directions) { + if (grid[row + down] && grid[row + down][col + right] === infected) { + infectedCoords.add(encode(row, col)) + } + } + } + } + for (let coord of infectedCoords) { + const [row, col] = decode(coord) + grid[row][col] = 1 + for (let [down, right] of directions) { + if (grid[row + down] && grid[row + down][col + right] === 1) { + union(coord, encode(row + down, col + right)) + } + } + } + } +} diff --git a/75-sort-colors.js b/75-sort-colors.js index b7252716..0aaa56b4 100644 --- a/75-sort-colors.js +++ b/75-sort-colors.js @@ -2,23 +2,19 @@ * @param {number[]} nums * @return {void} Do not return anything, modify nums in-place instead. */ - const sortColors = function(nums) { - let i = 0 - let j = 0 - for(let k = 0; k < nums.length; k++) { - let v = nums[k] - nums[k] = 2 - if(v < 2) { - nums[j] = 1 - j += 1 - } - - if(v === 0) { - nums[i] = 0 - i += 1 - } + let j = 0; + let k = nums.length - 1; + const swap = (a, b) => { + const t = nums[a]; + nums[a] = nums[b]; + nums[b] = t; + }; + for (let i = 0; i <= k; i++) { + if (nums[i] === 2) { + swap(i--, k--); + } else if (nums[i] === 0) { + swap(i, j++); } - - return nums; + } }; diff --git a/750-number-of-corner-rectangles.js b/750-number-of-corner-rectangles.js new file mode 100644 index 00000000..8f21c4a9 --- /dev/null +++ b/750-number-of-corner-rectangles.js @@ -0,0 +1,54 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const countCornerRectangles = function (grid) { + let ans = 0 + for (let i = 0; i < grid.length - 1; i++) { + for (let j = i + 1; j < grid.length; j++) { + let counter = 0 + for (let k = 0; k < grid[0].length; k++) { + if (grid[i][k] === 1 && grid[j][k] === 1) counter++ + } + ans += (counter * (counter - 1)) / 2 + } + } + return ans +} + +// another + +// optimized + +/** + * @param {number[][]} grid + * @return {number} + */ +const countCornerRectangles = function (grid) { + let ans = 0 + let largeLoopLen, smLoopLen, r + if(grid.length > grid[0].length) { + r = false + largeLoopLen = grid.length + smLoopLen = grid[0].length + } else { + r = true + largeLoopLen = grid[0].length + smLoopLen = grid.length + } + for (let i = 0; i < smLoopLen - 1; i++) { + for (let j = i + 1; j < smLoopLen; j++) { + let counter = 0 + for (let k = 0; k < largeLoopLen; k++) { + if(r) { + if (grid[i][k] === 1 && grid[j][k] === 1) counter++ + } else { + if (grid[k][i] === 1 && grid[k][j] === 1) counter++ + } + + } + ans += (counter * (counter - 1)) / 2 + } + } + return ans +} diff --git a/751-ip-to-cidr.js b/751-ip-to-cidr.js new file mode 100644 index 00000000..2ff6ac3c --- /dev/null +++ b/751-ip-to-cidr.js @@ -0,0 +1,21 @@ +/** + * @param {string} ip + * @param {number} n + * @return {string[]} + */ +const ipToCIDR = function (ip, n) { + const ipToLong = (ip) => + ip.split('.').reduce((acc, x) => 256 * acc + parseInt(x), 0) + const longToIp = (long) => + [24, 16, 8, 0].map((i) => (long >>> i) % 256).join('.') + const bitLength = (num) => Math.floor(Math.log2(num)) + 1 + const ans = [] + let long = ipToLong(ip) + while (n) { + let mask = Math.max(33 - bitLength(long & -long), 33 - bitLength(n)) + ans.push(longToIp(long) + '/' + mask) + long += 1 << (32 - mask) + n -= 1 << (32 - mask) + } + return ans +} diff --git a/755-pour-water.js b/755-pour-water.js new file mode 100644 index 00000000..1cacf38d --- /dev/null +++ b/755-pour-water.js @@ -0,0 +1,56 @@ +/** + * @param {number[]} heights + * @param {number} V + * @param {number} K + * @return {number[]} + */ +const pourWater = function (heights, V, K) { + if (!V) return heights + let bottom = K + //iterate through from k to find thee lowest bottom + for (let i = K; i >= 0; i--) { + if (heights[i] > heights[bottom]) break + if (heights[i] < heights[bottom]) bottom = i + } + //if bottom is not k increase height of bottom + //and run again but decrease water droplet V by one + if (bottom !== K) { + heights[bottom]++ + return pourWater(heights, V - 1, K) + } + for (let i = K + 1; i < heights.length; i++) { + if (heights[i] > heights[bottom]) break + if (heights[i] < heights[bottom]) bottom = i + } + heights[bottom]++ + return pourWater(heights, V - 1, K) +} + +// another + +/** + * @param {number[]} heights + * @param {number} V + * @param {number} K + * @return {number[]} + */ +const pourWater = function (heights, V, K) { + let cur = K + for (let i = 0; i < V; i++) { + // Move left + while (cur > 0 && heights[cur - 1] <= heights[cur]) { + cur-- + } + // Move right + while (cur < heights.length - 1 && heights[cur + 1] <= heights[cur]) { + cur++ + } + // Move left to K + while(cur > K && heights[cur - 1] === heights[cur]) { + cur-- + } + heights[cur]++ + } + return heights +} + diff --git a/756-pyramid-transition-matrix.js b/756-pyramid-transition-matrix.js new file mode 100644 index 00000000..2ff7aac8 --- /dev/null +++ b/756-pyramid-transition-matrix.js @@ -0,0 +1,23 @@ +/** + * @param {string} bottom + * @param {string[]} allowed + * @return {boolean} + */ +const pyramidTransition = function (bottom, allowed) { + const m = new Map() + for (let e of allowed) { + const p = e.slice(0, 2) + if (!m.has(p)) m.set(p, new Set()) + m.get(p).add(e[2]) + } + return dfs(bottom, '', m, 0) +} + +function dfs(row, next, m, i) { + if (row.length === 1) return true + if (next.length + 1 === row.length) return dfs(next, '', m, 0) + for (let c of m.get(row.slice(i, i + 2)) || new Set()) + if (dfs(row, next + c, m, i + 1)) return true + return false +} + diff --git a/757-set-intersection-size-at-least-two.js b/757-set-intersection-size-at-least-two.js index 6f7b7eea..6ee71d49 100644 --- a/757-set-intersection-size-at-least-two.js +++ b/757-set-intersection-size-at-least-two.js @@ -1,3 +1,62 @@ +/** + * @param {number[][]} intervals + * @return {number} + */ +var intersectionSizeTwo = function(intervals) { + intervals.sort((a, b) => a[1] === b[1] ? b[0] - a[0] : a[1] - b[1]); + let res = 2 + let a = intervals[0][1] - 1, b = intervals[0][1] + + for(const [s, e] of intervals) { + if(s <= a) continue + else if(s <= b) { + res++ + a = b + b = e + } else { + res += 2 + a = e - 1 + b = e + } + } + + return res +}; + +// another + + +/** + * @param {number[][]} intervals + * @return {number} + */ +const intersectionSizeTwo = function (intervals) { + if (intervals.length === 1) return 2 + intervals.sort((a, b) => (a[1] !== b[1] ? a[1] - b[1] : b[0] - a[0])) + let right = intervals[0][1] + let left = right - 1 + let res = 2 + + for (let i = 1, len = intervals.length; i < len; i++) { + const cur = intervals[i] + if(cur[0] <= left) continue + else if(cur[0] <= right) { + res++ + left = right + right = cur[1] + } else { + res += 2 + right = cur[1] + left = right - 1 + } + } + + return res +} + +// another + + /** * @param {number[][]} intervals * @return {number} @@ -52,3 +111,32 @@ const intersectionSizeTwo = function(intervals) { } return count; }; + +// another + +/** + * @param {number[][]} intervals + * @return {number} + */ +const intersectionSizeTwo = function (intervals) { + if (intervals.length === 1) return 2 + intervals.sort((a, b) => (a[1] !== b[1] ? a[1] - b[1] : b[0] - a[0])) + let right = intervals[0][1] + let left = right - 1 + let result = 2 + for (let i = 1, len = intervals.length; i < len; i++) { + const curr = intervals[i] + if (curr[0] <= right && curr[0] > left) { + result++ + left = right + right = curr[1] + } else if (curr[0] > right) { + result += 2 + left = curr[1] - 1 + right = curr[1] + } + } + + return result +} + diff --git a/758-bold-words-in-string.js b/758-bold-words-in-string.js new file mode 100644 index 00000000..402183ff --- /dev/null +++ b/758-bold-words-in-string.js @@ -0,0 +1,29 @@ +/** + * @param {string[]} words + * @param {string} S + * @return {string} + */ +const boldWords = function (words, S) { + const arr = new Array(S.length).fill(false) + for(let w of words) { + for(let i = 0, len = S.length - w.length; i <= len; i++) { + const tmp = S.slice(i) + if(tmp && tmp.startsWith(w)) { + for(let j = i; j < i + w.length; j++) { + arr[j] = true + } + } + } + } + let res = '' + for(let i = 0, len = S.length; i < len; i++) { + if(arr[i] && (i === 0 || !arr[i - 1])) { + res += '' + } + res += S[i] + if(arr[i] && (i === len - 1 || !arr[i + 1])) { + res += '' + } + } + return res +} diff --git a/759-employee-free-time.js b/759-employee-free-time.js new file mode 100644 index 00000000..1bb666d6 --- /dev/null +++ b/759-employee-free-time.js @@ -0,0 +1,181 @@ +/** + +We are given a list schedule of employees, which represents the working time for each employee. + +Each employee has a list of non-overlapping Intervals, and these intervals are in sorted order. + +Return the list of finite intervals representing common, positive-length free time for all employees, +also in sorted order. + +(Even though we are representing Intervals in the form [x, y], the objects inside are Intervals, +not lists or arrays. For example, schedule[0][0].start = 1, schedule[0][0].end = 2, +and schedule[0][0][0] is not defined). Also, we wouldn't include intervals like [5, 5] in our answer, +as they have zero length. + +Example 1: + +Input: schedule = [[[1,2],[5,6]],[[1,3]],[[4,10]]] +Output: [[3,4]] +Explanation: There are a total of three employees, and all common +free time intervals would be [-inf, 1], [3, 4], [10, inf]. +We discard any intervals that contain inf as they aren't finite. +Example 2: + +Input: schedule = [[[1,3],[6,7]],[[2,4]],[[2,5],[9,12]]] +Output: [[5,6],[7,9]] + +Constraints: + +1 <= schedule.length , schedule[i].length <= 50 +0 <= schedule[i].start < schedule[i].end <= 10^8 + +*/ + + +/** + * // Definition for an Interval. + * function Interval(start, end) { + * this.start = start; + * this.end = end; + * }; + */ +/** + * // Definition for an Interval. + * function Interval(start, end) { + * this.start = start; + * this.end = end; + * }; + */ + +/** + * @param {Interval[][]} schedule + * @return {Interval[]} + */ +const employeeFreeTime = function(schedule) { + const n = schedule.length + const time = mergeSort(schedule, 0, n - 1) + const free = [] + let end = time[0].end + for(let i = 1; i < time.length; i++) { + if(time[i].start > end) { + free.push(new Interval(end, time[i].start)) + } + end = Math.max(end, time[i].end) + } + return free +} + +function mergeSort(schedule, l, r) { + if(l === r) return schedule[l] + const mid = l + ((r - l) >> 1) + const left = mergeSort(schedule, l, mid) + const right = mergeSort(schedule, mid + 1, r) + return merge(left, right) +} + +function merge(A, B) { + const res = [] + const m = A.length, n = B.length + let i = 0, j = 0 + while(i < m || j < n) { + if(i === m) { + res.push(B[j++]) + } else if(j === n) { + res.push(A[i++]) + } else if(A[i].start < B[j].start) { + res.push(A[i++]) + } else { + res.push(B[j++]) + } + } + return res +} + + +// another + +const employeeFreeTime = function(schedule) { + const intervals = [] + schedule.forEach(s => s.forEach(t => intervals.push(t))) + intervals.sort((a, b) => + a.start !== b.start ? a.start - b.start : a.end - b.end + ) + let i1 = intervals[0] + const res = [] + for (let interval of intervals.slice(1)) { + let i2 = interval + if (i1.end >= i2.start) { + i1.end = Math.max(i1.end, i2.end) + } else { + res.push(new Interval(i1.end, i2.start)) + i1 = i2 + } + } + return res +} + +// another + +/** + * // Definition for an Interval. + * function Interval(start, end) { + * this.start = start; + * this.end = end; + * }; + */ + +/** + * @param {Interval[][]} schedule + * @return {Interval[]} + */ +const employeeFreeTime = function (schedule) { + const res = [], timeLine = [] + schedule.forEach(e => timeLine.push(...e)) + timeLine.sort((a, b) => a.start - b.start) + let tmp = timeLine[0] + for(let i = 1, n = timeLine.length; i < n; i++) { + const el = timeLine[i] + if(el.start > tmp.end) { + res.push(new Interval(tmp.end, el.start)) + tmp = el + } else { + tmp = el.end > tmp.end ? el : tmp + } + } + return res +} + +// another + +/** + * // Definition for an Interval. + * function Interval(start, end) { + * this.start = start; + * this.end = end; + * }; + */ + +/** + * @param {Interval[][]} schedule + * @return {Interval[]} + */ +var employeeFreeTime = function(schedule) { + const arr = schedule.reduce((ac, e) => { + ac.push(...e) + return ac + }, []) + arr.sort((a, b) => a.start - b.start || b.end - a.end) + const n = arr.length + const res = [] + let end = arr[0].end + for(let i = 1; i < n; i++) { + const cur = arr[i] + if(cur.start > end) { + res.push(new Interval(end, cur.start)) + } + + end = Math.max(end, cur.end) + } + + return res +}; diff --git a/76-minimum-window-substring.js b/76-minimum-window-substring.js new file mode 100644 index 00000000..7b3ac3e1 --- /dev/null +++ b/76-minimum-window-substring.js @@ -0,0 +1,78 @@ +/** + * @param {string} s + * @param {string} t + * @return {string} + */ +var minWindow = function(s, t) { + const a = 'a'.charCodeAt(0) + const A = 'A'.charCodeAt(0) + const arr = new Array(52).fill(0) + const n = s.length + const idx = (ch) => { + const code = ch.charCodeAt(0) + return code - (code >= a ? a : A) + (code >= a ? 26 : 0) + } + for (const ch of t) { + arr[idx(ch)]++ + } + let l = 0, r = 0 + let res = '' + while(r < n) { + const i = idx(s[r]) + arr[i]-- + while(l < r && arr[idx(s[l])] < 0) { + arr[idx(s[l])]++ + l++ + } + const tmp = s.slice(l, r + 1) + if(arr.every(x => x <= 0) && (res === '' || tmp.length < res.length)) { + res = tmp + } + r++ + } + + return res +}; + +// another + +/** + * @param {string} s + * @param {string} t + * @return {string} + */ +const minWindow = function(s, t) { + const map = {} + for (const c of t) { + map[c] = (map[c] || 0) + 1 + } + let counter = t.length + let start = 0 + let end = 0 + let minLen = Infinity + let minStart = 0 + while (end < s.length) { + const eChar = s[end] + if (map[eChar] > 0) { + counter-- + } + map[eChar] = (map[eChar] || 0) - 1 + end++ + while (counter === 0) { + if (end - start < minLen) { + minStart = start + minLen = end - start + } + const sChar = s[start] + map[sChar] = (map[sChar] || 0) + 1 + if (map[sChar] > 0) { + counter++ + } + start++ + } + } + if (minLen !== Infinity) { + return s.substring(minStart, minStart + minLen) + } + return '' +} diff --git a/760-find-anagram-mappings.js b/760-find-anagram-mappings.js new file mode 100644 index 00000000..e2a5e83a --- /dev/null +++ b/760-find-anagram-mappings.js @@ -0,0 +1,16 @@ +/** + * @param {number[]} A + * @param {number[]} B + * @return {number[]} + */ +const anagramMappings = function(A, B) { + const m = new Map() + for(let i = 0, len = B.length; i < len; i++) { + m.set(B[i], i) + } + const res = [] + for(let i = 0, len = A.length; i < len; i++) { + res.push(m.get(A[i])) + } + return res +}; diff --git a/761-special-binary-string.js b/761-special-binary-string.js new file mode 100644 index 00000000..8c8c31f1 --- /dev/null +++ b/761-special-binary-string.js @@ -0,0 +1,17 @@ +/** + * @param {string} S + * @return {string} + */ +const makeLargestSpecial = function(S) { + let count = 0, i = 0 + const res = [] + for(let j = 0, len = S.length; i < len; j++) { + if(S.charAt(j) === '1') count++ + else count-- + if(count === 0) { + res.push('1' + makeLargestSpecial(S.substring(i + 1, j)) + '0') + i = j + 1 + } + } + return res.sort().reverse().join('') +}; diff --git a/763-partition-labels.js b/763-partition-labels.js new file mode 100644 index 00000000..7ccbb56d --- /dev/null +++ b/763-partition-labels.js @@ -0,0 +1,27 @@ +/** + * @param {string} S + * @return {number[]} + */ +const partitionLabels = function (S) { + if (S == null || S.length === 0) { + return null + } + const list = [] + // record the last index of the each char + const map = new Array(26).fill(0) + const a = 'a'.charCodeAt(0) + for (let i = 0, len = S.length; i < len; i++) { + map[S.charCodeAt(i) - a] = i + } + // record the end index of the current sub string + let last = 0 + let start = 0 + for (let i = 0, len = S.length; i < len; i++) { + last = Math.max(last, map[S.charCodeAt(i) - a]) + if (last === i) { + list.push(last - start + 1) + start = last + 1 + } + } + return list +} diff --git a/764-largest-plus-sign.js b/764-largest-plus-sign.js new file mode 100644 index 00000000..7bd3e43a --- /dev/null +++ b/764-largest-plus-sign.js @@ -0,0 +1,26 @@ +/** + * @param {number} N + * @param {number[][]} mines + * @return {number} + */ +const orderOfLargestPlusSign = function (N, mines) { + const dp = [...Array(N)].map((_) => Array(N).fill(N)) + mines.map((m) => { + dp[m[0]][m[1]] = 0 + }) + for (let i = 0; i < N; i++) { + for (let j = 0, k = N - 1, l = (r = u = d = 0); j < N; j++, k--) { + dp[i][j] = Math.min(dp[i][j], (l = dp[i][j] == 0 ? 0 : l + 1)) + dp[i][k] = Math.min(dp[i][k], (r = dp[i][k] == 0 ? 0 : r + 1)) + dp[j][i] = Math.min(dp[j][i], (d = dp[j][i] == 0 ? 0 : d + 1)) + dp[k][i] = Math.min(dp[k][i], (u = dp[k][i] == 0 ? 0 : u + 1)) + } + } + let max = 0 + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + max = Math.max(dp[i][j], max) + } + } + return max +} diff --git a/765-couples-holding-hands.js b/765-couples-holding-hands.js new file mode 100644 index 00000000..3b5aa4d9 --- /dev/null +++ b/765-couples-holding-hands.js @@ -0,0 +1,106 @@ +/** + * @param {number[]} row + * @return {number} + */ +const minSwapsCouples = function (row) { + let res = 0, + N = row.length + const ptn = new Array(N).fill(0) + const pos = new Array(N).fill(0) + for (let i = 0; i < N; i++) { + ptn[i] = i % 2 === 0 ? i + 1 : i - 1 + pos[row[i]] = i + } + for (let i = 0; i < N; i++) { + for (let j = ptn[pos[ptn[row[i]]]]; i !== j; j = ptn[pos[ptn[row[i]]]]) { + swap(row, i, j) + swap(pos, row[i], row[j]) + res++ + } + } + return res +} + +function swap(arr, i, j) { + ;[arr[i], arr[j]] = [arr[j], arr[i]] +} + +// another + +/** + * @param {number[]} row + * @return {number} + */ +const minSwapsCouples = function (row) { + const parents = Array.from({ length: row.length / 2 }, (_, i) => i) + const positions = new Map() + for (let i = 0; i < row.length / 2; i++) { + const left = Math.floor(row[i * 2] / 2) + const right = Math.floor(row[i * 2 + 1] / 2) + if (positions.has(left)) { + union(i, positions.get(left)) + } else { + positions.set(left, i) + } + if (positions.has(right)) { + union(i, positions.get(right)) + } else { + positions.set(right, i) + } + } + + const uniqueRoots = new Set() + for (const parent of parents) { + uniqueRoots.add(find(parent)) + } + return parents.length - uniqueRoots.size + + function union(a, b) { + const aRoot = find(a) + const bRoot = find(b) + parents[aRoot] = bRoot + } + function root(x) { + while (x !== parents[x]) { + parents[x] = parents[parents[x]] + x = parents[x] + } + return x + } + function find(node) { + return root(node) + } +} + +// another + +/** + * @param {number[]} row + * @return {number} + */ +const minSwapsCouples = function (row) { + let res = 0 + const n = row.length + const ptn = Array(n).fill(0), pos = Array(n).fill(0) + + for(let i = 0; i < n; i++) { + ptn[i] = (i % 2 === 0 ? i + 1 : i - 1) + pos[row[i]] = i + } + + for (let i = 0; i < n ;i++) { + for (let j = ptn[pos[ptn[row[i]]]]; i != j; j = ptn[pos[ptn[row[i]]]]) { + swap(row, i, j); + swap(pos, row[i], row[j]); + res++; + } + } + + return res + + function swap(arr, i, j) { + const val = arr[i] + arr[i] = arr[j] + arr[j] = val + } +} diff --git a/767-reorganize-string.js b/767-reorganize-string.js index 222a2e25..be449e84 100644 --- a/767-reorganize-string.js +++ b/767-reorganize-string.js @@ -1,3 +1,47 @@ +/** + * @param {string} s + * @return {string} + */ +const reorganizeString = function (s) { + const freq = Array(26).fill(0) + const a = 'a'.charCodeAt(0), n = s.length + for(const e of s) { + freq[e.charCodeAt(0) - a]++ + } + let max = 0, maxIdx = 0 + for(let i = 0; i < 26; i++) { + if(freq[i] > max) { + max = freq[i] + maxIdx = i + } + } + + if(max > (n + 1) / 2) return '' + + const res = Array(n) + + let idx = 0 + while(freq[maxIdx]) { + res[idx] = String.fromCharCode(a + maxIdx) + idx += 2 + freq[maxIdx]-- + } + + for(let i = 0; i < 26; i++) { + while(freq[i]) { + if(idx >= n) idx = 1 + res[idx] = String.fromCharCode(i + a) + idx += 2 + freq[i]-- + } + } + + return res.join('') +} + +// another + + /** * @param {string} S * @return {string} @@ -36,3 +80,41 @@ const reorganizeString = function(S) { } return parts.join(''); }; + +// another + +/** + * @param {string} s + * @return {string} + */ +const reorganizeString = function(s) { + const arr = Array(26).fill(0), a = 'a'.charCodeAt(0) + for(let ch of s) arr[ch.charCodeAt(0) - a]++ + let max = 0, idx = -1 + for(let i = 0; i < 26; i++) { + if(arr[i] > max) { + max = arr[i] + idx = i + } + } + const n = s.length + const res = Array(n) + if(max > (n + 1) / 2) return '' + + let i = 0 + while(arr[idx] > 0) { + res[i] = String.fromCharCode(a + idx) + i += 2 + arr[idx]-- + } + + for(let j = 0; j < 26; j++) { + while(arr[j]) { + if(i >= n) i = 1 + res[i] = String.fromCharCode(a + j) + i += 2 + arr[j]-- + } + } + return res.join('') +}; diff --git a/770-basic-calculator-iv.js b/770-basic-calculator-iv.js new file mode 100644 index 00000000..ce2a77d9 --- /dev/null +++ b/770-basic-calculator-iv.js @@ -0,0 +1,146 @@ +/** + * @param {string} expression + * @param {string[]} evalvars + * @param {number[]} evalints + * @return {string[]} + */ +const basicCalculatorIV = function (expression, evalvars, evalints) { + // Tokenise and get list of unresolved variable names + let [variables, it] = (function () { + let variables = [] + let evalMap = new Map(evalvars.map((name, i) => [name, evalints[i]])) + let tokens = expression.match(/\w+|\d+|\S/g) + // Resolve occurrences of eval vars + for (let i = 0; i < tokens.length; i++) { + let token = tokens[i] + if (token[0] >= 'A') { + let num = evalMap.get(token) + if (num !== undefined) { + tokens[i] = num + } else { + variables.push(tokens[i]) + } + } + } + return [[...new Set(variables)].sort(), tokens.values()] // array & iterator + })() + // Map each unknown variable to a sequential ID: + let variableMap = new Map(variables.map((name, i) => [name, i])) + + // Parse tokens into Polynomial instance, and get output in required format + return (function parse(sign = 1) { + function parseTerm(sign = 1) { + let token = it.next().value + if (token === '(') return parse(sign) + let term = new Term(sign) + if (typeof token === 'string' && token >= 'A') { + term.setVar(variableMap.get(token)) + } else { + term.setCoefficient(+token) + } + return new Polynomial([term]) + } + + let polynomial = new Polynomial() + let term = parseTerm(sign) + for (let token; (token = it.next().value) && token !== ')'; ) { + if (token === '*') { + term.mul(parseTerm(1)) + } else { + polynomial.add(term) + term = parseTerm(token === '+' ? sign : -sign) + } + } + return polynomial.add(term) + })().output(variables) +} +class Term { + constructor(coefficient, variables = [], degree = 0) { + this.variables = variables + this.coefficient = coefficient + this.degree = degree + } + setVar(id) { + while (this.variables.length <= id) this.variables.push(0) + this.variables[id]++ + this.degree++ + } + setCoefficient(coefficient) { + this.coefficient *= coefficient + } + clone() { + return new Term(this.coefficient, [...this.variables], this.degree) + } + mul(term) { + let n = term.variables.length + while (this.variables.length < n) this.variables.push(0) + for (let i = 0; i < n; i++) { + this.variables[i] += term.variables[i] + } + this.degree += term.degree + this.coefficient *= term.coefficient + return this + } + cmp(term) { + let diff = term.degree - this.degree + if (diff) return Math.sign(diff) + for (let i = 0; i < this.variables.length; i++) { + diff = term.variables[i] - this.variables[i] + if (diff) return Math.sign(diff) + } + return 0 + } + format(variableNames) { + return !this.coefficient + ? '' + : this.coefficient + + this.variables.map((count, i) => + ('*' + variableNames[i]).repeat(count) + ).join`` + } +} + +class Polynomial { + constructor(terms = []) { + this.terms = terms + } + addTerm(term) { + let terms = this.terms + // binary search + let low = 0 + let high = terms.length + while (low < high) { + let mid = (low + high) >> 1 + let diff = terms[mid].cmp(term) + if (diff === 0) { + terms[mid].coefficient += term.coefficient + return this + } else if (diff < 0) { + low = mid + 1 + } else { + high = mid + } + } + terms.splice(low, 0, term) + return this + } + add(polynomial) { + for (let term of polynomial.terms) { + this.addTerm(term) + } + return this + } + mul(polynomial) { + let orig = new Polynomial(this.terms) + this.terms = [] // clear + for (let term1 of polynomial.terms) { + for (let term2 of orig.terms) { + this.addTerm(term1.clone().mul(term2)) + } + } + return this + } + output(variableNames) { + return this.terms.map((term) => term.format(variableNames)).filter(Boolean) + } +} diff --git a/771-jewels-and-stones.js b/771-jewels-and-stones.js new file mode 100644 index 00000000..4cede577 --- /dev/null +++ b/771-jewels-and-stones.js @@ -0,0 +1,14 @@ +/** + * @param {string} J + * @param {string} S + * @return {number} + */ +const numJewelsInStones = function(J, S) { + if(J == null || J === '' || S == null || S === '') return 0 + const m = new Set(J) + let res = 0 + for(let e of S) { + if(m.has(e)) res++ + } + return res +}; diff --git a/772-basic-calculator-iii.js b/772-basic-calculator-iii.js new file mode 100644 index 00000000..fe5bbf19 --- /dev/null +++ b/772-basic-calculator-iii.js @@ -0,0 +1,62 @@ +/** + * @param {string} s + * @return {number} + */ +const calculate = function ( + s, + start = 0, + end = s.length, + parentheses = findParentheses(s) +) { + const stack = [] + let op = '+' + let num = 0 + for (let i = start; i < end; i++) { + const c = s[i] + if (/[0-9]+/.test(c)) { + const n = parseInt(c) + num = 10 * num + n + } else if (isOperator(c)) { + compute(op, stack, num) + op = c + num = 0 + } else if (c === '(') { + num = calculate(s, i + 1, parentheses[i], parentheses) + i = parentheses[i] + } + } + compute(op, stack, num) + return stack.reduce((acc, cur) => acc + cur, 0) +} + +function findParentheses(s) { + const map = {} + const stack = [] + for (let i = 0; i < s.length; i++) { + if (s[i] === '(') { + stack.push(i) + } else if (s[i] === ')') { + map[stack.pop()] = i + } + } + return map +} + +function compute(op, stack, num) { + if (op === '-') { + stack.push(-num) + } else if (op === '+') { + stack.push(num) + } else if (op === '*') { + stack.push(stack.pop() * num) + } else if (op === '/') { + const pre = stack.pop() + const sign = pre / num >= 0 ? 1 : -1 + const val = Math.floor(Math.abs(pre / num)) + stack.push(Math.floor(sign * val)) + } +} + +function isOperator(c) { + return c === '+' || c === '-' || c === '*' || c === '/' +} diff --git a/774-minimize-max-distance-to-gas-station.js b/774-minimize-max-distance-to-gas-station.js new file mode 100644 index 00000000..20ee5131 --- /dev/null +++ b/774-minimize-max-distance-to-gas-station.js @@ -0,0 +1,132 @@ +/** + * @param {number[]} stations + * @param {number} K + * @return {number} + */ +const minmaxGasDist = function (stations, K) { + const dis = [] + let min = 0 + let max = 1e8 + for (let i = 0; i < stations.length - 1; i++) { + dis.push(stations[i + 1] - stations[i]) + } + while (max - min > 1e-6) { + const mid = min + (max - min) / 2 + if (possible(dis, mid, K)) { + max = mid + } else { + min = mid + } + } + return min +} + +const possible = (dis, res, K) => { + let need = 0 + for (let i = 0; i < dis.length; i++) { + need += dis[i] <= res ? 0 : Math.floor(dis[i] / res) + } + return need <= K +} + +// another + +/** + * @param {number[]} stations + * @param {number} k + * @return {number} + */ +const minmaxGasDist = function(stations, k) { + const pq = new PriorityQueue((a, b) => a[0] > b[0]) + for(let i = 1, n = stations.length; i < n; i++) { + const delta = stations[i] - stations[i - 1] + pq.push([delta, delta, 1]) + } + const limit = (stations[stations.length - 1] - stations[0]) / k + // console.log(pq.heap) + while(k>0) { + let [delta, gap, num] = pq.pop() + + let v = gap / (num + 1) + while(k > 0 && gap / (num + 1) > limit) { + k-- + num++ + } + + v = gap / ++num + k-- + + pq.push([v, gap, num]) + } + + return pq.peek()[0] +}; + + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/775-global-and-local-inversions.js b/775-global-and-local-inversions.js new file mode 100644 index 00000000..1616fc00 --- /dev/null +++ b/775-global-and-local-inversions.js @@ -0,0 +1,27 @@ +/** + * @param {number[]} A + * @return {boolean} + */ +const isIdealPermutation = function(A) { + if(A.length === 1 || A.length === 2) return true + let max = A[0] + for(let i = 0, len = A.length; i < len - 2; i++) { + max = Math.max(max, A[i]) + if(max > A[i + 2]) return false + } + return true; +}; + +// another + +/** + * @param {number[]} A + * @return {boolean} + */ +const isIdealPermutation = function(A) { + if(A.length === 1 || A.length === 2) return true + for(let i = 0, len = A.length; i < len; i++) { + if(Math.abs(A[i] - i) > 1) return false + } + return true; +}; diff --git a/776-split-bst.js b/776-split-bst.js new file mode 100644 index 00000000..8a1af38c --- /dev/null +++ b/776-split-bst.js @@ -0,0 +1,25 @@ +/** + * 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 + * @param {number} V + * @return {TreeNode[]} + */ +const splitBST = function(root, V) { + if(root == null) return [null, null] + if(root.val > V) { + const [left, right] = splitBST(root.left, V) + root.left = right + return [left, root] + } else { + const [left, right] = splitBST(root.right, V) + root.right = left + return [root, right] + } +}; diff --git a/778-swim-in-rising-water.js b/778-swim-in-rising-water.js index 43f52c67..22e51580 100644 --- a/778-swim-in-rising-water.js +++ b/778-swim-in-rising-water.js @@ -1,3 +1,152 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const swimInWater = function(grid) { + const pq = new PQ((a, b) => a[0] < b[0]) + const dirs = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0] + ] + const n = grid.length + const visited = Array.from({ length: n }, () => Array(n).fill(false)) + pq.push([grid[0][0], 0, 0]) + visited[0][0] = true + let res = 0 + + while (!pq.isEmpty()) { + const [h, x, y] = pq.pop() + res = Math.max(res, h) + if (x === n - 1 && y === n - 1) { + return res + } + for (const [dx, dy] of dirs) { + const nx = x + dx + const ny = y + dy + if (nx < 0 || nx >= n || ny < 0 || ny >= n || visited[nx][ny]) { + continue + } + pq.push([grid[nx][ny], nx, ny]) + visited[nx][ny] = true + } + } +}; + +class PQ { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } + } + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const swimInWater = function(grid) { + const n = grid.length + const limit = n * n, { floor } = Math + let l = 0, r = limit - 1 + + while(l < r) { + const mid = l + floor((r - l) / 2) + if(valid(mid)) r = mid + else l = mid + 1 + } + + return l + + + function valid(h) { + const visited = Array.from({ length: n }, () => Array(n).fill(0)) + if(grid[0][0] > h) return false + return dfs(h, 0, 0, visited) + } + + function dfs(h, i, j, visited) { + if(i === n - 1 && j === n - 1) return true + const dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]] + visited[i][j] = 1 + for(const [dx, dy] of dirs) { + const nx = i + dx, ny = j + dy + if(nx >= 0 && nx < n && ny >= 0 && ny < n && visited[nx][ny] === 0 && grid[nx][ny] <= h) { + if(dfs(h, nx, ny, visited)) return true + } + + } + + return false + } +}; + +// another + + /** * @param {number[][]} grid * @return {number} diff --git a/779-k-th-symbol-in-grammar.js b/779-k-th-symbol-in-grammar.js new file mode 100644 index 00000000..edb30029 --- /dev/null +++ b/779-k-th-symbol-in-grammar.js @@ -0,0 +1,24 @@ +/** + * @param {number} N + * @param {number} K + * @return {number} + */ +const kthGrammar = function(N, K) { + if (N === 1) return 0; + if (K % 2 === 0) return (kthGrammar(N - 1, K / 2) === 0) ? 1 : 0; + else return (kthGrammar(N - 1, (K + 1) / 2) === 0) ? 0 : 1; +}; + +/** + +// think of the problem like this +/* 0 + / \ + 0 1 + / \ / \ + 0 1 1 0 + / \ / \ / \ / \ + 0 1 1 0 1 0 0 1 +*/ + +*/ diff --git a/78-subsets.js b/78-subsets.js index 16987bb1..5467e85d 100755 --- a/78-subsets.js +++ b/78-subsets.js @@ -21,3 +21,22 @@ function subsets(nums) { } console.log(subsets([1, 2, 3])); + +// another + +/** + * @param {number[]} nums + * @return {number[][]} + */ + +function subsets(nums) { + const subs = [[]] + for (let num of nums) { + const n = subs.length + for (let i = 0; i < n; i++) { + subs.push(subs[i].slice(0)) + subs[subs.length - 1].push(num) + } + } + return subs +} diff --git a/781-rabbits-in-forest.js b/781-rabbits-in-forest.js new file mode 100644 index 00000000..870444fa --- /dev/null +++ b/781-rabbits-in-forest.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} answers + * @return {number} + */ +const numRabbits = function(answers) { + const h = {} + for(const e of answers) { + if(h[e] == null) h[e] = 0 + h[e]++ + } + let res = 0 + for(let [k,v] of Object.entries(h)) { + k = +k + if(k >= v ) res += k + 1 + else { + res += Math.ceil(v / (k + 1) ) * (k + 1) + } + } + + return res +}; diff --git a/782-transform-to-chessboard.js b/782-transform-to-chessboard.js new file mode 100644 index 00000000..5fa721f9 --- /dev/null +++ b/782-transform-to-chessboard.js @@ -0,0 +1,30 @@ +/** + * @param {number[][]} b + * @return {number} + */ +const movesToChessboard = function (b) { + let N = b.length, + rowSum = 0, + colSum = 0, + rowSwap = 0, + colSwap = 0; + for (let i = 0; i < N; ++i) + for (let j = 0; j < N; ++j) + if ((b[0][0] ^ b[i][0] ^ b[0][j] ^ b[i][j]) === 1) return -1; + for (let i = 0; i < N; ++i) { + rowSum += b[0][i]; + colSum += b[i][0]; + if (b[i][0] === i % 2) rowSwap++; + if (b[0][i] === i % 2) colSwap++; + } + if (rowSum !== ((N / 2) >> 0) && rowSum !== ((N + 1) / 2)>>0 ) return -1; + if (colSum !== ((N / 2) >> 0) && colSum !== ((N + 1) / 2)>>0 ) return -1; + if (N % 2 === 1) { + if (colSwap % 2 === 1) colSwap = N - colSwap; + if (rowSwap % 2 === 1) rowSwap = N - rowSwap; + } else { + colSwap = Math.min(N - colSwap, colSwap); + rowSwap = Math.min(N - rowSwap, rowSwap); + } + return (colSwap + rowSwap) / 2; +}; diff --git a/785-is-graph-bipartite.js b/785-is-graph-bipartite.js new file mode 100644 index 00000000..489d5bd2 --- /dev/null +++ b/785-is-graph-bipartite.js @@ -0,0 +1,28 @@ +/** + * @param {number[][]} graph + * @return {boolean} + */ +const isBipartite = function (graph) { + const visited = Array(graph.length).fill(0); + for (let i = 0; i < graph.length; i++) { + if (visited[i] !== 0) { + continue; + } + const queue = []; + queue.push(i); + visited[i] = 1; + while (queue.length > 0) { + const index = queue.shift(); + for (let j = 0; j < graph[index].length; j++) { + const temp = graph[index][j]; + if (visited[temp] === 0) { + visited[temp] = visited[index] * -1; + queue.push(temp); + } else { + if (visited[temp] === visited[index]) return false; + } + } + } + } + return true; +}; diff --git a/786-k-th-smallest-prime-fraction.js b/786-k-th-smallest-prime-fraction.js index 28d7e73d..99e39b35 100644 --- a/786-k-th-smallest-prime-fraction.js +++ b/786-k-th-smallest-prime-fraction.js @@ -1,9 +1,10 @@ /** - * @param {number[]} A - * @param {number} K + * @param {number[]} arr + * @param {number} k * @return {number[]} */ -const kthSmallestPrimeFraction = function(A, K) { +var kthSmallestPrimeFraction = function(arr, k) { + const A = arr, K = k let ans = [] let left = 0.0 let right = 1.0 @@ -34,4 +35,4 @@ const kthSmallestPrimeFraction = function(A, K) { } return { count, p, q } } -} +}; diff --git a/787-cheapest-flights-within-k-stops.js b/787-cheapest-flights-within-k-stops.js index c0cd2f99..ea51e87f 100644 --- a/787-cheapest-flights-within-k-stops.js +++ b/787-cheapest-flights-within-k-stops.js @@ -1,3 +1,73 @@ +/** + * @param {number} n + * @param {number[][]} flights + * @param {number} src + * @param {number} dst + * @param {number} k + * @return {number} + */ +var findCheapestPrice = function(n, flights, src, dst, k) { + let cost = Array(n).fill(Infinity) + cost[src] = 0 + + for(let i = 0; i <= k; i++) { + const tmp = [...cost] + for(const [f, t, p] of flights) { + if(cost[f] === Infinity) continue + tmp[t] = Math.min(tmp[t], cost[f] + p) + } + cost = tmp + } + + return cost[dst] === Infinity ? -1 : cost[dst] +}; + + +// another + +/** + * @param {number} n + * @param {number[][]} flights + * @param {number} src + * @param {number} dst + * @param {number} K + * @return {number} + */ +const findCheapestPrice = function(n, flights, src, dst, K) { + const arr = Array(n).fill(Infinity) + arr[src] = 0 + const g = {} + for(const [u,v,p] of flights) { + if(g[u] == null) g[u] = [] + g[u].push([v, p]) + } + + let step = 0 + let q = [[src,0]] + while(step < K + 1 && q.length) { + const len = q.length + const row = [] + for(let i = 0; i < len; i++) { + const el = q[i] + const [s, dis] = el + for(const e of (g[s] || [])) { + const [nxt, p] = e + if(arr[nxt] > p + dis) { + arr[nxt] = p + dis + row.push([nxt, arr[nxt]]) + } + + } + } + q = row + step++ + } + + return arr[dst] === Infinity ? -1 : arr[dst] +} + +// another + /** * @param {number} n * @param {number[][]} flights diff --git a/788-rotated-digits.js b/788-rotated-digits.js new file mode 100644 index 00000000..6954f420 --- /dev/null +++ b/788-rotated-digits.js @@ -0,0 +1,25 @@ +/** + * @param {number} n + * @return {number} + */ +const rotatedDigits = function(n) { + const dp = new Array(n + 1).fill(0); + let count = 0; + for(let i = 0; i <= n; i++){ + if(i < 10){ + if(i == 0 || i == 1 || i == 8) dp[i] = 1; + else if(i == 2 || i == 5 || i == 6 || i == 9){ + dp[i] = 2; + count++; + } + } else { + let a = dp[~~(i / 10)], b = dp[i % 10]; + if(a == 1 && b == 1) dp[i] = 1; + else if(a >= 1 && b >= 1){ + dp[i] = 2; + count++; + } + } + } + return count; +}; diff --git a/789-escape-the-ghosts.js b/789-escape-the-ghosts.js new file mode 100644 index 00000000..56e18c45 --- /dev/null +++ b/789-escape-the-ghosts.js @@ -0,0 +1,15 @@ +/** + * @param {number[][]} ghosts + * @param {number[]} target + * @return {boolean} + */ +var escapeGhosts = function(ghosts, target) { + let res = true + const { abs } = Math, steps = abs(target[0]) + abs(target[1]) + const [tx, ty] = target + for(const [x, y] of ghosts) { + if(abs(tx - x) + abs(ty - y) <= steps) return false + } + + return res +}; diff --git a/79-word-search.js b/79-word-search.js index 2964968c..d109fa4b 100644 --- a/79-word-search.js +++ b/79-word-search.js @@ -35,6 +35,9 @@ function dfs(board, x, y, dirs, word, start) { return false; } +// time complexity: O(M * N * 3^L), where L is the length of word. +// we have a visited array and we never go back, so 3 directions + // another /** diff --git a/792-number-of-matching-subsequences.js b/792-number-of-matching-subsequences.js index d1ac1e88..0fc3d939 100644 --- a/792-number-of-matching-subsequences.js +++ b/792-number-of-matching-subsequences.js @@ -1,3 +1,36 @@ +/** + * @param {string} s + * @param {string[]} words + * @return {number} + */ +const numMatchingSubseq = function(s, words) { + const hash = {} + for(let w of words) { + if(hash[w[0]] == null) hash[w[0]] = [] + const it = w[Symbol.iterator]() + hash[w[0]].push( it ) + it.next() + } + let res = 0 + for(let ch of s) { + const advance = hash[ch] || [] + hash[ch] = [] + for(let it of advance) { + const obj = it.next() + if(obj.done === false) { + if(hash[obj.value] == null) hash[obj.value] = [] + hash[obj.value].push(it) + } else { + res++ + } + } + } + + return res +}; + +// another + /** * @param {string} S * @param {string[]} words @@ -20,3 +53,35 @@ const numMatchingSubseq = function(S, words) { } return res }; + +// another + +/** + * @param {string} s + * @param {string[]} words + * @return {number} + */ +const numMatchingSubseq = function(s, words) { + const hash = {} + for(const w of words) { + const ch = w[0], it = w[Symbol.iterator]() + if(hash[ch] == null) hash[ch] = [] + hash[ch].push(it) + it.next() + } + let res = 0 + for(const e of s) { + const arr = hash[e] || [] + hash[e] = [] + for(const it of arr) { + const { value, done } = it.next() + if(done) res++ + else { + if(hash[value] == null) hash[value] = [] + hash[value].push(it) + } + } + } + + return res +}; diff --git a/795-number-of-subarrays-with-bounded-maximum.js b/795-number-of-subarrays-with-bounded-maximum.js index 3ade7405..2634c6fd 100644 --- a/795-number-of-subarrays-with-bounded-maximum.js +++ b/795-number-of-subarrays-with-bounded-maximum.js @@ -1,3 +1,81 @@ +/** + * @param {number[]} nums + * @param {number} left + * @param {number} right + * @return {number} + */ +const numSubarrayBoundedMax = function(nums, left, right) { + const n = nums.length; + let res = 0 + const preLargerOrEqual = Array(n).fill(-1) + const postLarger = Array(n).fill(n) + let stk = [] + stk.push(0) + for(let i = 1; i < n; i++) { + const e = nums[i] + while(stk.length && nums[stk[stk.length - 1]] < e) { + stk.pop() + } + if(stk.length) { + preLargerOrEqual[i] = stk[stk.length - 1] + } + stk.push(i) + } + stk = [] + stk.push(n - 1) + for(let i = n - 2; i >= 0; i--) { + const e = nums[i] + while(stk.length && nums[stk[stk.length - 1]] <= e) { + stk.pop() + } + if(stk.length) { + postLarger[i] = stk[stk.length - 1] + } + stk.push(i) + } + for(let i = 0; i < n; i++) { + const e = nums[i] + if(e >= left && e <= right) { + const pre = preLargerOrEqual[i] + const post = postLarger[i] + res += (i - pre) * (post - i) + } + } + + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} left + * @param {number} right + * @return {number} + */ +const numSubarrayBoundedMax = function(nums, left, right) { + let prev = -1, res = 0, dp = 0 + const n = nums.length + + for(let i = 0; i < n; i++) { + const e = nums[i] + if(e < left) { + + } else if(e > right) { + prev = i + dp = 0 + } else { + dp = i - prev + } + + res += dp + } + + return res +}; + +// another + /** * @param {number[]} A * @param {number} L @@ -21,3 +99,27 @@ const numSubarrayBoundedMax = function(A, L, R) { } return res }; + +// another + +/** + * @param {number[]} nums + * @param {number} left + * @param {number} right + * @return {number} + */ +const numSubarrayBoundedMax = function(nums, left, right) { + let prev = -1, dp = 0, res = 0 + for(let i = 0, n = nums.length; i < n; i++) { + const cur = nums[i] + if(cur < left) res += dp + else if(cur > right) { + dp = 0 + prev = i + } else { + dp = i - prev + res += dp + } + } + return res +}; diff --git a/797-all-paths-from-source-to-target.js b/797-all-paths-from-source-to-target.js new file mode 100644 index 00000000..3896c031 --- /dev/null +++ b/797-all-paths-from-source-to-target.js @@ -0,0 +1,19 @@ +/** + * @param {number[][]} graph + * @return {number[][]} + */ +const allPathsSourceTarget = function(graph) { + const res = [] + const path = [] + bt(graph, res, path, 0) + return res +}; + +function bt(g, res, path, cur) { + path.push(cur) + if(cur === g.length - 1) res.push(path.slice()) + else { + for(let i of g[cur]) bt(g, res, path, i) + } + path.pop() +} diff --git a/798-smallest-rotation-with-highest-score.js b/798-smallest-rotation-with-highest-score.js index fcb6fb0f..a76fca03 100644 --- a/798-smallest-rotation-with-highest-score.js +++ b/798-smallest-rotation-with-highest-score.js @@ -28,16 +28,22 @@ const bestRotation = function(A) { // another -const bestRotation = function(A) { - let n = A.length; - let c = new Array(n).fill(0); - for(let i = 0; i < n; i++) { - c[(i - A[i] + 1 + n) % n] -= 1; - } - let max = 0; - for(let i = 1; i < n; i++) { - c[i] += c[i-1] + 1; - max = c[i] > c[max] ? i : max; - } - return max; -} +/** + * @param {number[]} nums + * @return {number} + */ +var bestRotation = function(nums) { + const n = nums.length + const arr = Array(n).fill(0) + for(let i = 0; i < n; i++) { + arr[(i - nums[i] + 1 + n) % n] -= 1 + } + let res = 0 + for(let i = 1; i < n; i++) { + arr[i] += arr[i - 1] + 1 + if(arr[i] > arr[res]) res = i + } + return res +}; + + diff --git a/799-champagne-tower.js b/799-champagne-tower.js new file mode 100644 index 00000000..fba3c3bd --- /dev/null +++ b/799-champagne-tower.js @@ -0,0 +1,22 @@ +/** + * @param {number} poured + * @param {number} query_row + * @param {number} query_glass + * @return {number} + */ +const champagneTower = function(poured, query_row, query_glass) { + let curRow = [poured] + for(let i = 0; i <= query_row; i++) { + const nxtRow = Array(i + 2).fill(0) + for(let j = 0; j <= i; j++) { + if(curRow[j] > 1) { + nxtRow[j] += (curRow[j] - 1) / 2 + nxtRow[j + 1] += (curRow[j] - 1) / 2 + curRow[j] = 1 + } + } + if(i !== query_row) curRow = nxtRow + } + + return curRow[query_glass] +}; diff --git a/8-string-to-integer-(atoi).js b/8-string-to-integer-(atoi).js index 26bb1c86..aa0ff301 100755 --- a/8-string-to-integer-(atoi).js +++ b/8-string-to-integer-(atoi).js @@ -5,3 +5,33 @@ const myAtoi = function(str) { return Math.max(Math.min(parseInt(str) || 0, 2147483647), -2147483648); }; + +// anotther + +/** + * @param {string} s + * @return {number} + */ +const myAtoi = function(s) { + let n = s.length, i = 0, j = 0, sign = 1; + if(n === 0) { + return 0; + } + while(i < n && s[i] === ' ') { + i++; + } + if(i < n && (s[i] === '-' || s[i] === '+')) { + sign = (s[i] === '-') ? -1 : 1; + i++; + } + j = i + while(i < n) { + if(Number.isInteger(parseInt(s[i]))) i++; + else break; + } + let result = parseInt(s.slice(j, i)) + if(isNaN(result)) return 0 + if(sign * result < -(2**31)) return -(2**31); + else if(sign * result > (2**31-1)) return 2**31-1; + else return sign * result; +}; diff --git a/800-similar-rgb-color.js b/800-similar-rgb-color.js new file mode 100644 index 00000000..1b7974a8 --- /dev/null +++ b/800-similar-rgb-color.js @@ -0,0 +1,22 @@ +/** + * @param {string} color + * @return {string} + */ +const similarRGB = function(color) { + const candidates = ['00', '11', '22', '33', '44', '55', '66', '77', '88', '99', 'aa', 'bb', 'cc', 'dd', 'ee', 'ff'] + const r = color.slice(1, 3), g = color.slice(3, 5), b = color.slice(5, 7) + + return `#${min(r)}${min(g)}${min(b)}` + + function min(str) { + let res = '', max = Infinity + for(let s of candidates) { + const tmp = Math.abs(parseInt(s, 16) - parseInt(str, 16)) + if(tmp < max) { + max = tmp + res = s + } + } + return res + } +}; diff --git a/802-find-eventual-safe-states.js b/802-find-eventual-safe-states.js new file mode 100644 index 00000000..14b46cd1 --- /dev/null +++ b/802-find-eventual-safe-states.js @@ -0,0 +1,135 @@ +/** + * @param {number[][]} graph + * @return {number[]} + */ +var eventualSafeNodes = function (graph) { + const n = graph.length + const g = {}, + rg = {} + for (let i = 0; i < n; i++) { + const arr = graph[i] + g[i] = new Set(arr) + for (let j of arr) { + if (!rg[j]) { + rg[j] = new Set() + } + rg[j].add(i) + } + } + let q = [] + for (let i = 0; i < n; i++) { + if (g[i].size === 0) { + q.push(i) + } + } + const res = [] + while (q.length) { + const size = q.length + const nxt = [] + for (let i = 0; i < size; i++) { + const node = q[i] + res.push(node) + for (let j of rg[node] || []) { + g[j].delete(node) + if (g[j].size === 0) { + nxt.push(j) + } + } + } + + q = nxt + } + + res.sort((a, b) => a - b) + return res +} + +// another + + +/** + * @param {number[][]} graph + * @return {number[]} + */ +const eventualSafeNodes = function (graph) { + const ing = {}, + n = graph.length + const outDegree = Array(n).fill(0) + let q = [] + for (let i = 0; i < n; i++) { + outDegree[i] = graph[i].length + if (outDegree[i] === 0) { + q.push(i) + } + for (const e of graph[i]) { + if (ing[e] == null) ing[e] = [] + ing[e].push(i) + } + } + + for (const term of q) { + for (const come of ing[term] || []) { + outDegree[come]-- + if (outDegree[come] === 0) q.push(come) + } + } + q.sort((a, b) => a - b) + return q +} + +// another + + +/** + * @param {number[][]} graph + * @return {number[]} + */ +const eventualSafeNodes = function(graph) { + const n = graph.length, memo = {}, visited = new Set(), res = [] + for(let i = 0; i < n; i++) { + if(!dfs(graph, i, memo, visited)) res.push(i) + } + return res +}; + +function dfs(graph, node, memo, visited) { + if(memo[node] != null) return memo[node] + let hasCycle = false + visited.add(node) + for(let e of graph[node]) { + if(visited.has(e) || dfs(graph, e, memo, visited)) { + hasCycle = true + break + } + } + visited.delete(node) + memo[node] = hasCycle + return hasCycle +} + +// another + +/** + * @param {number[][]} graph + * @return {number[]} + */ +const eventualSafeNodes = function(graph) { + const res = [] + if(graph == null || graph.length === 0) return res + const n = graph.length + const color = Array(n).fill(0) + for(let i = 0; i < n; i++) { + if(bt(graph, i, color)) res.push(i) + } + return res + + function bt(graph, start, color) { + if(color[start] !== 0) return color[start] === 1 + color[start] = 2 + for(let next of graph[start]) { + if(!bt(graph, next, color)) return false + } + color[start] = 1 + return true + } +}; diff --git a/803-bricks-falling-when-hit.js b/803-bricks-falling-when-hit.js new file mode 100644 index 00000000..36c09fe0 --- /dev/null +++ b/803-bricks-falling-when-hit.js @@ -0,0 +1,253 @@ +/** + * @param {number[][]} grid + * @param {number[][]} hits + * @return {number[]} + */ +const hitBricks = function (grid, hits) { + const n = grid[0].length + const m = hits.length + const res = new Array(m).fill(0) + for (const [r, c] of hits) { + if (grid[r][c] == 1) grid[r][c] = 0 + else grid[r][c] = -1 + } + for (let j = 0; j < n; j++) { + getConnectedCount(grid, 0, j) + } + for (let i = m - 1; i >= 0; i--) { + const [r, c] = hits[i] + if (grid[r][c] == -1) continue + grid[r][c] = 1 + if (isConnectedToTop(grid, r, c)) { + res[i] = getConnectedCount(grid, r, c) - 1 + } + } + return res +} +const isConnectedToTop = (grid, i, j) => { + if (i == 0) return true + const dircs = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ] + for (const [dx, dy] of dircs) { + const nx = i + dx + const ny = j + dy + if ( + 0 <= nx && + nx < grid.length && + 0 <= ny && + ny < grid[0].length && + grid[nx][ny] == 2 + ) { + return true + } + } + return false +} + +const getConnectedCount = (grid, i, j) => { + if ( + i < 0 || + i >= grid.length || + j < 0 || + j >= grid[0].length || + grid[i][j] != 1 + ) + return 0 + let count = 1 + grid[i][j] = 2 + count += + getConnectedCount(grid, i + 1, j) + + getConnectedCount(grid, i - 1, j) + + getConnectedCount(grid, i, j + 1) + + getConnectedCount(grid, i, j - 1) + return count +} + +// another + +/** + * @param {number[][]} grid + * @param {number[][]} hits + * @return {number[]} + */ +const hitBricks = function (grid, hits) { + const SPACE = 0 + const BRICK = 1 + const WILL_HIT = 2 + const DIRECTIONS = [ + [0, 1], + [1, 0], + [0, -1], + [-1, 0], + ] + const rows = grid.length + const cols = grid[0].length + const ds = new DisjointSet(rows * cols + 1) + + for (const [hitR, hitC] of hits) { + if (grid[hitR][hitC] === BRICK) { + grid[hitR][hitC] = WILL_HIT + } + } + + function hash(r, c) { + return r * cols + c + 1 + } + + function unionAround(r, c) { + const hashed = hash(r, c) + for (const [rDiff, cDiff] of DIRECTIONS) { + const rNext = r + rDiff + const cNext = c + cDiff + if (grid[rNext] !== undefined && grid[rNext][cNext] === BRICK) { + ds.union(hashed, hash(rNext, cNext)) + } + } + if (r === 0) ds.union(0, hashed) + } + for (let i = 0; i < grid.length; i++) { + for (let j = 0; j < grid[i].length; j++) { + if (grid[i][j] === BRICK) unionAround(i, j) + } + } + let numBricksLeft = ds.size[ds.find(0)] + const numBricksDropped = new Array(hits.length) + // backwards + for (let i = hits.length - 1; i >= 0; i--) { + const [hitR, hitC] = hits[i] + if (grid[hitR][hitC] === WILL_HIT) { + grid[hitR][hitC] = BRICK + unionAround(hitR, hitC) + const newNumBricksLeft = ds.size[ds.find(0)] + numBricksDropped[i] = Math.max(newNumBricksLeft - numBricksLeft - 1, 0) + numBricksLeft = newNumBricksLeft + } else { + numBricksDropped[i] = 0 + } + } + return numBricksDropped +} + +class DisjointSet { + constructor(n) { + this.size = new Array(n).fill(1) + this.parent = new Array(n) + for (let i = 0; i < n; i++) { + this.parent[i] = i + } + } + find(x) { + if (x === this.parent[x]) return x + this.parent[x] = this.find(this.parent[x]) + + return this.parent[x] + } + union(x, y) { + const rootX = this.find(x) + const rootY = this.find(y) + if (rootX !== rootY) { + // attach X onto Y + this.parent[rootX] = rootY + this.size[rootY] += this.size[rootX] + } + } +} + +// another + +/** + * @param {number[][]} grid + * @param {number[][]} hits + * @return {number[]} + */ +const hitBricks = function(grid, hits) { + const res = Array(hits.length).fill(0), dirs = [-1, 0, 1, 0, -1] + for(let [r, c] of hits) { + grid[r][c] -= 1 + } + for(let i = 0; i < grid[0].length; i++) { + dfs(0, i, grid) + } + for(let i = hits.length - 1; i >= 0; i--) { + const [r, c] = hits[i] + grid[r][c] += 1 + if(grid[r][c] === 1 && isConnected(r, c, grid, dirs)) { + res[i] = dfs(r, c, grid) - 1 + } + } + return res +} +function dfs(i, j, grid) { + if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] !== 1) return 0 + grid[i][j] = 2 + return 1 + dfs(i + 1, j, grid) + dfs(i - 1, j, grid) + dfs(i, j + 1, grid) + dfs(i, j - 1, grid) +} +function isConnected(i, j, grid, dirs) { + if(i === 0) return true + for(let k = 1; k < dirs.length; k++) { + const r = i + dirs[k - 1], c = j + dirs[k] + if(r >= 0 && r < grid.length && c >= 0 && c < grid[0].length && grid[r][c] === 2) { + return true + } + } + return false +} + +// another + +/** + * @param {number[][]} grid + * @param {number[][]} hits + * @return {number[]} + */ +const hitBricks = function (grid, hits) { + const m = grid.length, + n = grid[0].length, + res = Array(hits.length).fill(0), + dirs = [ + [-1, 0], + [1, 0], + [0, 1], + [0, -1], + ]; + for (let [r, c] of hits) grid[r][c] -= 1; + + for (let i = 0; i < n; i++) dfs(grid, 0, i, m, n, dirs); + + for (let i = hits.length - 1; i >= 0; i--) { + const [r, c] = hits[i]; + grid[r][c] += 1; + if (grid[r][c] === 1 && connected(grid, r, c, m, n, dirs)) { + res[i] = dfs(grid, r, c, m, n, dirs) - 1; + } + } + + return res; +}; + +function dfs(grid, i, j, m, n, dirs) { + if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] !== 1) return 0; + grid[i][j] = 2; + let res = 1; + for (let [dr, dc] of dirs) { + res += dfs(grid, i + dr, j + dc, m, n, dirs); + } + return res; +} + +function connected(grid, i, j, m, n, dirs) { + if (i === 0) return true; + for (let [dr, dc] of dirs) { + const nr = i + dr, + nc = j + dc; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && grid[nr][nc] === 2) + return true; + } + + return false; +} + diff --git a/810-chalkboard-xor-game.js b/810-chalkboard-xor-game.js new file mode 100644 index 00000000..3a60cdd8 --- /dev/null +++ b/810-chalkboard-xor-game.js @@ -0,0 +1,8 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +const xorGame = function(nums) { + const xor = nums.reduce((xor,ele) => xor^ele, 0) + return xor === 0 || (nums.length & 1) === 0 +}; diff --git a/815-bus-routes.js b/815-bus-routes.js new file mode 100644 index 00000000..fb0e2eb0 --- /dev/null +++ b/815-bus-routes.js @@ -0,0 +1,38 @@ +/** + * @param {number[][]} routes + * @param {number} S + * @param {number} T + * @return {number} + */ +const numBusesToDestination = function (routes, S, T) { + if (S === T) return 0 + const map = {} + const visited = new Array(routes.length).fill(false), + queue = [S] + let rides = 0 + for (let i = 0; i < routes.length; i++) { + for (const stop of routes[i]) { + if (map[stop] === undefined) { + map[stop] = [] + } + map[stop].push(i) + } + } + while (queue.length > 0) { + let size = queue.length + rides += 1 + while (size > 0) { + const currStop = queue.shift() + size -= 1 + for (const bus of map[currStop]) { + if (visited[bus]) continue + visited[bus] = true + for (const stop of routes[bus]) { + if (stop === T) return rides + queue.push(stop) + } + } + } + } + return -1 +} diff --git a/818-race-car.js b/818-race-car.js new file mode 100644 index 00000000..0f0f545b --- /dev/null +++ b/818-race-car.js @@ -0,0 +1,19 @@ +/** + * @param {number} target + * @return {number} + */ +const racecar = function (target) { + const dp = new Array(target + 1).fill(0) + for (let i = 1; i <= target; i++) { + dp[i] = Number.MAX_VALUE + let m = 1, + j = 1 + for (; j < i; j = (1 << ++m) - 1) { + for (let q = 0, p = 0; p < j; p = (1 << ++q) - 1) { + dp[i] = Math.min(dp[i], m + 1 + q + 1 + dp[i - (j - p)]) + } + } + dp[i] = Math.min(dp[i], m + (i == j ? 0 : 1 + dp[j - i])) + } + return dp[target] +} diff --git a/824-goat-latin.js b/824-goat-latin.js new file mode 100644 index 00000000..da271e6c --- /dev/null +++ b/824-goat-latin.js @@ -0,0 +1,16 @@ +/** + * @param {string} sentence + * @return {string} + */ +const toGoatLatin = function(sentence) { + const arr = sentence.split(' ') + const vowel = new Set(['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U']) + for(let i = 0, n = arr.length; i < n; i++) { + const first = arr[i][0] + const ma = vowel.has(first) ? 'ma' : '' + const tmp = !vowel.has(first) ? `${arr[i].slice(1)}${first}ma` : arr[i] + const suffix = 'a'.repeat(i + 1) + arr[i] = `${tmp}${ma}${suffix}` + } + return arr.join(' ') +}; diff --git a/826-most-profit-assigning-work.js b/826-most-profit-assigning-work.js new file mode 100644 index 00000000..a2acbac0 --- /dev/null +++ b/826-most-profit-assigning-work.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} difficulty + * @param {number[]} profit + * @param {number[]} worker + * @return {number} + */ +const maxProfitAssignment = function(difficulty, profit, worker) { + let res = 0 + const n = profit.length + const jobs = [] + for(let i = 0; i < n; i++) { + jobs.push([difficulty[i], profit[i]]) + } + jobs.sort((a,b) => a[0] - b[0]) + worker.sort((a, b) => a - b) + let i = 0, tmp = 0 + for(let w of worker) { + while(i < n && w >= jobs[i][0]) { + tmp = Math.max(tmp, jobs[i++][1]) + } + res += tmp + } + + return res +}; + diff --git a/828-unique-letter-string.js b/828-unique-letter-string.js index aa19ae71..62fa088a 100644 --- a/828-unique-letter-string.js +++ b/828-unique-letter-string.js @@ -1,3 +1,27 @@ +/** + * @param {string} s + * @return {number} + */ +const uniqueLetterString = function(s) { + const n = s.length + const arr = Array.from({ length: 26 }, () => Array(2).fill(-1)) + const A = 'A'.charCodeAt(0) + let res = 0 + for(let i = 0; i < n; i++) { + const idx = s.charCodeAt(i) - A + res += (i - arr[idx][1]) * (arr[idx][1] - arr[idx][0]) + arr[idx] = [arr[idx][1], i] + } + + for(let i = 0; i < 26; i++) { + res += (n - arr[i][1]) * (arr[i][1] - arr[i][0]) + } + + return res +}; + +// another + /** * @param {string} S * @return {number} diff --git a/829-consecutive-numbers-sum.js b/829-consecutive-numbers-sum.js new file mode 100644 index 00000000..e2d5e98f --- /dev/null +++ b/829-consecutive-numbers-sum.js @@ -0,0 +1,29 @@ +/** + * @param {number} N + * @return {number} + */ +const consecutiveNumbersSum = function (N) { + let count = 1 + for (let k = 2; k < Math.sqrt(2 * N); k++) { + if ((N - (k * (k - 1)) / 2) % k === 0) count++ + } + return count +} + +// another + +/** + * @param {number} N + * @return {number} + */ +const consecutiveNumbersSum = function(N) { + let res = 0 + for(let i = 1; i <= N; i++) { + const diff = i * (i - 1) / 2 + const nd = N - diff + if(nd <= 0) break + if(nd % i === 0) res++ + } + + return res +}; diff --git a/83-remove-duplicates-from-sorted-list.js b/83-remove-duplicates-from-sorted-list.js index b78e214c..6339d4e7 100755 --- a/83-remove-duplicates-from-sorted-list.js +++ b/83-remove-duplicates-from-sorted-list.js @@ -20,3 +20,31 @@ const deleteDuplicates = function(head) { } return head; }; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const deleteDuplicates = function(head) { + let prev = null, cur = head + while(cur) { + if(prev && prev.val === cur.val) { + prev.next = cur.next + cur = cur.next + } else { + prev = cur + cur = cur.next + } + } + return head +}; + diff --git a/834-sum-of-distances-in-tree.js b/834-sum-of-distances-in-tree.js new file mode 100644 index 00000000..2e4df1d7 --- /dev/null +++ b/834-sum-of-distances-in-tree.js @@ -0,0 +1,90 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ +var sumOfDistancesInTree = function(n, edges) { + const res = new Array(n).fill(0); + const count = new Array(n).fill(1); + const graph = Array.from({ length: n }, () => []); + for (const [u, v] of edges) { + graph[u].push(v); + graph[v].push(u); + } + dfs1(0, -1); + dfs2(0, -1); + + return res + + function dfs1(node, parent) { + for (const child of graph[node]) { + if (child === parent) { + continue; + } + dfs1(child, node); + count[node] += count[child]; + res[node] += res[child] + count[child]; + } + } + function dfs2(node, parent) { + for (const child of graph[node]) { + if (child === parent) { + continue; + } + res[child] = res[node] - count[child] + n - count[child]; + dfs2(child, node); + } + } +}; + +// another + +/** + * @param {number} N + * @param {number[][]} edges + * @return {number[]} + */ +const sumOfDistancesInTree = function (N, edges) { + const graph = createGraph(N, edges) + const counts = new Array(N).fill(0) + const dists = new Array(N).fill(0) + dists[0] = getCount(graph, 0, -1, counts).sum + return transferDist(N, graph, 0, -1, counts, dists) +} + +function transferDist(N, graph, u, pre, counts, dists) { + if (pre >= 0) { + const nRight = counts[u] + const nLeft = N - nRight + dists[u] = dists[pre] - nRight + nLeft + } + for (const v of graph[u]) { + if (v !== pre) { + transferDist(N, graph, v, u, counts, dists) + } + } + return dists +} + +function getCount(graph, u, pre, counts) { + const output = { nNodes: 0, sum: 0 } + for (const v of graph[u]) { + if (v !== pre) { + const result = getCount(graph, v, u, counts) + output.nNodes += result.nNodes + output.sum += result.nNodes + result.sum + } + } + output.nNodes += 1 + counts[u] = output.nNodes + return output +} + +function createGraph(N, edges) { + const graph = new Array(N).fill(null).map(() => []) + for (const [u, v] of edges) { + graph[u].push(v) + graph[v].push(u) + } + return graph +} diff --git a/839-similar-string-groups.js b/839-similar-string-groups.js new file mode 100644 index 00000000..9c06d7e9 --- /dev/null +++ b/839-similar-string-groups.js @@ -0,0 +1,31 @@ +/** + * @param {string[]} A + * @return {number} + */ +const numSimilarGroups = function (A) { + const all = new Set(A) + const isSimilar = function (w1, w2) { + if (w1 === w2) return true + let misMatch = 0 + for (let i = 0; i < w1.length; i++) { + if (w1[i] !== w2[i]) misMatch++ + if (misMatch > 2) return false + } + return true + } + const recur = function (s) { + all.delete(s) + for (let n of all) { + if (isSimilar(s, n)) { + recur(n) + } + } + } + let ans = 0 + while (all.size) { + const current = all.values().next().value + recur(current) + ans++ + } + return ans +} diff --git a/84-largest-rectangle-in-histogram.js b/84-largest-rectangle-in-histogram.js new file mode 100644 index 00000000..a05263fe --- /dev/null +++ b/84-largest-rectangle-in-histogram.js @@ -0,0 +1,81 @@ +/** + * @param {number[]} heights + * @return {number} + */ +const largestRectangleArea = function(heights) { + let height = heights; + if (height == null || height.length == 0) { + return 0; + } + const lessFromLeft = new Array(height.length).fill(0); + const lessFromRight = new Array(height.length).fill(0); + lessFromRight[height.length - 1] = height.length; + lessFromLeft[0] = -1; + for (let i = 1; i < height.length; i++) { + let p = i - 1; + while (p >= 0 && height[p] >= height[i]) { + p = lessFromLeft[p]; + } + lessFromLeft[i] = p; + } + for (let i = height.length - 2; i >= 0; i--) { + let p = i + 1; + while (p < height.length && height[p] >= height[i]) { + p = lessFromRight[p]; + } + lessFromRight[i] = p; + } + let maxArea = 0; + for (let i = 0; i < height.length; i++) { + maxArea = Math.max( + maxArea, + height[i] * (lessFromRight[i] - lessFromLeft[i] - 1) + ); + } + return maxArea; +}; + + +// another + +/** + * @param {number[]} heights + * @return {number} + */ +const largestRectangleArea = function(heights) { + if (!heights.length) return 0; + let stack = []; + let max = 0; + for (let i = 0, cur, len = heights.length; i <= len; i++) { + cur = i === len ? -1 : heights[i]; + while (stack.length && cur < heights[stack[stack.length - 1]]) { + let index = stack.pop(); + let h = heights[index]; + let w = !stack.length ? i : i - stack[stack.length - 1] - 1; + max = Math.max(max, h * w); + } + stack.push(i); + } + return max; +}; + +// another + +/** + * @param {number[]} heights + * @return {number} + */ +const largestRectangleArea = function(heights) { + heights.push(0) + const st = [], n = heights.length + let res = 0 + for(let i = 0; i <= n; i++) { + while(st.length && heights[st[st.length - 1]] >= heights[i]) { + const top = st.pop() + const pre = st.length ? st[st.length - 1] : -1 + res = Math.max(res, heights[top] * (i - pre - 1)) + } + st.push(i) + } + return res +}; diff --git a/843-guess-the-word.js b/843-guess-the-word.js new file mode 100644 index 00000000..be49eabf --- /dev/null +++ b/843-guess-the-word.js @@ -0,0 +1,63 @@ +/** + * // This is the master's API interface. + * // You should not implement it, or speculate about its implementation + * function Master() { + * + * @param {string[]} wordlist + * @param {Master} master + * @return {integer} + * this.guess = function(word) { + * ... + * }; + * }; + */ +/** + * @param {string[]} wordlist + * @param {Master} master + * @return {void} + */ +const findSecretWord = function (wordlist, master) { + let group = wordlist + for (let i = 0; i < 10; i++) { + let currentGuess = findTheTypical(group) + let res = master.guess(currentGuess) + if (res === 6) return + let tmp = [] + for (let j = 0; j < group.length; j++) { + if (diff(group[j], currentGuess) === 6 - res) tmp.push(group[j]) + } + group = tmp + } +} +function findTheTypical(wordlist) { + const count = Array.from({ length: 6 }, (x) => new Object()) + for (let i = 0; i < wordlist.length; i++) { + for (let j = 0; j < 6; j++) { + const cur = wordlist[i][j] + if (count[j][cur] === undefined) count[j][cur] = 1 + else count[j][cur]++ + } + } + let maxPos = 0, + maxCount = 0, + maxAlp = '' + for (let i = 0; i < 6; i++) { + for (let k of Object.keys(count[i])) { + if (count[i][k] > maxCount) { + maxCount = count[i][k] + maxPos = i + maxAlp = k + } + } + } + for (let i = 0; i < wordlist.length; i++) { + if (wordlist[i][maxPos] === maxAlp) return wordlist[i] + } +} +function diff(a, b) { + let count = 0 + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) count++ + } + return count +} diff --git a/844-backspace-string-compare.js b/844-backspace-string-compare.js new file mode 100644 index 00000000..059aa76a --- /dev/null +++ b/844-backspace-string-compare.js @@ -0,0 +1,17 @@ +/** + * @param {string} S + * @param {string} T + * @return {boolean} + */ +const backspaceCompare = function(S, T) { + return chk(S) === chk(T) +}; + +function chk(str) { + const s = [] + for(let i = 0, len = str.length; i < len; i++) { + if(str[i] === '#') s.pop() + else s.push(str[i]) + } + return s.join('') +} diff --git a/85-maximal-rectangle.js b/85-maximal-rectangle.js index 8192ef62..2f06ea31 100644 --- a/85-maximal-rectangle.js +++ b/85-maximal-rectangle.js @@ -1,3 +1,95 @@ +/** + * @param {character[][]} matrix + * @return {number} + */ +const maximalRectangle = function(matrix) { + const m = matrix.length, n = matrix[0].length + const heights = Array(n).fill(0), left = Array(n).fill(0), right = Array(n).fill(n) + let res = 0 + for(let i = 0; i < m; i++) { + let l = 0, r = n + for(let j = 0; j < n; j++) { + if(matrix[i][j] === '1') { + heights[j]++ + } else { + heights[j] = 0 + } + } + + for(let j = 0; j < n; j++) { + if(matrix[i][j] === '1') { + left[j] = Math.max(l, left[j]) + } else { + left[j] = 0 + l = j + 1 + } + } + + for(let j = n - 1; j >= 0; j--) { + if(matrix[i][j] === '1') { + right[j] = Math.min(r, right[j]) + } else { + right[j] = n + r = j + } + } + + for(let j = 0; j < n; j++) { + res = Math.max(res, heights[j] * (right[j] - left[j])) + } + + } + + return res +}; + +// another + + +/** + * @param {character[][]} matrix + * @return {number} + */ +const maximalRectangle = function(matrix) { + const m = matrix.length, n = matrix[0].length + const left = Array(n).fill(0) + const right = Array(n).fill(n - 1) + const height = Array(n).fill(0) + + let res = 0 + + for(let i = 0; i < m; i++) { + let l = 0, r = n - 1 + for(let j = 0; j < n; j++) { + if(matrix[i][j] === '1') left[j] = Math.max(left[j], l) + else { + left[j] = 0 + l = j + 1 + } + } + + for(let j = n - 1; j >= 0; j--) { + if(matrix[i][j] === '1') right[j] = Math.min(right[j], r) + else { + right[j] = n - 1 + r = j - 1 + } + } + + for(let j = 0; j < n; j++) { + height[j] = matrix[i][j] === '1' ? height[j] + 1 : 0 + res = Math.max(res, (right[j] - left[j] + 1) * height[j]) + } + + // console.log(left, right, height) + } + + return res +}; + +// another + + /** * @param {character[][]} matrix * @return {number} diff --git a/851-loud-and-rich.js b/851-loud-and-rich.js new file mode 100644 index 00000000..a413c424 --- /dev/null +++ b/851-loud-and-rich.js @@ -0,0 +1,32 @@ +/** + * @param {number[][]} richer + * @param {number[]} quiet + * @return {number[]} + */ +const loudAndRich = function(richer, quiet) { + const hash = {} + for(const [a, b] of richer) { + if(hash[b] == null) hash[b] = [] + hash[b].push(a) + } + const n = quiet.length + + const res = [] + for(let i = 0; i < n; i++) { + dfs(i) + } + + return res + + function dfs(i) { + if(res[i] != null) return res[i] + res[i] = i + + const nxt = hash[i] || [] + for(const e of nxt) { + if(quiet[dfs(e)] < quiet[res[i]]) res[i] = res[e] + + } + return res[i] + } +}; diff --git a/855-exam-room.js b/855-exam-room.js new file mode 100644 index 00000000..e5025e9f --- /dev/null +++ b/855-exam-room.js @@ -0,0 +1,35 @@ +/** + * @param {number} n + */ +const ExamRoom = function(n) { + let a = []; + return { seat, leave } + function seat() { + if (a.length == 0) { + a.push(0); + return 0; + } + let dis = Math.max(a[0], n - 1 - a[a.length - 1]); + for (let i = 1; i < a.length; i++) dis = Math.max(dis, a[i] - a[i - 1] >> 1); + if (a[0] == dis) { + a.unshift(0); + return 0; + } + for (let i = 1; i < a.length; i++) { + if (a[i] - a[i - 1] >> 1 == dis) { + a.splice(i, 0, a[i] + a[i - 1] >> 1); + return a[i]; + } + } + a.push(n - 1); + return n - 1; + } + function leave(p) { + for (let i = 0; i < a.length; i++) { + if (a[i] == p) { + a.splice(i, 1); + break; + } + } + } +}; diff --git a/857-minimum-cost-to-hire-k-workers.js b/857-minimum-cost-to-hire-k-workers.js index 46394d91..76914b01 100644 --- a/857-minimum-cost-to-hire-k-workers.js +++ b/857-minimum-cost-to-hire-k-workers.js @@ -1,3 +1,36 @@ +/** + * @param {number[]} quality + * @param {number[]} wage + * @param {number} K + * @return {number} + */ +const mincostToHireWorkers = function(quality, wage, K) { + const workers = [], n = quality.length; + for (let i = 0; i < n; i++) { + workers[i] = { ratio: wage[i] / quality[i], quality: quality[i] } + } + workers.sort((a, b) => a.ratio - b.ratio); + const heap = new MaxPriorityQueue({ priority: x => x.quality }); + let totalQuality = 0, res = Infinity; + while (workers.length) { + const curWorker = workers.shift(); + totalQuality += curWorker.quality; + heap.enqueue(curWorker); + + if (heap.size() > K) { + totalQuality -= heap.dequeue().element.quality; + } + if (heap.size() === K) { + res = Math.min(res, curWorker.ratio * totalQuality) + } + } + return res; +}; + + + +// another + /** * @param {number[]} quality * @param {number[]} wage @@ -28,3 +61,38 @@ function insert(arr, el) { } arr.push(el) } + +// another + +/** + * @param {number[]} quality + * @param {number[]} wage + * @param {number} K + * @return {number} + */ +const mincostToHireWorkers = function(quality, wage, K) { + const workers = [], n = wage.length + for(let i = 0; i < n; i++) { + workers.push([wage[i] / quality[i], quality[i]]) + } + // wage[i] / wage[j] = quality[i] / quality[j] + // wage[i] * quality[j] = wage[j] * quality[i] + // wage[i] / quality[i] = wage[j] / quality[j] + workers.sort((a, b) => a[0] - b[0]) + const pq = new MaxPriorityQueue({ priority: (w) => w.quality }) + let res = Infinity, qualitySum = 0 + for(const worker of workers) { + const [ratio, quality] = worker + qualitySum += quality + pq.enqueue({ quality }) + + if(pq.size() > K) { + qualitySum -= pq.dequeue().element.quality + } + if(pq.size() === K) res = Math.min(res, qualitySum * ratio) + } + + return res +}; + + diff --git a/861-score-after-flipping-matrix.js b/861-score-after-flipping-matrix.js new file mode 100644 index 00000000..4c57cb6c --- /dev/null +++ b/861-score-after-flipping-matrix.js @@ -0,0 +1,67 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const matrixScore = function(grid) { + const m = grid.length, n = grid[0].length + let res = 0 + res += m * (1 << (n - 1)) + for(let j = 1; j < n; j++) { + let same = 0 + for(let i = 0; i < m; i++) { + if(grid[i][0] === grid[i][j]) same++ + } + res += Math.max(same, m - same) * (1 << (n - 1 - j)) + } + + return res +}; + +// another + +/** + * @param {number[][]} grid + * @return {number} + */ +const matrixScore = function(grid) { + const m = grid.length, n = grid[0].length + for(let i = 0; i < m; i++) { + if(grid[i][0] === 0) flipRow(i) + } + + for(let i = 0; i < n; i++) { + if(cntCol(i, 0) > cntCol(i, 1)) flipCol(i) + } + + let res = 0 + // console.log(grid) + for(const row of grid) { + res += parseInt(row.join(''), 2) + } + + return res + + + function flipRow(idx) { + for(let i = 0; i < n; i++) { + if(grid[idx][i] === 0) grid[idx][i] = 1 + else grid[idx][i] = 0 + } + } + + function cntCol(idx, target) { + let res = 0 + for(let i = 0; i < m; i++) { + if(grid[i][idx] === target) res++ + } + // console.log(res) + return res + } + + function flipCol(idx) { + for(let i = 0; i < m; i++) { + if(grid[i][idx] === 0) grid[i][idx] = 1 + else grid[i][idx] = 0 + } + } +}; diff --git a/862-shortest-subarray-with-sum-at-least-k.js b/862-shortest-subarray-with-sum-at-least-k.js index a45d8c5f..e09e2839 100644 --- a/862-shortest-subarray-with-sum-at-least-k.js +++ b/862-shortest-subarray-with-sum-at-least-k.js @@ -1,3 +1,33 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const shortestSubarray = function(nums, k) { + const q = [], n = nums.length + let res = Infinity, sum = 0 + const prefix = [] + for(let i = 0; i < n; i++) { + sum += nums[i] + prefix.push(sum) + if(sum >= k) res = Math.min(res, i + 1) + } + + for(let i = 0; i < n; i++) { + while(q.length && prefix[i] <= prefix[q[q.length - 1]]) q.pop() + while(q.length && prefix[i] - prefix[q[0]] >= k) { + res = Math.min(res, i - q[0]) + q.shift() + } + + q.push(i) + } + + return res === Infinity ? -1 : res +}; + +// another + /** * @param {number[]} A * @param {number} K diff --git a/863-all-nodes-distance-k-in-binary-tree.js b/863-all-nodes-distance-k-in-binary-tree.js new file mode 100644 index 00000000..51fc2e8f --- /dev/null +++ b/863-all-nodes-distance-k-in-binary-tree.js @@ -0,0 +1,103 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} target + * @param {number} K + * @return {number[]} + */ +const distanceK = function(root, target, K) { + const map = new Map(); + const res = []; + if (target == null || K < 0 || root == null) return res; + buildGraph(root, null); + const visited = new Set(); + const q = []; + visited.add(target); + q.push(target); + while (q.length) { + const len = q.length; + if (K === 0) { + for (let i = 0; i < len; i++) res.push(q.shift().val); + return res; + } + for (let i = 0; i < len; i++) { + const el = q.shift(); + for (let e of map.get(el)) { + if (visited.has(e)) continue; + visited.add(e); + q.push(e); + } + } + K--; + } + return res; + + function buildGraph(node, parent) { + if (node === null) return; + if (!map.has(node)) { + map.set(node, []); + if (parent !== null) { + map.get(node).push(parent); + if (!map.has(parent)) map.set(parent, []); + map.get(parent).push(node); + } + buildGraph(node.left, node); + buildGraph(node.right, node); + } + } +}; + +// another + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} target + * @param {number} K + * @return {number[]} + */ +const distanceK = function(root, target, K) { + let res = [] + dfs(root, target, K, res) + return res +} + +function dfs(node, target, k, res) { + if (node === null) return -1 + if (node === target) { + getRes(node, 0, k, res) + return 1 + } + let left = dfs(node.left, target, k, res) + let right = dfs(node.right, target, k, res) + if (left !== -1) { + if (left === k) res.push(node.val) + getRes(node.right, left + 1, k, res) + return left + 1 + } + if (right !== -1) { + if (right === k) res.push(node.val) + getRes(node.left, right + 1, k, res) + return right + 1 + } + return -1 +} + +function getRes(node, dist, k, res) { + if (node === null) return + if (dist === k) return res.push(node.val) + getRes(node.left, dist + 1, k, res) + getRes(node.right, dist + 1, k, res) +} diff --git a/865-smallest-subtree-with-all-the-deepest-nodes.js b/865-smallest-subtree-with-all-the-deepest-nodes.js index ad7fa163..cea0b7a0 100755 --- a/865-smallest-subtree-with-all-the-deepest-nodes.js +++ b/865-smallest-subtree-with-all-the-deepest-nodes.js @@ -26,3 +26,37 @@ function result(node, dist) { this.node = node; this.dist = dist; } + +// another + +/** + * 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 {TreeNode} + */ +const subtreeWithAllDeepest = function(root) { + let res = null, maxDepth = 0 + dfs(root, 0) + + return res + + function dfs(node, depth) { + if(node == null) return depth - 1 + + const left = dfs(node.left, depth + 1) + const right = dfs(node.right, depth + 1) + maxDepth = Math.max(maxDepth, left, right) + + if(left === maxDepth && right === maxDepth) { + res = node + } + return Math.max(left, right) + } +}; diff --git a/866-prime-palindrome.js b/866-prime-palindrome.js new file mode 100644 index 00000000..78d70c50 --- /dev/null +++ b/866-prime-palindrome.js @@ -0,0 +1,73 @@ +/** + * @param {number} n + * @return {number} + */ +const primePalindrome = function(n) { + if(n >= 8 && n <= 11) return 11 + const rev = str => str.split('').reverse().join('') + for (let i = 1; i < 1e5; i++) { + let left = `${i}`, right = rev(left).slice(1) + let num = +(left + right) + if (num >= n && isPrime(num)) return num + } + return -1 + + function isPrime(num) { + if(num < 2 || num % 2 === 0) return num === 2 + for(let i = 3; i * i <= num; i += 2) { + if(num % i === 0) return false + } + return true + } +}; + +// another + +/** + * @param {number} N + * @return {number} + */ +const primePalindrome = function(N) { + if(N >= 8 && N <= 11) return 11 + for(let x = 1; x < 100000; x++) { + let s = '' + x, r = s.split('').reverse().join('') + let y = +(s + r.slice(1)) + if(y >= N && isPrime(y)) return y + } + return -1 +}; + +function isPrime(x) { + if(x < 2 || x % 2 === 0) return x === 2 + for(let i = 3; i * i <= x; i += 2) { + if(x % i === 0) return false + } + return true +} + +// another + + +/** + * @param {number} n + * @return {number} + */ +const primePalindrome = function(n) { + if(n >= 8 && n <= 11) return 11 + + const rev = num => `${num}`.split('').reverse().join('') + for(let i = 1; i < 1e5; i++) { + let left = i, right = rev(left).slice(1) + const tmp = +(left + right) + if(tmp >= n && isPrime(tmp)) return tmp + } + + function isPrime(num) { + if(num <= 2) return num === 2 + if(num % 2 === 0) return false + for(let i = 3; i ** 2 <= num; i += 2) { + if(num % i === 0) return false + } + return true + } +}; diff --git a/87-scramble-string.js b/87-scramble-string.js new file mode 100644 index 00000000..7dbc3e0c --- /dev/null +++ b/87-scramble-string.js @@ -0,0 +1,28 @@ +/** + * @param {string} s1 + * @param {string} s2 + * @return {boolean} + */ +const isScramble = function(s1, s2) { + if (s1 === s2) return true + const letters = new Array(128).fill(0) + const a = 'a'.charCodeAt(0) + for (let i = 0; i < s1.length; i++) { + letters[s1.charCodeAt(i) - a]++ + letters[s2.charCodeAt(i) - a]-- + } + for (let i = 0; i < 128; i++) if (letters[i] !== 0) return false + for (let i = 1; i < s1.length; i++) { + if ( + isScramble(s1.substring(0, i), s2.substring(0, i)) && + isScramble(s1.substring(i), s2.substring(i)) + ) + return true + if ( + isScramble(s1.substring(0, i), s2.substring(s2.length - i)) && + isScramble(s1.substring(i), s2.substring(0, s2.length - i)) + ) + return true + } + return false +} diff --git a/871-minimum-number-of-refueling-stops.js b/871-minimum-number-of-refueling-stops.js new file mode 100644 index 00000000..cdf2b646 --- /dev/null +++ b/871-minimum-number-of-refueling-stops.js @@ -0,0 +1,19 @@ +/** + * @param {number} target + * @param {number} startFuel + * @param {number[][]} stations + * @return {number} + */ +const minRefuelStops = function (target, startFuel, stations) { + const dp = Array(stations.length + 1).fill(0) + dp[0] = startFuel + for (let i = 0; i < stations.length; ++i) { + for (let t = i; t >= 0 && dp[t] >= stations[i][0]; --t) { + dp[t + 1] = Math.max(dp[t + 1], dp[t] + stations[i][1]) + } + } + for (let t = 0; t <= stations.length; ++t) { + if (dp[t] >= target) return t + } + return -1 +} diff --git a/874-walking-robot-simulation.js b/874-walking-robot-simulation.js new file mode 100644 index 00000000..546f5da6 --- /dev/null +++ b/874-walking-robot-simulation.js @@ -0,0 +1,30 @@ +/** + * @param {number[]} commands + * @param {number[][]} obstacles + * @return {number} + */ +const robotSim = function(commands, obstacles) { + const dirs = [[1, 0], [0, -1], [-1, 0], [0, 1]] // east, south, west, north + const set = new Set() + obstacles.forEach(([x, y]) => set.add(`${x},${y}`)) + let idx = 3, x = 0, y = 0, res = 0 + for(let e of commands) { + if(e === -2) idx = (3 + idx) % 4 + else if(e === -1) idx = (1 + idx) % 4 + else { + const [dx, dy] = dirs[idx] + let dis = 0 + while(dis < e) { + const nx = x + dx, ny = y + dy + const k = `${nx},${ny}` + if(set.has(k)) break + x = nx + y = ny + dis++ + res = Math.max(res, x * x + y * y) + } + } + } + + return res +}; diff --git a/875-koko-eating-bananas.js b/875-koko-eating-bananas.js new file mode 100644 index 00000000..6bb679cd --- /dev/null +++ b/875-koko-eating-bananas.js @@ -0,0 +1,33 @@ +/** + * @param {number[]} piles + * @param {number} h + * @return {number} + */ +const minEatingSpeed = function(piles, h) { + let ma = -1 + for(const e of piles) { + if(e > ma) ma = e + } + + let l = 1, r = ma + + while(l < r) { + const mid = Math.floor((l + r) / 2) + if(valid(mid)) { + r = mid + } else { + l = mid + 1 + } + } + + return l + + function valid(val) { + let res = 0 + for(const e of piles) { + res += Math.ceil(e / val) + } + + return res <= h + } +}; diff --git a/876-middle-of-the-linked-list.js b/876-middle-of-the-linked-list.js new file mode 100644 index 00000000..fc709a48 --- /dev/null +++ b/876-middle-of-the-linked-list.js @@ -0,0 +1,26 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ +const middleNode = function (head) { + if (head == null) return null + let count = 1 + let iter = head + while (iter.next) { + iter = iter.next + count++ + } + count = (count / 2) >> 0 + while (count) { + head = head.next + count-- + } + return head +} diff --git a/879-profitable-schemes.js b/879-profitable-schemes.js index ccccac9a..9a1a366c 100644 --- a/879-profitable-schemes.js +++ b/879-profitable-schemes.js @@ -1,3 +1,56 @@ +/** + * @param {number} n + * @param {number} minProfit + * @param {number[]} group + * @param {number[]} profit + * @return {number} + */ +const profitableSchemes = function (n, minProfit, group, profit) { + const m = group.length + const dp = buildMatrix([m + 1, n + 1, minProfit + 1], 0) + const mod = 1e9 + 7 + group.unshift(0) + profit.unshift(0) + dp[0][0][0] = 1 + console.log(group, profit) + for (let i = 0; i < m; i++) { + const g = group[i + 1], + p = profit[i + 1] + for (let j = 0; j <= n; j++) { + for (let k = 0; k <= minProfit; k++) { + dp[i + 1][j][k] += dp[i][j][k] + dp[i + 1][j][k] = dp[i + 1][j][k] % mod + if (j + g <= n) { + const pp = Math.min(minProfit, k + p) + dp[i + 1][j + g][pp] += dp[i][j][k] + dp[i + 1][j + g][pp] = dp[i + 1][j + g][pp] % mod + } + } + } + } + let res = 0 + for (let j = 0; j <= n; j++) { + res = (res + dp[m][j][minProfit]) % mod + } + + return res +} + +function buildMatrix(dimensions, defaultVal) { + if (dimensions.length === 1) return Array(dimensions[0]).fill(defaultVal) + const res = [] + const [len, ...rest] = dimensions + + for (let i = 0; i < len; i++) { + res.push(buildMatrix(rest, defaultVal)) + } + + return res +} + +// another + + /** * @param {number} G * @param {number} P diff --git a/882-reachable-nodes-in-subdivided-graph.js b/882-reachable-nodes-in-subdivided-graph.js new file mode 100644 index 00000000..f83ea6f7 --- /dev/null +++ b/882-reachable-nodes-in-subdivided-graph.js @@ -0,0 +1,310 @@ +/** + * @param {number[][]} edges + * @param {number} maxMoves + * @param {number} n + * @return {number} + */ +const reachableNodes = function(edges, maxMoves, n) { + let res = 0, + heap = new Heap(), + state = new Array(n).fill(0), + graph = Array.from(new Array(n), () => []), + distance = new Array(n).fill(Number.MAX_SAFE_INTEGER); + for (let [u, v, d] of edges) { + graph[u].push([v, d]); + graph[v].push([u, d]); + } + distance[0] = 0; + heap.insert([0, distance[0]]); + while (heap.length != 0) { + let t = heap.remove(); + if (state[t[0]] === 1) continue; + if (distance[t[0]] <= maxMoves) res++; + state[t[0]] = 1; + for (let i of graph[t[0]]) { + if (distance[i[0]] > distance[t[0]] + i[1] + 1) { + distance[i[0]] = distance[t[0]] + i[1] + 1; + heap.insert([i[0], distance[i[0]]]); + } + } + } + for (let [u, v, d] of edges) { + let a = maxMoves - distance[u] >= 0 ? maxMoves - distance[u] : 0, + b = maxMoves - distance[v] >= 0 ? maxMoves - distance[v] : 0; + res += Math.min(d, a + b); + } + return res; +}; + +class Heap { + constructor() { + this.heap = []; + } + + get length() { + return this.heap.length; + } + + compare(i, j) { + if (!this.heap[j]) return false; + return this.heap[i][1] > this.heap[j][1]; + } + + swap(i, j) { + const temp = this.heap[i]; + this.heap[i] = this.heap[j]; + this.heap[j] = temp; + } + + insert(num) { + this.heap.push(num); + let idx = this.length - 1; + let parent = (idx - 1) >> 1; + while (idx !== 0 && this.compare(parent, idx)) { + this.swap(parent, idx); + idx = parent; + parent = (idx - 1) >> 1; + } + } + + remove() { + if (this.length === 1) return this.heap.pop(); + let res = this.heap[0], + idx = 0, + left = 1 | (idx << 1), + right = (1 + idx) << 1; + this.heap[0] = this.heap.pop(); + while (this.compare(idx, left) || this.compare(idx, right)) { + if (this.compare(left, right)) { + this.swap(idx, right); + idx = right; + } else { + this.swap(idx, left); + idx = left; + } + left = 1 | (idx << 1); + right = (1 + idx) << 1; + } + return res; + } +} + +// another + +/** + * @param {number[][]} edges + * @param {number} M + * @param {number} N + * @return {number} + */ +const reachableNodes = function (edges, M, N) { + const graph = Array.from({ length: N }, () => Array(N).fill(-1)) + for (let edge of edges) { + graph[edge[0]][edge[1]] = edge[2] + graph[edge[1]][edge[0]] = edge[2] + } + let result = 0 + const pq = new PriorityQueue((a, b) => a[1] > b[1]) + const visited = new Array(N).fill(false) + pq.push([0, M]) + while (!pq.isEmpty()) { + const cur = pq.pop() + const start = cur[0] + const move = cur[1] + if (visited[start]) { + continue + } + visited[start] = true + result++ + for (let i = 0; i < N; i++) { + if (graph[start][i] > -1) { + if (move > graph[start][i] && !visited[i]) { + pq.push([i, move - graph[start][i] - 1]) + } + graph[i][start] -= Math.min(move, graph[start][i]) + result += Math.min(move, graph[start][i]) + } + } + } + return result +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +// time complexity: +// Dijkstra + Heap is O(E log E) +// worst case: O(N ^ 2 * log (N ^ 2)) +/** + * @param {number[][]} edges + * @param {number} M + * @param {number} N + * @return {number} + */ +const reachableNodes = function(edges, M, N) { + const graph = {} + for(const [u,v,c] of edges) { + if(graph[u] == null) graph[u] = {} + if(graph[v] == null) graph[v] = {} + graph[u][v] = c + graph[v][u] = c + } + const pq = new PriorityQueue((a, b) => a[0] > b[0]) + pq.push([M, 0]) + const visited = {} + while(!pq.isEmpty()) { + const [moves, i] = pq.pop() + if(visited[i] == null) { + visited[i] = moves + for(const k of Object.keys(graph[i] || {})) { + const remain = moves - graph[i][k] - 1 + if(visited[k] == null && remain >= 0) { + pq.push([remain, k]) + } + } + } + } + let res = 0 + res += Object.keys(visited).length + for(const [u, v, c] of edges) { + const a = visited[u] || 0, b = visited[v] || 0 + res += Math.min(a + b, c) + } + + return res +}; + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} diff --git a/883-projection-area-of-3d-shapes.js b/883-projection-area-of-3d-shapes.js new file mode 100644 index 00000000..f4a914fc --- /dev/null +++ b/883-projection-area-of-3d-shapes.js @@ -0,0 +1,30 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const projectionArea = function(grid) { + let xy = 0, xz = 0, yz = 0 + const m = grid.length, n = grid[0].length + for (let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j]) xy++ + } + } + + for (let i = 0; i < m; i++) { + let tmp = 0 + for(let j = 0; j < n; j++) { + tmp = Math.max(tmp, grid[i][j]) + } + xz += tmp + } + for (let j = 0; j < n; j++) { + let tmp = 0 + for(let i = 0; i < m; i++) { + tmp = Math.max(tmp, grid[i][j]) + } + yz += tmp + } + + return xy + yz + xz +}; diff --git a/884-uncommon-words-from-two-sentences.js b/884-uncommon-words-from-two-sentences.js new file mode 100644 index 00000000..73b4f0f2 --- /dev/null +++ b/884-uncommon-words-from-two-sentences.js @@ -0,0 +1,23 @@ +/** + * @param {string} s1 + * @param {string} s2 + * @return {string[]} + */ +const uncommonFromSentences = function(s1, s2) { + const hash = {} + const a1 = s1.split(' '), a2 = s2.split(' ') + for(let e of a1) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + const res = [] + for(let e of a2) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + Object.keys(hash).forEach(k => { + if(hash[k] === 1) res.push(k) + }) + + return res +}; diff --git a/886-possible-bipartition.js b/886-possible-bipartition.js index e22bb029..0d1748fa 100644 --- a/886-possible-bipartition.js +++ b/886-possible-bipartition.js @@ -3,33 +3,69 @@ * @param {number[][]} dislikes * @return {boolean} */ -const possibleBipartition = function(N, dislikes) { - const graph = [] - for(let i = 0; i <= N; i++) { - graph[i] = [] - } - for(let el of dislikes) { - graph[el[0]].push(el[1]) - graph[el[1]].push(el[0]) - } - const color = new Array(N+1).fill(0) - for (let i = 1; i <= N; i++) { - if (color[i] == 0) { - color[i] = 1; - const q = []; - q.push(i); - while (q.length > 0) { - let cur = q.shift(); - for (let j of graph[cur]) { - if (color[j] == 0) { - color[j] = color[cur] == 1 ? 2 : 1; - q.push(j); - } else { - if (color[j] == color[cur]) return false; - } - } - } +const possibleBipartition = function (N, dislikes) { + const graph = [] + for (let i = 0; i <= N; i++) { + graph[i] = [] + } + for (let el of dislikes) { + graph[el[0]].push(el[1]) + graph[el[1]].push(el[0]) + } + const color = new Array(N + 1).fill(0) + for (let i = 1; i <= N; i++) { + if (color[i] == 0) { + color[i] = 1 + const q = [] + q.push(i) + while (q.length > 0) { + let cur = q.shift() + for (let j of graph[cur]) { + if (color[j] == 0) { + color[j] = color[cur] == 1 ? 2 : 1 + q.push(j) + } else { + if (color[j] == color[cur]) return false + } } + } + } + } + return true +} + +// another + +/** + * @param {number} N + * @param {number[][]} dislikes + * @return {boolean} + */ +const possibleBipartition = function (N, dislikes) { + const graph = new Array(N + 1) + for (const [a, b] of dislikes) { + if (!graph[a]) graph[a] = [] + graph[a].push(b) + if (!graph[b]) graph[b] = [] + graph[b].push(a) + } + + const colors = new Array(N + 1) + const dfs = (node, color = 0) => { + colors[node] = color + const nextColor = color ^ 1 + const children = graph[node] || [] + for (const child of children) { + if (colors[child] !== undefined) { + if (colors[child] !== nextColor) return false + } else { + if (!dfs(child, nextColor)) return false + } } return true -}; + } + for (let i = 1; i <= N; i++) { + if (colors[i] === undefined && !dfs(i)) return false + } + return true +} diff --git a/888-fair-candy-swap.js b/888-fair-candy-swap.js new file mode 100644 index 00000000..8764adaa --- /dev/null +++ b/888-fair-candy-swap.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} aliceSizes + * @param {number[]} bobSizes + * @return {number[]} + */ +const fairCandySwap = function(aliceSizes, bobSizes) { + let sum = 0 + for(let e of aliceSizes) sum += e + for(let e of bobSizes) sum -= e + // sum > 0, alice > bob + // sum < 0, alice < bob + sum /= 2 + const set = new Set() + for(let e of aliceSizes) set.add(e) + for(let e of bobSizes) { + if(set.has(e + sum)) return [e + sum, e] + } + return [0] +}; diff --git a/889-construct-binary-tree-from-preorder-and-postorder-traversal.js b/889-construct-binary-tree-from-preorder-and-postorder-traversal.js new file mode 100644 index 00000000..8bd0f678 --- /dev/null +++ b/889-construct-binary-tree-from-preorder-and-postorder-traversal.js @@ -0,0 +1,43 @@ +/** + +Return any binary tree that matches the given preorder and postorder traversals. +Values in the traversals pre and post are distinct positive integers. + +Example 1: + +Input: pre = [1,2,4,5,3,6,7], post = [4,5,2,6,7,3,1] +Output: [1,2,3,4,5,6,7] + +Note: + +1 <= pre.length == post.length <= 30 +pre[] and post[] are both permutations of 1, 2, ..., pre.length. +It is guaranteed an answer exists. +If there exists multiple answers, you can return any of them. + +*/ + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {number[]} pre + * @param {number[]} post + * @return {TreeNode} + */ +const constructFromPrePost = function(pre, post) { + let i = 0, + j = 0 + return (function dfs() { + let val = pre[i++] + let node = new TreeNode(val) + if (val !== post[j]) node.left = dfs() + if (val !== post[j]) node.right = dfs() + j++ + return node + })() +} diff --git a/89-gray-code.js b/89-gray-code.js new file mode 100644 index 00000000..862a618a --- /dev/null +++ b/89-gray-code.js @@ -0,0 +1,48 @@ +/** + * @param {number} n + * @return {number[]} + */ +const grayCode = function(n) { + if (n === 0) { + return [0] + } + const temp = grayCode(n - 1) + const nums = [].concat(temp) + const addNum = 1 << (n - 1) + for (let i = temp.length - 1; i >= 0; i--) { + nums.push(addNum + temp[i]) + } + return nums +} + +// another + +/** + * @param {number} n + * @return {number[]} + */ +const grayCode = function(n) { + const arr = [] + arr.push(0) + for (let i = 0; i < n; i++) { + let inc = 1 << i + for (let j = arr.length - 1; j >= 0; j--) { + arr.push(arr[j] + inc) + } + } + return arr +} + +// another + +/** + * @param {number} n + * @return {number[]} + */ +const grayCode = function(n) { + return n + ? (x => [...x, ...x.map((v, i) => x[x.length - 1 - i] + x.length)])( + grayCode(n - 1) + ) + : [0] +} diff --git a/890-find-and-replace-pattern.js b/890-find-and-replace-pattern.js new file mode 100644 index 00000000..118af02a --- /dev/null +++ b/890-find-and-replace-pattern.js @@ -0,0 +1,62 @@ +/** + * @param {string[]} words + * @param {string} pattern + * @return {string[]} + */ +const findAndReplacePattern = (words, pattern) => { + return words.reduce((acc, item, index) => { + if (compose(words[index], pattern)) acc.push(words[index]); + return acc; + }, []); + + function compose(element, pattern) { + const s = new Set(); + const m = new Map(); + for (let i = 0; i < element.length; i++) { + const e = element[i]; + const p = pattern[i]; + s.add(e); + if (m.get(p) === undefined) { + m.set(p, e); + } else if (m.get(p) !== e) { + return false; + } + } + return m.size === s.size; + } +}; + +// anoother + +/** + * @param {string[]} words + * @param {string} pattern + * @return {string[]} + */ +const findAndReplacePattern = function(words, pattern) { + const p = helper(pattern); + const res = []; + for (let w of words) { + if (arrEqual(helper(w), p)) res.push(w); + } + return res; +}; + +function arrEqual(a, b) { + if (a.length !== b.length) return false; + for (let i = 0, len = a.length; i < len; i++) { + if (a[i] !== b[i]) return false; + } + return true; +} + +function helper(w) { + const m = new Map(); + const n = w.length; + const res = new Array(n).fill(0); + for (let i = 0; i < n; i++) { + if (!m.has(w[i])) m.set(w[i], m.size); + res[i] = m.get(w[i]); + } + return res; +} diff --git a/891-sum-of-subsequence-widths.js b/891-sum-of-subsequence-widths.js new file mode 100644 index 00000000..995a714c --- /dev/null +++ b/891-sum-of-subsequence-widths.js @@ -0,0 +1,12 @@ +/** + * @param {number[]} A + * @return {number} + */ +const sumSubseqWidths = function(A) { + A.sort((a, b) => a - b) + let c = 1, res = 0, mod = 10 ** 9 + 7 + for (let i = 0, n = A.length; i < n; i++, c = c * 2 % mod) { + res = (res + A[i] * c - A[n - i - 1] * c) % mod; + } + return (res + mod) % mod; +}; diff --git a/892-surface-area-of-3d-shapes.js b/892-surface-area-of-3d-shapes.js new file mode 100644 index 00000000..fca60f28 --- /dev/null +++ b/892-surface-area-of-3d-shapes.js @@ -0,0 +1,27 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const surfaceArea = function(grid) { + if(grid == null || grid.length === 0) return 0 + const m = grid.length, n = grid[0].length + let res = 0, adj = 0 + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + const h = grid[i][j] + if(h) res += h * 4 + 2 + if(j > 0) { + if(grid[i][j - 1]) adj += Math.min(h, grid[i][j - 1]) + } + if(i > 0) { + if(grid[i - 1][j]) adj += Math.min(h, grid[i - 1][j]) + } + // console.log(adj) + } + } + + return res - adj * 2 +}; + +// 2 * 4 + 2 +// 6 + 10 + 14 + 18 - (1 + 2 + 3 + 1) * 2 diff --git a/896-monotonic-array.js b/896-monotonic-array.js new file mode 100644 index 00000000..03a547f6 --- /dev/null +++ b/896-monotonic-array.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} nums + * @return {boolean} + */ +const isMonotonic = function(nums) { + return inc(nums) || dec(nums) +}; + +function inc(nums) { + if(nums == null || nums.length <= 1) return true + for(let i = 1, n = nums.length; i < n; i++) { + if(nums[i] < nums[i - 1]) return false + } + return true +} +function dec(nums) { + if(nums == null || nums.length <= 1) return true + for(let i = 1, n = nums.length; i < n; i++) { + if(nums[i] > nums[i - 1]) return false + } + return true +} + +// another + +/** + * @param {number[]} nums + * @return {boolean} + */ +const isMonotonic = function(nums) { + let inc = true, dec = true + for(let i = 1, n = nums.length; i < n; i++) { + inc &= nums[i] >= nums[i - 1] + dec &= nums[i] <= nums[i - 1] + } + return inc || dec +}; diff --git a/897-increasing-order-search-tree.js b/897-increasing-order-search-tree.js new file mode 100644 index 00000000..afa41b35 --- /dev/null +++ b/897-increasing-order-search-tree.js @@ -0,0 +1,23 @@ +/** + * 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 {TreeNode} + */ +const increasingBST = function(root) { + return helper(root, null) +}; + +function helper(node, tail) { + if(node == null) return tail + const res = helper(node.left, node) + node.left = null + node.right = helper(node.right, tail) + return res +} diff --git a/899-orderly-queue.js b/899-orderly-queue.js new file mode 100644 index 00000000..4bd4a8ab --- /dev/null +++ b/899-orderly-queue.js @@ -0,0 +1,21 @@ +/** + * @param {string} S + * @param {number} K + * @return {string} + */ +const orderlyQueue = function (S, K) { + if (K === 0) return S + else if (K > 1) return S.split('').sort().join('') + let result = 0, + L = S.length + for (let i = 1; i < L; i++) { + for (let j = 0; j < L; j++) { + let d = S.charCodeAt((result + j) % L) - S.charCodeAt((i + j) % L) + if (d !== 0) { + if (d > 0) result = i + break + } + } + } + return S.slice(result) + S.slice(0, result) +} diff --git a/901-online-stock-span.js b/901-online-stock-span.js new file mode 100644 index 00000000..55eee528 --- /dev/null +++ b/901-online-stock-span.js @@ -0,0 +1,25 @@ +const StockSpanner = function() { + this.values = [] +} + +/** + * @param {number} price + * @return {number} + */ +StockSpanner.prototype.next = function(price) { + let count = 1 + while ( + this.values.length > 0 && + this.values[this.values.length - 1][0] <= price + ) { + count += this.values.pop()[1] + } + this.values.push([price, count]) + return count +} + +/** + * Your StockSpanner object will be instantiated and called as such: + * var obj = new StockSpanner() + * var param_1 = obj.next(price) + */ diff --git a/902-numbers-at-most-n-given-digit-set.js b/902-numbers-at-most-n-given-digit-set.js new file mode 100644 index 00000000..2e5da545 --- /dev/null +++ b/902-numbers-at-most-n-given-digit-set.js @@ -0,0 +1,61 @@ +/** + * @param {string[]} digits + * @param {number} n + * @return {number} + */ +const atMostNGivenDigitSet = function(digits, n) { + let res = 0 + const str = `${n}`, len = str.length + const { pow } = Math, base = digits.length + for(let i = 1; i < len; i++) { + res += pow(base, i) + } + + dfs(0) + + return res + + function dfs(pos) { + if(pos === len) { + res++ + return + } + for(const ch of digits) { + if(str[pos] > ch) { + res += pow(base, len - 1 - pos) + } else if(str[pos] === ch) { + dfs(pos + 1) + } else break + } + } +}; + +// another + + +/** + * @param {string[]} digits + * @param {number} n + * @return {number} + */ +const atMostNGivenDigitSet = function(digits, n) { + const str = '' + n, { pow } = Math + const len = str.length, dsize = digits.length + let res = 0 + + for(let i = 1; i < len; i++) { + res += pow(dsize, i) + } + + for(let i = 0; i < len; i++) { + let sameNum = false + for(const d of digits) { + if(+d < +str[i]) { + res += pow(dsize, len - i - 1) + } else if(+d === +str[i]) sameNum = true + } + if(sameNum === false) return res + } + + return res + 1 +}; diff --git a/903-valid-permutations-for-di-sequence.js b/903-valid-permutations-for-di-sequence.js index a46b3fbd..13844712 100644 --- a/903-valid-permutations-for-di-sequence.js +++ b/903-valid-permutations-for-di-sequence.js @@ -1,3 +1,75 @@ +/** + * @param {string} s + * @return {number} + */ +const numPermsDISequence = function(s) { + const mod = 1e9 + 7 + const n = s.length + const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0)) + s = '#' + s + dp[0][0] = 1 + for(let i = 1; i <= n; i++) { + const ch = s[i] + for(let j = 0; j <= i; j++) { + if(ch === 'I') { + for(let k = 0; k < j; k++) { + dp[i][j] += dp[i - 1][k] + dp[i][j] %= mod + } + } else { + for(let k = j; k < i; k++) { + dp[i][j] += dp[i - 1][k] + dp[i][j] %= mod + } + } + } + } + + + let res = 0 + + for(let i = 0; i <= n; i++) { + res = (res + dp[n][i]) % mod + } + + return res +}; + + +// another + + +/** + * @param {string} s + * @return {number} + */ +const numPermsDISequence = function(s) { + const n = s.length, mod = 1e9 + 7 + const dp = Array.from({ length: n + 1}, () => Array(n + 1).fill(0)) + dp[0][0] = 1 + for(let i = 1; i <= n; i++) { + for(let j = 0; j <= i; j++) { + if(s[i - 1] === 'D') { + for(let k = j; k <= i - 1; k++) { + dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod + } + } else { + for(let k = 0; k < j; k++) { + dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod + } + } + } + } + let res = 0 + for(let i = 0; i <= n; i++) { + res = (res + dp[n][i]) % mod + } + + return res +}; + +// another + /** * @param {string} S * @return {number} diff --git a/904-fruit-into-baskets.js b/904-fruit-into-baskets.js new file mode 100644 index 00000000..4936d3d0 --- /dev/null +++ b/904-fruit-into-baskets.js @@ -0,0 +1,26 @@ +/** + * @param {number[]} fruits + * @return {number} + */ +const totalFruit = function (fruits) { + let n = fruits.length + let i = 0, j = 0 + const map = new Map() + let res = 0 + for(;j < n; j++) { + const e = fruits[j] + if(!map.has(e)) map.set(e, 1) + else map.set(e, map.get(e) + 1) + + while(map.size > 2 && i < n) { + const tmp = fruits[i++] + map.set(tmp, map.get(tmp) - 1) + if(map.get(tmp) === 0) { + map.delete(tmp) + } + } + res = Math.max(res, j - i + 1) + } + + return res +} diff --git a/906-super-palindromes.js b/906-super-palindromes.js new file mode 100644 index 00000000..9b97b889 --- /dev/null +++ b/906-super-palindromes.js @@ -0,0 +1,200 @@ +/** + * @param {string} L + * @param {string} R + * @return {number} + */ +const superpalindromesInRange = function (L, R) { + // My idea was to take the root of L and R and then generate all palindromes between those numbers, + // and then put those palindromes to power 2 and check if those are palindrome as well. + + // The generation of palindromes is done like this: + // Lets say i want all palindromes of length 4, then i take all numbers of length 2. + // I reverse the length 2 numbers and concatenate them with themselves. + // So "19" becomes "19" + "91". For odd length I do the same, + // but put a for loop around them that puts nrs 0 - 9 inside them. + // So "19" + "0" + "91", then "19" + "1" + "91", etc. + + // Next I loop through the generated palindromes and just check whether they are + // inside sqrt(L) and sqrt(R). (sqrt(L) < palin < sqrt(R)) + // For every palin within sqrt(L) and sqrt(R), i put the palin to power 2 + // (with BigInt!) and then check if that is a palindrome. If so, then count++; + + const sqL = Math.sqrt(L) + const sqR = Math.sqrt(R) + const sqR_Length = parseInt(sqR).toString(10).length + // counting the valid super-palindromes + let palins = 0 + // L is a superpalindrome + if ( + isPalindrome(L) && + sqL === parseInt(sqL) && + isPalindrome(sqL.toString(10)) + ) + palins++ + // R is a superpalindrome + if ( + isPalindrome(R) && + sqR === parseInt(sqR) && + isPalindrome(sqR.toString(10)) + ) + palins++ + + let end + if (sqR === parseInt(sqR)) { + // or else the loop will possibly add R as well + end = parseInt(sqR) - 1 + } else { + end = parseInt(Math.floor(sqR)) + } + + let begin + if (sqL === parseInt(sqL)) { + // or else the loop will possibly add R as well + begin = parseInt(sqL) + 1 + } else { + begin = parseInt(Math.ceil(sqL)) + } + + // account for superpalins with for single digit 'sub-palins' + if (begin <= 1 && end >= 1) palins++ // 1 + if (begin <= 2 && end >= 2) palins++ // 4 + if (begin <= 3 && end >= 3) palins++ // 9 + const length = sqR_Length + const even = length % 2 === 0 + const half = Math.floor(length / 2) + const pow10Half = Math.pow(10, half) // 10 or 100 or 1000, etc + const pow10HalfMinOne = Math.pow(10, half - 1) + let pal = '' // init + let palinStr = '' // init + let palin = -1 // init + for (let i = 1, leni = pow10Half; i < leni; i++) { + pal = i.toString(10) + pal.padStart(half - pal.length, '0') + palReverse = reverseStr(pal) + // generate even length palindrome + palinStr = pal + palReverse + palin = parseInt(palinStr) + if (palin >= begin && palin <= end) { + if (isPalindromeInt(BigInt(palin) * BigInt(palin))) { + palins++ + } + } + // If I generate all palindromes up until some even length, + // lets say 4, then last step is to do length 2 + length 2 (19 + 91), + // and not the 19 + 0 + 91 step that generates odd length palindromes. + if (even && i >= pow10HalfMinOne) { + continue + } + for (let j = 0, lenj = 10; j < lenj; j++) { + // generate odd length palindrome + palinStr = pal + j + palReverse + palin = parseInt(palinStr) + if (palin >= begin && palin <= end) { + if (isPalindromeInt(BigInt(palin) * BigInt(palin))) { + palins++ + } + } + } + } + return palins +} + +const reverseStr = function (str) { + return str.split('').reverse().join('') +} + +const isPalindromeInt = function (nr) { + nr = nr.toString(10) + return nr === nr.split('').reverse().join('') +} +const isPalindrome = function (nr) { + return nr === nr.split('').reverse().join('') +} + +// another + +/** + * @param {string} left + * @param {string} right + * @return {number} + */ + const superpalindromesInRange = function(left, right) { + const palindromes = [] + let res = 0 + for(let i = 1; i < 10; i++) { + palindromes.push(`${i}`) + } + for(let i = 1; i < 1e4; i++) { + let l = `${i}`, r = l.split('').reverse().join('') + palindromes.push(`${l}${r}`) + for(let j = 0; j < 10; j++) { + palindromes.push(`${l}${j}${r}`) + } + } + + for(let p of palindromes) { + const square = BigInt(p) * BigInt(p) + if(!isPalindrome(`${square}`)) continue + if(BigInt(left) <= square && square <= BigInt(right)) res++ + } + + return res + + function isPalindrome(str) { + let i = 0; + let j = str.length - 1; + while (i < j) { + if (str.charAt(i) !== str.charAt(j)) { + return false; + } + i++; + j--; + } + return true; + } +}; + +// another + +/** + * @param {string} left + * @param {string} right + * @return {number} + */ +const superpalindromesInRange = function (left, right) { + let ans = 9 >= left && 9 <= right ? 1 : 0 + + const isPal = (str) => { + for (let i = 0, j = str.length - 1; i < j; i++, j--) + if (str.charAt(i) !== str.charAt(j)) return false + return true + } + + for (let dig = 1; dig < 10; dig++) { + let isOdd = dig % 2 && dig !== 1, + innerLen = (dig >> 1) - 1, + innerLim = Math.max(1, 2 ** innerLen), + midPos = dig >> 1, + midLim = isOdd ? 3 : 1 + for (let edge = 1; edge < 3; edge++) { + let pal = new Uint8Array(dig) + ;(pal[0] = edge), (pal[dig - 1] = edge) + if (edge === 2) (innerLim = 1), (midLim = Math.min(midLim, 2)) + for (let inner = 0; inner < innerLim; inner++) { + if (inner > 0) { + let innerStr = inner.toString(2).padStart(innerLen, '0') + for (let i = 0; i < innerLen; i++) + (pal[1 + i] = innerStr[i]), (pal[dig - 2 - i] = innerStr[i]) + } + for (let mid = 0; mid < midLim; mid++) { + if (isOdd) pal[midPos] = mid + let palin = ~~pal.join(''), + square = BigInt(palin) * BigInt(palin) + if (square > right) return ans + if (square >= left && isPal(square.toString())) ans++ + } + } + } + } + return ans +} diff --git a/907-sum-of-subarray-minimums.js b/907-sum-of-subarray-minimums.js index 9268882a..ffb2c2a1 100644 --- a/907-sum-of-subarray-minimums.js +++ b/907-sum-of-subarray-minimums.js @@ -1,36 +1,104 @@ + /** - * @param {number[]} A + * @param {number[]} arr * @return {number} */ -const sumSubarrayMins = function(A) { - let n = A.length; - let s1 = []; - let s2 = []; - let left = new Array(n); - let right = new Array(n); + const sumSubarrayMins = function (arr) { + const n = arr.length + const mod = 1e9 + 7, stk = [] + const left = Array(n), right = Array(n) + for(let i = 0; i< n; i++) { + left[i] = i + 1 + right[i] = n - i + } + let res = 0 + for(let i = 0; i < n; i++) { + while(stk.length && arr[stk[stk.length - 1]] > arr[i]) { + const idx = stk.pop() + right[idx] = i - idx + } + if (stk.length) left[i] = i - stk[stk.length - 1] + stk.push(i) + + } + for(let i = 0; i < n; i++) { + res = (res + arr[i] * left[i] * right[i]) % mod + } + + return res +} + +// another +/** + * @param {number[]} arr + * @return {number} + */ +const sumSubarrayMins = function (arr) { + const n = arr.length, + s1 = [], + s2 = [], + left = Array(n), + right = Array(n) for (let i = 0; i < n; i++) { - let count = 1; - while (s1.length && s1[s1.length - 1][0] > A[i]) { - count += s1.pop()[1]; + let cnt = 1 + while (s1.length && s1[s1.length - 1][0] > arr[i]) { + cnt += s1.pop()[1] } - left[i] = count; - s1.push([A[i], count]); + left[i] = cnt + s1.push([arr[i], cnt]) } for (let i = n - 1; i >= 0; i--) { - let count = 1; - while (s2.length && s2[s2.length - 1][0] >= A[i]) { - count += s2.pop()[1]; + let cnt = 1 + while (s2.length && s2[s2.length - 1][0] >= arr[i]) { + cnt += s2.pop()[1] } - right[i] = count; - s2.push([A[i], count]); + right[i] = cnt + s2.push([arr[i], cnt]) } - - let res = 0; - let mod = 1e9 + 7; + let res = 0 + const mod = 1e9 + 7 for (let i = 0; i < n; i++) { - res = (res + left[i] * A[i] * right[i]) % mod; + // left[i] number of starting positions + // right[i] number of ending positions + res = (res + arr[i] * left[i] * right[i]) % mod } - return res; + + return res +} + +// another + +/** + * @param {number[]} arr + * @return {number} + */ +const sumSubarrayMins = function(arr) { + const stk1 = [], stk2 = [] + const len = arr.length, mod = 1e9 + 7 + const left = new Array(len), right = new Array(len) + for(let i = 0; i < len; i++) { + left[i] = i + 1 + right[i] = len - i + } + for(let i = 0; i < len; i++) { + while(stk1.length && arr[stk1[stk1.length - 1]] > arr[i]) { + stk1.pop() + } + left[i] = i - (stk1.length ? stk1[stk1.length - 1] : -1) + stk1.push(i) + + while(stk2.length && arr[stk2[stk2.length - 1]] > arr[i]) { + let index = stk2.pop() + right[index] = i - index + } + stk2.push(i) + } + + let res = 0 + for(let i = 0; i < len; i++) { + res = (res + arr[i] * left[i] * right[i]) % mod + } + return res }; diff --git a/908-smallest-range-i.js b/908-smallest-range-i.js new file mode 100644 index 00000000..8139e659 --- /dev/null +++ b/908-smallest-range-i.js @@ -0,0 +1,13 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const smallestRangeI = function(nums, k) { + let min = Infinity, max = -Infinity + for(let e of nums) { + min = Math.min(min, e) + max = Math.max(max, e) + } + return max - k >= min + k ? max - k - (min + k) : 0 +}; diff --git a/91-decode-ways.js b/91-decode-ways.js index eb664299..300145d2 100644 --- a/91-decode-ways.js +++ b/91-decode-ways.js @@ -1,3 +1,27 @@ +/** + * @param {string} s + * @return {number} + */ +const numDecodings = function(s) { + if(s == null || s.length === 0) return 1 + if(s[0] === '0') return 0 + const set = new Set() + const n = s.length + for(let i = 1; i <= 26; i++) { + set.add(`${i}`) + } + const dp = Array(n + 1).fill(0) + dp[0] = dp[1] = 1 + for(let i = 2; i <= n; i++) { + if(set.has(s[i - 2] + s[i - 1])) dp[i] += dp[i - 2] + if(set.has(s[i - 1])) dp[i] += dp[i - 1] + } + return dp[n] +}; + + +// another + /** * @param {string} s * @return {number} diff --git a/910-smallest-range-ii.js b/910-smallest-range-ii.js new file mode 100644 index 00000000..2c14d07f --- /dev/null +++ b/910-smallest-range-ii.js @@ -0,0 +1,21 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const smallestRangeII = function (nums, k) { + let n = nums.length + nums.sort((a, b) => a - b) + // all elements plus k or minus k + let res = nums[n - 1] - nums[0] + + // left side elements plus k, right side elements minus k + let left = nums[0] + k, right = nums[n - 1] - k + for(let i = 0; i < n - 1; i++) { + const tmax = Math.max(right, nums[i] + k) + const tmin = Math.min(left, nums[i + 1] - k) + res = Math.min(res, tmax - tmin) + } + + return res +} diff --git a/912-sort-an-array.js b/912-sort-an-array.js new file mode 100644 index 00000000..3d89197d --- /dev/null +++ b/912-sort-an-array.js @@ -0,0 +1,32 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +function swap(items, l, r) { + const temp = items[l]; + items[l] = items[r]; + items[r] = temp; +} +function partition(items, start, end) { + let pivot = items[end], s = start + for(let i = start; i < end; i++) { + if(items[i] <= pivot) { + swap(items, s, i) + s++ + } + } + swap(items, s, end) + return s +} + +function quickSort(items, left, right) { + if(left < right) { + const pIdx = partition(items, left, right) + quickSort(items, left, pIdx - 1) + quickSort(items, pIdx + 1, right) + } + return items; +} +const sortArray = function(nums) { + return quickSort(nums, 0, nums.length - 1); +}; diff --git a/913-cat-and-mouse.js b/913-cat-and-mouse.js new file mode 100644 index 00000000..6a226e3f --- /dev/null +++ b/913-cat-and-mouse.js @@ -0,0 +1,68 @@ +/** + * @param {number[][]} graph + * @return {number} + */ +const catMouseGame = function (g) { + const n = g.length + const win = Array(2) + .fill(0) + .map(() => Array(n * n).fill(0)) + for (let i = 0; i < n; i++) { + win[0][i] = 1 + win[1][i] = 1 + } + for (let i = 1; i < n; i++) { + win[0][i * n + i] = 2 + win[1][i * n + i] = 2 + } + + while (true) { + let anew = false + for (let m = 0; m < n; m++) { + inner: for (let c = 1; c < n; c++) { + if (win[0][m * n + c] == 0) { + let und = false + for (let e of g[m]) { + if (win[1][e * n + c] == 1) { + win[0][m * n + c] = 1 + anew = true + continue inner + } + if (win[1][e * n + c] == 0) { + und = true + } + } + if (!und) { + win[0][m * n + c] = 2 + anew = true + } + } + } + } + for (let c = 1; c < n; c++) { + inner: for (let m = 0; m < n; m++) { + if (win[1][m * n + c] == 0) { + let und = false + for (e of g[c]) { + if (e == 0) continue + if (win[0][m * n + e] == 2) { + win[1][m * n + c] = 2 + anew = true + continue inner + } + if (win[0][m * n + e] == 0) { + und = true + } + } + if (!und) { + win[1][m * n + c] = 1 + anew = true + } + } + } + } + if (!anew) break + } + + return win[0][1 * n + 2] +} diff --git a/914-x-of-a-kind-in-a-deck-of-cards.js b/914-x-of-a-kind-in-a-deck-of-cards.js new file mode 100644 index 00000000..04754e03 --- /dev/null +++ b/914-x-of-a-kind-in-a-deck-of-cards.js @@ -0,0 +1,19 @@ +/** + * @param {number[]} deck + * @return {boolean} + */ +const hasGroupsSizeX = function(deck) { + if(deck == null || deck.length <= 1) return false + const hash = {} + for(let e of deck) { + if(hash[e] == null) hash[e] = 0 + hash[e]++ + } + let res = 0 + for(let k in hash) res = gcd(hash[k], res) + return res > 1 +}; + +function gcd(a, b) { + return b ? gcd(b, a % b) : a +} diff --git a/918-maximum-sum-circular-subarray.js b/918-maximum-sum-circular-subarray.js index fad5b9eb..745de31f 100644 --- a/918-maximum-sum-circular-subarray.js +++ b/918-maximum-sum-circular-subarray.js @@ -3,13 +3,13 @@ * @return {number} */ const maxSubarraySumCircular = function(A) { - let total = 0, maxSum = -30000, curMax = 0, minSum = 30000, curMin = 0; - for (let a of A) { - curMax = Math.max(curMax + a, a); - maxSum = Math.max(maxSum, curMax); - curMin = Math.min(curMin + a, a); - minSum = Math.min(minSum, curMin); - total += a; - } - return maxSum > 0 ? Math.max(maxSum, total - minSum) : maxSum; -} + let minSum = Infinity, sum = 0, maxSum = -Infinity, curMax = 0, curMin = 0 + for(let a of A) { + sum += a + curMax = Math.max(curMax + a, a); + maxSum = Math.max(maxSum, curMax); + curMin = Math.min(curMin + a, a); + minSum = Math.min(minSum, curMin); + } + return maxSum > 0 ? Math.max(maxSum, sum - minSum) : maxSum; +}; diff --git a/919-complete-binary-tree-inserter.js b/919-complete-binary-tree-inserter.js new file mode 100644 index 00000000..2187f8bb --- /dev/null +++ b/919-complete-binary-tree-inserter.js @@ -0,0 +1,53 @@ +/** + * 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 + */ +var CBTInserter = function(root) { + this.r = root +}; + +/** + * @param {number} val + * @return {number} + */ +CBTInserter.prototype.insert = function(val) { + let q = [this.r] + + while(q.length) { + const tmp = [] + for(let i = 0; i < q.length; i++) { + const cur = q[i] + if(cur.left == null) { + cur.left = new TreeNode(val) + return cur.val + } else tmp.push(cur.left) + if(cur.right == null) { + cur.right = new TreeNode(val) + return cur.val + } else tmp.push(cur.right) + } + + q = tmp + } +}; + +/** + * @return {TreeNode} + */ +CBTInserter.prototype.get_root = function() { + return this.r +}; + +/** + * Your CBTInserter object will be instantiated and called as such: + * var obj = new CBTInserter(root) + * var param_1 = obj.insert(val) + * var param_2 = obj.get_root() + */ diff --git a/92-reverse-linked-list-ii.js b/92-reverse-linked-list-ii.js index aaee3f2b..8b30ebfb 100644 --- a/92-reverse-linked-list-ii.js +++ b/92-reverse-linked-list-ii.js @@ -1,3 +1,43 @@ +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @param {number} left + * @param {number} right + * @return {ListNode} + */ +const reverseBetween = function(head, left, right) { + if(head == null) return head + const dummy = new ListNode(null, head) + let num = 0, cur = head + while (cur) { + num++ + cur = cur.next + } + let idx = 0, pre = null + cur = dummy + while (idx < right && idx <= num) { + if (idx === left - 1) pre = cur + if (idx >= left) { + const tmp = pre.next + pre.next = cur.next + cur.next = cur.next.next + pre.next.next = tmp + } + + if (idx < left) cur = cur.next + idx++ + } + return dummy.next +}; + +// another + /** * Definition for singly-linked list. * function ListNode(val) { @@ -50,3 +90,147 @@ const reverseBetween = function(head, m, n) { tail.next = cur; return head; }; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @param {number} m + * @param {number} n + * @return {ListNode} + */ +const reverseBetween = function(head, m, n) { + if (!head) return null; + const dummy = new ListNode(0); + dummy.next = head; + let pre = dummy; + for (let i = 0; i < m-1; i++) pre = pre.next + let start = pre.next; + let then = start.next; + + for (let i = 0; i < n-m; i++) { + start.next = then.next + then.next = pre.next + pre.next = then; + then = start.next; + } + return dummy.next; +}; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @param {number} left + * @param {number} right + * @return {ListNode} + */ +const reverseBetween = function(head, left, right) { + if(head == null || left === right) return head + const dummy = new ListNode() + dummy.next = head + let tail = null, p = dummy + for(let i = 1; i < left; i++) { + p = p.next + } + tail = p.next + let tmp + for(let i = 0; i < right - left; i++) { + tmp = p.next + p.next = tail.next + tail.next = tail.next.next + p.next.next = tmp + } + + return dummy.next +}; + +// another + +/** + * @param {ListNode} head + * @param {number} left + * @param {number} right + * @return {ListNode} + */ +const reverseBetween = function(head, left, right) { + if(head == null) return head + if(left === right) return head + let cur = head, prev = null + let step = 1 + while(step !== left) { + prev = cur + cur = cur.next + step++ + } + let l = cur + while(step !== right) { + cur = cur.next + step++ + } + let r = cur, next = cur.next + // reverse + + let start = l, p = null + while(start !== r) { + let n = start.next + start.next = p + p = start + start = n + } + + r.next = p + l.next = next + if(prev) prev.next = r + + return prev ? head : r +}; + +// another + +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @param {number} left + * @param {number} right + * @return {ListNode} + */ +const reverseBetween = function(head, left, right) { + if(head == null) return head + const dummy = new ListNode() + dummy.next = head + + let p = dummy + for(let i = 0; i < left - 1; i++) { + p = p.next + } + let tail = p.next, tmp = null + for(let i = 0; i < right - left; i++) { + tmp = p.next + p.next = tail.next + tail.next = tail.next.next + p.next.next = tmp + } + + return dummy.next +}; diff --git a/920-number-of-music-playlists.js b/920-number-of-music-playlists.js new file mode 100644 index 00000000..98101a66 --- /dev/null +++ b/920-number-of-music-playlists.js @@ -0,0 +1,20 @@ +/** + * @param {number} N + * @param {number} L + * @param {number} K + * @return {number} + */ +const numMusicPlaylists = function (N, L, K) { + const mod = 10 ** 9 + 7 + const dp = Array.from({ length: L + 1 }, () => Array(N + 1).fill(0)) + dp[0][0] = 1 + for (let i = 1; i <= L; i++) { + for (let j = 1; j <= N; j++) { + dp[i][j] = (dp[i - 1][j - 1] * (N - (j - 1))) % mod + if (j > K) { + dp[i][j] = (dp[i][j] + ((dp[i - 1][j] * (j - K)) % mod)) % mod + } + } + } + return dp[L][N] +} diff --git a/921-minimum-add-to-make-parentheses-valid.js b/921-minimum-add-to-make-parentheses-valid.js new file mode 100644 index 00000000..3b92cefc --- /dev/null +++ b/921-minimum-add-to-make-parentheses-valid.js @@ -0,0 +1,25 @@ +/** + * @param {string} S + * @return {number} + */ +const minAddToMakeValid = function(S) { + if(S === '' || S == null) return 0 + const len = S.length + const h = { + o: 0, + c: 0 + } + for(let i = 0; i < len; i++) { + if(S[i] === '(') { + h.o++ + } else { + if(h.o > 0) { + h.o-- + } else { + h.c++ + } + } + } + + return h.o + h.c +}; diff --git a/924-minimize-malware-spread.js b/924-minimize-malware-spread.js new file mode 100644 index 00000000..70d60a8d --- /dev/null +++ b/924-minimize-malware-spread.js @@ -0,0 +1,63 @@ +/** + * @param {number[][]} graph + * @param {number[]} initial + * @return {number} + */ +const minMalwareSpread = function (graph, initial) { + const l = graph.length + const p = [] + const children = [] + for (let i = 0; i < l; i++) { + p[i] = i + children[i] = [i] + } + + for (let i = 0; i < l; i++) { + for (let j = i + 1; j < l; j++) { + if (graph[i][j] === 1) { + const pi = find(i) + const pj = find(j) + if (pi !== pj) { + union(pi, pj) + } + } + } + } + + initial.sort((a, b) => (a > b ? 1 : -1)) + + const count = {} + + let index = initial[0] + let max = 0 + // find the index that not unioned with other indexes and with the most number of children + initial.forEach((e) => { + const pe = find(e) + if (!count[pe]) count[pe] = 0 + count[pe] += 1 + }) + initial.forEach((e, i) => { + const pe = find(e) + if (count[pe] === 1 && children[pe].length > max) { + max = children[pe].length + index = e + } + }) + + return index + + function find(x) { + while (p[x] !== x) { + p[x] = p[p[x]] + x = p[x] + } + return x + } + + function union(pi, pj) { + p[pj] = pi + //also move the children to the new parent + children[pi] = children[pi].concat(children[pj]) + children[pj] = [] + } +} diff --git a/925-long-pressed-name.js b/925-long-pressed-name.js new file mode 100644 index 00000000..68f487ae --- /dev/null +++ b/925-long-pressed-name.js @@ -0,0 +1,13 @@ +/** + * @param {string} name + * @param {string} typed + * @return {boolean} + */ +const isLongPressedName = function(name, typed) { + let i = 0, m = name.length, n = typed.length + for(let j = 0; j < n; j++) { + if(i < m && name[i] === typed[j]) i++ + else if(j === 0 || typed[j] !== typed[j - 1]) return false + } + return i === m +}; diff --git a/926-flip-string-to-monotone-increasing.js b/926-flip-string-to-monotone-increasing.js new file mode 100644 index 00000000..71f6bfff --- /dev/null +++ b/926-flip-string-to-monotone-increasing.js @@ -0,0 +1,45 @@ +/** + * @param {string} s + * @return {number} + */ +const minFlipsMonoIncr = function(s) { + const n = s.length + let res = 0, oneCnt = 0 + for(const e of s) { + if(e === '1') oneCnt++ + else { + const stayZero = oneCnt + const flipToOne = res + 1 + res = Math.min(stayZero, flipToOne) + } + } + + return res +}; + +// another + + +/** + * @param {string} s + * @return {number} + */ +const minFlipsMonoIncr = function(s) { + const n = s.length + const arr = Array(n).fill(0) + let oneCnt = 0 + for(let i = 0; i < n; i++) { + if(s[i] === '1') oneCnt++ + arr[i] = oneCnt + } + const zeroCnt = n - oneCnt + let res = Infinity + + for(let i = 0; i < n; i++) { + const cnt = arr[i] + const tmp = cnt + (zeroCnt - (i + 1 - cnt)) + res = Math.min(res, tmp) + } + res = Math.min(res, oneCnt, zeroCnt) + return res +}; diff --git a/927-three-equal-parts.js b/927-three-equal-parts.js new file mode 100644 index 00000000..8807ab57 --- /dev/null +++ b/927-three-equal-parts.js @@ -0,0 +1,39 @@ +/** + * @param {number[]} A + * @return {number[]} + */ +const threeEqualParts = function (A) { + let countNumberOfOnes = 0 + for (let c of A) if (c === 1) countNumberOfOnes++ + if (countNumberOfOnes === 0) return [0, A.length - 1] + if (countNumberOfOnes % 3 != 0) return [-1, -1] + const k = countNumberOfOnes / 3 + let i + // find the first 1 in the array + for (i = 0; i < A.length; i++) if (A[i] == 1) break + let start = i + // find (k+1)th 1 in the array + let count1 = 0 + for (i = 0; i < A.length; i++) { + if (A[i] == 1) count1++ + if (count1 == k + 1) break + } + let mid = i + //find (2*k +1)th 1 in the array + count1 = 0 + for (i = 0; i < A.length; i++) { + if (A[i] === 1) count1++ + if (count1 === 2 * k + 1) break + } + let end = i + // Match all values till the end of the array + while (end < A.length && A[start] === A[mid] && A[mid] === A[end]) { + start++ + mid++ + end++ + } + // Return appropriate values if all the values have matched till the end + if (end == A.length) return [start - 1, mid] + // otherwise, no such indices found + return [-1, -1] +} diff --git a/928-minimize-malware-spread-ii.js b/928-minimize-malware-spread-ii.js new file mode 100644 index 00000000..dbe1249e --- /dev/null +++ b/928-minimize-malware-spread-ii.js @@ -0,0 +1,96 @@ +/** + * @param {number[][]} graph + * @param {number[]} initial + * @return {number} + */ +var minMalwareSpread = function (graph, initial) { + const map = new Map() // node -> initial nodes infect this node + for (let i of initial) { + const visited = new Set(initial) + const q = [] + q.push(i) + while (q.length) { + let cur = q.shift() + for (let j = 0; j < graph[cur].length; j++) { + if (graph[cur][j] == 1) { + if (!visited.has(j)) { + visited.add(j) + q.push(j) + + if (map.get(j) == null) map.set(j, []) + map.get(j).push(i) + } + } + } + } + } + + const res = Array(graph.length).fill(0) // node -> safe nodes it infects + for (let node of map.keys()) { + if (map.get(node).length == 1) { + let i = map.get(node)[0] + res[i]++ + } + } + let max = 0 + let removed = -1 + for (let i = 0; i < res.length; i++) { + if (res[i] > max) { + max = res[i] + removed = i + } + } + initial.sort((a, b) => a - b) + return removed == -1 ? initial[0] : removed +} + +// another + +/** + * @param {number[][]} graph + * @param {number[]} initial + * @return {number} + */ +const minMalwareSpread = function (graph, initial) { + const map = new Map(), n = graph.length + for(let init of initial) { + const visited = new Set(initial) + const q = [init] + while(q.length) { + const cur = q.pop() + for(let i = 0; i < n; i++) { + if(graph[cur][i] === 1 && !visited.has(i)) { + visited.add(i) + q.push(i) + if(map.get(i) == null) map.set(i, []) + map.get(i).push(init) + } + } + } + } + + let res = 0, max = -1 + const arr = Array(n) + for(let [k,v] of map) { + if(v.length === 1) { + if(arr[v[0]] == null) arr[v[0]] = 0 + arr[v[0]]++ + } + } + + for(let k = 0; k < n; k++) { + const v = arr[k] + if(v > max) { + max = v + res = +k + } + } + + let min = Infinity + for(let e of initial) { + if(e < min) min = e + } + return max === -1 ? min: res + +} + diff --git a/929-unique-email-addresses.js b/929-unique-email-addresses.js new file mode 100644 index 00000000..4ef8394c --- /dev/null +++ b/929-unique-email-addresses.js @@ -0,0 +1,26 @@ +/** + * @param {string[]} emails + * @return {number} + */ +const numUniqueEmails = function(emails) { + const res = new Set() + emails.forEach(el => helper(el, res)) + return res.size +}; + +function helper(str, s) { + const arr = str.split('@') + const p = arr[0] + const d = arr[1] + let res = '' + for(let i = 0, len = p.length; i < len; i++) { + if(p[i] === '.') { + continue + } else if(p[i] === '+') { + break + } else { + res += p[i] + } + } + s.add(`${res}@${d}`) +} diff --git a/930-binary-subarrays-with-sum.js b/930-binary-subarrays-with-sum.js index e94beea5..546d03a5 100644 --- a/930-binary-subarrays-with-sum.js +++ b/930-binary-subarrays-with-sum.js @@ -1,3 +1,27 @@ +/** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ +var numSubarraysWithSum = function(nums, goal) { + const n = nums.length + const hash = { 0: 1 } + let res = 0 + let sum = 0 + for(let i = 0; i < n; i++) { + const e = nums[i] + sum += e + const diff = sum - goal + if(hash[diff] != null) res += hash[diff] + if(hash[sum] == null) hash[sum] = 1 + else hash[sum]++ + } + + return res +}; + +// another + /** * @param {number[]} A * @param {number} S @@ -17,3 +41,27 @@ const numSubarraysWithSum = function(A, S) { } return ans; }; + +// another + +/** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ +const numSubarraysWithSum = function(nums, goal) { + const hash = {} + const n = nums.length + let res = 0, sum = 0 + for(let i = 0; i < n; i++) { + const cur = nums[i] + sum += cur + const pre = sum - goal + if(hash[sum] == null) hash[sum] = 0 + if(hash[pre] != null) res += hash[pre] + if(sum === goal) res++ + hash[sum]++ + } + + return res +}; diff --git a/931-minimum-falling-path-sum.js b/931-minimum-falling-path-sum.js new file mode 100644 index 00000000..d41ece0e --- /dev/null +++ b/931-minimum-falling-path-sum.js @@ -0,0 +1,44 @@ +/** + * @param {number[][]} A + * @return {number} + */ +const minFallingPathSum = function(A) { + for (let i = 1, rows = A.length; i < rows; i++) { + for (let j = 0, cols = A[0].length; j < cols; j++) { + A[i][j] += Math.min( + getValueOrMax(A, i - 1, j - 1), + getValueOrMax(A, i - 1, j), + getValueOrMax(A, i - 1, j + 1) + ); + } + } + return Math.min(...A[A.length - 1]); +}; + +function getValueOrMax(A, i, j) { + return A[i][j] !== undefined ? A[i][j] : Number.MAX_VALUE; +} + +// another + +/** + * @param {number[][]} A + * @return {number} + */ +const minFallingPathSum = function(A) { + for (let i = A.length - 2; i >= 0; i -= 1) { + for (let j = 0; j < A[i].length; j += 1) { + A[i][j] += Math.min( + getValueOrMax(A, i + 1, j - 1), + getValueOrMax(A, i + 1, j), + getValueOrMax(A, i + 1, j + 1) + ) + } + } + return Math.min(...A[0]) + } + + function getValueOrMax(A, i, j) { + return A[i][j] !== undefined ? A[i][j] : Number.MAX_VALUE + } + diff --git a/932-beautiful-array.js b/932-beautiful-array.js new file mode 100644 index 00000000..a0e5d999 --- /dev/null +++ b/932-beautiful-array.js @@ -0,0 +1,15 @@ +/** + * @param {number} N + * @return {number[]} + */ +const beautifulArray = function(N) { + let res = []; + res.push(1); + while (res.length < N) { + const tmp = []; + for (let i of res) if (i * 2 - 1 <= N) tmp.push(i * 2 - 1); + for (let i of res) if (i * 2 <= N) tmp.push(i * 2); + res = tmp; + } + return res; +}; diff --git a/936-stamping-the-sequence.js b/936-stamping-the-sequence.js new file mode 100644 index 00000000..6da09237 --- /dev/null +++ b/936-stamping-the-sequence.js @@ -0,0 +1,51 @@ +/** + * @param {string} stamp + * @param {string} target + * @return {number[]} + */ +const movesToStamp = function (stamp, target) { + const S = stamp.split('') + const T = target.split('') + const res = [] + const visited = Array(T.length).fill(false) + let stars = 0 + + while (stars < T.length) { + let doneReplace = false + for (let i = 0; i <= T.length - S.length; i++) { + if (!visited[i] && canReplace(T, i, S)) { + stars = doReplace(T, i, S.length, stars) + doneReplace = true + visited[i] = true + res.unshift(i) + if (stars === T.length) { + break + } + } + } + + if (!doneReplace) { + return [] + } + } + + return res + function canReplace(T, p, S) { + for (let i = 0; i < S.length; i++) { + if (T[i + p] !== '*' && T[i + p] !== S[i]) { + return false + } + } + return true + } + + function doReplace(T, p, len, count) { + for (let i = 0; i < len; i++) { + if (T[i + p] !== '*') { + T[i + p] = '*' + count++ + } + } + return count + } +} diff --git a/937-reorder-data-in-log-files.js b/937-reorder-data-in-log-files.js new file mode 100644 index 00000000..aa103f4e --- /dev/null +++ b/937-reorder-data-in-log-files.js @@ -0,0 +1,62 @@ +/** + * @param {string[]} logs + * @return {string[]} + */ +const reorderLogFiles = function(logs) { + const letterLog = [], + digitLog = [] + for (let log of logs) { + if (isNaN(log.split(' ')[1])) { + letterLog.push(log) + } else { + digitLog.push(log) + } + } + letterLog.sort((log1, log2) => { + let body1 = log1.slice(log1.indexOf(' ')) + let body2 = log2.slice(log2.indexOf(' ')) + if (body1 === body2) { + return log1.split(' ')[0] > log2.split(' ')[0] ? 1 : -1 + } else { + return body1 > body2 ? 1 : -1 + } + }) + return [...letterLog, ...digitLog] +} + +// another + +/** + * @param {string[]} logs + * @return {string[]} + */ +const reorderLogFiles = function(logs) { + if(logs == null || logs.length === 0) return [] + const ll = [] + const dl = [] + const zero = '0'.charCodeAt(0) + const nine = '9'.charCodeAt(0) + for(let e of logs) { + const arr = e.split(' ') + if(arr[1].charCodeAt(0) >= zero && arr[1].charCodeAt(0) <= nine) { + dl.push(arr) + } else { + ll.push(arr) + } + } + const rll = ll.map(el => { + const r = el.slice(1).join(' ') + return [el[0], r] + }).sort((a, b) => { + if(a[1] < b[1]) return -1 + else if(a[1] > b[1]) return 1 + else { + if(`${a[0]} ${a[1]}` > `${b[0]} ${b[1]}`) return 1 + else if(`${a[0]} ${a[1]}` < `${b[0]} ${b[1]}`) return -1 + else return 0 + } + }).map(el => el.join(' ')) + + const rdl = dl.map(el => el.join(' ')) + return rll.concat(rdl) +}; diff --git a/939-minimum-area-rectangle.js b/939-minimum-area-rectangle.js new file mode 100644 index 00000000..722d4940 --- /dev/null +++ b/939-minimum-area-rectangle.js @@ -0,0 +1,50 @@ +/** + * @param {number[][]} points + * @return {number} + */ +const minAreaRect = function(points) { + const xmap = {}, ymap = {} + points.forEach(e => { + const [x, y] = e + if(!xmap.hasOwnProperty(x)) xmap[x] = new Set() + if(!ymap.hasOwnProperty(y)) ymap[y] = new Set() + xmap[x].add(y) + ymap[y].add(x) + }) + let res = Infinity + for(let i = 0, len = points.length; i < len - 1; i++) { + const [x, y] = points[i] + for(let j = i + 1; j < len; j++) { + const [x1, y1] = points[j] + if(x === x1 || y === y1) continue + let area = Infinity + if(xmap[x].has(y1) && ymap[y].has(x1)) area = Math.abs(x - x1) * Math.abs(y - y1) + else continue + res = Math.min(res, area) + } + } + return res === Infinity ? 0 : res +}; + +// another + +/** + * @param {number[][]} points + * @return {number} + */ +const minAreaRect = function (points) { + let ans = Infinity + const isPoint = {} + points.forEach(([x, y]) => (isPoint[x * 40000 + y] = true)) + for (let idx1 = 0; idx1 < points.length - 1; idx1++) { + const [x1, y1] = points[idx1] + for (let idx2 = idx1 + 1; idx2 < points.length; idx2++) { + const [x2, y2] = points[idx2] + const area = Math.abs((x1 - x2) * (y1 - y2)) + if (area === 0 || area >= ans) continue + if (isPoint[x1 * 40000 + y2] && isPoint[x2 * 40000 + y1]) ans = area + } + } + return ans !== Infinity ? ans : 0 +} + diff --git a/940-distinct-subsequences-ii.js b/940-distinct-subsequences-ii.js index ba309c5a..723acd12 100644 --- a/940-distinct-subsequences-ii.js +++ b/940-distinct-subsequences-ii.js @@ -1,3 +1,25 @@ +/** + * @param {string} s + * @return {number} + */ +const distinctSubseqII = function(s) { + const n = s.length, + dp = Array(26).fill(0), + a = 'a'.charCodeAt(0), + mod = 1e9 + 7 + let res = 0 + for(let ch of s) { + const idx = ch.charCodeAt(0) - a + let tmp = 0 + for(let i = 0; i < 26; i++) tmp = (tmp + dp[i]) % mod + tmp = (tmp + 1) % mod + dp[idx] = tmp + } + return dp.reduce((ac, e) => (ac + e) % mod, 0) +}; + +// another + /** * @param {string} S * @return {number} diff --git a/942-di-string-match.js b/942-di-string-match.js index e8530c2f..7fee2f08 100644 --- a/942-di-string-match.js +++ b/942-di-string-match.js @@ -19,3 +19,32 @@ const diStringMatch = function(S) { res.push(arr.pop()) return res }; + +// another + +/* + +it is greedy and one pass !! +so every time when we meet an I, we need to keep in mind that we may meet another I later, +so the safest way is use the smallest number available. same idea when we meet D, +so in order to keep us safe, we always take largest one available, until we traverse the whole string. +And since the available numbers are sorted(from 0 to S.length()), +so we can set two pointers one starts from the head(smallest number), +another from the ends(largest number), then we begin to fill the res array. + +*/ + +/** + * @param {string} s + * @return {number[]} + */ +const diStringMatch = function(s) { + const n = s.length + let l = 0, r = n + const res = [] + for(let i = 0; i < n; i++) { + res.push(s[i] === 'I' ? l++ : r--) + } + res.push(r) + return res +}; diff --git a/945-minimum-increment-to-make-array-unique.js b/945-minimum-increment-to-make-array-unique.js new file mode 100644 index 00000000..0ce8f909 --- /dev/null +++ b/945-minimum-increment-to-make-array-unique.js @@ -0,0 +1,42 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const minIncrementForUnique = function(nums) { + const seen = new Set() + const queue = [] + let res = 0 + for(const e of nums) { + if(!seen.has(e)) seen.add(e) + else queue.push(e) + } + queue.sort((a, b) => b - a) + for(let i = 0; i <= 1e5 || queue.length; i++) { + if(!seen.has(i) && i > last(queue)) { + res += i - queue.pop() + } + } + + return res + + function last(arr) { + return arr[arr.length - 1] + } +}; + +// another + +/** + * @param {number[]} nums + * @return {number} + */ +const minIncrementForUnique = function(nums) { + let res = 0, nxt = 0 + nums.sort((a, b) => a - b) + for(const e of nums) { + res += Math.max(0, nxt - e) + nxt = Math.max(nxt, e) + 1 + } + + return res +}; diff --git a/948-bag-of-tokens.js b/948-bag-of-tokens.js new file mode 100644 index 00000000..6f9a68b9 --- /dev/null +++ b/948-bag-of-tokens.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} tokens + * @param {number} P + * @return {number} + */ +const bagOfTokensScore = function (tokens, P) { + tokens.sort((a, b) => a - b) + let res = 0, + score = 0, + i = 0, + j = tokens.length - 1 + while (i <= j) { + if (P >= tokens[i]) { + P -= tokens[i++] + res = Math.max(res, ++score) + } else if (score > 0) { + score-- + P += tokens[j--] + } else break + } + return res +} diff --git a/950-reveal-cards-in-increasing-order.js b/950-reveal-cards-in-increasing-order.js new file mode 100644 index 00000000..d25244e7 --- /dev/null +++ b/950-reveal-cards-in-increasing-order.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} deck + * @return {number[]} + */ +const deckRevealedIncreasing = function(deck) { + const n= deck.length; + + deck.sort((a, b) => a - b) + const q = []; + for (let i=0; i i) + } + find(x) { + if (this.root[x] !== x) { + this.root[x] = this.find(this.root[x]) + } + return this.root[x] + } + union(x, y) { + const xr = this.find(x) + const yr = this.find(y) + this.root[yr] = xr + } +} + +// another + + /** * @param {number[]} A * @return {number} diff --git a/953-verifying-an-alien-dictionary.js b/953-verifying-an-alien-dictionary.js new file mode 100644 index 00000000..d2717a39 --- /dev/null +++ b/953-verifying-an-alien-dictionary.js @@ -0,0 +1,27 @@ +/** + * @param {string[]} words + * @param {string} order + * @return {boolean} + */ +const isAlienSorted = function(words, order) { + const mapping = Array(26).fill(0), a = 'a'.charCodeAt(0) + for(let i = 0, len = order.length; i < len; i++) { + mapping[order.charCodeAt(i) - a] = i + } + + for(let i = 1, n = words.length; i < n; i++) { + if(bigger(words[i - 1], words[i])) return false + } + + return true + + function bigger(s1, s2) { + const n = s1.length, m = s2.length; + for (let i = 0; i < n && i < m; ++i) { + if (s1.charAt(i) != s2.charAt(i)) return mapping[s1.charCodeAt(i) - a] > mapping[s2.charCodeAt(i) - a]; + } + + return n > m; + } + +}; diff --git a/955-delete-columns-to-make-sorted-ii.js b/955-delete-columns-to-make-sorted-ii.js index 8c87fc56..0a9b4f52 100644 --- a/955-delete-columns-to-make-sorted-ii.js +++ b/955-delete-columns-to-make-sorted-ii.js @@ -2,27 +2,66 @@ * @param {string[]} A * @return {number} */ -const minDeletionSize = function(A) { - let res = 0, n = A.length, m = A[0].length, i, j; //n: 有多少个字符串,对应i. m:每个字符串的长度,对应j - let sorted = new Array(n - 1).fill(false); - for (j = 0; j < m; ++j) { //从第一个字符到最后一个字符 - for (i = 0; i < n - 1; ++i) { //i从第一个字到最后一个字 - if (!sorted[i] && A[i].charAt(j) > A[i + 1].charAt(j)) { - res++; - break; - } - } - if (i < n - 1) continue; +const minDeletionSize = function (A) { + let res = 0, + i, + j //n: 有多少个字符串,对应i. m:每个字符串的长度,对应j + const n = A.length, + m = A[0].length, + sorted = new Array(n - 1).fill(false) + for (j = 0; j < m; ++j) { + //从第一个字符到最后一个字符 + for (i = 0; i < n - 1; ++i) { + //i从第一个字到最后一个字 + if (!sorted[i] && A[i].charAt(j) > A[i + 1].charAt(j)) { + res++ + break + } + } + if (i < n - 1) continue + + //假设输入是["xgag","xfba","yfac"] + //那么第一轮j=0,比较第一列: x=xf,进入if条件语句,所以res = 1, break + //然后第三轮j=2,aa,这里b虽然>a,但是由于sorted[xfb] = true,所以不会进入到上面的循环体,然后sorted[xga] = true + //然后第四轮j=3,这一轮已经不再重要,因为通过前面几轮 sorted[0] = true, sorted[1] = true, 这意味着已经实现了排序,所以res最终结果就是1 + + for ( + i = 0; + i < n - 1; + ++i //这一段代码结合最外面的循环可以用作比较string大小的通用代码 + ) + if (A[i].charAt(j) < A[i + 1].charAt(j)) sorted[i] = true + } + return res +} - //假设输入是["xgag","xfba","yfac"] - //那么第一轮j=0,比较第一列: x=xf,进入if条件语句,所以res = 1, break - //然后第三轮j=2,aa,这里b虽然>a,但是由于sorted[xfb] = true,所以不会进入到上面的循环体,然后sorted[xga] = true - //然后第四轮j=3,这一轮已经不再重要,因为通过前面几轮 sorted[0] = true, sorted[1] = true, 这意味着已经实现了排序,所以res最终结果就是1 +// another - for (i = 0; i < n - 1; ++i) //这一段代码结合最外面的循环可以用作比较string大小的通用代码 - if (A[i].charAt(j) < A[i + 1].charAt(j)) - sorted[i] = true; +/** + * @param {string[]} A + * @return {number} + */ +const minDeletionSize = function (A) { + const set = new Set() + const m = A.length + let res = 0 + if(m === 0) return 0 + const n = A[0].length + for(j = 0; j < n; j++) { + if(set.size === m - 1) return res + for(i = 0; i < m - 1; i++) { + if(!set.has(i) && A[i][j] > A[i + 1][j]) { + res++ + break + } } - return res; -}; + if(i < m - 1) continue + for(i = 0; i < m - 1; i++) { + if(A[i][j] < A[i + 1][j]) set.add(i) + } + } + + return res +} + diff --git a/956-tallest-billboard.js b/956-tallest-billboard.js index 3b2cc2f8..2d322d8e 100644 --- a/956-tallest-billboard.js +++ b/956-tallest-billboard.js @@ -1,3 +1,28 @@ +/** + * @param {number[]} rods + * @return {number} + */ +const tallestBillboard = function(rods) { + const sum = rods.reduce((ac, e) => ac + e, 0) + const dp = Array(sum + 1).fill(-1), { abs, max, min } = Math + dp[0] = 0 + for(const e of rods) { + const bak = dp.slice() + for(let delta = 0; delta <= sum; delta++) { + if(bak[delta] < 0) continue + if(delta + e <= sum) dp[delta + e] = max(dp[delta + e], bak[delta]) + dp[abs(delta - e)] = max(dp[abs(delta - e)], bak[delta] + min(e, delta)) + } + } + + + return dp[0] +}; + + +// another + + /** * @param {number[]} rods * @return {number} diff --git a/957-prison-cells-after-n-days.js b/957-prison-cells-after-n-days.js new file mode 100644 index 00000000..7b30847e --- /dev/null +++ b/957-prison-cells-after-n-days.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} cells + * @param {number} N + * @return {number[]} + */ +const prisonAfterNDays = function (cells, N) { + const temp = [...cells] + const maxIter = 2 * cells.length - 2 + N = N % maxIter === 0 ? maxIter : N % maxIter + while (N > 0) { + for (let i = 0; i < cells.length; i++) { + temp[i] = cells[i - 1] === cells[i + 1] ? 1 : 0 + } + cells = [...temp] + N-- + } + return cells +} diff --git a/958-check-completeness-of-a-binary-tree.js b/958-check-completeness-of-a-binary-tree.js new file mode 100644 index 00000000..577628a0 --- /dev/null +++ b/958-check-completeness-of-a-binary-tree.js @@ -0,0 +1,49 @@ +/** + * 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} + */ +const isCompleteTree = function(root) { + let cur = [root] + let depth = 1 + while(cur.length) { + const nxt = [] + // console.log(cur) + for(let i = 0; i < cur.length; i++) { + const e = cur[i] + if(e == null) nxt.push(null, null) + else if(e) nxt.push(e.left, e.right) + } + + if(!valid(cur) || (cur[cur.length - 1] == null && valid(nxt))) { + return false + } + + if(nxt.some(e => e != null)) { + cur = nxt + } else { + cur = [] + } + depth++ + } + + return true + + function valid(arr) { + let firstNull = arr.length, lastNonNull = arr.length + for(let i = 0; i < arr.length; i++) { + const e = arr[i] + if(firstNull === arr.length && e == null) firstNull = i + if(e != null) lastNonNull = i + } + // console.log(firstNull, lastNonNull) + return firstNull >= lastNonNull + } +}; diff --git a/96-unique-binary-search-trees.js b/96-unique-binary-search-trees.js new file mode 100644 index 00000000..59e886d5 --- /dev/null +++ b/96-unique-binary-search-trees.js @@ -0,0 +1,40 @@ +/** + * @param {number} n + * @return {number} + */ +const numTrees = function(n) { + const arr = new Array(n + 1).fill(0) + arr[0] = arr[1] = 1 + for (let i = 2; i <= n; i++) { + for (let j = 1; j <= i; j++) { + arr[i] += arr[j - 1] * arr[i - j] + } + } + return arr[n] +} + +// another + +/** + * @param {number} n + * @return {number} + */ +const numTrees = function(n) { + const hash = { + 0: 1, + 1: 1 + } + return doNumTrees(n, hash) +} + +function doNumTrees(n, hash) { + if (hash[n]) return hash[n] + let sum = 0 + for (let i = 1; i <= n; i++) { + const left = doNumTrees(i - 1, hash) + const right = doNumTrees(n - i, hash) + sum += left * right + } + hash[n] = sum + return sum +} diff --git a/962-maximum-width-ramp.js b/962-maximum-width-ramp.js new file mode 100644 index 00000000..8cd14c1e --- /dev/null +++ b/962-maximum-width-ramp.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const maxWidthRamp = function(nums) { + const s = []; + let res = 0, n = nums.length; + for (let i = 0; i < n; ++i) { + if (s.length === 0 || nums[s.at(-1)] > nums[i]) s.push(i); + } + + for (let i = n - 1; i > res; --i) { + while (s.length && nums[s.at(-1)] <= nums[i]) res = Math.max(res, i - s.pop()); + } + + return res; +}; diff --git a/967-numbers-with-same-consecutive-differences.js b/967-numbers-with-same-consecutive-differences.js new file mode 100644 index 00000000..8bd4a423 --- /dev/null +++ b/967-numbers-with-same-consecutive-differences.js @@ -0,0 +1,29 @@ +/** + * @param {number} n + * @param {number} k + * @return {number[]} + */ +const numsSameConsecDiff = function (n, k) { + const res = [] + + for(let i = 1; i <= 9; i++) { + dfs(n - 1, [i]) + } + + return res + + function dfs(num, arr) { + if(num === 0) { + res.push(+arr.join('')) + return + } + + for(let i = 0; i <= 9; i++) { + if(Math.abs(i - arr[arr.length - 1]) === k) { + arr.push(i) + dfs(num - 1, arr) + arr.pop() + } + } + } +} diff --git a/969-pancake-sorting.js b/969-pancake-sorting.js new file mode 100644 index 00000000..2404c612 --- /dev/null +++ b/969-pancake-sorting.js @@ -0,0 +1,41 @@ +/** + * @param {number[]} arr + * @return {number[]} + */ + const pancakeSort = function (arr) { + const res = [] + let n = arr.length + while(n) { + const idx = indexOf(0, n - 1, n) + if(idx === n - 1) { + n-- + } else { + flip(0, idx) + flip(0, n - 1) + res.push(idx + 1, n) + n-- + } + } + return res + + function flip(l, r) { + while(l < r) { + const tmp = arr[l] + arr[l] = arr[r] + arr[r] = tmp + l++ + r-- + } + } + + function indexOf(start, end, target) { + let res = -1 + for(let i = start; i <= end; i++) { + if(arr[i]===target) { + res = i + break + } + } + return res + } +} diff --git a/971-flip-binary-tree-to-match-preorder-traversal.js b/971-flip-binary-tree-to-match-preorder-traversal.js new file mode 100644 index 00000000..e21fd117 --- /dev/null +++ b/971-flip-binary-tree-to-match-preorder-traversal.js @@ -0,0 +1,32 @@ +/** + * 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 + * @param {number[]} voyage + * @return {number[]} + */ +const flipMatchVoyage = function (root, voyage) { + const n = voyage.length + const res = [] + let idx = 0 + return dfs(root, 0) ? res : [-1] + + function dfs(node) { + if (node == null) return true + if (node.val !== voyage[idx]) { + return false + } + idx++ + if (node.left && node.left.val !== voyage[idx]) { + res.push(node.val) + return dfs(node.right) && dfs(node.left) + } + return dfs(node.left) && dfs(node.right) + } +} diff --git a/972-equal-rational-numbers.js b/972-equal-rational-numbers.js new file mode 100644 index 00000000..43e91a5b --- /dev/null +++ b/972-equal-rational-numbers.js @@ -0,0 +1,19 @@ +/** + * @param {string} S + * @param {string} T + * @return {boolean} + */ +const isRationalEqual = function (S, T) { + return f(S) === f(T) +} + +function f(S) { + let i = S.indexOf('(') + if (i > 0) { + let base = S.slice(0, i) + let rep = S.slice(i + 1, S.length - 1) + for (let j = 0; j < 20; ++j) base += rep + return +base + } + return +S +} diff --git a/973-k-closest-points-to-origin.js b/973-k-closest-points-to-origin.js index 3d5fe69b..b02f1611 100644 --- a/973-k-closest-points-to-origin.js +++ b/973-k-closest-points-to-origin.js @@ -39,3 +39,130 @@ function swap(arr, i, j) { function compare(p1, p2) { return p1[0] * p1[0] + p1[1] * p1[1] - p2[0] * p2[0] - p2[1] * p2[1] } + + +// another + +/** + * @param {number[][]} points + * @param {number} K + * @return {number[][]} + */ +const kClosest = (points, K) => { + const pq = new PriorityQueue( + (p1, p2) => p1[0] * p1[0] + p1[1] * p1[1] > p2[0] * p2[0] + p2[1] * p2[1] + ) + for (let p of points) { + pq.push(p) + if (pq.size() > K) { + pq.pop() + } + } + const res = new Array(K) + while (K > 0) { + res[--K] = pq.pop() + } + return res +} + +class PriorityQueue { + constructor(comparator = (a, b) => a > b) { + this.heap = [] + this.top = 0 + this.comparator = comparator + } + size() { + return this.heap.length + } + isEmpty() { + return this.size() === 0 + } + peek() { + return this.heap[this.top] + } + push(...values) { + values.forEach((value) => { + this.heap.push(value) + this.siftUp() + }) + return this.size() + } + pop() { + const poppedValue = this.peek() + const bottom = this.size() - 1 + if (bottom > this.top) { + this.swap(this.top, bottom) + } + this.heap.pop() + this.siftDown() + return poppedValue + } + replace(value) { + const replacedValue = this.peek() + this.heap[this.top] = value + this.siftDown() + return replacedValue + } + + parent = (i) => ((i + 1) >>> 1) - 1 + left = (i) => (i << 1) + 1 + right = (i) => (i + 1) << 1 + greater = (i, j) => this.comparator(this.heap[i], this.heap[j]) + swap = (i, j) => ([this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]) + siftUp = () => { + let node = this.size() - 1 + while (node > this.top && this.greater(node, this.parent(node))) { + this.swap(node, this.parent(node)) + node = this.parent(node) + } + } + siftDown = () => { + let node = this.top + while ( + (this.left(node) < this.size() && this.greater(this.left(node), node)) || + (this.right(node) < this.size() && this.greater(this.right(node), node)) + ) { + let maxChild = + this.right(node) < this.size() && + this.greater(this.right(node), this.left(node)) + ? this.right(node) + : this.left(node) + this.swap(node, maxChild) + node = maxChild + } + } +} + +// another + +/** + * @param {number[][]} points + * @param {number} k + * @return {number[][]} + */ +const kClosest = function(points, k) { + let len = points.length, l = 0, r = len - 1 + while (l <= r) { + let mid = helper(points, l, r) + if (mid === k) break + if (mid < k) l = mid + 1 + else r = mid - 1 + } + return points.slice(0, k) + + function helper(arr, l, r) { + const pivot = arr[l] + while(l < r) { + while(l < r && cmp(arr[r], pivot) >= 0) r-- + arr[l] = arr[r] + while(l < r && cmp(arr[l], pivot) <= 0) l++ + arr[r] = arr[l] + } + arr[l] = pivot + return l + } + + function cmp(a, b) { + return a[0] * a[0] + a[1] * a[1] - b[0] * b[0] - b[1] * b[1] + } +}; diff --git a/974-subarray-sums-divisible-by-k.js b/974-subarray-sums-divisible-by-k.js new file mode 100644 index 00000000..6c456912 --- /dev/null +++ b/974-subarray-sums-divisible-by-k.js @@ -0,0 +1,59 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var subarraysDivByK = function(nums, k) { + const n = nums.length; + const prefix = new Array(n).fill(0); + for(let i = 0; i < n; i++) { + prefix[i] = (prefix[i - 1] || 0) + nums[i]; + } + const count = new Array(k + 1).fill(0); + count[0] = 1; + let res = 0 + for(let i = 0; i < n; i++) { + const remain = ((prefix[i] % k) + k) % k + res += count[remain]; + count[remain]++; + } + return res +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const subarraysDivByK = function (nums, k) { + const memo = {0: 1} + let sum = 0, res = 0 + for(const e of nums) { + sum += e + const remain = ( sum % k + k) % k + res += memo[remain] ?? 0 + memo[remain] = (memo[remain] ?? 0) + 1 + } + return res +} + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const subarraysDivByK = function(nums, k) { + const memo = {0: 1} + let sum = 0, res = 0 + for(const e of nums) { + sum += e + const remain = (k - (sum % k)) % k + res += memo[remain] ?? 0 + memo[remain] = (memo[remain] ?? 0) + 1 + } + return res +}; diff --git a/975-odd-even-jump.js b/975-odd-even-jump.js new file mode 100644 index 00000000..2ffee5c4 --- /dev/null +++ b/975-odd-even-jump.js @@ -0,0 +1,52 @@ +/** + * @param {number[]} A + * @return {number} + */ +const oddEvenJumps = function (A) { + // Creates an array with ONLY the indices of the sorted array + let sorted = A.map((el, idx) => idx).sort((a, b) => A[a] - A[b] || a - b) + // Create an array of '-1's of the same array length for odd and even jumps + let oddJumps = new Array(A.length).fill(-1) + let evenJumps = new Array(A.length).fill(-1) + // Create an empty stack + let stack = [] + // Loop the the sorted array of the indices + for (let i of sorted) { + // Loops as long the stack is full OR if the index is greater than the the last index of the stack + while (stack.length && i > stack[stack.length - 1]) { + // Pops the index from the stack and place and add the 'i' index in sortedJumps + oddJumps[stack.pop()] = i + } + // Pushes the index onto the stack + stack.push(i) + } + // Empty the stack + stack = [] + // Reverses the sorted index array + let reverseSorted = sorted.sort((a, b) => A[b] - A[a] || a - b) + // Does the exact thing but for even jumps + for (let i of reverseSorted) { + while (stack.length && i > stack[stack.length - 1]) { + evenJumps[stack.pop()] = i + } + stack.push(i) + } + // Starts the count at 0 + let count = 1 + // Creates a boolean array of false elements for even and odd ends + let oddEnd = new Array(A.length).fill(false) + let evenEnd = new Array(A.length).fill(false) + // Switches the end of each array to true + oddEnd[A.length - 1] = true + evenEnd[A.length - 1] = true + // Loops through the array, starting from the 2nd from the right (since we do not need to worry about the last index) + for (let i = A.length - 2; i >= 0; --i) { + // If even jumps does + if (evenJumps[i] !== -1 && oddEnd[evenJumps[i]]) evenEnd[i] = true + if (oddJumps[i] !== -1 && evenEnd[oddJumps[i]]) { + oddEnd[i] = true + count++ + } + } + return count +} diff --git a/976-largest-perimeter-triangle.js b/976-largest-perimeter-triangle.js new file mode 100644 index 00000000..6cae6005 --- /dev/null +++ b/976-largest-perimeter-triangle.js @@ -0,0 +1,11 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const largestPerimeter = function(nums) { + nums.sort((a, b) => a - b) + for(let i = nums.length - 1; i > 1; i--) { + if(nums[i] < nums[i - 1] + nums[i - 2]) return nums[i - 2] + nums[i - 1] + nums[i] + } + return 0 +}; diff --git a/978-longest-turbulent-subarray.js b/978-longest-turbulent-subarray.js new file mode 100644 index 00000000..c44dc883 --- /dev/null +++ b/978-longest-turbulent-subarray.js @@ -0,0 +1,37 @@ +/** + * @param {number[]} arr + * @return {number} + */ +const maxTurbulenceSize = function(arr) { + const n = arr.length + + return Math.max(helper(), helper1()) + // < > < + function helper() { + const cnt = Array(n).fill(1) + + for(let i = 0; i < n - 1; i++) { + if(i % 2 === 1 && arr[i] > arr[i + 1]) { + cnt[i + 1] = cnt[i] + 1 + } else if(i % 2 === 0 && arr[i] < arr[i + 1]) { + cnt[i + 1] = cnt[i] + 1 + } + } + + return Math.max(...cnt) + } + + function helper1() { + const cnt = Array(n).fill(1) + + for(let i = 0; i < n - 1; i++) { + if(i % 2 === 1 && arr[i] < arr[i + 1] ) { + cnt[i + 1] = cnt[i] + 1 + } else if(i % 2 === 0 && arr[i] > arr[i + 1] ) { + cnt[i + 1] = cnt[i] + 1 + } + } + + return Math.max(...cnt) + } +}; diff --git a/979-distribute-coins-in-binary-tree.js b/979-distribute-coins-in-binary-tree.js new file mode 100644 index 00000000..ba29ee10 --- /dev/null +++ b/979-distribute-coins-in-binary-tree.js @@ -0,0 +1,25 @@ +/** + * 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 {number} + */ +const distributeCoins = function(root) { + let res = 0 + helper(root) + return res + + function helper(node) { + if(node == null) return 0 + const left = helper(node.left) + const right = helper(node.right) + res += Math.abs(left) + Math.abs(right) + return node.val + left + right - 1 + } +}; diff --git a/98-validate-binary-search-tree.js b/98-validate-binary-search-tree.js new file mode 100644 index 00000000..22856821 --- /dev/null +++ b/98-validate-binary-search-tree.js @@ -0,0 +1,23 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {boolean} + */ +const isValidBST = function(root) { + return helper(root, -Infinity, Infinity) +} +function helper(root, minValue, maxValue) { + if (!root) return true + if (root.val <= minValue || root.val >= maxValue) { + return false + } + let leftSide = helper(root.left, minValue, root.val) + let rightSide = helper(root.right, root.val, maxValue) + return leftSide && rightSide +} diff --git a/981-time-based-key-value-store.js b/981-time-based-key-value-store.js new file mode 100644 index 00000000..67101e69 --- /dev/null +++ b/981-time-based-key-value-store.js @@ -0,0 +1,97 @@ +/** + * Initialize your data structure here. + */ +const TimeMap = function() { + this.hash = {} +}; + +/** + * @param {string} key + * @param {string} value + * @param {number} timestamp + * @return {void} + */ +TimeMap.prototype.set = function(key, value, timestamp) { + if(this.hash[key] == null) this.hash[key] = [] + this.hash[key].push([value, timestamp]) +}; + +/** + * @param {string} key + * @param {number} timestamp + * @return {string} + */ +TimeMap.prototype.get = function(key, timestamp) { + if(this.hash[key] == null) return '' + const arr = this.hash[key] + + let l = 0, r = arr.length - 1; + while(l <= r) { + const pick = Math.floor((l + r) / 2); + if (arr[pick][1] < timestamp) { + l = pick + 1; + } else if (arr[pick][1] > timestamp) { + r = pick - 1 + } else { + return arr[pick][0]; + } + } + return arr[r]?.[0] || '' +}; + +/** + * Your TimeMap object will be instantiated and called as such: + * var obj = new TimeMap() + * obj.set(key,value,timestamp) + * var param_2 = obj.get(key,timestamp) + */ + +// another + +/** + * Initialize your data structure here. + */ +const TimeMap = function() { + this.hash = {} +}; + +/** + * @param {string} key + * @param {string} value + * @param {number} timestamp + * @return {void} + */ +TimeMap.prototype.set = function(key, value, timestamp) { + if(this.hash[key] == null) this.hash[key] = [] + this.hash[key].push([value, timestamp]) +}; + +/** + * @param {string} key + * @param {number} timestamp + * @return {string} + */ +TimeMap.prototype.get = function(key, timestamp) { + if(this.hash[key] == null) return '' + const arr = this.hash[key] + + let l = 0, r = arr.length + while(l < r) { + const mid = l + ((r - l) >> 1) + if(arr[mid][1] <= timestamp) { + l = mid + 1 + } else { + r = mid + } + } + + if(r === 0) return '' + return arr[r - 1][0] +}; + +/** + * Your TimeMap object will be instantiated and called as such: + * var obj = new TimeMap() + * obj.set(key,value,timestamp) + * var param_2 = obj.get(key,timestamp) + */ diff --git a/982-triples-with-bitwise-and-equal-to-zero.js b/982-triples-with-bitwise-and-equal-to-zero.js new file mode 100644 index 00000000..947d0d5d --- /dev/null +++ b/982-triples-with-bitwise-and-equal-to-zero.js @@ -0,0 +1,18 @@ +/** + * @param {number[]} A + * @return {number} + */ +const countTriplets = function (A) { + const N = 1 << 16, + M = 3 + const dp = Array.from({ length: M + 1 }, () => Array(N).fill(0)) + dp[0][N - 1] = 1 + for (let i = 0; i < M; i++) { + for (let k = 0; k < N; k++) { + for (let a of A) { + dp[i + 1][k & a] += dp[i][k] + } + } + } + return dp[M][0] +} diff --git a/983-minimum-cost-for-tickets.js b/983-minimum-cost-for-tickets.js new file mode 100644 index 00000000..60c0181e --- /dev/null +++ b/983-minimum-cost-for-tickets.js @@ -0,0 +1,17 @@ +/** + * @param {number[]} days + * @param {number[]} costs + * @return {number} + */ +const mincostTickets = function(days, costs) { + const last7 = [], last30 = [] + let res = 0 + for(let d of days) { + while(last7.length && last7[0][0] + 7 <= d) last7.shift() + while(last30.length && last30[0][0] + 30 <= d) last30.shift() + last7.push([d, res + costs[1]]) + last30.push([d, res + costs[2]]) + res = Math.min(res + costs[0], last7[0][1], last30[0][1]) + } + return res +}; diff --git a/984-string-without-aaa-or-bbb.js b/984-string-without-aaa-or-bbb.js new file mode 100644 index 00000000..b5996159 --- /dev/null +++ b/984-string-without-aaa-or-bbb.js @@ -0,0 +1,87 @@ +/** + * @param {number} a + * @param {number} b + * @return {string} + */ +const strWithout3a3b = function (a, b) { + let res = '' + + while(a > 0 || b > 0) { + if(endsWith(res, 'aa')) { + res += 'b' + b-- + } else if(endsWith(res, 'bb')) { + res += 'a' + a-- + } else if(a >= b) { + res += 'a' + a-- + } else { + res += 'b' + b-- + } + } + + return res + + function endsWith(str, sub) { + let i = str.length - 1, j = sub.length - 1 + for(; i >=0 && j >= 0;i--,j--) { + if(str[i] !== sub[j]) return false + } + if(j >= 0) return false + + return true + } +} + +// another + + +/** + * @param {number} a + * @param {number} b + * @return {string} + */ +const strWithout3a3b = function(a, b) { + let m = a, n = b, ch1 = 'a', ch2 = 'b' + if(b > a) { + m = b, n = a, ch1 = 'b', ch2 = 'a' + } + let res = '' + while(m-- > 0) { + res += ch1 + if(m > n) { + res += ch1 + m-- + } + if(n > 0) { + res += ch2 + n-- + } + } + return res +}; + +// another + +/** + * @param {number} a + * @param {number} b + * @return {string} + */ +const strWithout3a3b = function (a, b, ac = 'a', bc = 'b') { + const delta = a - b + let res = '' + if (delta < 0) { + return strWithout3a3b(b, a, 'b', 'a') + } else { + while(a-- > 0) { + res += ac + if(a > b) res += ac, a-- + if(b-- > 0) res += bc + } + } + + return res +} diff --git a/986-interval-list-intersections.js b/986-interval-list-intersections.js new file mode 100644 index 00000000..362e81d3 --- /dev/null +++ b/986-interval-list-intersections.js @@ -0,0 +1,49 @@ +/** + * Definition for an interval. + * function Interval(start, end) { + * this.start = start; + * this.end = end; + * } + */ +/** + * @param {Interval[]} A + * @param {Interval[]} B + * @return {Interval[]} + */ +const intervalIntersection = function (A, B) { + const intersection = [] + let i = (j = 0) + while (i < A.length && j < B.length) { + const min = Math.max(A[i][0], B[j][0]) + const max = Math.min(A[i][1], B[j][1]) + if (min <= max) intersection.push([min, max]) + A[i][1] > B[j][1] ? j++ : i++ + } + return intersection +} + +// another + +/** + * @param {number[][]} firstList + * @param {number[][]} secondList + * @return {number[][]} + */ +const intervalIntersection = function(firstList, secondList) { + const res = []; + let i = 0; + let j = 0; + while (i < firstList.length && j < secondList.length) { + const [start1, end1] = firstList[i]; + const [start2, end2] = secondList[j]; + if (start1 <= end2 && start2 <= end1) { + res.push([Math.max(start1, start2), Math.min(end1, end2)]); + } + if (end1 < end2) { + i++; + } else { + j++; + } + } + return res; +}; diff --git a/987-vertical-order-traversal-of-a-binary-tree.js b/987-vertical-order-traversal-of-a-binary-tree.js new file mode 100644 index 00000000..5dbc84f0 --- /dev/null +++ b/987-vertical-order-traversal-of-a-binary-tree.js @@ -0,0 +1,32 @@ +/** + * 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 {number[][]} + */ +const verticalTraversal = function(root) { + const arr = [] + helper(root, 0, 0, arr) + arr.sort((a, b) => a[0] - b[0] || b[1] - a[1] || a[2] - b[2]) + const res = new Map() + + for(let [x, y, val] of arr) { + if(!res.has(x)) res.set(x, []) + res.get(x).push(val) + } + return [...res.values()] +}; + +function helper(node, x, y, arr) { + if(node) { + helper(node.left, x - 1, y - 1, arr) + arr.push([x, y, node.val]) + helper(node.right, x + 1, y - 1, arr) + } +} diff --git a/989-add-to-array-form-of-integer.js b/989-add-to-array-form-of-integer.js new file mode 100644 index 00000000..9d43f139 --- /dev/null +++ b/989-add-to-array-form-of-integer.js @@ -0,0 +1,20 @@ +/** + * @param {number[]} num + * @param {number} k + * @return {number[]} + */ +const addToArrayForm = function(num, k) { + const res = [] + for(let i = num.length - 1; i >= 0; i--) { + const tmp = num[i] + k + res.push(tmp % 10) + k = ~~(tmp / 10) + } + + while(k > 0) { + res.push(k % 10) + k = ~~(k / 10) + } + res.reverse() + return res +}; diff --git a/992-subarrays-with-k-different-integers.js b/992-subarrays-with-k-different-integers.js index bb7ab822..21afa918 100644 --- a/992-subarrays-with-k-different-integers.js +++ b/992-subarrays-with-k-different-integers.js @@ -1,3 +1,62 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const subarraysWithKDistinct = function(nums, k) { + return mostK(k) - mostK(k - 1) + + function mostK(k) { + const map = new Map(), n = nums.length + let i = 0, j = 0, res = 0 + for(; j < n; j++) { + const e = nums[j] + map.set(e, (map.get(e) || 0) + 1) + while(map.size > k) { + const tmp = nums[i] + map.set(tmp, map.get(tmp) - 1) + if(map.get(tmp) === 0) map.delete(tmp) + i++ + } + res += j - i + 1 + } + + + return res + } +}; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const subarraysWithKDistinct = function(nums, k) { + return mostK(k) - mostK(k - 1) + function mostK(limit) { + const map = new Map() + let i = 0, j = 0, res = 0 + const n = nums.length + for(; j< n; j++) { + const e = nums[j] + map.set(e, (map.get(e) || 0) + 1) + while(map.size > limit) { + const tmp = nums[i] + map.set(tmp, (map.get(tmp) || 0) - 1) + if(map.get(tmp) === 0) map.delete(tmp) + i++ + } + res += j - i + 1 + } + + return res + } +}; + +// another + /** * @param {number[]} A * @param {number} K @@ -7,7 +66,7 @@ const subarraysWithKDistinct = function(A, K) { let res = 0 let prefix = 0 const m = new Array(A.length + 1).fill(0) - for (let i = 0, j = 0, cnt = 0; i < A.length; i++) { + for (let i = 0, j = 0, cnt = 0, len = A.length; i < len; i++) { if (m[A[i]]++ === 0) cnt++ if (cnt > K) { m[A[j++]]-- @@ -22,3 +81,61 @@ const subarraysWithKDistinct = function(A, K) { } return res } + +// another + +/** + * @param {number[]} A + * @param {number} K + * @return {number} + */ +const subarraysWithKDistinct = function (A, K) { + return mostK(K) - mostK(K - 1) + function mostK(num) { + const m = {}, len = A.length + let i = 0, j = 0, res = 0 + for(j = 0; j < len; j++) { + if(!m[A[j]]) m[A[j]] = 0, num-- + m[A[j]]++ + while(num < 0) { + m[A[i]]-- + if(!m[A[i]]) num++ + i++ + } + res += j - i + 1 + } + return res + } +} + +// another + +const subarraysWithKDistinct = function (nums, k) { + const n = nums.length + const atMost = (k) => { + const freq = new Array(n + 1).fill(0) + let l = 0, + r = 0 + let res = 0 + let cnt = 0 + while (r < n) { + if (freq[nums[r]] === 0) { + cnt++ + } + freq[nums[r]]++ + while (cnt > k) { + freq[nums[l]]-- + if (freq[nums[l]] === 0) { + cnt-- + } + l++ + } + res += r - l + 1 + r++ + } + return res + } + return atMost(k) - atMost(k - 1) +} + + diff --git a/993.cousins-in-binary-tree.js b/993.cousins-in-binary-tree.js index ddacddac..82cbd579 100644 --- a/993.cousins-in-binary-tree.js +++ b/993.cousins-in-binary-tree.js @@ -1,3 +1,42 @@ +/** + * 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 + * @param {number} x + * @param {number} y + * @return {boolean} + */ +const isCousins = (root, x, y, depth = 1, P = {}, D = {}) => { + let q = [root] + while (q.length) { + let K = q.length + while (K--) { + let p = q.shift() + if (p.left) { + if (p.left.val === x) (P.x = p.val), (D.x = depth) + if (p.left.val === y) (P.y = p.val), (D.y = depth) + q.push(p.left) + } + if (p.right) { + if (p.right.val === x) (P.x = p.val), (D.x = depth) + if (p.right.val === y) (P.y = p.val), (D.y = depth) + q.push(p.right) + } + } + ++depth + } + return P.x !== P.y && D.x === D.y +} + + +// another + /** * Definition for a binary tree node. * function TreeNode(val) { diff --git a/994-rotting-oranges.js b/994-rotting-oranges.js index e78c1ca8..2fa9a406 100644 --- a/994-rotting-oranges.js +++ b/994-rotting-oranges.js @@ -1,3 +1,42 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +const orangesRotting = function(grid) { + const m = grid.length, n = grid[0].length + const dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]] + const visited = new Set() + let q = [] + let num = 0 + for(let i = 0; i < m; i++) { + for(let j = 0; j < n; j++) { + if(grid[i][j] === 2) q.push([i, j]), visited.add(`${i},${j}`) + if(grid[i][j] !== 0) num++ + } + } + let res = 0 + while(q.length) { + const size = q.length + const tmp = [] + for(let i = 0; i < size; i++) { + const [x, y] = q[i] + for(let [dx, dy] of dirs) { + const nx = x + dx, ny = y + dy + if(nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] === 1 && !visited.has(`${nx},${ny}`)) { + tmp.push([nx, ny]) + visited.add(`${nx},${ny}`) + } + } + } + q = tmp + if(q.length) res++ + } + return visited.size === num ? res : -1 +}; + +// another + + /** * @param {number[][]} grid * @return {number} diff --git a/995-minimum-number-of-k-consecutive-bit-flips.js b/995-minimum-number-of-k-consecutive-bit-flips.js index ae3a47d1..90a4ad92 100644 --- a/995-minimum-number-of-k-consecutive-bit-flips.js +++ b/995-minimum-number-of-k-consecutive-bit-flips.js @@ -1,3 +1,25 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minKBitFlips = function(nums, k) { + let cur = 0, res = 0 + const n = nums.length + for(let i = 0; i < n; i++) { + if(i >= k && nums[i - k] === 2) cur-- + if(cur % 2 === nums[i]) { + if(i + k > n) return -1 + nums[i] = 2 + cur++ + res++ + } + } + return res +}; + +// another + /** * @param {number[]} A * @param {number} K @@ -16,3 +38,31 @@ const minKBitFlips = function(A, K) { } return res; }; + +// another + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const minKBitFlips = function(nums, k) { + const n = nums.length, q = [] + let res = 0 + for(let i = 0; i < n; i++) { + if(nums[i] === 0) { + if(q.length === 0 || q.length % 2 === 0) { + res++ + q.push(i + k - 1) + } + } else { + if(q.length % 2 === 1) { + res++ + q.push(i + k - 1) + } + } + if(q.length && i >= q[0]) q.shift() + } + return q.length ? -1 : res +}; + diff --git a/996-number-of-squareful-arrays.js b/996-number-of-squareful-arrays.js index de84d5a8..ef73e378 100644 --- a/996-number-of-squareful-arrays.js +++ b/996-number-of-squareful-arrays.js @@ -3,43 +3,43 @@ * @return {number} */ -const numSquarefulPerms = function(A) { - const cntMap = {}; - const squareMap = {}; - let cnt = 0; +const numSquarefulPerms = function (A) { + const cntMap = {} + const squareMap = {} + let cnt = 0 for (let num of A) { if (!cntMap.hasOwnProperty(num)) { - cntMap[num] = 1; - squareMap[num] = new Set(); + cntMap[num] = 1 + squareMap[num] = new Set() } else { - cntMap[num] = cntMap[num] + 1; + cntMap[num] = cntMap[num] + 1 } } for (let num1 of Object.keys(cntMap)) { for (let num2 of Object.keys(cntMap)) { - let c = Math.sqrt(+num1 + +num2); + let c = Math.sqrt(+num1 + +num2) if (c === Math.floor(c)) { - squareMap[num1].add(+num2); - squareMap[num2].add(+num1); + squareMap[num1].add(+num2) + squareMap[num2].add(+num1) } } } for (let num of Object.keys(cntMap)) { - countPerm(num, A.length - 1); + countPerm(num, A.length - 1) } - return cnt; + return cnt function countPerm(num, left) { - cntMap[num] = cntMap[num] - 1; + cntMap[num] = cntMap[num] - 1 if (left === 0) { - cnt++; + cnt++ } else { for (let next of squareMap[num]) { if (cntMap[next] !== 0) { - countPerm(next, left - 1); + countPerm(next, left - 1) } } } - cntMap[num] = cntMap[num] + 1; + cntMap[num] = cntMap[num] + 1 } -}; +} diff --git a/997-find-the-town-judge.js b/997-find-the-town-judge.js new file mode 100644 index 00000000..55b28506 --- /dev/null +++ b/997-find-the-town-judge.js @@ -0,0 +1,41 @@ +/** + * @param {number} N + * @param {number[][]} trust + * @return {number} + */ +const findJudge = function(N, trust) { + const arr = new Array(N + 1).fill(0) + for(let [t, ted] of trust) { + arr[t]-- + arr[ted]++ + } + for(let i = 1; i <= N; i++) { + if(arr[i] === N - 1) return i + } + return -1 +}; + +// another + +/** + * @param {number} N + * @param {number[][]} trust + * @return {number} + */ +const findJudge = function(N, trust) { + const m = new Map() + for(let i = 1; i<= N; i++) { + const e = new Map() + e.set('t', new Set()) + e.set('ted', new Set()) + m.set(i, e) + } + for(let [t, ted] of trust) { + m.get(t).get('t').add(ted) + m.get(ted).get('ted').add(t) + } + for(let [k,v] of m) { + if(v.get('t').size === 0 && v.get('ted').size === N - 1) return k + } + return -1 +}; diff --git a/999-available-captures-for-rook.js b/999-available-captures-for-rook.js new file mode 100644 index 00000000..d6fb8571 --- /dev/null +++ b/999-available-captures-for-rook.js @@ -0,0 +1,18 @@ +/** + * @param {character[][]} board + * @return {number} + */ +const numRookCaptures = function(board) { + for (let i = 0; i < board.length; ++i) + for (let j = 0; j < board[i].length; ++j) + if (board[i][j] == 'R') return cap(board,i,j,0,1)+cap(board,i,j,0,-1)+cap(board,i,j,1,0)+cap(board,i,j,-1,0); + return 0; +}; + +function cap(b, x, y, dx, dy) { + while (x >= 0 && x < b.length && y >= 0 && y < b[x].length && b[x][y] != 'B') { + if (b[x][y] == 'p') return 1; + x += dx; y += dy; + } + return 0; +} diff --git a/LICENSE b/LICENSE index 584ad7e8..be19a0e2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 everthis +Copyright (c) 2022 everthis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/TBD-leftmost-column-with-at-least-a-one.js b/TBD-leftmost-column-with-at-least-a-one.js new file mode 100644 index 00000000..bfd5e911 --- /dev/null +++ b/TBD-leftmost-column-with-at-least-a-one.js @@ -0,0 +1,34 @@ +/** + * // This is the BinaryMatrix's API interface. + * // You should not implement it, or speculate about its implementation + * function BinaryMatrix() { + * @param {integer} x, y + * @return {integer} + * this.get = function(x, y) { + * ... + * }; + * + * @return {[integer, integer]} + * this.dimensions = function() { + * ... + * }; + * }; + */ + +/** + * @param {BinaryMatrix} binaryMatrix + * @return {number} + */ +const leftMostColumnWithOne = function (binaryMatrix) { + const [rows, cols] = binaryMatrix.dimensions() + let candidate = -1 + for (let r = 0, c = cols - 1; r < rows && c >= 0; ) { + if (binaryMatrix.get(r, c) === 1) { + candidate = c + c-- + } else { + r++ + } + } + return candidate +} diff --git a/detailed/156-binary-tree-upside-down.md b/detailed/156-binary-tree-upside-down.md new file mode 100644 index 00000000..571e5c9c --- /dev/null +++ b/detailed/156-binary-tree-upside-down.md @@ -0,0 +1,44 @@ +![alt text](https://github.com/everthis/leetcode-js/blob/master/images/binary-tree-upside-down.webp "binary-tree-upside-down") + +```js +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {TreeNode} + */ +const upsideDownBinaryTree = function(root) { + let curr = root + let next = null + let temp = null + let prev = null + while (curr !== null) { + next = curr.left + curr.left = temp + temp = curr.right + curr.right = prev + prev = curr + curr = next + } + return prev +} + +// another + +const upsideDownBinaryTree = function(root) { + if (root == null || root.left == null) { + return root + } + const newRoot = upsideDownBinaryTree(root.left) + root.left.left = root.right + root.left.right = root + root.left = null + root.right = null + return newRoot +} +``` diff --git a/detailed/918-maximum-sum-circular-subarray.md b/detailed/918-maximum-sum-circular-subarray.md new file mode 100644 index 00000000..b40bbc18 --- /dev/null +++ b/detailed/918-maximum-sum-circular-subarray.md @@ -0,0 +1,19 @@ +![alt text](https://github.com/everthis/leetcode-js/blob/master/images/maximum-sum-circular-subarray.png "maximum-sum-circular-subarray") + +```js +/** + * @param {number[]} A + * @return {number} + */ +const maxSubarraySumCircular = function(A) { + let minSum = Infinity, sum = 0, maxSum = -Infinity, curMax = 0, curMin = 0 + for(let a of A) { + sum += a + curMax = Math.max(curMax + a, a); + maxSum = Math.max(maxSum, curMax); + curMin = Math.min(curMin + a, a); + minSum = Math.min(minSum, curMin); + } + return maxSum > 0 ? Math.max(maxSum, sum - minSum) : maxSum; +}; +``` diff --git a/detailed/meeting-room-ii.md b/detailed/meeting-room-ii.md new file mode 100644 index 00000000..10342eb3 --- /dev/null +++ b/detailed/meeting-room-ii.md @@ -0,0 +1,27 @@ +![alt text](https://github.com/everthis/leetcode-js/blob/master/images/meeting-room-ii-0.jpg "meeting-room-ii") +![alt text](https://github.com/everthis/leetcode-js/blob/master/images/meeting-room-ii-1.jpg "meeting-room-ii") + +```javascript +/** + * @param {number[][]} intervals + * @return {number} + */ +const minMeetingRooms = function(intervals) { + const len = intervals.length + const starts = new Array(len) + const ends = new Array(len) + for (let i = 0; i < len; i++) { + starts[i] = intervals[i][0] + ends[i] = intervals[i][1] + } + starts.sort((a, b) => a - b) + ends.sort((a, b) => a - b) + let rooms = 0 + let endsIdx = 0 + for (let i = 0; i < len; i++) { + if (starts[i] < ends[endsIdx]) rooms++ + else endsIdx++ + } + return rooms +} +``` diff --git a/images/.keep b/images/.keep new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/images/.keep @@ -0,0 +1 @@ + diff --git a/images/310.jpeg b/images/310.jpeg new file mode 100644 index 00000000..94f48a59 Binary files /dev/null and b/images/310.jpeg differ diff --git a/images/689.png b/images/689.png new file mode 100644 index 00000000..3a19a37a Binary files /dev/null and b/images/689.png differ diff --git a/images/Sieve_of_Eratosthenes_animation.gif b/images/Sieve_of_Eratosthenes_animation.gif new file mode 100644 index 00000000..cd385eec Binary files /dev/null and b/images/Sieve_of_Eratosthenes_animation.gif differ diff --git a/images/binary-tree-upside-down.webp b/images/binary-tree-upside-down.webp new file mode 100644 index 00000000..22974412 Binary files /dev/null and b/images/binary-tree-upside-down.webp differ diff --git a/images/maximum-sum-circular-subarray.png b/images/maximum-sum-circular-subarray.png new file mode 100644 index 00000000..949ccd72 Binary files /dev/null and b/images/maximum-sum-circular-subarray.png differ diff --git a/images/meeting-room-ii-0.jpg b/images/meeting-room-ii-0.jpg new file mode 100644 index 00000000..65dae20e Binary files /dev/null and b/images/meeting-room-ii-0.jpg differ diff --git a/images/meeting-room-ii-1.jpg b/images/meeting-room-ii-1.jpg new file mode 100644 index 00000000..881687fb Binary files /dev/null and b/images/meeting-room-ii-1.jpg differ diff --git a/tmp.js b/tmp.js new file mode 100644 index 00000000..4e53563a --- /dev/null +++ b/tmp.js @@ -0,0 +1,141 @@ +/** + * @param {string} s + * @return {boolean} + */ +var isDecomposable = function(s) { + let hasTwo = false + let i = 0 + let j = 0 + + while(j < s.length) { + while(j + 1 < s.length && s[j + 1] === s[i]) { + j += 1 + } + + if (((j - i + 1) % 3) === 2) { + if (!hasTwo) { + hasTwo = true + } else { + return false + } + } else if (((j - i + 1) % 3) === 1) { + return false + } + j++ + i = j + } + + return hasTwo +}; + + +class Solution { +public: + vector longestCommomSubsequence(vector>& arrays) { + int n = arrays.size(); + vector nums = vector(100); // 100 possible numbers as stated in the question + for (int i = 0; i < n; i++) { + for (int j = 0; j < arrays[i].size(); j++) { + nums[arrays[i][j] - 1]++; // count occurrences + } + } + vector ans; + for (int i = 0; i < 100; i++) { + if (nums[i] == n) ans.push_back(i + 1); // save it if it appears in every array + } + return ans; + } +}; + +class Solution { + public int[] findMaximums(int[] nums) { + if(nums == null || nums.length == 0) return nums; + // calc the [l, r] for each ele where in [l, r]: ele is the min value + int len = nums.length; + TreeSet idx = new TreeSet<>(); + Integer[] indices = new Integer[len]; + for(int i = 0; i < len; i++) indices[i] = i; + Arrays.sort(indices, (l, r) -> nums[l] - nums[r]); + int prev = -1; + int[] ranges = new int[len]; + Queue sameLevel = new LinkedList<>(); + int[] ans = new int[len]; + for(int i = 0; i < len; i++) { + if(nums[indices[i]] > prev) { + while(!sameLevel.isEmpty()) { + idx.add(sameLevel.poll()); + } + } + Integer l = idx.lower(indices[i]); + Integer r = idx.higher(indices[i]); + ranges[indices[i]] = (r == null?len - 1:r - 1) - (l == null?0:l + 1) + 1; + prev = nums[indices[i]]; + sameLevel.add(indices[i]); + } + // we iterate ranges from maximum to minimum to construct the ans array + int j = len - 1; + for(int i = len - 1; i >= 0; i--) { + while(j >= 0 && ranges[indices[j]] < len - i) { + j--; + } + ans[len - 1 - i] = nums[indices[j]]; + } + return ans; + } +} + +class Solution: + def minDayskVariants(self, points: List[List[int]], k: int) -> int: + lo = 0 + hi = int(1e9) + + # binary search check helper function + def check(day): + lines = collections.defaultdict(collections.Counter) + + # 2d sweep line + for x, y in points: + lbx, lby = (x, y - day) # left point + ubx, uby = (x - day, y) # bottom point + + # lbx + lby == ubx + uby == new x axis's open line + lines[lbx+lby][lby-lbx] += 1 + lines[ubx+uby][uby-ubx+1] -= 1 # + + # lbx + lby == ubx + uby == new x axis's close line + lbx, lby = (x + day, y) # right point + ubx, uby = (x, y + day) # upper point + lines[lbx+lby+1][lby-lbx] -= 1 + lines[ubx+uby+1][uby-ubx+1] += 1 + + # hold a new ranges to sweep all lines from left to right on new x axis + ranges = collections.Counter() + + # for every critical points on new x axis (it's a diag on the original axis), + # add the sweep lines on new y axis + for diag in sorted(lines): + for num in sorted(lines[diag]): + cnt = lines[diag][num] + ranges[num] += cnt + + # for every critical points, check whether there is an area having + # overlapping points >= k + cur = 0 + for num in sorted(ranges): + cnt = ranges[num] + cur += cnt + + if cur >= k: + return True + + return False + + # binary search + while lo < hi: + mid = (lo + hi) // 2 + if check(mid): + hi = mid + else: + lo = mid + 1 + + return lo