【LeetCode 周赛题解】第338场周赛题解
题目列表
6354. K 件物品的最大和(easy)
6355. 质数减法运算(medium)
6357. 使数组元素全部相等的最少操作次数(medium)
6356. 收集树中金币(hard)
6354. K 件物品的最大和
直接模拟,优先级为: + 1 > + 0 > − 1 +1>+0>-1 +1>+0>−1
class Solution {public:int kItemsWithMaximumSum(int numOnes, int numZeros, int numNegOnes, int k) {if(k<=numOnes)return k;else if(k<=numOnes+numZeros){//数量不够需要0凑数return numOnes;}else{k-=numOnes+numZeros;//还不够,不得不扣return numOnes-k;}}
};
6355. 质数减法运算
从高到低,如果遇到 n u m s [ i ] > = n u m s [ i + 1 ] nums[i]>=nums[i+1] nums[i]>=nums[i+1] ,则寻找一个最小的质数 q q q ,使得 n u m s [ i ] − q < n u m s [ i + 1 ] nums[i]-q<nums[i+1] nums[i]−q<nums[i+1] 。如果找到了, n u m s [ i ] = n u m s [ i ] − q nums[i]=nums[i]-q nums[i]=nums[i]−q ,继续下一个数;如果找不到,返回 f a l s e false false 。
以为1是质数,WA了一次。小学数学老师气死。
class Solution {public:bool isPrime(int n){if(n==1) return false;if(n==2)return true;for(int i=2;i<=sqrt(n);i++){if(n%i==0)return false;}return true;}bool primeSubOperation(vector<int>& nums) {for(int i=nums.size()-2;i>=0;i--){if(nums[i]>=nums[i+1]){bool flag=false;for(int j=1;j<nums[i];j++){if(isPrime(j)){if(nums[i]-j<nums[i+1]){nums[i]-=j;flag=true;break;}}}if(!flag) return flag;}}for(auto num:nums) cout<<num<<" ";cout<<endl;return true;}
};
6357.使数组元素全部相等的最少操作次数
数据范围是 1 0 5 10^5 105,暴力必超。但是不信邪,也找不到更好的办法了,头铁了一下,贡献了一个WA。 O ( n ) O(n) O(n)时间也是不可能的,所以这题的优化肯定在 O ( n l o g n ) O(nlogn) O(nlogn) 上。提到 O ( n l o g n ) O(nlogn) O(nlogn),那必然就涉及排序、二分等等。这题也确实是这个方向。
观察可以发现,每次大于 q u e r i e s [ i ] queries[i] queries[i] 的数字得往下减,小于的得往上加。那能不能不一个一个减,一次就把小于 q u e r i e s [ i ] queries[i] queries[i] 的数拉到等于 q u e r i e s [ i ] queries[i] queries[i] ,再一次性把大于 q u e r i e s [ i ] queries[i] queries[i] 的数拉到等于 q u e r i e s [ i ] queries[i] queries[i] 。当然可以,假设小于 q u e r i e s [ i ] queries[i] queries[i] 的数一共有 n n n 个,且这 n n n 个数的和为 s u m sum sum ,则 + 1 +1 +1 的操作次数为 q u e r i e s [ i ] ∗ n − s u m queries[i]*n-sum queries[i]∗n−sum ,大于的部分同理。如果这样做的话,我们每次需要分别统计大于和小于 q u e r i e s [ i ] queries[i] queries[i] 的数的个数,还得分别算他们的和,貌似并没有优化。但是如果我们把原数组排序,并且计算一个前缀和,那我们可以用二分查找,查找 q u e r i e s [ i ] queries[i] queries[i] 在排序后的数组里面的位置,就可以一次性得到上述所需的四个值。
class Solution {public:vector<long long> minOperations(vector<int>& nums, vector<int>& queries) {int m=queries.size();int n=nums.size();vector<long long> res(m,0);vector<long long> sum(n+1,0);sort(nums.begin(),nums.end());for(int i=1;i<=n;i++){sum[i]+=sum[i-1]+nums[i-1];}for(int i=0;i<m;i++){long long q=queries[i];int idx=upper_bound(nums.begin(),nums.end(),q)-nums.begin();// cout<<idx<<endl;res[i]+=sum[n]-sum[idx]-q*(n-idx)+(idx)*q-sum[idx];}return res;}
};
6356. 收集树中金币
这种题再给我十个脑子我也想不出来,像极了数学证明题。看着答案都要想半天才知道为什么要这么做。
先把没金币的子树删掉,因为没必要走过去。此时剩下的拓扑就是都得去走一遍的;然后我们从叶子节点往上走一次,并记录每个点进队的时间。由于是从叶子倒着走的,所以其实这个时间就代表了该点到叶子节点的距离。神奇之处在于,这么走一遍之后,所有两端节点的时间大于2的边,都是需要经过的边,且由于需要回到起点,经过次数为两次。换个说法就是,没有任何一条边需要走三次,且每一条边都要走两次!我也很Amazing。因为主干道上的金币在走的过程中顺路收集,而叶子节点不用走到头,所以其实考虑走到何处可以拿到叶子节点上的金币,并在此处停下掉头就行了。至于为什么不会有经过超过两次的边,其实知道这个结论之后去举例子,发现确实很容易证明,难点在于怎么想得到这个约束条件呢。
class Solution {public:int collectTheCoins(vector<int>& coins, vector<vector<int>>& edges) {int n=coins.size();vector<vector<int>> g(n);//邻接表vector<int> deg(n,0);//每个节点的度for(auto e:edges){int x=e[0],y=e[1];g[x].push_back(y);g[y].push_back(x);deg[x]++;deg[y]++;}//删掉无金币的子树queue<int> q;for(int i=0;i<n;i++){if(deg[i]==1&&coins[i]==0){//度为一,即叶子节点,且无金币q.push(i);}}while(!q.empty()){int x=q.front();q.pop();for(auto y:g[x]){//由于队里都是无金币叶子,故y就是与其相连的唯一的一个节点,也就是其父亲//如果删掉当前叶子之后父亲的度为1且父亲也没金币,那父亲也变成了无金币叶子,应该在下一轮被删掉,故入队//而且由于第二次访问的时候也是倒着走的,且留下的都是有金币的叶子,我们直接度减一就可以做到删掉该节点,而无需去删对应的边if(--deg[y]==1&&coins[y]==0){q.push(y);}}}//现在只剩下有金币叶子及其路径了,再走一遍,计算每个节点到叶子的距离for(int i=0;i<n;i++){if(deg[i]==1&&coins[i]){q.push(i);}}if(q.size()<=1) return 0;//如果只有一个叶子有金币,或完全无金币,则不需要拿金币或站在起点就能拿到金币vector<int> time(n,0);while(!q.empty()){int x=q.front();q.pop();for(auto y:g[x]){if(--deg[y]==1){//只有当孩子全都没了,当前节点是叶子了,才入队并更新时间time[y]=time[x]+1;q.push(y);}}}int res=0;for(auto e:edges){int x=e[0],y=e[1];if(time[x]>=2&&time[y]>=2) res+=2;}return res;}
};
【LeetCode 周赛题解】第338场周赛题解相关推荐
- [LeetCode周赛复盘] 第 314 场周赛20221009
[LeetCode周赛复盘] 第 314 场周赛20221009 一.本周周赛总结 二. [Easy] 6201. 找出前缀异或的原始数组 1. 题目描述 2. 思路分析 3. 代码实现 三.[Eas ...
- [LeetCode周赛复盘] 第 324 场周赛20221218
[LeetCode周赛复盘] 第 324 场周赛20221218 一.本周周赛总结 二. [Easy] 6265. 统计相似字符串对的数目 1. 题目描述 2. 思路分析 3. 代码实现 三.[Med ...
- [LeetCode周赛复盘] 第 310 场周赛20220911
[LeetCode周赛复盘] 第 310 场周赛20220911 一.本周周赛总结 二. [Easy] 6176. 出现最频繁的偶数元素 1. 题目描述 2. 思路分析 3. 代码实现 三.[Medi ...
- 【力扣周赛】第349场周赛
[力扣周赛]第349场周赛 6470. 既不是最小值也不是最大值 题目描述 解题思路 6465. 执行子串操作后的字典序最小字符串 题目描述 解题思路 6449. 收集巧克力 题目描述 解题思路 64 ...
- 【力扣周赛】第342场周赛
[力扣周赛]第342场周赛 6387:计算列车到站时间 题目描述 解题思路 6391:倍数求和 题目描述 解题思路 6390:滑动子数组的美丽值 题目描述 解题思路 6392:使数组所有元素变成1的最 ...
- 【力扣周赛】第343场周赛
[力扣周赛]第343场周赛 2660:保龄球游戏的获胜者 题目描述 解题思路 2661:找出叠涂元素 题目描述 解题思路 2660:保龄球游戏的获胜者 题目描述 描述:给你两个下标从 0 开始的整数数 ...
- 【力扣周赛】第345场周赛
[力扣周赛]第345场周赛 6430: 找出转圈游戏输家 题目描述 解题思路 6431: 相邻值的按位异或 题目描述 解题思路 6433: 矩阵中移动的最大次数 题目描述 解题思路 6432: 统计完 ...
- 【力扣周赛】第340场周赛
[力扣周赛]第340场周赛 6361:对角线上的质数 题目描述 解题思路 6360:等值距离和 题目描述 解题思路 6361:对角线上的质数 题目描述 描述:给你一个下标从 0 开始的二维整数数组 n ...
- 【力扣周赛】第346场周赛
[力扣周赛]第346场周赛 6439. 删除子串后的字符串最小长度 题目描述 解题思路 6454. 字典序最小回文串 题目描述 解题思路 6441. 求一个整数的惩罚数 题目描述 解题思路 6439. ...
- 【力扣周赛】第347场周赛
[力扣周赛]第347场周赛 6457. 移除字符串中的尾随零 题目描述 解题思路 2711. 对角线上不同值的数量差 题目描述 解题思路 6455. 使所有字符相等的最小成本 题目描述 解题思路 64 ...
最新文章
- 《OpenCV3编程入门》学习笔记5 Core组件进阶(五)离散傅里叶变换(DFT)
- Judge Route Circle
- Java程序员应知道的十条Java优化策略,让你的系统健步如飞
- 生产者消费者的实际使用
- 求一个数的阶乘值c语言代码,求10000的阶乘(c语言代码实现)
- 一个空间配置多个虚拟主机
- forms、forms_toolbar例子理解
- maven install 错误
- Intel张旭:通信和计算的融合将是5G的关键
- 【To Do! 重点 正则表达式】LeetCode 65. Valid Number
- chrome正受到自动软件的控制_河南科信混凝土搅拌站电脑全自动控制系统PLY1200A称重控制器上位机软件现场安装调试...
- 边缘计算:发展与挑战
- 【无标题】 2022淘宝天猫双十一喵果总动员玩法攻略
- win7与internet时间同步出错_电脑时间同步出错,教您电脑时间同步出错怎么办
- C语言实现哈夫曼树求解及其编码输出
- habor私有镜像仓库部署
- 向日葵远程控制引起惠普战笔记本亮度无法调节问题
- 整理:学术论文发表过程中的审稿人意见答复技巧
- MapReduce(深入)---案例之用户上行流量 下行流量 总流量倒序 按省份分区
- 使用多线程时@Service工具类出现NullPoint错误解决