• 【算法竞赛01】leetcode第363场周赛


    前言

    笔者为数不多AK的比赛

    T1.计算K位置下标对应元素的和(Easy

    题目链接

            计算K位置下标对应元素的和

    题目描述

            给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。

            请你用整数形式返回nums中的特定元素之 ,这些特定元素满足:其对应下标的二进制表示中恰存在k个置位。

            整数的二进制表示中的1就是这个整数的置位 。

            例如,21的二进制表示为10101,其中有3置位

    输入范围
    • 1 <= nums.length <= 1000
    • 1 <= nums[i] <= 10^5
    • 0 <= k <= 10
    问题分析&思路

            显然是LowBit模版题,可以用LowBit求置位数,也可以直接用库函数求置位数,以下展示LowBit做法。

    代码实现(Java&Python)
    1. //Java
    2. class Solution {
    3. public int sumIndicesWithKSetBits(List nums, int k) {
    4. int ans = 0;
    5. for(int i = 0;i
    6. int cnt = 0;
    7. int tmp = i;
    8. while(tmp>0){
    9. cnt+=1;
    10. tmp&=tmp-1;
    11. }
    12. if(cnt == k){
    13. ans+=nums.get(i);
    14. }
    15. }
    16. return ans;
    17. }
    18. }
    1. #Python
    2. class Solution:
    3. def sumIndicesWithKSetBits(self, nums: List[int], k: int) -> int:
    4. ans = 0
    5. for i,x in enumerate(nums):
    6. cnt = 0
    7. while i:
    8. cnt+=1
    9. i&=i-1
    10. if cnt == k:
    11. ans+=x
    12. return ans
    时间&空间复杂度分析
    • 时间复杂度:\mathcal{O}(n\log k),n为数组长度,k为最大数的二进制位数。
    • 空间复杂度:\mathcal{O}(1)

    T2.让所有学生保持开心的分组方法数(Medium

    题目链接

                    让所有学生保持开心的分组方法数

    题目描述

            给你一个下标从 0 开始、长度为 n 的整数数组 nums ,其中 n 是班级中学生的总数。班主任希望能够在让所有学生保持开心的情况下选出一组学生:

            如果能够满足下述两个条件之一,则认为第 i 位学生将会保持开心:

    • 这位学生被选中,并且被选中的学生人数 严格大于 nums[i] 。
    • 这位学生没有被选中,并且被选中的学生人数 严格小于 nums[i] 。

            返回能够满足让所有学生保持开心的分组方法的数目。

    输入范围
    • 1 <= nums.length <= 10^5
    • 0 <= nums[i] < nums.length
    问题分析&思路

            考虑如何选择k个学生,用贪心的思想考虑,被选中的k个学生的nums都要尽可能小,以便保证被选中的学生人数严格大于被选中的学生的nums;而没被选择的n-k个学生的nums都要尽可能大,以便保证被选中的学生人数严格小于没被选中的学生的nums

            因此,一个合理的想法就是先把数组升序排序(显然原数组的下标顺序对于本题无影响),对于排序好后的数组,对于每个i(0<=i如果nums[i],这就意味着可以选择前i+1个学生,同时后面n-i-1个未被选择的学生中的nums最小值是nums[i+1]>i+1个被选中的学生,可以保证这是一个合理的方案。

            特别地,我们要特判一个都不选全部都选这两种情况。

    代码实现(Java&Python)
    1. //Java
    2. class Solution {
    3. public int countWays(List nums) {
    4. Collections.sort(nums);//数组排序
    5. int choose = 0;
    6. int ans = 0;
    7. int n = nums.size();
    8. if(nums.get(0)>0){//特判一个都不选
    9. ans+=1;
    10. }
    11. for(int i = 0;i1;i++){
    12. if(nums.get(i)1&&i+11)){//判断是可行的分配
    13. ans+=1;
    14. }
    15. }
    16. if(nums.get(n-1)//特判全都选
    17. ans+=1;
    18. }
    19. return ans;
    20. }
    21. }
    1. #Python
    2. class Solution:
    3. def countWays(self, nums: List[int]) -> int:
    4. nums.sort()
    5. ans = 0
    6. n = len(nums)
    7. if nums[0]>0:
    8. ans+= 1
    9. for i in range(0,n-1):
    10. if nums[i]1 and nums[i+1]>i+1:
    11. ans+=1
    12. if n>nums[-1]:
    13. ans+=1
    14. return ans
    时间&空间复杂度分析
    • 时间复杂度:\mathcal{O}(n\log n+n),n为数组长度,时间复杂度卡在排序上面。
    • 空间复杂度:\mathcal{O}(1)

    T3.最大合金数(Medium

    题目链接

           最大合金数

    题目描述

            假设你是一家合金制造公司的老板,你的公司使用多种金属来制造合金。现在共有 n 种不同类型的金属可以使用,并且你可以使用 k 台机器来制造合金。每台机器都需要特定数量的每种金属来创建合金。

            对于第 i 台机器而言,创建合金需要 composition[i][j] 份 j 类型金属。最初,你拥有 stock[i] 份 i 类型金属,而每购入一份 i 类型金属需要花费 cost[i] 的金钱。

            给你整数 nkbudget,下标从 1 开始的二维数组 composition,两个下标从 1 开始的数组 stock 和 cost,请你在预算不超过 budget 金钱的前提下,最大化 公司制造合金的数量。

            所有合金都需要由同一台机器制造。

            返回公司可以制造的最大合金数。

    输入范围
    • 1 <= n, k <= 100
    • 0 <= budget <= 10^8
    • composition.length == k
    • composition[i].length == n
    • 1 <= composition[i][j] <= 100
    • stock.length == cost.length == n
    • 0 <= stock[i] <= 10^8
    • 1 <= cost[i] <= 100
    问题分析&思路

            根据题意,所有合金都需要由同一台机器制造,显然制造的合金数越多,花费就越多,具有单调性,因此,可以想到用二分答案的方法二分去查找答案以降低时间复杂度,达到高效寻找答案的目的。

            二分答案:即逆向验证,二分枚举可能的答案,然后对于答案进行判断,直至找到满足条件的答案。难点是判断函数的设计。

            本题判断函数(check(lim))可以这样设计:对于所制造的合金数lim,判断是否存在机器能够制造lim个合金并且开销小于等于budget

    代码实现(Java&Python)
    1. //Java
    2. class Solution {
    3. public int maxNumberOfAlloys(int n, int k, int budget, List> composition, List stock, List cost) {
    4. long l = 0;
    5. long r = 200000000;//因为答案的最大值是budget+max(stock) <=2*10^8,所以设r为2*10^8
    6. while(l//二分答案查找模版
    7. long mid = (l+r+1)>>1;
    8. if(check(mid,n,k,budget,composition,stock,cost)) l = mid;
    9. else r = mid-1;
    10. }
    11. return (int)l;
    12. }
    13. public boolean check(long lim,int n,int k,int budget,List> composition,List stock, List cost){
    14. for(int i = 0;i//遍历总共k台机器
    15. long c = 0;//计算每台机器的制作合金数目的开销
    16. List lst = composition.get(i);
    17. for(int j = 0;j//遍历总共n种合金
    18. if(lst.get(j)*lim<=stock.get(j)) continue;
    19. c+=(lst.get(j)*lim - stock.get(j))*cost.get(j);//计算开销
    20. }
    21. if(c<=budget) return true;//如果这台机器的总开销低于预算则可行
    22. }
    23. return false;//没有机器的开销低于预算
    24. }
    25. }
    1. #Python
    2. class Solution:
    3. def maxNumberOfAlloys(self, n: int, k: int, budget: int, composition: List[List[int]], stock: List[int], cost: List[int]) -> int:
    4. def check(lim):
    5. for lst in composition:
    6. s = 0
    7. for i,x in enumerate(lst):
    8. if x*lim>stock[i]:
    9. s+=(x*lim-stock[i])*cost[i]
    10. if s<=budget:
    11. return True
    12. return False
    13. l,r = 0,10**9+1
    14. while l
    15. mid = (l+r+1)>>1
    16. if check(mid): l = mid
    17. else: r = mid - 1
    18. return l
    时间&空间复杂度分析
    • 时间复杂度:\mathcal{O}(kn\log U),其中k为机器数,n为合金总数,U = budget+max(stock)
    • 空间复杂度:\mathcal{O}(1)

    T4.完全子集的最大元素和(Hard

    题目链接

            完全子集的最大元素和

    题目描述

            给你一个下标从 1 开始、由 n 个整数组成的数组。

            如果一组数字中每对元素的乘积都是一个完全平方数,则称这组数字是一个 完全集 。

            下标集 {1, 2, ..., n} 的子集可以表示为 {i1, i2, ..., ik},我们定义对应该子集的 元素和 为 nums[i1] + nums[i2] + ... + nums[ik] 。

            返回下标集 {1, 2, ..., n} 的 完全子集 所能取到的 最大元素和 。

            完全平方数是指可以表示为一个整数和其自身相乘的数。

    输入范围
    • 1 <= n == nums.length <= 10^4
    • 1 <= nums[i] <= 10^9
    问题分析&思路

            由于所有的nums[i]都是正整数,显然是数越多,能取到的完全子集的元素和最大,所以以下完全集均考虑取在[1,n]范围内长度最大的完全集。

            很容易想到的一个最大完全集是{1,4,9,16,……,k^2}(k^2<=n<(k+1)^2)试想一下,对于在某个完全集中已经出现的数,是否有可能出现在另一个完全集中?

            答案显然是否定的,可以用反证法证明。假设x,y属于不同的完全集,而z同时属于x,y所属的完全集。则有x*z = a^2,y*z = b^2,那么有x*y = (a*b/z)^2,由于x,y都是正整数,显然a*b/z也是正整数,那么x,y相乘为完全平方数,是属于同一完全集的,因此假设不成立。自此,我们验证了各个完全集是独立的,即交集为空集。

            在得到了上述结论之后,我们已经构造了一个完全集为{1,4,9,16,......}那么我们考虑如何构造在[1,n]范围内的所有的完全集。显然{2*1,2*4,2*9,2*16,......}也是一个完全集,那么我们就很容易可以构造出[1,n]范围内的所有的最大完全集,即为k*{1,4,9,16,......}。最后我们输出所有完全集所对应下标的元素的最大和即可。

    代码实现(Java&Python)

            

    1. //Java
    2. class Solution {
    3. public long maximumSum(List nums) {
    4. List pf = new ArrayList<>();//1,4,9,16....完全集
    5. int n = nums.size();
    6. if(n == 1) return nums.get(0);//特判数组长度为1的情况
    7. long ans = 0;
    8. int i = 1;
    9. while(i<=n){//构造1,4,9,16....完全集
    10. pf.add(i*i);
    11. i+=1;
    12. }
    13. int[] vis = new int[n+1];//判断某一下标是否已经加入集合
    14. for(i = 1;i<=n;i++){
    15. if(vis[i] == 1) continue;
    16. int cnt = 0;
    17. long s = 0;//记录某一完全集的最大元素和
    18. while(i*pf.get(cnt)<=n){//当该完全集的最大元素超过n时退出循环
    19. s+=nums.get(i*pf.get(cnt)-1);
    20. vis[i*pf.get(cnt)] = 1;
    21. cnt+=1;
    22. }
    23. ans = Math.max(ans,s);//ans即取为最大值
    24. }
    25. return ans;
    26. }
    27. }
    1. #Python
    2. class Solution:
    3. def maximumSum(self, nums: List[int]) -> int:
    4. n = len(nums)
    5. if n == 1:return nums[0]
    6. fa = [i for i in range(n+1)]
    7. ans = 0
    8. vis = [0]*(n+1)
    9. pf = [i**2 for i in range(1,n+1)]
    10. for i in range(1,n+1):
    11. if vis[i]: continue
    12. tmp = 0
    13. l = 0
    14. while pf[l]*i<=n:
    15. tmp+=nums[pf[l]*i-1]
    16. vis[pf[l]*i] = 1
    17. l+=1
    18. ans = max(tmp,ans)
    19. return ans
    时间&空间复杂度分析
    • 时间复杂度:\mathcal{O}(n),循环次数可以近似看做n,因为每次遍历会确保把下标记录到vis数组中,因此每个下标仅访问操作一次,总共有n个下标,须访问n次。
    • 空间复杂度:\mathcal{O}(n)
  • 相关阅读:
    火车卖票---Ticketer类
    Invalid bound statement (not found)解决方法总结
    网工内推 | 上市公司,云平台运维,IP认证优先,13薪
    Redis-应用问题(缓存穿透/缓存击穿/缓存雪崩/分布式锁)
    synchronized(string)
    SQl 经验总结
    Android笔记: 设置PopupMenu宽度
    c++类对象的内存分布 以及 虚继承实现原理
    VMware 安装Ubuntu22.04
    【密码学】RSA密码体制存在的问题
  • 原文地址:https://blog.csdn.net/m0_46121643/article/details/132944724