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/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/1066-campus-bikes-ii.js b/1066-campus-bikes-ii.js index ddf46b3d..8b536b6d 100644 --- a/1066-campus-bikes-ii.js +++ b/1066-campus-bikes-ii.js @@ -1,3 +1,51 @@ +/** + * @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 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/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/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/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/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/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 index b2d7011a..b553502c 100644 --- a/1201-ugly-number-iii.js +++ b/1201-ugly-number-iii.js @@ -28,3 +28,46 @@ const nthUglyNumber = function(n, a, b, c) { 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/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/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/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/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/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/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/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/1371-find-the-longest-substring-containing-vowels-in-even-counts.js b/1371-find-the-longest-substring-containing-vowels-in-even-counts.js index 9b9130d8..b2c505d0 100644 --- a/1371-find-the-longest-substring-containing-vowels-in-even-counts.js +++ b/1371-find-the-longest-substring-containing-vowels-in-even-counts.js @@ -1,3 +1,38 @@ +/** + * @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} @@ -124,3 +159,41 @@ const findTheLongestSubstring = function(s) { 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/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/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 index 03581889..e5568823 100644 --- 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 @@ -1,3 +1,27 @@ +/** + * @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 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/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/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/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/1462-course-schedule-iv.js b/1462-course-schedule-iv.js index abbcaf55..d06b42f0 100644 --- a/1462-course-schedule-iv.js +++ b/1462-course-schedule-iv.js @@ -1,3 +1,56 @@ +/** + * @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 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/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/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 index 8803f183..e7de9469 100644 --- a/1498-number-of-subsequences-that-satisfy-the-given-sum-condition.js +++ b/1498-number-of-subsequences-that-satisfy-the-given-sum-condition.js @@ -4,17 +4,17 @@ * @return {number} */ const numSubseq = function(nums, target) { - const n = nums.length, pow = Array(n), mod = 1e9 + 7 - pow[0] = 1 + const n = nums.length, mod = 1e9 + 7 + const pows = Array(n).fill(1) for(let i = 1; i < n; i++) { - pow[i] = (pow[i - 1] * 2) % mod + pows[i] = pows[i - 1] * 2 % mod } + let res = 0, l = 0, r = n - 1 nums.sort((a, b) => a - b) - let l = 0, r = n - 1, res = 0 while(l <= r) { if(nums[l] + nums[r] > target) r-- else { - res = (res + pow[r - l]) % mod + res = (res + pows[r - l]) % mod l++ } } 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/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/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/1542-find-longest-awesome-substring.js b/1542-find-longest-awesome-substring.js index aaa37653..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} 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/1589-maximum-sum-obtained-of-any-permutation.js b/1589-maximum-sum-obtained-of-any-permutation.js index 54b7f955..2a42dd8b 100644 --- a/1589-maximum-sum-obtained-of-any-permutation.js +++ b/1589-maximum-sum-obtained-of-any-permutation.js @@ -1,3 +1,33 @@ +/** + * @param {number[]} nums + * @param {number[][]} requests + * @return {number} + */ +const maxSumRangeQuery = function(nums, requests) { + nums.sort((a, b) => b - a) + const n = nums.length + const arr = Array(n).fill(0) + for(const [s, e] of requests) { + arr[s] += 1 + if(e + 1 < n) arr[e + 1] -= 1 + } + for(let i = 1; i < n; i++) { + arr[i] += arr[i - 1] + } + arr.sort((a, b) => b - a) + + let res = 0 + const mod = 1e9 + 7 + + for(let i = 0; i < n; i++) { + res = (res + nums[i] * arr[i]) % mod + } + + return res +}; + +// another + /** * @param {number[]} nums * @param {number[][]} requests diff --git a/1590-make-sum-divisible-by-p.js b/1590-make-sum-divisible-by-p.js index 91857ae1..4c903d90 100644 --- a/1590-make-sum-divisible-by-p.js +++ b/1590-make-sum-divisible-by-p.js @@ -1,3 +1,62 @@ +/** + * @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 diff --git a/1591-strange-printer-ii.js b/1591-strange-printer-ii.js index 4dd5b521..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} 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/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/1631-path-with-minimum-effort.js b/1631-path-with-minimum-effort.js index aa094e96..76e5611d 100644 --- a/1631-path-with-minimum-effort.js +++ b/1631-path-with-minimum-effort.js @@ -1,3 +1,47 @@ +/** + * @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} 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/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/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/1655-distribute-repeating-integers.js b/1655-distribute-repeating-integers.js index ece2391f..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 diff --git a/1658-minimum-operations-to-reduce-x-to-zero.js b/1658-minimum-operations-to-reduce-x-to-zero.js index 15935ef5..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,31 @@ +/** + * @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 diff --git a/1674-minimum-moves-to-make-array-complementary.js b/1674-minimum-moves-to-make-array-complementary.js index c257d2e2..3c5243ef 100644 --- a/1674-minimum-moves-to-make-array-complementary.js +++ b/1674-minimum-moves-to-make-array-complementary.js @@ -116,4 +116,31 @@ const minMoves = function (nums, limit) { return res } +// another + +/** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ +const minMoves = function(nums, limit) { + const n = nums.length + const arr = Array(2 * limit + 2).fill(0) + for(let i = 0; i < n / 2; i++) { + const a = nums[i], b = nums[n - 1 - i] + const l = Math.min(a, b), r = Math.max(a, b) + arr[l + 1]-- + arr[l + r]-- + arr[l + r + 1]++ + arr[r + limit + 1]++ + } + let res = n, cur = n + for(let e of arr) { + cur += e + res = Math.min(res, cur) + } + + return res +}; + diff --git a/1675-minimize-deviation-in-array.js b/1675-minimize-deviation-in-array.js 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 c9893c3f..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,15 +3,18 @@ * @return {number[]} */ const getSumAbsoluteDifferences = function(nums) { - const res = [], n = nums.length - let sum = 0 - for(let first = nums[0], i = 1; i < n; i++) { - sum += nums[i] - first + const n = nums.length, { abs } = Math + const res = [] + let e0 = 0 + for(let i = 1; i < n; i++) { + e0 += abs(nums[i] - nums[0]) } - res[0] = sum + res[0] = e0 for(let i = 1; i < n; i++) { - res[i] = res[i - 1] - (nums[i] - nums[i - 1]) * (n - i - 1) + (nums[i] - nums[i - 1]) * (i - 1) + 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 91f38a94..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} diff --git a/1707-maximum-xor-with-an-element-from-array.js b/1707-maximum-xor-with-an-element-from-array.js index 7aa24804..b7104d10 100644 --- a/1707-maximum-xor-with-an-element-from-array.js +++ b/1707-maximum-xor-with-an-element-from-array.js @@ -1,3 +1,112 @@ +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +var maximizeXor = function(nums, queries) { + nums.sort((a, b) => a - b) + const n = nums.length + queries.forEach((query, index) => { + query.push(index) + }) + queries.sort((a, b) => a[1] - b[1]) + const trie = new Trie() + let i = 0 + const res = [] + queries.forEach(([x, m, index]) => { + while (i < n && nums[i] <= m) { + trie.insert(nums[i]) + i++ + } + + res[index] = trie.query(x) + + }) + return res +}; + +class Trie { + constructor() { + this.root = {} + } + insert(num) { + let node = this.root + for (let i = 31; i >= 0; i--) { + const bit = (num >> i) & 1 + if (!node[bit]) { + node[bit] = {} + } + node = node[bit] + } + } + query(num) { + let node = this.root + if (Object.keys(node).length === 0) return -1 + let res = 0 + for (let i = 31; i >= 0; i--) { + const bit = (num >> i) & 1 + if(node == null) break + if (node[1 - bit]) { + res |= 1 << i + node = node[1 - bit] + } else { + node = node[bit] + } + } + return res + } +} + +// another + + +/** + * @param {number[]} nums + * @param {number[][]} queries + * @return {number[]} + */ +const maximizeXor = function(nums, queries) { + nums.sort((a, b) => a - b) + queries.forEach((e, i) => e.push(i)) + queries.sort((a, b) => a[1] - b[1]) + const n = nums.length + let idx = 0 + const res = [] + const root = [null, null] + for(const [x, m, qi] of queries) { + while(idx < n && nums[idx] <= m) { + let cur = root, val = nums[idx] + for(let i = 29; i >= 0; i--) { + const tmp = (val >> i) & 1 + if(cur[tmp] == null) cur[tmp] = [null, null] + cur = cur[tmp] + } + idx++ + } + if(idx === 0) { + res[qi] = -1 + continue + } + + let tmp = 0, cur = root + for(let i = 29; i >= 0; i--) { + const val = 1 - ((x >> i) & 1) + if(cur[val] != null) { + tmp = tmp * 2 + 1 + cur = cur[val] + } else { + tmp = tmp * 2 + cur = cur[1 - val] + } + } + res[qi] = tmp + } + + return res +}; + +// another + /** * @param {number[]} nums * @param {number[][]} queries @@ -99,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/1723-find-minimum-time-to-finish-all-jobs.js b/1723-find-minimum-time-to-finish-all-jobs.js index 40f5824e..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,37 @@ +/** + * @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 @@ -17,12 +51,9 @@ const minimumTimeRequired = function(jobs, k) { res = Math.min(res, Math.max(...workers)) return } - const visited = new Set() const e = jobs[idx] for(let i = 0; i < k; i++) { - if(visited.has(workers[i])) continue if(workers[i] + e >= res) continue - visited.add(workers[i]) workers[i] += e dfs(idx + 1) workers[i] -= e 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 aa948052..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 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/1786-number-of-restricted-paths-from-first-to-last-node.js b/1786-number-of-restricted-paths-from-first-to-last-node.js index 6a80fd88..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 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 b9678076..8e95f7ce 100644 --- a/1801-number-of-orders-in-the-backlog.js +++ b/1801-number-of-orders-in-the-backlog.js @@ -2,64 +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 - - 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/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/1825-finding-mk-average.js b/1825-finding-mk-average.js index a6936047..8ef45ae2 100644 --- a/1825-finding-mk-average.js +++ b/1825-finding-mk-average.js @@ -1,3 +1,79 @@ +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 diff --git a/1830-minimum-number-of-operations-to-make-string-sorted.js b/1830-minimum-number-of-operations-to-make-string-sorted.js index e7808cbd..702e0c27 100644 --- a/1830-minimum-number-of-operations-to-make-string-sorted.js +++ b/1830-minimum-number-of-operations-to-make-string-sorted.js @@ -1,3 +1,66 @@ +/** + * @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} 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 8ada2371..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. diff --git a/1838-frequency-of-the-most-frequent-element.js b/1838-frequency-of-the-most-frequent-element.js index b57a76f9..1be16f31 100644 --- a/1838-frequency-of-the-most-frequent-element.js +++ b/1838-frequency-of-the-most-frequent-element.js @@ -1,3 +1,31 @@ +/** + * @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 diff --git a/1847-closest-room.js b/1847-closest-room.js index f2c7aa85..f23d4cf2 100644 --- a/1847-closest-room.js +++ b/1847-closest-room.js @@ -1,3 +1,111 @@ +/** + * @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 diff --git a/1857-largest-color-value-in-a-directed-graph.js b/1857-largest-color-value-in-a-directed-graph.js index ed99ed48..670144e8 100644 --- a/1857-largest-color-value-in-a-directed-graph.js +++ b/1857-largest-color-value-in-a-directed-graph.js @@ -1,3 +1,70 @@ +/** + * @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 diff --git a/1879-minimum-xor-sum-of-two-arrays.js b/1879-minimum-xor-sum-of-two-arrays.js index 0225d947..31c752c9 100644 --- a/1879-minimum-xor-sum-of-two-arrays.js +++ b/1879-minimum-xor-sum-of-two-arrays.js @@ -1,3 +1,39 @@ +/** + * @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 diff --git a/1882-process-tasks-using-servers.js b/1882-process-tasks-using-servers.js index 311fafc7..db62a07e 100644 --- a/1882-process-tasks-using-servers.js +++ b/1882-process-tasks-using-servers.js @@ -1,3 +1,112 @@ +/** + * @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 diff --git a/1915-number-of-wonderful-substrings.js b/1915-number-of-wonderful-substrings.js index 8402c87d..800696e7 100644 --- a/1915-number-of-wonderful-substrings.js +++ b/1915-number-of-wonderful-substrings.js @@ -1,3 +1,59 @@ +/** + * @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} diff --git a/1931-painting-a-grid-with-three-different-colors.js b/1931-painting-a-grid-with-three-different-colors.js index 1433b0e4..2e3cec5a 100644 --- a/1931-painting-a-grid-with-three-different-colors.js +++ b/1931-painting-a-grid-with-three-different-colors.js @@ -100,3 +100,50 @@ const colorTheGrid = function(m, n) { 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/1942-the-number-of-the-smallest-unoccupied-chair.js b/1942-the-number-of-the-smallest-unoccupied-chair.js index 65b9cd46..643058c6 100644 --- a/1942-the-number-of-the-smallest-unoccupied-chair.js +++ b/1942-the-number-of-the-smallest-unoccupied-chair.js @@ -1,3 +1,209 @@ +/** + * @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 diff --git a/1944-number-of-visible-people-in-a-queue.js b/1944-number-of-visible-people-in-a-queue.js index d74994b3..b2864dfc 100644 --- a/1944-number-of-visible-people-in-a-queue.js +++ b/1944-number-of-visible-people-in-a-queue.js @@ -1,3 +1,27 @@ +/** + * @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[]} diff --git a/1947-maximum-compatibility-score-sum.js b/1947-maximum-compatibility-score-sum.js index e6148d33..7debdc44 100644 --- a/1947-maximum-compatibility-score-sum.js +++ b/1947-maximum-compatibility-score-sum.js @@ -1,3 +1,50 @@ +/** + * @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 diff --git a/198-house-robber.js b/198-house-robber.js index 3ce91fff..17f82e5f 100644 --- a/198-house-robber.js +++ b/198-house-robber.js @@ -31,3 +31,18 @@ const rob = function(nums) { 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/1986-minimum-number-of-work-sessions-to-finish-the-tasks.js b/1986-minimum-number-of-work-sessions-to-finish-the-tasks.js index 2b5b5758..a3237bb6 100644 --- a/1986-minimum-number-of-work-sessions-to-finish-the-tasks.js +++ b/1986-minimum-number-of-work-sessions-to-finish-the-tasks.js @@ -1,3 +1,36 @@ +/** + * @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 diff --git a/1994-the-number-of-good-subsets.js b/1994-the-number-of-good-subsets.js index 8ca7236d..56f86517 100644 --- a/1994-the-number-of-good-subsets.js +++ b/1994-the-number-of-good-subsets.js @@ -1,3 +1,156 @@ +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} diff --git a/1998-gcd-sort-of-an-array.js b/1998-gcd-sort-of-an-array.js index 55c9526d..68ecd546 100644 --- a/1998-gcd-sort-of-an-array.js +++ b/1998-gcd-sort-of-an-array.js @@ -3,25 +3,92 @@ * @return {boolean} */ const gcdSort = function(nums) { - const spf = Array(nums.length).fill(0) - let maxNum = Math.max(...nums); - sieve(maxNum); + 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) - const uf = new UnionFind(maxNum+1); - for (let x of nums) { - for (let f of getFactors(x)) uf.union(f, x); + 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); +} - const sortedArr = nums.slice(); - sortedArr.sort((a, b) => a - b) +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; + } +}; - 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; +// 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; 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/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js b/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js index ad4a1b79..49a6f516 100644 --- a/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js +++ b/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js @@ -1,3 +1,46 @@ +/** + * @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} @@ -27,3 +70,47 @@ function palindromic( i, s) { } 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 index fccbd9db..0089f20a 100644 --- a/2003-smallest-missing-genetic-value-in-each-subtree.js +++ b/2003-smallest-missing-genetic-value-in-each-subtree.js @@ -1,3 +1,61 @@ +/** + * @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 diff --git a/2013-detect-squares.js b/2013-detect-squares.js index 3cb84312..4efeefa0 100644 --- a/2013-detect-squares.js +++ b/2013-detect-squares.js @@ -1,4 +1,57 @@ +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 = {} 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/2033-minimum-operations-to-make-a-uni-value-grid.js b/2033-minimum-operations-to-make-a-uni-value-grid.js index edb3acc4..43f45805 100644 --- a/2033-minimum-operations-to-make-a-uni-value-grid.js +++ b/2033-minimum-operations-to-make-a-uni-value-grid.js @@ -1,3 +1,30 @@ +/** + * @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 diff --git a/204-count-primes.js b/204-count-primes.js index e1a61978..6882fda6 100755 --- a/204-count-primes.js +++ b/204-count-primes.js @@ -1,3 +1,28 @@ +/** + * @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} diff --git a/2045-second-minimum-time-to-reach-destination.js b/2045-second-minimum-time-to-reach-destination.js index bec00cad..8bb74c36 100644 --- a/2045-second-minimum-time-to-reach-destination.js +++ b/2045-second-minimum-time-to-reach-destination.js @@ -1,16 +1,3 @@ -const initializeGraph = (n) => { - let G = [] - for (let i = 0; i < n; i++) { - G.push([]) - } - return G -} -const addEdgeToG = (G, Edges) => { - for (const [u, v] of Edges) { - G[u].push(v) - G[v].push(u) - } -} /** * @param {number} n * @param {number[][]} edges @@ -18,15 +5,15 @@ const addEdgeToG = (G, Edges) => { * @param {number} change * @return {number} */ -const secondMinimum = (n, edges, time, change) => { +var secondMinimum = function(n, edges, time, change) { let adj = initializeGraph(n + 1) addEdgeToG(adj, edges) let cost = initializeGraph(n + 1) - let pq = new MinPriorityQueue({ priority: (x) => x[0] }) - pq.enqueue([0, 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.dequeue().element + let cur = pq.pop() let [t, node] = cur if (cost[node].length == 2) continue let nextT = @@ -45,9 +32,89 @@ const secondMinimum = (n, edges, time, change) => { continue } } - for (const next_node of adj[node]) pq.enqueue([nextT + time, next_node]) + 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 diff --git a/2050-parallel-courses-iii.js b/2050-parallel-courses-iii.js index 1be35f37..521a0eb0 100644 --- a/2050-parallel-courses-iii.js +++ b/2050-parallel-courses-iii.js @@ -1,3 +1,48 @@ +/** + * @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 diff --git a/206-reverse-linked-list.js b/206-reverse-linked-list.js index 94c78a97..82ccda9a 100755 --- a/206-reverse-linked-list.js +++ b/206-reverse-linked-list.js @@ -14,7 +14,7 @@ const reverseList = function(head) { const pre = new ListNode(null, head) let cur = head while(cur.next) { - let tmp = pre.next + const tmp = pre.next pre.next = cur.next cur.next = cur.next.next pre.next.next = tmp diff --git a/210-course-schedule-ii.js b/210-course-schedule-ii.js index 350c4d33..acfd8832 100644 --- a/210-course-schedule-ii.js +++ b/210-course-schedule-ii.js @@ -104,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/2102-sequentially-ordinal-rank-tracker.js b/2102-sequentially-ordinal-rank-tracker.js index 745f2173..3e2f8c83 100644 --- a/2102-sequentially-ordinal-rank-tracker.js +++ b/2102-sequentially-ordinal-rank-tracker.js @@ -1,3 +1,113 @@ +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] } diff --git a/2121-intervals-between-identical-elements.js b/2121-intervals-between-identical-elements.js index 2c99b424..3507ba0e 100644 --- a/2121-intervals-between-identical-elements.js +++ b/2121-intervals-between-identical-elements.js @@ -1,3 +1,41 @@ +/** + * @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[]} diff --git a/2127-maximum-employees-to-be-invited-to-a-meeting.js b/2127-maximum-employees-to-be-invited-to-a-meeting.js index bcaa93f1..8a8efe69 100644 --- a/2127-maximum-employees-to-be-invited-to-a-meeting.js +++ b/2127-maximum-employees-to-be-invited-to-a-meeting.js @@ -1,3 +1,62 @@ +/** + * @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} diff --git a/2152-minimum-number-of-lines-to-cover-points.js b/2152-minimum-number-of-lines-to-cover-points.js index 8c0878b4..78453f54 100644 --- a/2152-minimum-number-of-lines-to-cover-points.js +++ b/2152-minimum-number-of-lines-to-cover-points.js @@ -3,56 +3,48 @@ * @return {number} */ const minimumLines = function(points) { - const n = points.length; - const connects = Array.from({ length: n }, () => Array(n).fill(0)); - for(let i = 0; i < n; ++i) { - for(let j = i + 1; j < n; ++j) { - connects[i][j] = (1 << i) | (1 << j); - let dx = points[j][0] - points[i][0]; - let dy = points[j][1] - points[i][1]; - for(let k = j + 1; k < n; ++k) { // check if k will be on the line connecting i and j. - let dx2 = points[k][0] - points[i][0]; - let dy2 = points[k][1] - points[i][1]; - if (dx * dy2 == dy * dx2) { - connects[i][j] |= (1 << k); - } - } + 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) } + } } - const dp = new Array(1<= n - 2) { // if only 2 points left - dp[mask] = 1; - } else { // if there are more than 2 points, try a line connecting first to second, third, ... - let i = 0; - for(let x = (1 << i); i < n; ++i, x <<= 1) { - if ((mask & x) == 0) { - break; - } - } - for(let j = i + 1, x = (1 << j); j < n; ++j, x <<= 1) { - if ((mask & x) == 0) { - let mask2 = mask | connects[i][j]; - dp[mask] = Math.min(dp[mask], 1 + helper(n, mask2, dp, connects)); - } - } + 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 } - return dp[mask]; -} +}; + -function numOfOne(num) { - const str = (num >>> 0).toString(2) +function bitCnt(num) { let res = 0 - for(let ch of str) { - if(ch === '1') res++ + 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/2163-minimum-difference-in-sums-after-removal-of-elements.js b/2163-minimum-difference-in-sums-after-removal-of-elements.js index 938e51e7..862bbe53 100644 --- a/2163-minimum-difference-in-sums-after-removal-of-elements.js +++ b/2163-minimum-difference-in-sums-after-removal-of-elements.js @@ -1,3 +1,51 @@ +/** + * @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} 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/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/2184-number-of-ways-to-build-sturdy-brick-wall.js b/2184-number-of-ways-to-build-sturdy-brick-wall.js index 1d53cd50..99624b12 100644 --- a/2184-number-of-ways-to-build-sturdy-brick-wall.js +++ b/2184-number-of-ways-to-build-sturdy-brick-wall.js @@ -1,3 +1,57 @@ +/** + * @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 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/2223-sum-of-scores-of-built-strings.js b/2223-sum-of-scores-of-built-strings.js index 18cc57f1..2f8c3d48 100644 --- a/2223-sum-of-scores-of-built-strings.js +++ b/2223-sum-of-scores-of-built-strings.js @@ -1,3 +1,36 @@ +/** + * @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} diff --git a/2261-k-divisible-elements-subarrays.js b/2261-k-divisible-elements-subarrays.js index 8b930531..691bcf2b 100644 --- a/2261-k-divisible-elements-subarrays.js +++ b/2261-k-divisible-elements-subarrays.js @@ -5,20 +5,19 @@ * @return {number} */ const countDistinct = function(nums, k, p) { - let ans = 0; - const se = new Set(); - let n = nums.length; + const se = new Set() + let n = nums.length for (let i = 0; i < n; i++) { - let tmp = ""; - let cnt = 0; + let tmp = "" + let cnt = 0 for (let j = i; j < n; j++) { if (nums[j] % p == 0) - cnt++; + cnt++ if (cnt <= k) { - tmp = tmp + (nums[j]) + "-"; - se.add(tmp); - } else break; + tmp = tmp + (nums[j]) + "-" + se.add(tmp) + } else break } } - return se.size; + return se.size }; diff --git a/2277-closest-node-to-path-in-tree.js b/2277-closest-node-to-path-in-tree.js index 275e550d..b8ef00ef 100644 --- a/2277-closest-node-to-path-in-tree.js +++ b/2277-closest-node-to-path-in-tree.js @@ -1,3 +1,54 @@ +/** + * @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 diff --git a/2280-minimum-lines-to-represent-a-line-chart.js b/2280-minimum-lines-to-represent-a-line-chart.js index 96ae3aa4..a8d50bf9 100644 --- a/2280-minimum-lines-to-represent-a-line-chart.js +++ b/2280-minimum-lines-to-represent-a-line-chart.js @@ -1,3 +1,33 @@ +/** + * @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} 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/2291-maximum-profit-from-trading-stocks.js b/2291-maximum-profit-from-trading-stocks.js index 4a69461f..27aba95e 100644 --- a/2291-maximum-profit-from-trading-stocks.js +++ b/2291-maximum-profit-from-trading-stocks.js @@ -15,3 +15,29 @@ const maximumProfit = function(present, future, budget) { } 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/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/2313-minimum-flips-in-binary-tree-to-get-result.js b/2313-minimum-flips-in-binary-tree-to-get-result.js index 4354aee3..f11fa541 100644 --- a/2313-minimum-flips-in-binary-tree-to-get-result.js +++ b/2313-minimum-flips-in-binary-tree-to-get-result.js @@ -1,3 +1,65 @@ +/** + * 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) { diff --git a/2322-minimum-score-after-removals-on-a-tree.js b/2322-minimum-score-after-removals-on-a-tree.js index fe2fc586..5adcde91 100644 --- a/2322-minimum-score-after-removals-on-a-tree.js +++ b/2322-minimum-score-after-removals-on-a-tree.js @@ -139,3 +139,96 @@ var minimumScore = function (nums, edges) { 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/2327-number-of-people-aware-of-a-secret.js b/2327-number-of-people-aware-of-a-secret.js index 83cf4e8f..8339fb12 100644 --- a/2327-number-of-people-aware-of-a-secret.js +++ b/2327-number-of-people-aware-of-a-secret.js @@ -1,3 +1,32 @@ +/** + * @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 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/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/2354-number-of-excellent-pairs.js b/2354-number-of-excellent-pairs.js index aec51380..1907ddcb 100644 --- a/2354-number-of-excellent-pairs.js +++ b/2354-number-of-excellent-pairs.js @@ -1,3 +1,71 @@ +/** + * @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 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 index da87392d..32eed7a3 100644 --- a/2360-longest-cycle-in-a-graph.js +++ b/2360-longest-cycle-in-a-graph.js @@ -1,3 +1,52 @@ +/** + * @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} 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/2376-count-special-integers.js b/2376-count-special-integers.js index c2f74b4f..af386f2f 100644 --- a/2376-count-special-integers.js +++ b/2376-count-special-integers.js @@ -58,3 +58,59 @@ const countSpecialNumbers = function (n) { 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/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/2392-build-a-matrix-with-conditions.js b/2392-build-a-matrix-with-conditions.js index 8bd4d8ac..a18b14d3 100644 --- a/2392-build-a-matrix-with-conditions.js +++ b/2392-build-a-matrix-with-conditions.js @@ -1,3 +1,69 @@ +/** + * @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 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/2401-longest-nice-subarray.js b/2401-longest-nice-subarray.js index 0af71e12..b6200957 100644 --- a/2401-longest-nice-subarray.js +++ b/2401-longest-nice-subarray.js @@ -1,3 +1,47 @@ +/** + * @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} diff --git a/2402-meeting-rooms-iii.js b/2402-meeting-rooms-iii.js index aa3ab2fc..22d0bf36 100644 --- a/2402-meeting-rooms-iii.js +++ b/2402-meeting-rooms-iii.js @@ -1,3 +1,116 @@ +/** + * @param {number} n + * @param {number[][]} meetings + * @return {number} + */ +const mostBooked = function(n, meetings) { + const rooms = Array(n).fill(0) + const busy = new PQ((a, b) => 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 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/2411-smallest-subarrays-with-maximum-bitwise-or.js b/2411-smallest-subarrays-with-maximum-bitwise-or.js index 0c5f82b2..6f00bf51 100644 --- a/2411-smallest-subarrays-with-maximum-bitwise-or.js +++ b/2411-smallest-subarrays-with-maximum-bitwise-or.js @@ -2,14 +2,16 @@ * @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); +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; -}; + 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/2416-sum-of-prefix-scores-of-strings.js b/2416-sum-of-prefix-scores-of-strings.js index 11ea9edf..b9b48503 100644 --- a/2416-sum-of-prefix-scores-of-strings.js +++ b/2416-sum-of-prefix-scores-of-strings.js @@ -1,3 +1,88 @@ +/** + * @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[]} 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/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/2444-count-subarrays-with-fixed-bounds.js b/2444-count-subarrays-with-fixed-bounds.js index e2d969e1..9ad838c7 100644 --- a/2444-count-subarrays-with-fixed-bounds.js +++ b/2444-count-subarrays-with-fixed-bounds.js @@ -1,3 +1,31 @@ +/** + * @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 diff --git a/2448-minimum-cost-to-make-array-equal.js b/2448-minimum-cost-to-make-array-equal.js index ea777961..39f0e560 100644 --- a/2448-minimum-cost-to-make-array-equal.js +++ b/2448-minimum-cost-to-make-array-equal.js @@ -29,3 +29,44 @@ const minCost = function (nums, cost) { 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/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/2461-maximum-sum-of-distinct-subarrays-with-length-k.js b/2461-maximum-sum-of-distinct-subarrays-with-length-k.js index f2d9bb8e..a9700555 100644 --- a/2461-maximum-sum-of-distinct-subarrays-with-length-k.js +++ b/2461-maximum-sum-of-distinct-subarrays-with-length-k.js @@ -1,3 +1,75 @@ +/** + * @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 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/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/2488-count-subarrays-with-median-k.js b/2488-count-subarrays-with-median-k.js index 54a7d129..fadcdcb5 100644 --- a/2488-count-subarrays-with-median-k.js +++ b/2488-count-subarrays-with-median-k.js @@ -25,3 +25,39 @@ const permutationArrayWithMedianK = (a, k) => { } 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/2492-minimum-score-of-a-path-between-two-cities.js b/2492-minimum-score-of-a-path-between-two-cities.js index de7ed10e..43c7f362 100644 --- a/2492-minimum-score-of-a-path-between-two-cities.js +++ b/2492-minimum-score-of-a-path-between-two-cities.js @@ -1,3 +1,36 @@ +/** + * @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() 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/2503-maximum-number-of-points-from-grid-queries.js b/2503-maximum-number-of-points-from-grid-queries.js index fbc8688f..af835d99 100644 --- a/2503-maximum-number-of-points-from-grid-queries.js +++ b/2503-maximum-number-of-points-from-grid-queries.js @@ -1,3 +1,115 @@ +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 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 61a6a0db..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} 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/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 69960ce7..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} 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/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/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/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/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/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/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/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 17797b5a..28de12d6 100644 --- a/31-next-permutation.js +++ b/31-next-permutation.js @@ -4,7 +4,7 @@ */ const nextPermutation = function(nums) { const n = nums.length - let k + let k = null for(let i = n - 2; i >= 0; i--) { if(nums[i] < nums[i + 1]) { k = i diff --git a/310-minimum-height-trees.js b/310-minimum-height-trees.js index eeaa1111..9bdaed7f 100644 --- a/310-minimum-height-trees.js +++ b/310-minimum-height-trees.js @@ -1,3 +1,53 @@ +/** + * @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 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/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/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/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/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/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 0c795775..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 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/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/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 bd231408..d8b22cc0 100644 --- a/334-increasing-triplet-subsequence.js +++ b/334-increasing-triplet-subsequence.js @@ -35,3 +35,22 @@ const increasingTriplet = function(nums) { 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/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/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 9aca0ff3..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} 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/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/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/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/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/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/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/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/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/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/502-ipo.js b/502-ipo.js index e095989d..9938088e 100644 --- a/502-ipo.js +++ b/502-ipo.js @@ -111,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 fc284214..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[]} 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/56-merge-intervals.js b/56-merge-intervals.js index a772b911..244a9fad 100644 --- a/56-merge-intervals.js +++ b/56-merge-intervals.js @@ -1,3 +1,28 @@ +/** + * @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[][]} 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/60-permutation-sequence.js b/60-permutation-sequence.js index f25ea1a4..ea812807 100644 --- a/60-permutation-sequence.js +++ b/60-permutation-sequence.js @@ -62,6 +62,36 @@ const getPermutation = function(n, k) { // 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 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 f9558beb..b2f0f289 100644 --- a/630-course-schedule-iii.js +++ b/630-course-schedule-iii.js @@ -1,3 +1,119 @@ +/** + * @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} 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/645-set-mismatch.js b/645-set-mismatch.js index 98106af4..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 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/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/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 abeb83e4..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 = [] } 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 bf562c67..893d1432 100644 --- a/743-network-delay-time.js +++ b/743-network-delay-time.js @@ -1,3 +1,58 @@ +/** + * @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 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/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/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/795-number-of-subarrays-with-bounded-maximum.js b/795-number-of-subarrays-with-bounded-maximum.js index beb84f9d..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 diff --git a/802-find-eventual-safe-states.js b/802-find-eventual-safe-states.js index f1d74624..14b46cd1 100644 --- a/802-find-eventual-safe-states.js +++ b/802-find-eventual-safe-states.js @@ -1,3 +1,52 @@ +/** + * @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[]} 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 fd57a2d6..2f06ea31 100644 --- a/85-maximal-rectangle.js +++ b/85-maximal-rectangle.js @@ -1,3 +1,51 @@ +/** + * @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} 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/857-minimum-cost-to-hire-k-workers.js b/857-minimum-cost-to-hire-k-workers.js index 028bcf65..76914b01 100644 --- a/857-minimum-cost-to-hire-k-workers.js +++ b/857-minimum-cost-to-hire-k-workers.js @@ -61,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/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/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/902-numbers-at-most-n-given-digit-set.js b/902-numbers-at-most-n-given-digit-set.js index c45b9fef..2e5da545 100644 --- a/902-numbers-at-most-n-given-digit-set.js +++ b/902-numbers-at-most-n-given-digit-set.js @@ -1,3 +1,38 @@ +/** + * @param {string[]} digits + * @param {number} n + * @return {number} + */ +const atMostNGivenDigitSet = function(digits, n) { + let res = 0 + const str = `${n}`, len = str.length + const { pow } = Math, base = digits.length + for(let i = 1; i < len; i++) { + res += pow(base, i) + } + + dfs(0) + + return res + + function dfs(pos) { + if(pos === len) { + res++ + return + } + for(const ch of digits) { + if(str[pos] > ch) { + res += pow(base, len - 1 - pos) + } else if(str[pos] === ch) { + dfs(pos + 1) + } else break + } + } +}; + +// another + + /** * @param {string[]} digits * @param {number} n diff --git a/907-sum-of-subarray-minimums.js b/907-sum-of-subarray-minimums.js index 52e0a139..ffb2c2a1 100644 --- a/907-sum-of-subarray-minimums.js +++ b/907-sum-of-subarray-minimums.js @@ -67,3 +67,38 @@ const sumSubarrayMins = function (arr) { 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/930-binary-subarrays-with-sum.js b/930-binary-subarrays-with-sum.js index 785bf86c..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 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/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/974-subarray-sums-divisible-by-k.js b/974-subarray-sums-divisible-by-k.js index 26306870..6c456912 100644 --- a/974-subarray-sums-divisible-by-k.js +++ b/974-subarray-sums-divisible-by-k.js @@ -1,3 +1,27 @@ +/** + * @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 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/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/images/689.png b/images/689.png new file mode 100644 index 00000000..3a19a37a Binary files /dev/null and b/images/689.png differ