Leetcode - 双周赛135

目录

  • [一、3512. 使数组和能被 K 整除的最少操作次数](#一、3512. 使数组和能被 K 整除的最少操作次数)
  • [二、3513. 不同 XOR 三元组的数目 I](#二、3513. 不同 XOR 三元组的数目 I)
  • [三、3514. 不同 XOR 三元组的数目 II](#三、3514. 不同 XOR 三元组的数目 II)
  • [四、3515. 带权树中的最短路径](#四、3515. 带权树中的最短路径)

一、3512. 使数组和能被 K 整除的最少操作次数

题目链接

本题实际上求的就是数组 nums 和的余数,代码如下:

java 复制代码
class Solution {
    public int minOperations(int[] nums, int k) {
        int s = 0;
        for(int x : nums){
            s += x;
        }
        return s % k;
    }
}

二、3513. 不同 XOR 三元组的数目 I

题目链接

本题给出的数组 nums 包含 [1,n] 中的所有数,问选 3 个时可以得到的所有异或值,分情况讨论:

  • n = 1,只能与自己异或,答案为 {1}
  • n = 2,必有两个相同值异或(a^a=0),然后再与 1/2 异或,答案为 {1,2}
  • n > 2:
    • 1 ^ 2 ^ 3 = 0,所以可以取到 0
    • a ^ a ^ a = a,所以可以得到 [1,n]
    • 对于大于 n 的值,可以使用构造的方式来获得,比如说 1101,可以通过 {1000,100,1} 获得;1100 可以通过 {1000,101,1} 获得;得到一般公式,对于 n+1, 2 l 2\^{l} 2l-1 中任意一个数 a 来说,它可以通过 { 2 l − 1 2^{l-1} 2l−1,a ^ 1 ^ 2 l − 1 2^{l-1} 2l−1,1} 获得。
    • 特殊情况,a = 2 l − 1 2^{l-1} 2l−1 + 1(即1001100001 这种情况),无法使用上述公式得到,这里特殊处理,可以使用 { 2 l − 1 2^{l-1} 2l−1,2,3} 得到

代码如下:

java 复制代码
class Solution {
    public int uniqueXorTriplets(int[] nums) {
        int n = nums.length;
        if(n == 1) return 1;
        if(n == 2) return 2;
        // [1, n] 选 3 个数
        for(int i = 31; i >= 0; i--){
            if((n >> i & 1) == 1){
                return 1 << (i + 1);
            }
        }
        return -1;
    }
}

三、3514. 不同 XOR 三元组的数目 II

题目链接

本题数据范围小,可以使用 O( n 2 n^{2} n2) 的时间复杂度解决,先处理出 nums数组 中两个数的异或值,然后拿该异或值再与 nums 数组异或。代码如下:

java 复制代码
class Solution {
    public int uniqueXorTriplets(int[] nums) {
        int mx = 0;
        for(int x : nums){
            mx = Math.max(mx, x);
        }
        int u = 1 << (32 - Integer.numberOfLeadingZeros(mx));
        // 这里不要使用 set 来存储,会超时
        boolean[] has = new boolean[u];
        for(int i = 0; i < nums.length; i++){
            for(int j = i; j < nums.length; j++){
                has[nums[i] ^ nums[j]] = true;
            }
        }
        boolean[] has1 = new boolean[u];
        for(int i = 0; i < u; i++){
            if(!has[i]) continue;
            for(int x : nums){
                has1[i ^ x] = true;
            }
        }
        int ans = 0;
        for(boolean x : has1){
            if(x) ans++;
        }
        return ans;
    }
}

四、3515. 带权树中的最短路径

题目链接

本题的难点在于怎么知道更新的(u,v)之间的边权会影响根节点到哪些点的路径距离,由于本题是一个树,所以影响的肯定是(u,v)的所有子节点,那么问题变成了如何维护一个节点的所有子节点?这里可以使用 dfs时间戳 来维护:

  • dfs时间戳就是通过先序遍历,对于每个节点 x,记录进入 x 节点的时间in[x]以及出该节点的时间out[x],如果其他节点的[in[y], out[y]][in[x],out[x]] 中,说明 y 是 x 的子节点。

此时,对于 (u,v) 之间边权的更新,就可以转换成 [in[v], out[v]] 区间的更新(u 是 v 的父节点),可以使用差分的思想来做,由于数据最多只能支持 O(nlogn) 的时间复杂度,所以需要一个 logn 查询/修改的数据结构来维护,可以选择线段树/树状数组,这里使用树状数组。

代码如下:

java 复制代码
class Solution {
	// 树状数组模板
    static class FenwickTree{
        int[] tree;
        public FenwickTree(int n){
            tree = new int[n + 1];
        }
        public void update(int i, int val){
            while(i < tree.length){
                tree[i] += val;
                i += i & -i;
            }
        }
        public int pre(int i){
            int res = 0;
            while(i > 0){
                res += tree[i];
                i -= i & -i;
            }
            return res;
        }
    }
    // 根据进出时间来记录每次修改干涉的路径
    // 根据{进出时间+差分}来修改/得到最短路径
    public int[] treeQueries(int n, int[][] edges, int[][] queries) {
        List<Integer>[] g = new ArrayList[n+1];
        Arrays.setAll(g, e->new ArrayList<>());
        for(int[] e : edges){
            int u = e[0];
            int v = e[1];
            g[u].add(v);
            g[v].add(u);
        }
        in = new int[n+1];
        out = new int[n+1];
        dfs(1, -1, g);

        weight = new int[n+1];// 记录边权
        FenwickTree t = new FenwickTree(n);
        for(int[] e : edges){
            update(e[0], e[1], e[2], t);
        }

        List<Integer> ans = new ArrayList<>();
        for(int[] q : queries){
            if(q[0] == 1){
                update(q[1], q[2], q[3], t);
            }else{
                ans.add(t.pre(in[q[1]]));
            }
        }

        return ans.stream().mapToInt(i -> i).toArray();
    }
    int clock = 0;
    int[] in;
    int[] out;
    int[] weight;
    void dfs(int x, int fa, List<Integer>[] g){
        in[x] = ++clock;
        for(int y : g[x]){
            if(y == fa) continue;
            dfs(y, x, g);
        }
        out[x] = clock;
    }
    void update(int x, int y, int w, FenwickTree t){
        if(in[x] > in[y]){
            y = x;
        }
        int d = w - weight[y];
        weight[y] = w;
        t.update(in[y], d);
        t.update(out[y]+1, -d);
    }
}
相关推荐
罗西的思考1 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX2 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面3 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号3 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽3 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI3 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者5 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者5 小时前
【征程6】校准量化中HistogramObserver解析
算法
OuO-26 小时前
笔试强训 Day 34:ISBN 号码、kotori 和迷宫、矩阵最长递增路径
java·算法·矩阵
程序喵大人6 小时前
【C++进阶】STL算法与函数对象 - 04 find、count和any_of把查询写成意图
开发语言·c++·算法