双周赛113(枚举、分类讨论 + 二分查找、枚举值域两数之和、换根DP)

news2024/12/23 23:07:35

文章目录

  • 双周赛113
    • [2855. 使数组成为递增数组的最少右移次数](https://leetcode.cn/problems/minimum-right-shifts-to-sort-the-array/)
      • 暴力枚举
      • 贪心 O(n)
    • [2856. 删除数对后的最小数组长度](https://leetcode.cn/problems/minimum-array-length-after-pair-removals/)
      • 分类讨论
      • 二分查找 O(logn)
    • [2857. 统计距离为 k 的点对](https://leetcode.cn/problems/count-pairs-of-points-with-distance-k/)
      • 枚举值域 ==> 两数之和
    • [2858. 可以到达每一个节点的最少边反转次数](https://leetcode.cn/problems/minimum-edge-reversals-so-every-node-is-reachable/)
      • 换根DP

双周赛113

2855. 使数组成为递增数组的最少右移次数

简单

给你一个长度为 n 下标从 0 开始的数组 nums ,数组中的元素为 互不相同 的正整数。请你返回让 nums 成为递增数组的 最少右移 次数,如果无法得到递增数组,返回 -1

一次 右移 指的是同时对所有下标进行操作,将下标为 i 的元素移动到下标 (i + 1) % n 处。

示例 1:

输入:nums = [3,4,5,1,2]
输出:2
解释:
第一次右移后,nums = [2,3,4,5,1] 。
第二次右移后,nums = [1,2,3,4,5] 。
现在 nums 是递增数组了,所以答案为 2 。

示例 2:

输入:nums = [1,3,5]
输出:0
解释:nums 已经是递增数组了,所以答案为 0 。

示例 3:

输入:nums = [2,1,4]
输出:-1
解释:无法将数组变为递增数组。

提示:

  • 1 <= nums.length <= 100
  • 1 <= nums[i] <= 100
  • nums 中的整数互不相同。

暴力枚举

至多移动n-1次,枚举以每个下标为第一位元素,然后查看是否为递增数组

贪心 O(n)

使数组成为递增数组,那么最小值一定在最左边,找到最小值,然后检查一遍右侧元素是否都小于当前元素

class Solution {
    public int minimumRightShifts(List<Integer> nums) {
        int mnidx = -1, mn = Integer.MAX_VALUE;
        for(int i = 0; i < nums.size(); i++){
            if(nums.get(i) < mn){
                mn = nums.get(i);
                mnidx = i;
            }
        }
        int j = mnidx;
        for(int i = 0; i < nums.size()-1; i++){
            int suf = nums.get((j+1)% nums.size());
            if(suf < nums.get(j)) return -1;
            j = (j + 1) % nums.size();
        }
        return (nums.size() - mnidx) % nums.size();
    }
}

2856. 删除数对后的最小数组长度

中等

给你一个下标从 0 开始的 非递减 整数数组 nums

你可以执行以下操作任意次:

  • 选择 两个 下标 ij ,满足 i < jnums[i] < nums[j]
  • nums 中下标在 ij 处的元素删除。剩余元素按照原来的顺序组成新的数组,下标也重新从 0 开始编号。

请你返回一个整数,表示执行以上操作任意次后(可以执行 0 次),nums 数组的 最小 数组长度。

示例 1:

输入:nums = [1,3,4,9]
输出:0
解释:一开始,nums = [1, 3, 4, 9] 。
第一次操作,我们选择下标 0 和 1 ,满足 nums[0] < nums[1] <=> 1 < 3 。
删除下标 0 和 1 处的元素,nums 变成 [4, 9] 。
下一次操作,我们选择下标 0 和 1 ,满足 nums[0] < nums[1] <=> 4 < 9 。
删除下标 0 和 1 处的元素,nums 变成空数组 [] 。
所以,可以得到的最小数组长度为 0 。

示例 2:

输入:nums = [2,3,6,9]
输出:0
解释:一开始,nums = [2, 3, 6, 9] 。
第一次操作,我们选择下标 0 和 2 ,满足 nums[0] < nums[2] <=> 2 < 6 。
删除下标 0 和 2 处的元素,nums 变成 [3, 9] 。
下一次操作,我们选择下标 0 和 1 ,满足 nums[0] < nums[1] <=> 3 < 9 。
删除下标 0 和 1 处的元素,nums 变成空数组 [] 。
所以,可以得到的最小数组长度为 0 。

示例 3:

输入:nums = [1,1,2]
输出:1
解释:一开始,nums = [1, 1, 2] 。
第一次操作,我们选择下标 0 和 2 ,满足 nums[0] < nums[2] <=> 1 < 2 。
删除下标 0 和 2 处的元素,nums 变成 [1] 。
无法对数组再执行操作。
所以,可以得到的最小数组长度为 1 。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
  • nums非递减 数组。

分类讨论

https://leetcode.cn/problems/minimum-array-length-after-pair-removals/solutions/2446146/olog-n-tan-xin-er-fen-cha-zhao-pythonjav-t3qn/

class Solution {
    /**
    设元素 x 的出现次数为 cx

    从特例入手,分类讨论:
    1. 当 cx > n/2:2*cx-n
        没法全部抵消: 2*cx-n
            众数 x 出现 cx 次,其他数出现 n-cx 次
            那么 可以抵消 2*(n-cx) 个,剩余元素数量为 n - 2*(n-cx) 个
            花间 2cx - n
    
    2. 当 cx <= n/2: 
        可以几乎全部抵消
            n 是偶数,剩余 0 个数
            n 是奇数,剩余 1 个数
     */
    public int minLengthAfterRemovals(List<Integer> nums) {
        int n = nums.size();
        Map<Integer, Integer> map = new HashMap<>();
        for(int num : nums){
            map.merge(num, 1, Integer::sum);
        }
        int cx = -1;
        for(Map.Entry<Integer, Integer> entry : map.entrySet()){
            if(entry.getValue() > cx)
                cx = entry.getValue();
        }
        if(cx > n / 2) return 2*cx - n;
        else return n % 2;
        
    }
}

二分查找 O(logn)

class Solution {
    /**
    由于数组是有序的,如果maxcnt超过数组的一半,那么nums[n/2]一定是出现次数最多的那个数
    然后用二分查找计算出nums[n/2]第一次和最后一次出现的位置,从而算出maxcnt
    
     */
    public int minLengthAfterRemovals(List<Integer> nums) {
        int n = nums.size();
        int x = nums.get(n / 2);
        int left = lowerBound(nums, x);
        int right = lowerBound(nums, x+1); // upperBound(nums, x);
        // x个数:[left, right)
        return Math.max((right - left) * 2 - n, n % 2);
    }

    // upper_bound : 返回第一个大于key的元素下标
    public int upperBound(List<Integer> list, int target){
        int left = 0, right = list.size();
        while(left < right){
            int mid = (left + right) >> 1;
            if(list.get(mid) > target) right = mid;
            else left = mid + 1;
        }
        return left;
    }
    // lower_bound : 返回第一个大于或等于key的元素下标
    public int lowerBound(List<Integer> list, int target){
        int left = 0, right = list.size();
        while(left < right){
            int mid = (left + right) >> 1;
            if(list.get(mid) < target) left = mid + 1;
            else right = mid;
        }
        return left;
    }
}

2857. 统计距离为 k 的点对

中等

给你一个 二维 整数数组 coordinates 和一个整数 k ,其中 coordinates[i] = [xi, yi] 是第 i 个点在二维平面里的坐标。

我们定义两个点 (x1, y1)(x2, y2)距离(x1 XOR x2) + (y1 XOR y2)XOR 指的是按位异或运算。

请你返回满足 i < j 且点 i 和点 j之间距离为 k 的点对数目。

示例 1:

输入:coordinates = [[1,2],[4,2],[1,3],[5,2]], k = 5
输出:2
解释:以下点对距离为 k :
- (0, 1):(1 XOR 4) + (2 XOR 2) = 5 。
- (2, 3):(1 XOR 5) + (3 XOR 2) = 5 。

示例 2:

输入:coordinates = [[1,3],[1,3],[1,3],[1,3],[1,3]], k = 0
输出:10
解释:任何两个点之间的距离都为 0 ,所以总共有 10 组点对。

提示:

  • 2 <= coordinates.length <= 50000
  • 0 <= xi, yi <= 106
  • 0 <= k <= 100

枚举值域 ==> 两数之和

https://leetcode.cn/problems/count-pairs-of-points-with-distance-k/solutions/2445629/bao-li-zhu-yi-k-de-fan-wei-by-endlessche-3i1b/

class Solution {
    // 点 i 和点 j之间距离为 k
    // (x1 XOR x2) + (y1 XOR y2) = k
    // 由于 0 <= x1 XOR x2 <= i
    //      0 <= y1 XOR y2 <= k-i
    // 枚举 (x2, y2) => (x1 ^ i, y1 ^ (k-i))
    // 两数之和
    public int countPairs(List<List<Integer>> coordinates, int k) {
        Map<String, Integer> map = new HashMap<>();
        int cnt = 0;
        for(List<Integer> coordinate : coordinates){
            int x = coordinate.get(0), y = coordinate.get(1);
            for(int i = 0; i <= k; i++){
                String key = (x ^ i) + "_" + (y ^ (k-i));
                cnt += map.getOrDefault(key, 0);
            }
            map.merge(x + "_" + y, 1, Integer::sum);
        }
        return cnt;
    }
}

2858. 可以到达每一个节点的最少边反转次数

困难

给你一个 n 个点的 简单有向图 (没有重复边的有向图),节点编号为 0n - 1 。如果这些边是双向边,那么这个图形成一棵

给你一个整数 n 和一个 二维 整数数组 edges ,其中 edges[i] = [ui, vi] 表示从节点 ui 到节点 vi 有一条 有向边

边反转 指的是将一条边的方向反转,也就是说一条从节点 ui 到节点 vi 的边会变为一条从节点 vi 到节点 ui 的边。

对于范围 [0, n - 1] 中的每一个节点 i ,你的任务是分别 独立 计算 最少 需要多少次 边反转 ,从节点 i 出发经过 一系列有向边 ,可以到达所有的节点。

请你返回一个长度为 n 的整数数组 answer ,其中 answer[i]表示从节点 i 出发,可以到达所有节点的 最少边反转 次数。

示例 1:

img

输入:n = 4, edges = [[2,0],[2,1],[1,3]]
输出:[1,1,0,2]
解释:上图表示了与输入对应的简单有向图。
对于节点 0 :反转 [2,0] ,从节点 0 出发可以到达所有节点。
所以 answer[0] = 1 。
对于节点 1 :反转 [2,1] ,从节点 1 出发可以到达所有节点。
所以 answer[1] = 1 。
对于节点 2 :不需要反转就可以从节点 2 出发到达所有节点。
所以 answer[2] = 0 。
对于节点 3 :反转 [1,3] 和 [2,1] ,从节点 3 出发可以到达所有节点。
所以 answer[3] = 2 。

示例 2:

img

输入:n = 3, edges = [[1,2],[2,0]]
输出:[2,0,1]
解释:上图表示了与输入对应的简单有向图。
对于节点 0 :反转 [2,0] 和 [1,2] ,从节点 0 出发可以到达所有节点。
所以 answer[0] = 2 。
对于节点 1 :不需要反转就可以从节点 2 出发到达所有节点。
所以 answer[1] = 0 。
对于节点 2 :反转 [1,2] ,从节点 2 出发可以到达所有节点。
所以 answer[2] = 1 。

提示:

  • 2 <= n <= 105
  • edges.length == n - 1
  • edges[i].length == 2
  • 0 <= ui == edges[i][0] < n
  • 0 <= vi == edges[i][1] < n
  • ui != vi
  • 输入保证如果边是双向边,可以得到一棵树。

换根DP

https://leetcode.cn/problems/minimum-edge-reversals-so-every-node-is-reachable/solutions/2445681/mo-ban-huan-gen-dppythonjavacgojs-by-end-8qiu/

class Solution {
    private List<int[]>[] g;
    private int[] ans, size;


    public int[] minEdgeReversals(int n, int[][] edges) {
        g = new ArrayList[n]; // g[x] 表示 x 的所有邻居
        Arrays.setAll(g, e -> new ArrayList<>());
        for(int[] e : edges){
            int x = e[0], y = e[1];
            g[x].add(new int[]{y, 1});
            g[y].add(new int[]{x, -1}); // 有向图,标记y到x为反向
        }
        ans = new int[n];
        dfs(0, -1); // 计算ans[0]
        reroot(0, -1); // 0 没有父节点 
        return ans;
    }

    private void dfs(int x, int fa){
        for(int[] e : g[x]){ // 遍历 x 的邻居 y
            int y = e[0], dir = e[1];
            if(y != fa){ // 避免访问父节点
                if(dir < 0) 
                    ans[0] += 1;
                dfs(y, x); // x 是 y 的父节点
            }
        }
    }

    private void reroot(int x, int fa){
        for(int[] e : g[x]){ // 遍历 x 的邻居 y
            int y = e[0], dir = e[1];
            if(y != fa){ // 避免访问父节点
            	// 这里是变化点,按照题目要求更改
                ans[y] = ans[x] + dir; // dir 就是 从 x 换到 y 的 变化量
                reroot(y, x); // x 是 y 的父节点
            }
        }
    }

}

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

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

相关文章

[MAUI]实现动态拖拽排序网格

文章目录 创建页面元素创建可绑定对象创建绑定服务类拖拽&#xff08;Drag&#xff09;拖拽悬停&#xff0c;经过&#xff08;DragOver&#xff09;释放&#xff08;Drop&#xff09; 限流(Throttle)和防抖(Debounce)项目地址 上一章我们使用拖放(drag-drop)手势识别实现了可拖…

TCP/IP协议栈各层涉及到的协议

21/tcp FTP 文件传输协议 22/tcp SSH 安全登录、文件传送(SCP)和端口重定向 23/tcp Telnet 远程连接 80/tcp HTTP 443/tcp HTTPS 计算机各层网络协议 五层&#xff1a;应用层: (典型设备:应用程序&#xff0c;如FTP&#xff0c;SMTP &#xff0c;HTTP) DHCP(Dynamic Host…

Pikachu Burte Force(暴力破解)

一、Burte Force&#xff08;暴力破解&#xff09;概述 ​ “暴力破解”是一攻击具手段&#xff0c;在web攻击中&#xff0c;一般会使用这种手段对应用系统的认证信息进行获取。 其过程就是使用大量的认证信息在认证接口进行尝试登录&#xff0c;直到得到正确的结果。 为了提高…

RFID与人工智能怎么融合,RFID与人工智能融合的应用

随着物联网技术的不断发展&#xff0c;现实世界与数字世界的桥梁已经被打通。物联网通过各种传感器&#xff0c;将现实世界中的光、电、热等信号转化为有价值的数据。这些数据可以通过RFID技术进行自动收集和传输&#xff0c;然后经由人工智能算法进行分析、建模和预测&#xf…

uniapp cli创建 vue3 + typeScript项目 配置eslint prettier husky

1 命令创建项目 npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project2 下载依赖 npm install3 填写appid 4 运行项目并且微信开发工具打开 npm run dev:mp-weixin5 安装 vscode 插件 安装 **Vue Language Features (Volar)** &#xff1a;Vue3 语法提示插件 安装 *…

伦敦银一手是多少?

伦敦银是以国际现货白银价格为跟踪对象的电子合约交易&#xff0c;无论投资者通过什么地方的平台进入市场&#xff0c;执行的都是统一国际的标准&#xff0c;一手标准的合约所代表的就是5000盎司的白银&#xff0c;如果以国内投资者比较熟悉的单位计算&#xff0c;那约相当于15…

http客户端Feign使用

一、RestTemplate方式调用存在的问题 先来看我们以前利用RestTemplate发起远程调用的代码&#xff1a; String url "http://userservice/user/" order.getUserId(); User user restTemplate.getForObject(url, User.class);存在下面的问题&#xff1a; 代码可读…

Mosh Java课程自学(一)

目录 一、前言 二、全局介绍 三、Types 一、前言 首先推荐一下B站上转载的Mosh讲Java课程&#xff0c;当然&#xff0c;建议有一定基础并且英文水平尚可的同学学习&#xff0c;否则你可能会被搞得很累并逐渐失去对编程的兴趣。 Mosh 【JAVA终极教程】中英文字幕 高清完整版…

口袋参谋:如何高效一键下载真实买家秀?

​在淘宝天猫上&#xff0c;即使卖一支笔都有上万个宝贝竞争&#xff0c;所有卖家拼的就是权重带来的曝光度&#xff0c;能展示给买家多少&#xff0c;自己收获多少流量。 如何用自己的优势将流量访客转化为顾客&#xff0c;提升店铺的转化率。而买家秀&#xff0c;就是为此而生…

Java常用类之 String、StringBuffer、StringBuilder

Java常用类 文章目录 一、字符串相关的类1.1、String的 不可变性1.2、String不同实例化方式的对比1.3、String不同拼接操作的对比1.4、String的常用方法1.5、String类与其他结构之间的转换1.5.1、String 与基本数据类型、包装类之间的转换1.5.2、String 与char[]的转换1.5.3、…

ipad可以使用其他品牌的手写笔吗?开学平价电容笔推荐

新学期已经来临&#xff0c;相信不少同学已经开始着手筹备新学期的该准备什么了&#xff0c;毕竟原装的苹果Pencil&#xff0c;功能强大&#xff0c;但价格昂贵&#xff0c;一般人根本买不起。那么&#xff0c;有没有像苹果原装那样的电容笔呢&#xff1f;当然是有的。国产的平…

长安链上线可视化敏捷测试工具v1.0版本

开发者对区块链底层平台进行初步的了解后&#xff0c;一项经常会涉及到的工作是对平台进行测试以考量其性能及稳定性是否符合自身使用需求。长安链推出了可视化UI操作界面的区块链敏捷测试工具v1.0版本&#xff0c;当前版本可对内置合约进行压测并生成网络拓扑图以验证组网方式…

免费开箱即用微鳄售后工单管理系统

编者按&#xff1a;本文介绍基于天翎MyApps低代码平台开发的微鳄售后工单管理系统&#xff0c; 引入低代码平台可以帮助企业快速搭建和部署售后工单管理系统&#xff0c; 以工作流作为支撑&#xff0c;在线完成各环节数据审批&#xff0c;解决售后 工单 服务的全生命周期过程管…

《2023中国氢能源行业分析报告》丨附下载_三叠云

✦ ✦✦ ✦✦ ✦✦ ✦ 1. 国内氢能政策梳理 直接涉及氢能政策&#xff1a;1&#xff09;21年以来&#xff0c;发布国家级10个、省级83个、 市县级252个&#xff1b;2&#xff09;涉及发展规划占比45%、财政支持占比 20%、项目支持占比17%、管理办法占比16%、 氢能安全和标准占…

公私钥非对称加密 生成和验证JSON Web Token (JWT)

前言 这是我在这个网站整理的笔记&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 公私钥非对称加密 生成和验证JSON Web Token 什么是JSON Web Token (JWT)Java程序中生成和验证JWT代码解析 什么是JSON Web Token (JWT) JSON Web Tok…

【C++】泛型算法(二)泛型指针Iterator(迭代器)

迭代器iterator定义 迭代器是一种检查容器内元素并遍历元素的数据类型&#xff1b;迭代器提供一个对容器对象或者string对象的访问方法&#xff0c;并定义了容器范围&#xff1b;迭代器的使用可以提高编程的效率。 其定义应该提供&#xff1a; 迭代对象&#xff08;某个容器&a…

拆贡献算总和(抓住双射)+竞赛图与连通分量相关计数:arc163_d

https://atcoder.jp/contests/arc163/tasks/arc163_d 首先竞赛图有个性质&#xff1a; 然后有了这个性质&#xff0c;我们就可以考虑计数题的经典套路&#xff0c;拆贡献算总和。 考虑假如我们成功划分成两个集合 A , B A,B A,B&#xff0c;其中一个可以为空&#xff08;我们…

Qt --- Day02

实现效果&#xff1a; 点击登录&#xff0c;检验用户密码是否正确&#xff0c;正确则弹出消息框&#xff0c;点击ok转到另一个页面 不正确跳出错误消息框&#xff0c;默认选线为Cancel&#xff0c;点击Yes继续登录 点击Cancel跳出问题消息框&#xff0c;默认选项No&#xff0c…

netty之pipeline

Netty抽象出流水线(pipeline)这一层数据结构进行处理或拦截channel相关事件。 事件分为入站事件(inBound event)和出站事件(outBound event)的ChannelHandlers列表。ChannelPipeline使用先进的Intercepting Filter模式&#xff0c;使用户可以完全控制如何处理事件以及管道中的…