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/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 fdc1b195..2ce978c9 100644 --- a/1024-video-stitching.js +++ b/1024-video-stitching.js @@ -1,3 +1,34 @@ +/** + * @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 diff --git a/1041-robot-bounded-in-circle.js b/1041-robot-bounded-in-circle.js index 59b27fb2..65146881 100644 --- a/1041-robot-bounded-in-circle.js +++ b/1041-robot-bounded-in-circle.js @@ -34,3 +34,26 @@ const isRobotBounded = function(instructions) { } 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/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 48291448..9403a04b 100644 --- a/1044-longest-duplicate-substring.js +++ b/1044-longest-duplicate-substring.js @@ -1,3 +1,36 @@ +/** + * @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} 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/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/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 index e7b365ce..8b536b6d 100644 --- a/1066-campus-bikes-ii.js +++ b/1066-campus-bikes-ii.js @@ -1,3 +1,111 @@ +/** + * @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 diff --git a/1067-digit-count-in-range.js b/1067-digit-count-in-range.js index 55a147f6..7b75d18d 100644 --- a/1067-digit-count-in-range.js +++ b/1067-digit-count-in-range.js @@ -1,3 +1,50 @@ +/** + * @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 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/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/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/11-container-with-most-water.js b/11-container-with-most-water.js index 2b3aa808..763f29d5 100755 --- a/11-container-with-most-water.js +++ b/11-container-with-most-water.js @@ -12,3 +12,27 @@ const maxArea = function(height) { } 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-- + rightMax = max(rightMax, height[j]) + } + } + + 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/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/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 index 4b6b6db5..6f727b6e 100644 --- a/1136-parallel-courses.js +++ b/1136-parallel-courses.js @@ -1,3 +1,50 @@ +/** + * @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 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/1146-snapshot-array.js b/1146-snapshot-array.js index 31164a7e..28e93963 100644 --- a/1146-snapshot-array.js +++ b/1146-snapshot-array.js @@ -1,3 +1,59 @@ +/** + * @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 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/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/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/1167-minimum-cost-to-connect-sticks.js b/1167-minimum-cost-to-connect-sticks.js index ff6d7fa1..6eeb60c6 100644 --- a/1167-minimum-cost-to-connect-sticks.js +++ b/1167-minimum-cost-to-connect-sticks.js @@ -124,4 +124,90 @@ const connectSticks = function(sticks) { 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/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/1186-maximum-subarray-sum-with-one-deletion.js b/1186-maximum-subarray-sum-with-one-deletion.js index 553245f0..6938f589 100644 --- a/1186-maximum-subarray-sum-with-one-deletion.js +++ b/1186-maximum-subarray-sum-with-one-deletion.js @@ -2,15 +2,41 @@ * @param {number[]} arr * @return {number} */ -const maximumSum = function(arr) { +const maximumSum = function (arr) { const n = arr.length - let d1 = arr[0], - d2 = arr[0], - best = arr[0] - for (let i = 1; i < n; ++i) { - d2 = Math.max(d2 + arr[i], Math.max(d1, arr[i])) - d1 = Math.max(d1 + arr[i], arr[i]) - best = Math.max(d2, best) + 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 best + + 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/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/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/1203-sort-items-by-groups-respecting-dependencies.js b/1203-sort-items-by-groups-respecting-dependencies.js index e0e9ac0a..0894cd98 100644 --- a/1203-sort-items-by-groups-respecting-dependencies.js +++ b/1203-sort-items-by-groups-respecting-dependencies.js @@ -1,3 +1,53 @@ +/** + * @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 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/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= 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/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/1224-maximum-equal-frequency.js b/1224-maximum-equal-frequency.js index 0f1bb6b1..192cc0e6 100644 --- a/1224-maximum-equal-frequency.js +++ b/1224-maximum-equal-frequency.js @@ -1,3 +1,49 @@ +/** + * @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} 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 index 3170ce2c..ea4d1768 100644 --- a/1231-divide-chocolate.js +++ b/1231-divide-chocolate.js @@ -21,3 +21,34 @@ const maximizeSweetness = function (sweetness, K) { } 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/1235-maximum-profit-in-job-scheduling.js b/1235-maximum-profit-in-job-scheduling.js index 5870bc35..a5a0fa3b 100644 --- a/1235-maximum-profit-in-job-scheduling.js +++ b/1235-maximum-profit-in-job-scheduling.js @@ -1,3 +1,40 @@ +/** + * @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 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/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 index a7947edc..f73084af 100644 --- a/1246-palindrome-removal.js +++ b/1246-palindrome-removal.js @@ -34,3 +34,32 @@ const minimumMoves = function (arr) { } 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 index eb294a6e..1599e395 100644 --- a/1249-minimum-remove-to-make-valid-parentheses.js +++ b/1249-minimum-remove-to-make-valid-parentheses.js @@ -18,3 +18,58 @@ } 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/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/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/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/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 index 0d950897..2ec22d2d 100644 --- 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 @@ -1,3 +1,99 @@ +/** + * @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} @@ -281,3 +377,86 @@ const minPushBox = function (grid) { } } +// 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/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/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/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 index f0f1bd44..61494fcb 100644 --- a/1277-count-square-submatrices-with-all-ones.js +++ b/1277-count-square-submatrices-with-all-ones.js @@ -1,3 +1,27 @@ +/** + * @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} 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 index 52f950e6..a79ab5e6 100644 --- 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 @@ -1,3 +1,47 @@ +/** + * @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} diff --git a/1286-iterator-for-combination.js b/1286-iterator-for-combination.js index 2357732c..314526bf 100644 --- a/1286-iterator-for-combination.js +++ b/1286-iterator-for-combination.js @@ -41,3 +41,108 @@ function build(max, str, out = [], curr = '') { 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/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/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/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/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/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/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 index c528343b..56ebb6cb 100644 --- a/131-palindrome-partitioning.js +++ b/131-palindrome-partitioning.js @@ -31,3 +31,40 @@ function isPalindrome(str, start, i) { } 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 index efad256d..e2b63cb2 100644 --- a/1310-xor-queries-of-a-subarray.js +++ b/1310-xor-queries-of-a-subarray.js @@ -17,3 +17,26 @@ const xorQueries = function(arr, queries) { }) 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/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/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 index 26c3b1d7..478c3c0a 100644 --- a/1316-distinct-echo-substrings.js +++ b/1316-distinct-echo-substrings.js @@ -17,3 +17,4 @@ const distinctEchoSubstrings = function (text) { } return set.size } + 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 index e228bae1..1acc085e 100644 --- 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 @@ -1,3 +1,35 @@ +/** + * @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 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/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/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/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/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/1349-maximum-students-taking-exam.js b/1349-maximum-students-taking-exam.js index 03153525..0a45d165 100644 --- a/1349-maximum-students-taking-exam.js +++ b/1349-maximum-students-taking-exam.js @@ -1,3 +1,59 @@ +/** + * @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} 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/1353-maximum-number-of-events-that-can-be-attended.js b/1353-maximum-number-of-events-that-can-be-attended.js index 58ec8b08..f0cdc48d 100644 --- a/1353-maximum-number-of-events-that-can-be-attended.js +++ b/1353-maximum-number-of-events-that-can-be-attended.js @@ -220,3 +220,29 @@ function maxEvents(events) { // 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/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/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/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 index 41e48b07..f186049e 100644 --- a/1367-linked-list-in-binary-tree.js +++ b/1367-linked-list-in-binary-tree.js @@ -1,3 +1,117 @@ +/** + * 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) { 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 index 1607e02e..def7dab1 100644 --- 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 @@ -1,3 +1,35 @@ +/** + * @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} @@ -33,3 +65,34 @@ const minCost = function (grid) { } 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/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/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/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/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 index be6db2f7..5b214871 100644 --- a/1388-pizza-with-3n-slices.js +++ b/1388-pizza-with-3n-slices.js @@ -36,3 +36,32 @@ function maxSum(arr, n) { } 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/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/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/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 e1c6adc3..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 @@ -57,3 +88,35 @@ const wordBreak = function (s, wordDict) { 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/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/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/1411-number-of-ways-to-paint-n-3-grid.js b/1411-number-of-ways-to-paint-n-3-grid.js index c644c37b..199a4a5b 100644 --- a/1411-number-of-ways-to-paint-n-3-grid.js +++ b/1411-number-of-ways-to-paint-n-3-grid.js @@ -1,3 +1,24 @@ +/** + * @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} 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/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 index 1fb3cb59..81ac967e 100644 --- a/1425-constrained-subsequence-sum.js +++ b/1425-constrained-subsequence-sum.js @@ -20,3 +20,82 @@ const constrainedSubsetSum = function(nums, k) { } 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/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/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 index 6704ff78..4656736b 100644 --- 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 @@ -1,3 +1,46 @@ +/** + * @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} 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 index 249cfbc6..11628f47 100644 --- 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 @@ -16,20 +16,23 @@ const kthSmallest = function(mat, k) { if (row === mat.length) return 1; let totalcnt = 0; for(let v of mat[row]) { - const cnt = check(row + 1, v + sum, limit); + let cnt = check(row+1, v+sum, limit); totalcnt += cnt; - if (cnt === 0 || totalcnt > k) break; + if (cnt === 0 || totalcnt > k) break; + } + return totalcnt; }; - while(lo <= hi) { - const m = (lo + (hi - lo) / 2) >> 0; - const cnt = check(0, 0, m); + + while(lo < hi) { + let m = Math.floor((lo+hi)/2); + let cnt = check(0,0,m); if (cnt < k) { - lo = m + 1; + lo = m+1; } else { - hi = m - 1; + hi = m; } } 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 index 02a65836..3c66d205 100644 --- 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 @@ -1,4 +1,32 @@ +/** + * @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} @@ -39,3 +67,31 @@ const countTriplets = function(arr) { } 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/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/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 index 8ceae82d..04f0c568 100644 --- 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 @@ -1,3 +1,34 @@ +/** + * @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 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/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/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 index 204580c6..12701fe7 100644 --- 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 @@ -18,3 +18,27 @@ function getMax(limit, cuts) { } 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 index 91fd6105..465ec0b8 100644 --- 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 @@ -1,3 +1,71 @@ +/** + * @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} diff --git a/1473-paint-house-iii.js b/1473-paint-house-iii.js index d5fc1315..6ae1b718 100644 --- a/1473-paint-house-iii.js +++ b/1473-paint-house-iii.js @@ -1,3 +1,51 @@ +/** + * @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 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/1478-allocate-mailboxes.js b/1478-allocate-mailboxes.js index aac971f9..0281bb7c 100644 --- a/1478-allocate-mailboxes.js +++ b/1478-allocate-mailboxes.js @@ -24,3 +24,39 @@ const minDistance = function (A, K) { } 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/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/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 index af6c6a1d..17397e68 100644 --- a/1494-parallel-courses-ii.js +++ b/1494-parallel-courses-ii.js @@ -1,3 +1,55 @@ +/** + * @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 @@ -48,3 +100,51 @@ function bitCount(n) { 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/15-3sum.js b/15-3sum.js index c6f4a983..65defff5 100755 --- a/15-3sum.js +++ b/15-3sum.js @@ -1,3 +1,37 @@ +/** + * @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; 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[][]} @@ -54,5 +88,37 @@ const threeSum = function(nums) { } } + 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 }; 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/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/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/1514-path-with-maximum-probability.js b/1514-path-with-maximum-probability.js index bd47209e..e134e58b 100644 --- a/1514-path-with-maximum-probability.js +++ b/1514-path-with-maximum-probability.js @@ -6,7 +6,7 @@ * @param {number} end * @return {number} */ -const maxProbability = function (n, edges, succProb, start, end) { +var maxProbability = function (n, edges, succProb, start, end) { const g = {} for (let i = 0; i < edges.length; ++i) { const a = edges[i][0], @@ -16,15 +16,13 @@ const maxProbability = function (n, edges, succProb, start, end) { g[a].push([b, i]) g[b].push([a, i]) } - const p = new Array(n).fill(0) + const p = new Array(n).fill(-1) p[start] = 1 - const pq = new PriorityQueue((a, b) => p[a] > p[b]) + const pq = new PQ((a, b) => p[a] > p[b]) pq.push(start) while (!pq.isEmpty()) { const cur = pq.pop() - if (cur === end) { - return p[end] - } + for (let a of g[cur] || []) { const neighbor = a[0], index = a[1] @@ -34,9 +32,9 @@ const maxProbability = function (n, edges, succProb, start, end) { } } } - return 0 + return p[end] === -1 ? 0 : p[end] } -class PriorityQueue { +class PQ { constructor(comparator = (a, b) => a > b) { this.heap = [] this.top = 0 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/152-maximum-product-subarray.js b/152-maximum-product-subarray.js index fe71634f..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} 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/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 index 10d9f567..8464391c 100644 --- 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 @@ -1,3 +1,19 @@ +/** + * @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} 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/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/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/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/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 index a4597cc6..7426ad8f 100644 --- a/1542-find-longest-awesome-substring.js +++ b/1542-find-longest-awesome-substring.js @@ -1,3 +1,37 @@ +/** + * @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} @@ -15,3 +49,27 @@ const longestAwesome = function (s) { } 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/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/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 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/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/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/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 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 @@ -18,3 +48,62 @@ const maxSumRangeQuery = function (nums, requests) { 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/1590-make-sum-divisible-by-p.js b/1590-make-sum-divisible-by-p.js index 61d36c0c..4c903d90 100644 --- a/1590-make-sum-divisible-by-p.js +++ b/1590-make-sum-divisible-by-p.js @@ -1,3 +1,89 @@ +/** + * @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 diff --git a/1591-strange-printer-ii.js b/1591-strange-printer-ii.js index c5a48fd6..1db9c901 100644 --- a/1591-strange-printer-ii.js +++ b/1591-strange-printer-ii.js @@ -1,3 +1,71 @@ +/** + * @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} @@ -13,13 +81,13 @@ const isPrintable = function (targetGrid) { 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 + 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 > 0) { + while (colorSet.size) { const tmp = new Set() for (let color of colorSet) { if (!isRect(targetGrid, color)) { @@ -45,6 +113,83 @@ const isPrintable = function (targetGrid) { 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/1595-minimum-cost-to-connect-two-groups-of-points.js b/1595-minimum-cost-to-connect-two-groups-of-points.js index 900ec1dc..43e3d060 100644 --- a/1595-minimum-cost-to-connect-two-groups-of-points.js +++ b/1595-minimum-cost-to-connect-two-groups-of-points.js @@ -1,3 +1,50 @@ +/** + * @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} 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/1601-maximum-number-of-achievable-transfer-requests.js b/1601-maximum-number-of-achievable-transfer-requests.js index 969324af..b99d414f 100644 --- a/1601-maximum-number-of-achievable-transfer-requests.js +++ b/1601-maximum-number-of-achievable-transfer-requests.js @@ -1,3 +1,37 @@ +// 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 diff --git a/1605-find-valid-matrix-given-row-and-column-sums.js b/1605-find-valid-matrix-given-row-and-column-sums.js index 2aff69a5..f1ab5894 100644 --- a/1605-find-valid-matrix-given-row-and-column-sums.js +++ b/1605-find-valid-matrix-given-row-and-column-sums.js @@ -15,3 +15,23 @@ const restoreMatrix = function(rowSum, colSum) { } 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/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 index 6964d8c3..9866bd82 100644 --- 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 @@ -1,3 +1,29 @@ +/** + * @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} @@ -30,3 +56,21 @@ const specialArray = function(nums) { // 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/1617-count-subtrees-with-max-distance-between-cities.js b/1617-count-subtrees-with-max-distance-between-cities.js index aa468b83..3cc321c8 100644 --- a/1617-count-subtrees-with-max-distance-between-cities.js +++ b/1617-count-subtrees-with-max-distance-between-cities.js @@ -49,3 +49,70 @@ const countSubgraphsForEachDiameter = function (n, edges) { 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/1625-lexicographically-smallest-string-after-applying-operations.js b/1625-lexicographically-smallest-string-after-applying-operations.js index 6c603c5d..ec693a8b 100644 --- a/1625-lexicographically-smallest-string-after-applying-operations.js +++ b/1625-lexicographically-smallest-string-after-applying-operations.js @@ -1,3 +1,156 @@ +/** + * @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 diff --git a/1627-graph-connectivity-with-threshold.js b/1627-graph-connectivity-with-threshold.js index 05eac3ca..cafcb215 100644 --- a/1627-graph-connectivity-with-threshold.js +++ b/1627-graph-connectivity-with-threshold.js @@ -1,3 +1,53 @@ +/** + * @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 diff --git a/1631-path-with-minimum-effort.js b/1631-path-with-minimum-effort.js index 1e07dfcb..76e5611d 100644 --- a/1631-path-with-minimum-effort.js +++ b/1631-path-with-minimum-effort.js @@ -1,3 +1,189 @@ +/** + * @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} diff --git a/1632-rank-transform-of-a-matrix.js b/1632-rank-transform-of-a-matrix.js index 69233377..6145eff0 100644 --- a/1632-rank-transform-of-a-matrix.js +++ b/1632-rank-transform-of-a-matrix.js @@ -1,3 +1,91 @@ +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[][]} 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/1638-count-substrings-that-differ-by-one-character.js b/1638-count-substrings-that-differ-by-one-character.js index c95a6d31..e1a9a64f 100644 --- a/1638-count-substrings-that-differ-by-one-character.js +++ b/1638-count-substrings-that-differ-by-one-character.js @@ -25,3 +25,30 @@ const countSubstrings = function (s, t) { } 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/1644-lowest-common-ancestor-of-a-binary-tree-ii.js b/1644-lowest-common-ancestor-of-a-binary-tree-ii.js index 32c2a70a..bd9407bb 100644 --- a/1644-lowest-common-ancestor-of-a-binary-tree-ii.js +++ b/1644-lowest-common-ancestor-of-a-binary-tree-ii.js @@ -33,3 +33,41 @@ const lowestCommonAncestor = function (root, p, q) { 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/1648-sell-diminishing-valued-colored-balls.js b/1648-sell-diminishing-valued-colored-balls.js index b0d3d636..f38bf0b2 100644 --- a/1648-sell-diminishing-valued-colored-balls.js +++ b/1648-sell-diminishing-valued-colored-balls.js @@ -1,3 +1,43 @@ +/** + * @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 @@ -65,3 +105,70 @@ const maxProfit = function (inventory, orders) { 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 index 6f30ca3c..d186bcd8 100644 --- a/1649-create-sorted-array-through-instructions.js +++ b/1649-create-sorted-array-through-instructions.js @@ -34,3 +34,50 @@ const createSortedArray = function(instructions) { } 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/1653-minimum-deletions-to-make-string-balanced.js b/1653-minimum-deletions-to-make-string-balanced.js index ac09dbf2..4cf12446 100644 --- a/1653-minimum-deletions-to-make-string-balanced.js +++ b/1653-minimum-deletions-to-make-string-balanced.js @@ -1,3 +1,23 @@ +/** + * @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} diff --git a/1654-minimum-jumps-to-reach-home.js b/1654-minimum-jumps-to-reach-home.js index 6969ab4a..11ce519d 100644 --- a/1654-minimum-jumps-to-reach-home.js +++ b/1654-minimum-jumps-to-reach-home.js @@ -1,3 +1,50 @@ +/** + * @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 diff --git a/1655-distribute-repeating-integers.js b/1655-distribute-repeating-integers.js index 8a7b0120..201a7fad 100644 --- a/1655-distribute-repeating-integers.js +++ b/1655-distribute-repeating-integers.js @@ -1,3 +1,54 @@ + +/** + * @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 @@ -70,3 +121,100 @@ const canDistribute = function (nums, quantity) { 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/1658-minimum-operations-to-reduce-x-to-zero.js b/1658-minimum-operations-to-reduce-x-to-zero.js index ed2b66ef..1e9fd1d6 100644 --- a/1658-minimum-operations-to-reduce-x-to-zero.js +++ b/1658-minimum-operations-to-reduce-x-to-zero.js @@ -1,3 +1,56 @@ +/** + * @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 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/1673-find-the-most-competitive-subsequence.js b/1673-find-the-most-competitive-subsequence.js index 51acc346..bf913f46 100644 --- a/1673-find-the-most-competitive-subsequence.js +++ b/1673-find-the-most-competitive-subsequence.js @@ -43,3 +43,27 @@ const mostCompetitive = function (nums, k) { } 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 index 99f147c9..3c5243ef 100644 --- a/1674-minimum-moves-to-make-array-complementary.js +++ b/1674-minimum-moves-to-make-array-complementary.js @@ -1,29 +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 min = Math.min, max = Math.max - const n = nums.length; - const delta = Array(limit * 2 + 2).fill(0); - for (let i = 0; i < n / 2; ++i) { - let lo = 1 + min(nums[i], nums[n - i - 1]); - let hi = limit + max(nums[i], nums[n - i - 1]); - let 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; + 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 index 4d2821fe..f8fab346 100644 --- a/1675-minimize-deviation-in-array.js +++ b/1675-minimize-deviation-in-array.js @@ -1,3 +1,97 @@ +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} diff --git a/1676-lowest-common-ancestor-of-a-binary-tree-iv.js b/1676-lowest-common-ancestor-of-a-binary-tree-iv.js index f5cb150b..1057137e 100644 --- a/1676-lowest-common-ancestor-of-a-binary-tree-iv.js +++ b/1676-lowest-common-ancestor-of-a-binary-tree-iv.js @@ -20,3 +20,32 @@ const lowestCommonAncestor = function(root, 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/1681-minimum-incompatibility.js b/1681-minimum-incompatibility.js index eb5a21a8..255ef859 100644 --- a/1681-minimum-incompatibility.js +++ b/1681-minimum-incompatibility.js @@ -1,3 +1,49 @@ +/** + * @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 diff --git a/1685-sum-of-absolute-differences-in-a-sorted-array.js b/1685-sum-of-absolute-differences-in-a-sorted-array.js index 0092062e..a4273d0e 100644 --- a/1685-sum-of-absolute-differences-in-a-sorted-array.js +++ b/1685-sum-of-absolute-differences-in-a-sorted-array.js @@ -3,14 +3,17 @@ * @return {number[]} */ const getSumAbsoluteDifferences = function(nums) { - const res = [], n = nums.length - let first = 0 + const n = nums.length, { abs } = Math + const res = [] + let e0 = 0 for(let i = 1; i < n; i++) { - first += nums[i] - nums[0] + e0 += abs(nums[i] - nums[0]) } - res[0] = first + res[0] = e0 for(let i = 1; i < n; i++) { - res[i] = res[i - 1] + (nums[i] - nums[i - 1]) * i - (nums[i] - nums[i - 1]) * (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/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/1697-checking-existence-of-edge-length-limited-paths.js b/1697-checking-existence-of-edge-length-limited-paths.js index 12928026..72ef93c5 100644 --- a/1697-checking-existence-of-edge-length-limited-paths.js +++ b/1697-checking-existence-of-edge-length-limited-paths.js @@ -1,3 +1,53 @@ +/** + * @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 @@ -16,13 +66,11 @@ const distanceLimitedPathsExist = function (n, edgeList, queries) { for (let i of order) { const limit = queries[i][2] while (idx < edgeList.length && edgeList[idx][2] < limit) { - const u = edgeList[idx][0], - v = edgeList[idx][1] + const [u, v] = edgeList[idx] uf.union(u, v) idx++ } - const u0 = queries[i][0], - v0 = queries[i][1] + const [u0, v0] = queries[i] if (uf.find(u0) === uf.find(v0)) ans[i] = true } return ans diff --git a/1698-number-of-distinct-substrings-in-a-string.js b/1698-number-of-distinct-substrings-in-a-string.js index 595ec3f7..f67060eb 100644 --- a/1698-number-of-distinct-substrings-in-a-string.js +++ b/1698-number-of-distinct-substrings-in-a-string.js @@ -12,3 +12,31 @@ const countDistinct = function(s) { 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/1703-maximum-binary-string-after-change.js b/1703-maximum-binary-string-after-change.js index 2f587761..903e97d4 100644 --- a/1703-maximum-binary-string-after-change.js +++ b/1703-maximum-binary-string-after-change.js @@ -1,3 +1,39 @@ +/** + * @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 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 @@ -17,10 +126,10 @@ const maximizeXor = function (nums, queries) { if (m < nums[mid])r = mid else l = mid + 1 } - r -= 1 + r-- l = 0 let ans = x & ~maxMask - for (let bit = numOfBits - 1; bit >= 0; bit -= 1) { + for (let bit = numOfBits - 1; bit >= 0; bit--) { const mask = 1 << bit if (x & mask) { if ((nums[l] & mask) === 0) { @@ -46,6 +155,7 @@ const maximizeXor = function (nums, queries) { } } + // another /** @@ -98,3 +208,58 @@ const maximizeXor = function (nums, queries) { } 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/1713-minimum-operations-to-make-a-subsequence.js b/1713-minimum-operations-to-make-a-subsequence.js index 8e751863..72b75060 100644 --- a/1713-minimum-operations-to-make-a-subsequence.js +++ b/1713-minimum-operations-to-make-a-subsequence.js @@ -1,3 +1,29 @@ +/** + * @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 @@ -75,3 +101,41 @@ const minOperations = function(target, arr) { 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/1723-find-minimum-time-to-finish-all-jobs.js b/1723-find-minimum-time-to-finish-all-jobs.js index 4a61666c..94a8c01b 100644 --- a/1723-find-minimum-time-to-finish-all-jobs.js +++ b/1723-find-minimum-time-to-finish-all-jobs.js @@ -1,3 +1,69 @@ +/** + * @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 @@ -45,3 +111,41 @@ const minimumTimeRequired = function (jobs, k) { 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/1734-decode-xored-permutation.js b/1734-decode-xored-permutation.js index 4b0ecdf9..1ae0f396 100644 --- a/1734-decode-xored-permutation.js +++ b/1734-decode-xored-permutation.js @@ -1,3 +1,24 @@ +/** + * @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[]} 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 index 3b29d69d..503c429e 100644 --- a/1737-change-minimum-characters-to-satisfy-one-of-three-conditions.js +++ b/1737-change-minimum-characters-to-satisfy-one-of-three-conditions.js @@ -1,3 +1,55 @@ +/** + * @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 @@ -28,3 +80,69 @@ const minCharacters = function (a, b) { } 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/1740-find-distance-in-a-binary-tree.js b/1740-find-distance-in-a-binary-tree.js index 9d982dec..97dae690 100644 --- a/1740-find-distance-in-a-binary-tree.js +++ b/1740-find-distance-in-a-binary-tree.js @@ -1,3 +1,43 @@ +/** + * 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) { 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 index 0de7c6d0..6f1ce829 100644 --- a/1751-maximum-number-of-events-that-can-be-attended-ii.js +++ b/1751-maximum-number-of-events-that-can-be-attended-ii.js @@ -1,3 +1,31 @@ +/** + * @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 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/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/1764-form-array-by-concatenating-subarrays-of-another-array.js b/1764-form-array-by-concatenating-subarrays-of-another-array.js index 1fd9fc52..c8013442 100644 --- a/1764-form-array-by-concatenating-subarrays-of-another-array.js +++ b/1764-form-array-by-concatenating-subarrays-of-another-array.js @@ -1,3 +1,59 @@ +/** + * @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 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 index 6364c519..11f47aa6 100644 --- 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 @@ -45,3 +45,27 @@ function helper(str, 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/1774-closest-dessert-cost.js b/1774-closest-dessert-cost.js index a274115a..6d918079 100644 --- a/1774-closest-dessert-cost.js +++ b/1774-closest-dessert-cost.js @@ -1,3 +1,33 @@ +/** + * @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 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/1786-number-of-restricted-paths-from-first-to-last-node.js b/1786-number-of-restricted-paths-from-first-to-last-node.js index 0552741f..511174a9 100644 --- a/1786-number-of-restricted-paths-from-first-to-last-node.js +++ b/1786-number-of-restricted-paths-from-first-to-last-node.js @@ -1,3 +1,117 @@ +/** + * @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 @@ -116,3 +230,57 @@ class PriorityQueue { } } } + +// 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/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 index 3f896373..2aee0b58 100644 --- a/1798-maximum-number-of-consecutive-values-you-can-make.js +++ b/1798-maximum-number-of-consecutive-values-you-can-make.js @@ -11,3 +11,26 @@ const getMaximumConsecutive = function(coins) { } 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 index 28e97a5c..4e4ec0cf 100644 --- a/1799-maximize-score-after-n-operations.js +++ b/1799-maximize-score-after-n-operations.js @@ -1,3 +1,43 @@ +/** + * @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} diff --git a/18-4sum.js b/18-4sum.js index 069b349b..fd34cdf7 100644 --- a/18-4sum.js +++ b/18-4sum.js @@ -88,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/1801-number-of-orders-in-the-backlog.js b/1801-number-of-orders-in-the-backlog.js index c5bcd0af..8e95f7ce 100644 --- a/1801-number-of-orders-in-the-backlog.js +++ b/1801-number-of-orders-in-the-backlog.js @@ -2,66 +2,75 @@ * @param {number[][]} orders * @return {number} */ -const getNumberOfBacklogOrders = function (orders) { - const h0 = new PriorityQueue((a, b) => a[0] > b[0]) - const h1 = new PriorityQueue((a, b) => a[0] > b[0]) - const P = 10 ** 9 + 7 - const { min } = Math - - while (!h0.isEmpty()) h0.pop() - while (!h1.isEmpty()) h1.pop() - let i, - j, - i1, - j1, - ans = 0 - for (let c of orders) { - i = c[0] - j = c[1] - if (c[2]) { - while (!h0.isEmpty() && h0.peek()[0] >= i) { - i1 = h0.peek()[0] - j1 = h0.peek()[1] - h0.pop() - if (j > j1) j -= j1 - else { - j1 -= j - j = 0 - if (j1) h0.push([i1, j1]) - break +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 (j) h1.push([-i, j]) - } else { - while (!h1.isEmpty() && -h1.peek()[0] <= i) { - i1 = h1.peek()[0] - j1 = h1.peek()[1] - h1.pop() - if (j > j1) j -= j1 - else { - j1 -= j - j = 0 - if (j1) h1.push([i1, j1]) - break + 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 (j) h0.push([i, j]) + if(e[1]) { + sellPQ.push(e) + } } } - while (!h0.isEmpty()) { - ans += h0.peek()[1] - h0.pop() - if (ans >= P) ans -= P + + let res = 0 + + while(!buyPQ.isEmpty()) { + res = (res + buyPQ.pop()[1]) % mod } - while (!h1.isEmpty()) { - ans += h1.peek()[1] - h1.pop() - if (ans >= P) ans -= P + while(!sellPQ.isEmpty()) { + res = (res + sellPQ.pop()[1]) % mod } - return ans -} + + return res % mod +}; -class PriorityQueue { +class PQ { constructor(comparator = (a, b) => a > b) { this.heap = [] this.top = 0 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 index 54bbb8c4..64d18833 100644 --- 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 @@ -1,3 +1,116 @@ +/** + * @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 diff --git a/1803-count-pairs-with-xor-in-a-range.js b/1803-count-pairs-with-xor-in-a-range.js index 1cd9f17c..03ee2ffe 100644 --- a/1803-count-pairs-with-xor-in-a-range.js +++ b/1803-count-pairs-with-xor-in-a-range.js @@ -44,3 +44,51 @@ class Trie { 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/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/1834-single-threaded-cpu.js b/1834-single-threaded-cpu.js index ddf36092..192aedec 100644 --- a/1834-single-threaded-cpu.js +++ b/1834-single-threaded-cpu.js @@ -209,3 +209,76 @@ class PriorityQueue { } } } + +// 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 index bab1cf9a..795a8fcf 100644 --- a/1835-find-xor-sum-of-all-pairs-bitwise-and.js +++ b/1835-find-xor-sum-of-all-pairs-bitwise-and.js @@ -1,3 +1,19 @@ +/** + * @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. @@ -40,3 +56,16 @@ const getXORSum = function(arr1, arr2) { 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/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/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/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/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/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/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/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 eeaa3925..06f99a30 100755 --- a/2-add-two-numbers.js +++ b/2-add-two-numbers.js @@ -117,4 +117,45 @@ const addTwoNumbers = function(l1, 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} 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/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/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/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 index bbec50c5..09233baa 100644 --- a/207-course-schedule.js +++ b/207-course-schedule.js @@ -1,3 +1,84 @@ +/** + * @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 @@ -72,3 +153,40 @@ const canFinish = function(vertices, edges) { } 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/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/210-course-schedule-ii.js b/210-course-schedule-ii.js index f9c01679..acfd8832 100644 --- a/210-course-schedule-ii.js +++ b/210-course-schedule-ii.js @@ -1,3 +1,40 @@ +/** + * @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 @@ -67,3 +104,53 @@ const findOrder = function(numCourses, prerequisites) { 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 fce3267e..a278095f 100644 --- a/214-shortest-palindrome.js +++ b/214-shortest-palindrome.js @@ -50,3 +50,37 @@ function getFail(s) { 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/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/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 index 9705eb73..cf886088 100644 --- a/224-basic-calculator.js +++ b/224-basic-calculator.js @@ -34,3 +34,92 @@ const calculate = function(s) { } 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 index 311f4a05..60a57563 100644 --- a/226-invert-binary-tree.js +++ b/226-invert-binary-tree.js @@ -48,3 +48,25 @@ const invertTree = function (root) { } 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 index 1aecde43..e0f174ae 100644 --- a/227-basic-calculator-ii.js +++ b/227-basic-calculator-ii.js @@ -1,3 +1,36 @@ +/** + * @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} @@ -20,3 +53,43 @@ const calculate = function(s) { 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/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/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/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 938403e6..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} 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/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/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/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/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/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/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/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/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 index 40e0d8a1..bf6a75e2 100644 --- a/25-reverse-nodes-in-k-group.js +++ b/25-reverse-nodes-in-k-group.js @@ -28,3 +28,130 @@ const reverseKGroup = function(head, k) { } 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/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/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/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 index ea7bcd27..fb5d5915 100644 --- a/253-meeting-rooms-ii.js +++ b/253-meeting-rooms-ii.js @@ -15,6 +15,27 @@ 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} @@ -37,3 +58,104 @@ const minMeetingRooms = function(intervals) { 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/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/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/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/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/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/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/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/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 index b062b445..af94e904 100644 --- a/264-ugly-number-ii.js +++ b/264-ugly-number-ii.js @@ -2,15 +2,19 @@ * @param {number} n * @return {number} */ -const nthUglyNumber = function(n) { - const dp = [1] - let [a, b, c] = [0, 0, 0] +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++) { - let [ua, ub, uc] = [dp[a] * 2, dp[b] * 3, dp[c] * 5] - dp[i] = Math.min(ua, ub, uc) - if (dp[i] === ua) a++ - if (dp[i] === ub) b++ - if (dp[i] === uc) c++ + 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 dp[n - 1] + 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/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/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/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/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/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/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/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/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/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/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/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/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 98513914..5bd5a760 100755 --- a/28-implement-strStr().js +++ b/28-implement-strStr().js @@ -1,3 +1,44 @@ +/** + * @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 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/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/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/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/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 e4a2fa62..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} 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/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 index c0243b91..91f77ac2 100644 --- a/291-word-pattern-ii.js +++ b/291-word-pattern-ii.js @@ -28,3 +28,41 @@ function isMatch(str, i, pat, j, map, set) { } 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/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/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/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 index a4cdcdd0..deceaa09 100644 --- a/296-best-meeting-point.js +++ b/296-best-meeting-point.js @@ -53,3 +53,45 @@ function min(arr) { } 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/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 index 6acc441a..dd67443e 100644 --- a/299-bulls-and-cows.js +++ b/299-bulls-and-cows.js @@ -1,3 +1,28 @@ +/** + * @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 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 78f0636b..773dc4ff 100755 --- a/3-longest-substring-without-repeating-characters.js +++ b/3-longest-substring-without-repeating-characters.js @@ -1,3 +1,24 @@ +/** + * @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} @@ -19,6 +40,36 @@ const lengthOfLongestSubstring = function(s) { // 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 196f7ba3..3d79c6ec 100644 --- a/300-longest-increasing-subsequence.js +++ b/300-longest-increasing-subsequence.js @@ -68,3 +68,34 @@ const lengthOfLIS = function(nums) { } 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/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/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/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/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 baf10d95..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. 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/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 index 4de633c8..598944b8 100644 --- a/313-super-ugly-number.js +++ b/313-super-ugly-number.js @@ -20,3 +20,95 @@ const nthSuperUglyNumber = function(n, primes) { } 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/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 index e06503f9..a64a93b2 100644 --- a/316-remove-duplicate-letters.js +++ b/316-remove-duplicate-letters.js @@ -52,3 +52,27 @@ const removeDuplicateLetters = function(s) { } 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/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 index 016c0045..b8fc1b48 100644 --- a/320-generalized-abbreviation.js +++ b/320-generalized-abbreviation.js @@ -11,6 +11,40 @@ Output: */ +/** + * @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[]} 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/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/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/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/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/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 c71b8477..6cce9611 100644 --- a/329-longest-increasing-path-in-a-matrix.js +++ b/329-longest-increasing-path-in-a-matrix.js @@ -1,3 +1,41 @@ +/** + * @param {number[][]} matrix + * @return {number} + */ +const longestIncreasingPath = function(matrix) { + const m = matrix.length, n = matrix[0].length + let res = 1 + + 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 < 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} 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 index 83e6f9f6..295d8b70 100644 --- a/330-patching-array.js +++ b/330-patching-array.js @@ -1,3 +1,48 @@ +/** + * @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 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/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/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/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 index a1417bf8..9ec5af05 100644 --- a/337-house-robber-iii.js +++ b/337-house-robber-iii.js @@ -1,3 +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 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) { 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/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/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/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/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/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/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/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/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/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 index 749c4cf6..e8fc35eb 100644 --- a/351-android-unlock-patterns.js +++ b/351-android-unlock-patterns.js @@ -38,3 +38,43 @@ function DFS(vis, skip, cur, remain) { 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/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/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/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 index f0f22313..825883f5 100644 --- a/358-rearrange-string-k-distance-apart.js +++ b/358-rearrange-string-k-distance-apart.js @@ -61,3 +61,107 @@ function findValidMax(count, valid, index) { 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/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/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/3608-minimum-time-for-k-connected-components.js b/3608-minimum-time-for-k-connected-components.js new file mode 100644 index 00000000..49e51055 --- /dev/null +++ b/3608-minimum-time-for-k-connected-components.js @@ -0,0 +1,41 @@ +/** + * @param {number} n + * @param {number[][]} edges + * @param {number} k + * @return {number} + */ +var minTime = function(n, edges, k) { + edges.sort((a, b) => b[2] - a[2]) + const uf = new UF(n) + let cnt = n + + for(let i = 0; i < edges.length; i++) { + const [u, v, t] = edges[i] + if(uf.union(u, v)) cnt-- + if(cnt < k) return t + } + return 0 +}; + +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) + if(xr === yr) { + return false + } else { + this.root[yr] = xr + return true + } + + } +} 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/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/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/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/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/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/3691-maximum-total-subarray-value-ii.js b/3691-maximum-total-subarray-value-ii.js new file mode 100644 index 00000000..89c56f1d --- /dev/null +++ b/3691-maximum-total-subarray-value-ii.js @@ -0,0 +1,80 @@ +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +const maxTotalValue = function (nums, k) { + const n = nums.length + const K = Math.floor(Math.log2(n)) + 1 + + const mn = Array.from({ length: n }, () => Array(K + 1).fill(Infinity)) + const mx = Array.from({ length: n }, () => Array(K + 1).fill(-Infinity)) + + for (let i = 0; i < n; i++) { + mn[i][0] = nums[i] + mx[i][0] = nums[i] + } + + for (let kk = 1; kk <= K; kk++) { + for (let i = 0; i + (1 << kk) - 1 < n; i++) { + mn[i][kk] = Math.min(mn[i][kk - 1], mn[i + (1 << (kk - 1))][kk - 1]) + mx[i][kk] = Math.max(mx[i][kk - 1], mx[i + (1 << (kk - 1))][kk - 1]) + } + } + + let lo = 0, + hi = 2e9 + while (lo < hi) { + const mid = hi - Math.floor((hi - lo) / 2) + if (count_ge(mid) >= k) { + lo = mid + } else { + hi = mid - 1 + } + } + const th = lo + + let ret_g = 0n + let count_g = 0n + for (let i = 0; i < n; i++) { + let l = i, + r = n - 1 + while (l < r) { + const mid = l + Math.floor((r - l) / 2) + if (GetDiff(i, mid) > th) { + r = mid + } else { + l = mid + 1 + } + } + if (GetDiff(i, r) > th) { + count_g += BigInt(n - r) + for (let j = r; j < n; j++) { + ret_g += BigInt(GetDiff(i, j)) + } + } + } + + const ret = ret_g + BigInt(th) * (BigInt(k) - count_g) + + return Number(ret) + + function GetDiff(L, R) { + const length = R - L + 1 + const k = Math.floor(Math.log2(length)) + return ( + Math.max(mx[L][k], mx[R - (1 << k) + 1][k]) - + Math.min(mn[L][k], mn[R - (1 << k) + 1][k]) + ) + } + + function count_ge(th) { + let count = 0 + let j = 0 + for (let i = 0; i < n; i++) { + while (j < n && GetDiff(i, j) < th) j++ + count += n - j + } + return count + } +} 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/373-find-k-pairs-with-smallest-sums.js b/373-find-k-pairs-with-smallest-sums.js index 6b4c9123..35fd1146 100644 --- a/373-find-k-pairs-with-smallest-sums.js +++ b/373-find-k-pairs-with-smallest-sums.js @@ -1,3 +1,96 @@ +/** + * @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 diff --git a/3733-minimum-time-to-complete-all-deliveries.js b/3733-minimum-time-to-complete-all-deliveries.js new file mode 100644 index 00000000..13972da6 --- /dev/null +++ b/3733-minimum-time-to-complete-all-deliveries.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} d + * @param {number[]} r + * @return {number} + */ +var minimumTime = function (d, r) { + const [d0, d1] = d, [r0, r1] = r + let low = d0 + d1, hi = 2 * low * 2 + const lcm = r0 * r1 / gcd(r0, r1) + const {floor: flr} = Math + + while(low < hi) { + const mid = low + flr((hi - low) / 2) + if(isOK(mid)) { + hi = mid + } else low = mid + 1 + } + + return low + + function isOK(t) { + const s0 = t - flr(t / r0), s1 = t - flr(t / r1) + const total = t - flr(t / lcm) + if(s0 >= d0 && s1 >= d1 && total >= d0 + d1) { + return true + } + + return false + } +} + +function gcd(a, b) { + return b === 0 ? a : gcd(b, a % b) +} diff --git a/386-lexicographical-numbers.js b/386-lexicographical-numbers.js index cd11275b..d593eb57 100644 --- a/386-lexicographical-numbers.js +++ b/386-lexicographical-numbers.js @@ -1,3 +1,28 @@ +/** + * @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[]} 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/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/402-remove-k-digits.js b/402-remove-k-digits.js index ea693f3b..21ef2e47 100644 --- a/402-remove-k-digits.js +++ b/402-remove-k-digits.js @@ -48,3 +48,28 @@ const removeKdigits = function(num, k) { 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/407-trapping-rain-water-ii.js b/407-trapping-rain-water-ii.js index 21892090..31ef3c93 100644 --- a/407-trapping-rain-water-ii.js +++ b/407-trapping-rain-water-ii.js @@ -1,3 +1,107 @@ +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} diff --git a/41-first-missing-positive.js b/41-first-missing-positive.js index 3bd7ef24..fa054946 100644 --- a/41-first-missing-positive.js +++ b/41-first-missing-positive.js @@ -68,3 +68,32 @@ function swap(arr, i, j) { 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/416-partition-equal-subset-sum.js b/416-partition-equal-subset-sum.js index c118c8e6..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} diff --git a/42-trapping-rain-water.js b/42-trapping-rain-water.js index 4b2a964a..1b31b415 100644 --- a/42-trapping-rain-water.js +++ b/42-trapping-rain-water.js @@ -93,3 +93,27 @@ const trap = function(height) { 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 ed3ff2a3..1e71476c 100644 --- a/421-maximum-xor-of-two-numbers-in-an-array.js +++ b/421-maximum-xor-of-two-numbers-in-an-array.js @@ -21,6 +21,20 @@ const findMaximumXOR = function(nums) { // 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 * 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/435-non-overlapping-intervals.js b/435-non-overlapping-intervals.js index 5b57a608..7f4ffa45 100644 --- a/435-non-overlapping-intervals.js +++ b/435-non-overlapping-intervals.js @@ -1,3 +1,21 @@ +/** + * @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} 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/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/452-minimum-number-of-arrows-to-burst-balloons.js b/452-minimum-number-of-arrows-to-burst-balloons.js index c47b87fa..ca8f8d45 100644 --- a/452-minimum-number-of-arrows-to-burst-balloons.js +++ b/452-minimum-number-of-arrows-to-burst-balloons.js @@ -1,3 +1,47 @@ +/** + * @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} diff --git a/459-repeated-substring-pattern.js b/459-repeated-substring-pattern.js index 2ed1fcce..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} 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/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/470-implement-rand10-using-rand7.js b/470-implement-rand10-using-rand7.js index 9ea03193..eef7543c 100644 --- a/470-implement-rand10-using-rand7.js +++ b/470-implement-rand10-using-rand7.js @@ -10,3 +10,17 @@ const rand10 = function() { } 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/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/479-largest-palindrome-product.js b/479-largest-palindrome-product.js index 515ba62a..429c8aa4 100644 --- a/479-largest-palindrome-product.js +++ b/479-largest-palindrome-product.js @@ -1,3 +1,50 @@ +/** + * @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} 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/484-find-permutation.js b/484-find-permutation.js index 024f433f..18d3d441 100644 --- a/484-find-permutation.js +++ b/484-find-permutation.js @@ -1,3 +1,50 @@ +/** + * @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[]} diff --git a/490-the-maze.js b/490-the-maze.js index ff002f72..a19f6cb2 100644 --- a/490-the-maze.js +++ b/490-the-maze.js @@ -138,3 +138,78 @@ function isValid(maze, row, col) { 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/493-reverse-pairs.js b/493-reverse-pairs.js index bb76e4c8..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} 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/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/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/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/518-coin-change-2.js b/518-coin-change-2.js index 54db7941..92577234 100644 --- a/518-coin-change-2.js +++ b/518-coin-change-2.js @@ -1,3 +1,29 @@ +/** + * @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 diff --git a/524-longest-word-in-dictionary-through-deleting.js b/524-longest-word-in-dictionary-through-deleting.js index 4e52aeaf..bfe2742f 100644 --- a/524-longest-word-in-dictionary-through-deleting.js +++ b/524-longest-word-in-dictionary-through-deleting.js @@ -1,3 +1,110 @@ +/** + * @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 diff --git a/525-contiguous-array.js b/525-contiguous-array.js index fcd03339..9b0da1ea 100644 --- a/525-contiguous-array.js +++ b/525-contiguous-array.js @@ -1,3 +1,27 @@ +/** + * @param {number[]} nums + * @return {number} + */ +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} 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/540-single-element-in-a-sorted-array.js b/540-single-element-in-a-sorted-array.js index 7c8518d9..a840caa3 100755 --- a/540-single-element-in-a-sorted-array.js +++ b/540-single-element-in-a-sorted-array.js @@ -15,6 +15,42 @@ 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} diff --git a/543-diameter-of-binary-tree.js b/543-diameter-of-binary-tree.js index a8d6dd5f..acf2deac 100755 --- a/543-diameter-of-binary-tree.js +++ b/543-diameter-of-binary-tree.js @@ -23,3 +23,57 @@ const diameterOfBinaryTree = function (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) { + 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 + } +}; + +// 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/56-merge-intervals.js b/56-merge-intervals.js index 89a5fb3e..244a9fad 100644 --- a/56-merge-intervals.js +++ b/56-merge-intervals.js @@ -1,3 +1,50 @@ +/** + * @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[][]} diff --git a/560-subarray-sum-equals-k.js b/560-subarray-sum-equals-k.js index 5024c772..c81bff23 100644 --- a/560-subarray-sum-equals-k.js +++ b/560-subarray-sum-equals-k.js @@ -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/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/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/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/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/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/588-design-in-memory-file-system.js b/588-design-in-memory-file-system.js index 61695f2c..e23ea7dd 100644 --- a/588-design-in-memory-file-system.js +++ b/588-design-in-memory-file-system.js @@ -73,3 +73,77 @@ FileSystem.prototype.readContentFromFile = function (filePath) { * 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/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/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/60-permutation-sequence.js b/60-permutation-sequence.js index 5cd3a8fe..ea812807 100644 --- a/60-permutation-sequence.js +++ b/60-permutation-sequence.js @@ -1,3 +1,97 @@ +/** + * @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; 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 + } + } +}; + +// 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 @@ -19,3 +113,33 @@ const getPermutation = function (n, k) { } 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/621-task-scheduler.js b/621-task-scheduler.js index 079639a0..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 @@ -39,3 +72,32 @@ const leastInterval = function(tasks, n) { } 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/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 index 824fca51..b2f0f289 100644 --- a/630-course-schedule-iii.js +++ b/630-course-schedule-iii.js @@ -1,3 +1,142 @@ +/** + * @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} diff --git a/632-smallest-range.js b/632-smallest-range.js index 16153b17..0dcca794 100644 --- a/632-smallest-range.js +++ b/632-smallest-range.js @@ -188,7 +188,7 @@ var smallestRange = function(nums) { // another -class PriorityQueue { +class PQ { constructor(comparator = (a, b) => a > b) { this.heap = [] this.top = 0 @@ -260,7 +260,7 @@ class PriorityQueue { * @return {number[]} */ const smallestRange = function (nums) { - const pq = new PriorityQueue((a, b) => a[0] < b[0]) + const pq = new PQ((a, b) => a[0] < b[0]) const limit = 10 ** 5, n = nums.length, { max } = Math diff --git a/638-shopping-offers.js b/638-shopping-offers.js index 9870b16c..49747e60 100644 --- a/638-shopping-offers.js +++ b/638-shopping-offers.js @@ -1,3 +1,51 @@ +/** + * @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 diff --git a/642-design-search-autocomplete-system.js b/642-design-search-autocomplete-system.js index d00efdb3..1f4a5657 100644 --- a/642-design-search-autocomplete-system.js +++ b/642-design-search-autocomplete-system.js @@ -105,3 +105,154 @@ Trie.prototype.stringsStartingWith = function (prefix) { 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/645-set-mismatch.js b/645-set-mismatch.js index b55c998b..c3f0a6a7 100644 --- a/645-set-mismatch.js +++ b/645-set-mismatch.js @@ -1,3 +1,24 @@ +/** + * @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 ec50ac9d..3a0661cd 100755 --- a/646-maximum-length-of-pair-chain.js +++ b/646-maximum-length-of-pair-chain.js @@ -1,3 +1,46 @@ +/** + * @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} 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/652-find-duplicate-subtrees.js b/652-find-duplicate-subtrees.js index 65949019..8a1a84da 100644 --- a/652-find-duplicate-subtrees.js +++ b/652-find-duplicate-subtrees.js @@ -1,27 +1,58 @@ /** * 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) * } */ /** * @param {TreeNode} root * @return {TreeNode[]} */ -const findDuplicateSubtrees = function (root) { - const obj = {}, - res = [] - preOrder(root, obj, res) +const findDuplicateSubtrees = function(root) { + const hash = {}, res = [] + pre(root, hash, res) return res -} +}; -function preOrder(root, map, res) { - if (root === null) return '#' - const str = - root.val + preOrder(root.left, map, res) + preOrder(root.right, map, res) - if (!map[str]) map[str] = 0 - map[str]++ - if (map[str] === 2) res.push(root) +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/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/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/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/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/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/69-sqrt(x).js b/69-sqrt(x).js index d392b5ee..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} 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/699-falling-squares.js b/699-falling-squares.js index aeebee63..f0d08104 100644 --- a/699-falling-squares.js +++ b/699-falling-squares.js @@ -1,36 +1,40 @@ +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], 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) } - console.log(intervals) + 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 diff --git a/7-reverse-integer.js b/7-reverse-integer.js index 4a2fef60..1048c8cf 100755 --- a/7-reverse-integer.js +++ b/7-reverse-integer.js @@ -40,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/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/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/727-minimum-window-subsequence.js b/727-minimum-window-subsequence.js index 54599fdb..635bc00f 100644 --- a/727-minimum-window-subsequence.js +++ b/727-minimum-window-subsequence.js @@ -1,3 +1,118 @@ +/** + * @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 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/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/743-network-delay-time.js b/743-network-delay-time.js index 153e225e..893d1432 100644 --- a/743-network-delay-time.js +++ b/743-network-delay-time.js @@ -1,3 +1,159 @@ +/** + * @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 @@ -47,3 +203,104 @@ const networkDelayTime = function(times, N, K) { 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/757-set-intersection-size-at-least-two.js b/757-set-intersection-size-at-least-two.js index c89077ec..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} diff --git a/759-employee-free-time.js b/759-employee-free-time.js index 401a5d9f..1bb666d6 100644 --- a/759-employee-free-time.js +++ b/759-employee-free-time.js @@ -113,3 +113,69 @@ const employeeFreeTime = function(schedule) { } 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 index a6fbcb99..7b3ac3e1 100644 --- a/76-minimum-window-substring.js +++ b/76-minimum-window-substring.js @@ -1,3 +1,41 @@ +/** + * @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 diff --git a/765-couples-holding-hands.js b/765-couples-holding-hands.js index 4fec7b3e..3b5aa4d9 100644 --- a/765-couples-holding-hands.js +++ b/765-couples-holding-hands.js @@ -72,3 +72,35 @@ const minSwapsCouples = function (row) { } } +// 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/774-minimize-max-distance-to-gas-station.js b/774-minimize-max-distance-to-gas-station.js index 32bc695b..20ee5131 100644 --- a/774-minimize-max-distance-to-gas-station.js +++ b/774-minimize-max-distance-to-gas-station.js @@ -24,7 +24,109 @@ const minmaxGasDist = function (stations, K) { const possible = (dis, res, K) => { let need = 0 for (let i = 0; i < dis.length; i++) { - need += Math.floor(dis[i] / res) + 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/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/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/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/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/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/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 index d2cda611..36c09fe0 100644 --- a/803-bricks-falling-when-hit.js +++ b/803-bricks-falling-when-hit.js @@ -196,3 +196,58 @@ function isConnected(i, j, grid, dirs) { } 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/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/834-sum-of-distances-in-tree.js b/834-sum-of-distances-in-tree.js index 673af449..2e4df1d7 100644 --- a/834-sum-of-distances-in-tree.js +++ b/834-sum-of-distances-in-tree.js @@ -1,3 +1,44 @@ +/** + * @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 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/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 index aaa749f5..78d70c50 100644 --- a/866-prime-palindrome.js +++ b/866-prime-palindrome.js @@ -1,3 +1,28 @@ +/** + * @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} @@ -19,3 +44,30 @@ function isPrime(x) { } 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/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/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 index 89c1afbe..f83ea6f7 100644 --- a/882-reachable-nodes-in-subdivided-graph.js +++ b/882-reachable-nodes-in-subdivided-graph.js @@ -196,3 +196,115 @@ class PriorityQueue { } } } + +// 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/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/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/902-numbers-at-most-n-given-digit-set.js b/902-numbers-at-most-n-given-digit-set.js index 82d157dd..2e5da545 100644 --- a/902-numbers-at-most-n-given-digit-set.js +++ b/902-numbers-at-most-n-given-digit-set.js @@ -1,21 +1,61 @@ /** - * @param {string[]} D - * @param {number} N + * @param {string[]} digits + * @param {number} n * @return {number} */ -const atMostNGivenDigitSet = function (D, N) { - const NS = '' + N - const digit = NS.length, - dsize = D.length - let rtn = 0 - for (let i = 1; i < digit; ++i) rtn += Math.pow(dsize, i) - for (let i = 0; i < digit; ++i) { - let hasSameNum = false - for (let d of D) { - if (d < NS[i]) rtn += Math.pow(dsize, digit - i - 1) - else if (d == NS[i]) hasSameNum = true +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 (!hasSameNum) return rtn + if(sameNum === false) return res } - return rtn + 1 -} + + 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 index 5c876add..9b97b889 100644 --- a/906-super-palindromes.js +++ b/906-super-palindromes.js @@ -110,3 +110,91 @@ const isPalindromeInt = function (nr) { 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/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/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/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 e9c73874..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) { 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/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/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/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/952-largest-component-size-by-common-factor.js b/952-largest-component-size-by-common-factor.js index 9d9f2bef..c01f0348 100644 --- a/952-largest-component-size-by-common-factor.js +++ b/952-largest-component-size-by-common-factor.js @@ -1,3 +1,72 @@ +/** + * @param {number[]} nums + * @return {number} + */ +const largestComponentSize = function (nums) { + const { sqrt } = Math + const n = nums.length + const uf = new UF(n) + const primes = {} + for (let i = 0; i < n; i++) { + const num = nums[i] + const prSet = primesSet(num) + for (const e of prSet) { + if (primes[e] == null) primes[e] = [] + primes[e].push(i) + } + } + + const vals = Object.values(primes) + for(const idxArr of vals) { + const len = idxArr.length + for(let i = 0; i < len - 1; i++) { + uf.union(idxArr[i], idxArr[i + 1]) + } + } + let res = 0 + const hash = {} + for(let i = 0; i < n; i++) { + const root = uf.find(i) + if(hash[root] == null) hash[root] = 0 + hash[root]++ + } + return Math.max(...Object.values(hash)) + + function primesSet(n) { + const limit = ~~(sqrt(n) + 1) + for (let i = 2; i < limit; i++) { + if (n % i === 0) { + const res = primesSet(n / i) + res.add(i) + return res + } + } + return new Set([n]) + } +} + +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[]} A * @return {number} 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/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/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/973-k-closest-points-to-origin.js b/973-k-closest-points-to-origin.js index 5e110353..b02f1611 100644 --- a/973-k-closest-points-to-origin.js +++ b/973-k-closest-points-to-origin.js @@ -132,3 +132,37 @@ class PriorityQueue { } } } + +// 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/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/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 index d82ad773..362e81d3 100644 --- a/986-interval-list-intersections.js +++ b/986-interval-list-intersections.js @@ -21,3 +21,29 @@ const intervalIntersection = function (A, B) { } 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/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 ed497d7b..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 @@ -49,3 +108,34 @@ const subarraysWithKDistinct = function (A, K) { } } +// 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/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/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/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/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