Leetcode Weekly Contest 222(详细解析)

题目链接: Leetcode Weekly Contest 222

写在前面:

本次周赛又是尴尬只做了第一题,第二题暴力求解超时了,第三题没有思路。

1、1710. Maximum Units on a Truck

难度:Easy

题目大意:

简化版的背包问题。

思路:

贪心,因为卡车是可以刚好装满的,优先装价值高的箱子。

代码

class Solution {
    public int maximumUnits(int[][] boxTypes, int truckSize) {
        Arrays.sort(boxTypes,(o1,o2)->o2[1]-o1[1]);
        //按每个箱子中所能容纳的小箱子数按从大到小进行排序
        int res=0,i=0;
        while(truckSize>0 && i<boxTypes.length){
            if(truckSize>boxTypes[i][0]){//如果能全部装下boxTypes[i]
                res=res+boxTypes[i][0]*boxTypes[i][1];
                truckSize-=boxTypes[i][0];
                i++;
            }
            else{
                res=res+truckSize*boxTypes[i][1];
                break;
            }
        }
        return res;
        
    }
}

2、1711. Count Good Meals

难度:Medium

题目大意:

从一个非负数组中随机选两个数,如果两个数的和是2的次幂,则符合题意,求一个有多少种满足题意的组合。

思路:

参考高赞回答,如果数组中两个数之和为2的幂次,那么2的幂次减去其中一个元素得到的数也一定包含在该数组中。因为数组中元素的大小是有限的,两个元素之和最大只能是2^21,穷举所有的情况即可。用map来统计数组元素的个数。

代码

class Solution {
    
    public int countPairs(int[] deliciousness) {
        int res=0,n=deliciousness.length;
        int m=1000000007;
        //Arrays.sort(deliciousness);
        TreeMap<Integer,Integer> map=new TreeMap<>();
        for(int d:deliciousness){//统计数组中各个元素的个数
            int power=1;
            for(int i=0;i<22;i++){
                //deliciousness[i] <= 2^20,最大的值为2^20+2^20=2^21
                if(map.containsKey(power-d)){
                    res+=map.get(power-d);
                    res=res%m;
                }
                power*=2;
            }
            map.put(d,map.getOrDefault(d,0)+1);
        }
         
        return res;
    }
}


 

3、1712. Ways to Split Array Into Three Subarrays

难度:Medium

题目大意:

将一个非负的数组分割成左中右三个数组,这三个子数组都是非空数组,子数组的和分别为leftSum,midSum,rightSum,并且要求满足leftSum<=midSum<=rightSum,求一共有几种分割方法。

思路:

参考高赞回答。运用前缀数组,暴力查找会超时,使用二分查找。因为没有搞清楚break和continue的区别,找了半天的bug不知道自己错在哪里,心态都调崩了,算是一个教训。

代码

class Solution {
    public int waysToSplit(int[] nums) {
        int n=nums.length,res=0;
        int[] pre=new int[n];//前缀和
        int M=1000000007;
        pre[0]=nums[0];
        for(int i=1;i<n;i++){
            pre[i]=pre[i-1]+nums[i];
            //pre[i]=nums[0]+nums[1]+...+nums[i]
        }
        for(int i=0;i<n-2;i++){
            int leftBound=-1;//leftbound表示中间子数组最后一个元素元素的下标所能取到的最小值
            int rightBound=-1;//leftbound表示中间子数组最后一个元素元素的下标所能取到的最大值 
             
            //用二分进行查找,为什么能用二分呢,因为所有元素都是非负的,两个子数组的和一定是此消彼长的关系
            int l=i+1,r=n-2;
            int leftSum=pre[i];
            while(l<=r){
                int m=l+(r-l)/2;
                int midSum=pre[m]-pre[i];
                if(leftSum<=midSum){
                    leftBound=m;
                    r=m-1;//要找尽可能小的leftBound
                }
                else{
                    l=m+1;
                }
            }
            
            l=i+1;
            r=n-2;
            while(l<=r){
                int m=l+(r-l)/2;
                int midSum=pre[m]-pre[i];
                int rightSum=pre[n-1]-pre[m];
                if(midSum<=rightSum){
                    rightBound=m;
                    l=m+1;//要找尽可能大的rightBound
                }
                else{
                    r=m-1;
                }
            }
             
            if(leftBound==-1||rightBound==-1||leftBound>rightBound){
                continue;//注意continue与break的区别!!!,因为这个找了半天的bug,血的教训啊!
            }
            res+=(rightBound-leftBound+1);
            res=res%M;
        }
        return res;
    }
}

4、1713. Minimum Operations to Make a Subsequence

难度:Hard

题目大意:

改日再写

思路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值