题目链接: 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
题目大意:
改日再写