title: '[Leetcode Weekly Contest]361'
date: 2023-08-21 15:18:48
tags: [OJ]
mathjax: true
链接:LeetCode
[Leetcode]2843. 统计对称整数的数目
给你两个正整数 low 和 high 。
对于一个由 2 * n 位数字组成的整数 x ,如果其前 n 位数字之和与后 n 位数字之和相等,则认为这个数字是一个对称整数。
返回在 [low, high] 范围内的 对称整数的数目 。
遍历即可。
class Solution {
public int countSymmetricIntegers(int low, int high) {
int res = 0;
for(int i=low;i<=high;++i) {
if(isSymmetricIntegers(i)) {
res ++;
}
}
return res;
}
private boolean isSymmetricIntegers(int val) {
int n = (""+val).length();
if((n&1)!=0) return false;
n = n/2;
int val1 = 0, val2 = 0, i = 0;
while(val != 0) {
int num = val % 10;
val = val / 10;
if(i < n) val1 += num;
else val2 += num;
++i;
}
return val1 == val2;
}
}
[Leetcode]2844. 生成特殊数字的最少操作
给你一个下标从 0 开始的字符串 num ,表示一个非负整数。
在一次操作中,您可以选择 num 的任意一位数字并将其删除。请注意,如果你删除 num 中的所有数字,则 num 变为 0。
返回最少需要多少次操作可以使 num 变成特殊数字。
如果整数 x 能被 25 整除,则该整数 x 被认为是特殊数字。
枚举删除后以 00/25/50/75 结尾
class Solution {
public int minimumOperations(String num) {
int res = num.length();
boolean getZero = false, getFive = false;
int n = num.length();
for(int i=n-1;i>=0;--i) {
char ch = num.charAt(i);
if(ch == '0') {
if(!getZero) getZero = true;
else return n-(i+2);
}
if(ch == '5') {
if(!getFive) getFive = true;
if(getZero) return n-(i+2);
}
if(ch == '2' || ch == '7') {
if(getFive) return n-(i+2);
}
}
return getZero ? res-1 : res;
}
}
[Leetcode]2845. 统计趣味子数组的数目
给你一个下标从 0 开始的整数数组 nums ,以及整数 modulo 和整数 k 。
请你找出并统计数组中 趣味子数组 的数目。
如果 子数组 nums[l..r] 满足下述条件,则称其为 趣味子数组 :
在范围 [l, r] 内,设 cnt 为满足 nums[i] % modulo == k 的索引 i 的数量。并且 cnt % modulo == k 。
以整数形式表示并返回趣味子数组的数目。
注意:子数组是数组中的一个连续非空的元素序列。
前缀和+数学式子变形。对于本题,由于需要统计 \(\textit{cnt}\),我们可以把满足要求的nums[i] 视作 1,不满足为0, 如此转换后,算出 \(\textit{nums}\) 的前缀和数组 s,那么题目中的cnt mod modulo=k等价于满足 (s[r+1]−s[l])mod modulo=k, 对于这个等式,等同于 \(s[r+1]\%modulo -s[l]\%modulo = k\), 考虑到负数的情况,即\((s[r+1]\%modulo -s[l]\%modulo + modulo) \% modulo = k\)
class Solution {
public long countInterestingSubarrays(List<Integer> nums, int modulo, int k) {
int n = nums.size();
int[] presum = new int[n+1];
int sum = 0;
for(int i=0;i<n;++i) {
if(nums.get(i) % modulo == k) {
sum ++;
}
presum[i+1] = sum;
}
Map<Integer, Integer> map = new HashMap<>();
long res = 0L;
for(int num:presum) {
res += map.getOrDefault((num % modulo - k + modulo) % modulo, 0);
map.put(num % modulo, map.getOrDefault(num % modulo, 0) + 1);
}
return res;
}
}
[Leetcode]2846. 边权重均等查询
现有一棵由 n 个节点组成的无向树,节点按从 0 到 n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ui, vi, wi] 表示树中存在一条位于节点 ui 和节点 vi 之间、权重为 wi 的边。
另给你一个长度为 m 的二维整数数组 queries ,其中 queries[i] = [ai, bi] 。对于每条查询,请你找出使从 ai 到 bi 路径上每条边的权重相等所需的 最小操作次数 。在一次操作中,你可以选择树上的任意一条边,并将其权重更改为任意值。
注意:
- 查询之间 相互独立 的,这意味着每条新的查询时,树都会回到 初始状态 。
- 从 ai 到 bi的路径是一个由 不同 节点组成的序列,从节点 ai 开始,到节点 bi 结束,且序列中相邻的两个节点在树中共享一条边。
返回一个长度为 m 的数组 answer ,其中 answer[i] 是第 i 条查询的答案。
LCA 模板,对于每个询问,在计算 a 和 b 的最近公共祖先的同时,也同样地维护从 a 到 b 路径上的每种边权的个数 cnt。
class Solution {
public int[] minOperationsQueries(int n, int[][] edges, int[][] queries) {
List<int[]>[] g = new ArrayList[n];
Arrays.setAll(g, e -> new ArrayList<>());
for (var e : edges) {
int x = e[0], y = e[1], w = e[2] - 1;
g[x].add(new int[]{y, w});
g[y].add(new int[]{x, w});
}
int m = 32 - Integer.numberOfLeadingZeros(n); // n 的二进制长度
var pa = new int[n][m];
for (int i = 0; i < n; i++) {
Arrays.fill(pa[i], -1);
}
var cnt = new int[n][m][26];
var depth = new int[n];
dfs(0, -1, g, pa, cnt, depth);
for (int i = 0; i < m - 1; i++) {
for (int x = 0; x < n; x++) {
int p = pa[x][i];
if (p != -1) {
int pp = pa[p][i];
pa[x][i + 1] = pp;
for (int j = 0; j < 26; j++) {
cnt[x][i + 1][j] = cnt[x][i][j] + cnt[p][i][j];
}
}
}
}
var ans = new int[queries.length];
for (int qi = 0; qi < queries.length; qi++) {
int x = queries[qi][0], y = queries[qi][1];
int pathLen = depth[x] + depth[y];
var cw = new int[26];
if (depth[x] > depth[y]) {
int temp = x;
x = y;
y = temp;
}
// 让 y 和 x 在同一深度
for (int k = depth[y] - depth[x]; k > 0; k &= k - 1) {
int i = Integer.numberOfTrailingZeros(k);
int p = pa[y][i];
for (int j = 0; j < 26; ++j) {
cw[j] += cnt[y][i][j];
}
y = p;
}
if (y != x) {
for (int i = m - 1; i >= 0; i--) {
int px = pa[x][i];
int py = pa[y][i];
if (px != py) {
for (int j = 0; j < 26; j++) {
cw[j] += cnt[x][i][j] + cnt[y][i][j];
}
x = px;
y = py; // x 和 y 同时上跳 2^i 步
}
}
for (int j = 0; j < 26; j++) {
cw[j] += cnt[x][0][j] + cnt[y][0][j];
}
x = pa[x][0];
}
int lca = x;
pathLen -= depth[lca] * 2;
int maxCw = 0;
for (int i = 0; i < 26; i++) {
maxCw = Math.max(maxCw, cw[i]);
}
ans[qi] = pathLen - maxCw;
}
return ans;
}
private void dfs(int x, int fa, List<int[]>[] g, int[][] pa, int[][][] cnt, int[] depth) {
pa[x][0] = fa;
for (var e : g[x]) {
int y = e[0], w = e[1];
if (y != fa) {
cnt[y][0][w] = 1;
depth[y] = depth[x] + 1;
dfs(y, x, g, pa, cnt, depth);
}
}
}
}
参考:LeetCode
- Leetcode Contest Weekly 361leetcode contest weekly 361 leetcode contest weekly 355 leetcode contest weekly 365 leetcode contest weekly 367 leetcode contest weekly 368 leetcode contest weekly 350 leetcode contest weekly 351 leetcode contest weekly 339 leetcode contest weekly 364 leetcode contest weekly 359