周赛361(模拟、枚举、记忆化搜索、统计子数组数目(前缀和+哈希)、LCA应用题)

news2024/11/18 8:42:02

文章目录

  • 周赛361
    • [2843. 统计对称整数的数目](https://leetcode.cn/problems/count-symmetric-integers/)
      • 模拟
    • [2844. 生成特殊数字的最少操作](https://leetcode.cn/problems/minimum-operations-to-make-a-special-number/)
      • 记忆化搜索
      • 枚举
    • [2845. 统计趣味子数组的数目](https://leetcode.cn/problems/count-of-interesting-subarrays/)
      • 前缀和 + 哈希表(区间计数经常是前缀和)
    • [2846. 边权重均等查询](https://leetcode.cn/problems/minimum-edge-weight-equilibrium-queries-in-a-tree/)
      • LCA应用题

周赛361

2843. 统计对称整数的数目

简单

给你两个正整数 lowhigh

对于一个由 2 * n 位数字组成的整数 x ,如果其前 n 位数字之和与后 n 位数字之和相等,则认为这个数字是一个对称整数。

返回在 [low, high] 范围内的 对称整数的数目

示例 1:

输入:low = 1, high = 100
输出:9
解释:在 1 到 100 范围内共有 9 个对称整数:11、22、33、44、55、66、77、88 和 99 。

示例 2:

输入:low = 1200, high = 1230
输出:4
解释:在 1200 到 1230 范围内共有 4 个对称整数:1203、1212、1221 和 1230 。

提示:

  • 1 <= low <= high <= 104

模拟

class Solution {
    public int countSymmetricIntegers(int low, int high) {
        int ans = 0;
        for(int num = low; num <= high; num++){
            String str = String.valueOf(num);
            if(str.length() % 2 != 0) continue;
            if(f(str, 0, str.length()/2) == f(str, str.length()/2, str.length()))
                ans += 1;
        }
        return ans;
    }

    public int f(String str, int start, int end){
        int sum = 0;
        for(int i = start; i < end; i++)
            sum += str.charAt(i) - '0';
        return sum;
    }
}

2844. 生成特殊数字的最少操作

中等

给你一个下标从 0 开始的字符串 num ,表示一个非负整数。

在一次操作中,您可以选择 num 的任意一位数字并将其删除。请注意,如果你删除 num 中的所有数字,则 num 变为 0

返回最少需要多少次操作可以使 num 变成特殊数字。

如果整数 x 能被 25 整除,则该整数 x 被认为是特殊数字。

示例 1:

输入:num = "2245047"
输出:2
解释:删除数字 num[5] 和 num[6] ,得到数字 "22450" ,可以被 25 整除。
可以证明要使数字变成特殊数字,最少需要删除 2 位数字。

示例 2:

输入:num = "2908305"
输出:3
解释:删除 num[3]、num[4] 和 num[6] ,得到数字 "2900" ,可以被 25 整除。
可以证明要使数字变成特殊数字,最少需要删除 3 位数字。

示例 3:

输入:num = "10"
输出:1
解释:删除 num[0] ,得到数字 "0" ,可以被 25 整除。
可以证明要使数字变成特殊数字,最少需要删除 1 位数字。

提示

  • 1 <= num.length <= 100
  • num 仅由数字 '0''9' 组成
  • num 不含任何前导零

记忆化搜索

class Solution {
    String num;
    int[][] cache;
    public int minimumOperations(String num) {
        this.num = num;
        int n = num.length();
        cache = new int[n][25];
        for(int i = 0; i < n; i++)
            Arrays.fill(cache[i], -1);
        return dfs(0, 0);
    }
    // 定义dfs(i, last) 表示 枚举到第i位,0-i位上被25整除后的余数为last,要操作的次数
    // 枚举第i位删还是不删
    public int dfs(int i, int last){
        if(i == num.length())
            return last == 0 ? 0 : num.length();
        if(cache[i][last] >= 0) return cache[i][last];
        int res = num.length();
        res = Math.min(res, dfs(i+1, (last*10 + (num.charAt(i) - '0')) % 25));
        res = Math.min(res, dfs(i+1, last) + 1);
        return cache[i][last] = res;
    }
}

枚举

枚举删除后以 00/25/50/75 结尾

https://leetcode.cn/problems/minimum-operations-to-make-a-special-number/solutions/2424068/mei-ju-shan-chu-hou-yi-00255075-jie-wei-zhjlu/

class Solution {
    public int minimumOperations(String num) {
        int n = num.length();
        // 如果数字中有0,删除除0外其他数字可以被25整除; 
       // 如果没有,全部删掉使之为0
       int ans = num.contains("0")? n-1 : n;
       ans = Math.min(ans, Math.min(f("00", num), f("25", num)));
       ans = Math.min(ans, Math.min(f("50", num), f("75", num)));
       return ans;
    }

    public int f(String target, String num){
        int i = num.lastIndexOf(target.substring(1));
        // i < 0 代表没有这个数字 (lastIndexOf未找到返回-1)
        if (i < 0) return num.length();
        i = num.substring(0, i).lastIndexOf(target.substring(0, 1));
        if(i < 0) return num.length();
        // 需要删除的数字是 i以后所有除了target的数字
        return num.length() - i - 2;
        
    }
}

2845. 统计趣味子数组的数目

中等

给你一个下标从 0 开始的整数数组 nums ,以及整数 modulo 和整数 k

请你找出并统计数组中 趣味子数组 的数目。

如果 子数组 nums[l..r] 满足下述条件,则称其为 趣味子数组

  • 在范围 [l, r] 内,设 cnt 为满足 nums[i] % modulo == k 的索引 i 的数量。并且 cnt % modulo == k

以整数形式表示并返回趣味子数组的数目。

**注意:**子数组是数组中的一个连续非空的元素序列。

示例 1:

输入:nums = [3,2,4], modulo = 2, k = 1
输出:3
解释:在这个示例中,趣味子数组分别是: 
子数组 nums[0..0] ,也就是 [3] 。 
- 在范围 [0, 0] 内,只存在 1 个下标 i = 0 满足 nums[i] % modulo == k 。
- 因此 cnt = 1 ,且 cnt % modulo == k 。
子数组 nums[0..1] ,也就是 [3,2] 。
- 在范围 [0, 1] 内,只存在 1 个下标 i = 0 满足 nums[i] % modulo == k 。
- 因此 cnt = 1 ,且 cnt % modulo == k 。
子数组 nums[0..2] ,也就是 [3,2,4] 。
- 在范围 [0, 2] 内,只存在 1 个下标 i = 0 满足 nums[i] % modulo == k 。
- 因此 cnt = 1 ,且 cnt % modulo == k 。
可以证明不存在其他趣味子数组。因此,答案为 3 。

示例 2:

输入:nums = [3,1,9,6], modulo = 3, k = 0
输出:2
解释:在这个示例中,趣味子数组分别是: 
子数组 nums[0..3] ,也就是 [3,1,9,6] 。
- 在范围 [0, 3] 内,只存在 3 个下标 i = 0, 2, 3 满足 nums[i] % modulo == k 。
- 因此 cnt = 3 ,且 cnt % modulo == k 。
子数组 nums[1..1] ,也就是 [1] 。
- 在范围 [1, 1] 内,不存在下标满足 nums[i] % modulo == k 。
- 因此 cnt = 0 ,且 cnt % modulo == k 。
可以证明不存在其他趣味子数组,因此答案为 2 。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • 1 <= modulo <= 109
  • 0 <= k < modulo

前缀和 + 哈希表(区间计数经常是前缀和)

class Solution {
    /**
    1. 转换 设 cnt 为满足 nums[i] % m == k 的索引 i 的数量
        如果 nums[i] % m == k,则 nums[i] = 1,否则 nums[i] = 0
        ==> cnt = 子数组的元素和   ==> 前缀和

    2. 取模 cnt % modulo == k  ==> (pre[r] - pre[l]) % m = k
                               ==> (pre[r] % m - pre[l] % m + m) % m = k
    3. 式子变形 (pre[r] % m - pre[l] % m + m) % m = k
                (pre[r] - k + m) % m = pre[l]
        用哈希表记录pre[l]出现的次数  => 两数之和
     */
    public long countInterestingSubarrays(List<Integer> nums, int m, int k) {
        int n = nums.size();
        int[] arr = new int[n];
        for(int i = 0; i < n; i++)
            arr[i] = (nums.get(i) % m == k) ? 1 : 0;
        int[] pre = new int[n+1];
        for(int i = 0; i < n; i++)
            pre[i+1] = pre[i] + arr[i];
        Map<Integer, Integer> map = new HashMap<>();
        long ans = 0;
        for(int num : pre){
            int target = (num%m - k + m) % m;
            if(map.containsKey(target)) 
                ans += map.get(target);
            map.merge(num%m, 1, Integer::sum);
        }
        return ans;
    }
}

2846. 边权重均等查询

困难

现有一棵由 n 个节点组成的无向树,节点按从 0n - 1 编号。给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges ,其中 edges[i] = [ui, vi, wi] 表示树中存在一条位于节点 ui 和节点 vi 之间、权重为 wi 的边。

另给你一个长度为 m 的二维整数数组 queries ,其中 queries[i] = [ai, bi] 。对于每条查询,请你找出使从 aibi 路径上每条边的权重相等所需的 最小操作次数 。在一次操作中,你可以选择树上的任意一条边,并将其权重更改为任意值。

注意:

  • 查询之间 相互独立 的,这意味着每条新的查询时,树都会回到 初始状态
  • aibi的路径是一个由 不同 节点组成的序列,从节点 ai 开始,到节点 bi 结束,且序列中相邻的两个节点在树中共享一条边。

返回一个长度为 m 的数组 answer ,其中 answer[i] 是第 i 条查询的答案。

示例 1:

img

输入:n = 7, edges = [[0,1,1],[1,2,1],[2,3,1],[3,4,2],[4,5,2],[5,6,2]], queries = [[0,3],[3,6],[2,6],[0,6]]
输出:[0,0,1,3]
解释:第 1 条查询,从节点 0 到节点 3 的路径中的所有边的权重都是 1 。因此,答案为 0 。
第 2 条查询,从节点 3 到节点 6 的路径中的所有边的权重都是 2 。因此,答案为 0 。
第 3 条查询,将边 [2,3] 的权重变更为 2 。在这次操作之后,从节点 2 到节点 6 的路径中的所有边的权重都是 2 。因此,答案为 1 。
第 4 条查询,将边 [0,1]、[1,2]、[2,3] 的权重变更为 2 。在这次操作之后,从节点 0 到节点 6 的路径中的所有边的权重都是 2 。因此,答案为 3 。
对于每条查询 queries[i] ,可以证明 answer[i] 是使从 ai 到 bi 的路径中的所有边的权重相等的最小操作次数。

示例 2:

img

输入:n = 8, edges = [[1,2,6],[1,3,4],[2,4,6],[2,5,3],[3,6,6],[3,0,8],[7,0,2]], queries = [[4,6],[0,4],[6,5],[7,4]]
输出:[1,2,2,3]
解释:第 1 条查询,将边 [1,3] 的权重变更为 6 。在这次操作之后,从节点 4 到节点 6 的路径中的所有边的权重都是 6 。因此,答案为 1 。
第 2 条查询,将边 [0,3]、[3,1] 的权重变更为 6 。在这次操作之后,从节点 0 到节点 4 的路径中的所有边的权重都是 6 。因此,答案为 2 。
第 3 条查询,将边 [1,3]、[5,2] 的权重变更为 6 。在这次操作之后,从节点 6 到节点 5 的路径中的所有边的权重都是 6 。因此,答案为 2 。
第 4 条查询,将边 [0,7]、[0,3]、[1,3] 的权重变更为 6 。在这次操作之后,从节点 7 到节点 4 的路径中的所有边的权重都是 6 。因此,答案为 3 。
对于每条查询 queries[i] ,可以证明 answer[i] 是使从 ai 到 bi 的路径中的所有边的权重相等的最小操作次数。 

提示:

  • 1 <= n <= 104
  • edges.length == n - 1
  • edges[i].length == 3
  • 0 <= ui, vi < n
  • 1 <= wi <= 26
  • 生成的输入满足 edges 表示一棵有效的树
  • 1 <= queries.length == m <= 2 * 104
  • queries[i].length == 2
  • 0 <= ai, bi < n

LCA应用题

https://leetcode.cn/problems/minimum-edge-weight-equilibrium-queries-in-a-tree/solutions/2424060/lca-mo-ban-by-endlesscheng-j54b/

class Solution {
    /** 关键:提炼问题中需要的信息
    【保留出现次数最多的边,其余的边全部修改】
    1. 从 a 到 b 的路径长度(边数)
        = depth[a] - depth[lca] + (depth[b] - depth[lca]) (lca 为 a 和 b 的最近公共祖先)
        ==> 从 a 到 b 的边数为 depth[a] + depth[b] - 2 * depth[lca]
    2. 从 a 到 b 出现次数最多的边
        1 <= wi <= 26  
        ==> 统计从节点 x 到 x的第 2^i 个祖先节点这条路径上 每种边权的出现次数
     */
    public int[] minOperationsQueries(int n, int[][] edges, int[][] queries) {
        List<int[]>[] g = new ArrayList[n]; // x, y, weight
        Arrays.setAll(g, e -> new ArrayList<>());
        for(int[] 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 的二进制长度
        int[][] pa = new int[n][m];
        for(int i = 0; i < n; i++){
            Arrays.fill(pa[i], -1);
        }

        // cnt:从节点 x 到 x的第 2^i 个祖先节点这条路径上 每种边权的出现次数
        int[][][] cnt = new int[n][m][26];
        int[] depth = new int[n];
        // 一次dfs处理出 从【节点x 到 x父节点】 的 【边数 + 各边权出现次数 + 深度】
        dfs(0, -1, g, pa, cnt, depth);
        
        // 倍增求 【从节点x到 x^i个祖先节点】 的 各边权出现次数
        for(int i = 0; i < m-1; i++){
            for(int x = 0; x < n; x++){
                int p = pa[x][i]; // p:x 的祖先节点
                if(p != -1){
                    int pp = pa[p][i]; // pp : x祖先的祖先节点
                    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];
                    }
                }
            }
        }

        int[] 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];
            int[] cw = new int[26];
            if(depth[x] > depth[y]){ // 目的是让x的深度小于y的深度
                int tmp = x; 
                x = y; 
                y = tmp;
            }

            // 让 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;
            }

            // 求 x 和 y 上的lca节点
            if(y != x){ // 从大到小尝试跳(lca模板)
                for(int i = m-1; i >= 0; i--){
                    int px = pa[x][i], py = pa[y][i];
                    if(px != py){ // 说明 lca节点在pa节点上面,更新x和y
                        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]; // 循环结束,x和lca节点只有一步之遥,即lca节点是x的父节点
            }

            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;
    }

    public void dfs(int x, int fa, List<int[]>[] g, int[][] pa, int[][][] cnt, int[] depth){
        pa[x][0] = fa;
        for(int[] e : g[x]){
            int y = e[0], w = e[1];
            if(y != fa){
                cnt[y][0][w] = 1; // 表示 从 y 到 y的第2^0节点(x节点) 有一个边权为w的边
                depth[y] = depth[x] + 1;
                dfs(y, x, g, pa, cnt, depth);
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/972192.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Servlet属性、监听者和会话

没有servlet能单独存在。在当前的现代Web应用中&#xff0c;许多组件都是在一起协作共同完成一个目标。怎么让这些组件共享信息&#xff1f;如何隐藏信息&#xff1f;怎样让信息做到线程安全&#xff1f; 1 属性和监听者 1.1 初始化 容器初始化一个servlet时&#xff0c;会为…

Text-to-SQL小白入门(四)指令进化大模型WizardLM

摘要 本文主要对大模型WizardLM的基本信息进行了简单介绍&#xff0c;展示了WizardLM取得的优秀性能&#xff0c;分析了论文的核心——指令进化方法。 论文概述 基本信息 英文标题&#xff1a;WizardLM: Empowering Large Language Models to Follow Complex Instructions中…

【实践篇】Redis使用规范清单详解

Redis 使用规范清单详解 文章目录 Redis 使用规范清单详解0. 前言参考资料 1. 键值对使用规范1. Key的命名规范2. 避免使用 bigkey2.1. "bigkey"的导致的问题2.2 避免"bigkey"问题解决方法2.2 1. 数据分片2.2.2. 数据压缩 3. 使用高效序列化方法和压缩方法…

jmeter 计数器Counter

计数器可以用于生成动态的数值或字符串&#xff0c;以模拟不同的用户或数据。 计数器通常与用户线程组结合使用&#xff0c;以生成不同的变量值并在测试中应用。以下是计数器的几个常用属性&#xff1a; 变量前缀&#xff08;Variable Name Prefix&#xff09;&#xff1a;定义…

C语言中结构体和位段的一些知识

一、结构体 struct stu {char name[20];//20//对齐数为8int age;//4//两个数中最大对齐数为8&#xff0c;而24又是8的整数倍 }; int main () {printf("%d\n", sizeof(struct stu));//只有vs中有对齐数为8&#xff0c;gcc没有对齐数&#xff0c;对齐数为成员变量自…

【MySQL】MySQL8.0安装教程

下载 MySQL官网下载安装包 安装 1、双击安装程序开始安装 2、选择安装类型 选Server only&#xff08;只安装mysql&#xff09;&#xff0c;然后点击“next”。 3、检测需要的安装&#xff0c; 直接点击Execute开始安装 4、点击next 5、点击next 6、next 7、密码验证方式&a…

EXCEL 中find,if and,if or

接上一篇sql中find函数的作用&#xff0c;由于工作需求是用帆软做报表&#xff0c;他的一些代码不仅有js&#xff0c;sql中的还有一些excel的相关知识&#xff0c;故作整理。 FIND() excel中的find原理和sql中相似&#xff0c;具体可查看 SQL函数 $FIND_Yangshiwei....的博客…

SAP 邮件发送配置

SICF激活服务SCOT邮箱发送配置 具体步骤如下&#xff1a; 1. SICF激活服务 进入事务码&#xff1a; SCIF 选中SAPconnect,右击选中激活SMT机&#xff0c;进行激活 2. SCOT配置邮箱发送设置 进入事务码&#xff1a; SCOT 点开业务通信管理-》设置-》SMTP连接-》出站信息-》…

vscode新建vue3文件模板

输入快捷新建的名字 enter 确认后在文件中输入以下内容 {// Place your snippets for vue here. Each snippet is defined under a snippet name and has a prefix, body and// description. The prefix is what is used to trigger the snippet and the body will be expand…

【计算机网络】 静态库与动态库

文章目录 静态库实践使用方法总结 动态库实践使用方法总结 静态库与动态库的优缺点静态库优点缺点 动态库缺点优点 库有两种&#xff1a;静态库&#xff08;.a、.lib&#xff09;和动态库&#xff08;.so、.dll&#xff09;。所谓静态、动态是指链接。静态库是将整个库文件都拷…

Github 下载指定文件夹(git sparse-checkout)

比如要下载这里的 data_utils 步骤 1、新建空文件夹&#xff0c;并进入新建的空文件夹。 2、git init 初始化 3、git remote add origin 添加远程仓库 4、git config core.sparsecheckout true 允许稀疏检出 5、git sparse-checkout set 设置需要拉取的文件夹&#xff08;可…

Lite transformer

图片以及思想来源请参考论文 Lite Transformer with Long-Short Range Attention 瓶颈结构&#xff08;bottleneck&#xff09;是否真的有效 注意力机制被广泛应用在诸多领域&#xff0c;包括自然语言处理&#xff0c;图像处理和视频处理。它通过计算所有输入元素的点积来建模…

idea 无法识别maven的解决

问题描述 从git拉取代码或者修改文件夹以后&#xff0c;整个项目所有依赖爆红无法通过修改或者重新加载maven解决版本为idea 2021 问题定位 maven的版本太高&#xff0c;而idea的般本太低&#xff0c;导致识别的时候稳定性差 解决 使用idea原生的maven版本 选择已捆绑的m…

Tribon二次开发-tbwautodraw

在Assembly模块中,通过设置和生成,可以在手动的基础上自动生成组立装配图。 1、设置视向,根据组立的具体情况选择,一般横向结构,是向船首看,纵向结构向左舷看,水平结构向下看。 2、在组立节点上右键,选项“Generate Assembly Drawing…” 确保图框A4L_…

无涯教程-JavaScript - DAYS函数

描述 DAYS函数返回两个日期之间的天数。 语法 DAYS (end_date, start_date)争论 Argument描述Required/OptionalEnd_dateStart_date and End_date are the two dates between which you want to know the number of days.RequiredStart_dateStart_date and End_date are th…

C# 基础面试题(万字)

1.选择题 1. 简述下面选项能够捕获运算溢出的异常类型的有 &#xff1f; A)Exception B)SystemException C)ArithmeticException D)OverflowException 试题回答&#xff1a;AD 2. 程序员可使用&#xff08;&#xff09;语句以程序方式引发异常 &#xff1f; A)run B)try C)th…

并发编程的故事——JUC

JUC 文章目录 JUC一、Semaphore二、CountDownLatch三、线程安全类 一、Semaphore 为什么需要用到Semaphore? 限流 Semaphore的场景&#xff1f; 秒杀商品的时候&#xff0c;不能够让那些没有秒杀成功的线程进入&#xff0c;只有占了坑位的才可以使用&#xff0c;这里可以用re…

Myvatis关联关系映射与表对象之间的关系

目录 一、关联关系映射 1.1 一对一 1.2 一对多 1.3 多对多 二、处理关联关系的方式 2.1 嵌套查询 2.2 嵌套结果 三、一对一关联映射 3.1 建表 ​编辑 3.2 配置文件 3.3 代码生成 3.4 编写测试 四、一对多关联映射 五、多对多关联映射 六、小结 一、关联关系映射 …

现货黄金代理好吗?

做黄金代理这个职业好吗&#xff1f;从目前的市场现状来看&#xff0c;其实做黄金代理很不错的。在股票市场中&#xff0c;投资者只能通过买涨进盈利&#xff0c;所以当市场行情不好的时候&#xff0c;股票经纪人的业务将很难展开&#xff0c;而现货黄金投资者不一样&#xff0…

mac 安装java1.8

1、下载jdk1.8 https://www.oracle.com/java/technologies/downloads/#java8-mac 2、 安装jdk1.8 一路默认&#xff0c;安装后的位置在这儿。 /Library/Java/JavaVirtualMachines/jdk-1.8.jdk 3、配置环境 打开终端&#xff0c;输入命令 sudo vim /etc/profile 添加以下配…