【Leetcode第285场周赛】——周赛总结

1、6027. 统计数组中峰和谷的数量 - 力扣(LeetCode) (leetcode-cn.com)

给你一个下标从 0 开始的整数数组 nums 。如果两侧距 i 最近的不相等邻居的值均小于 nums[i] ,则下标 i 是 nums 中某个峰的一部分。类似地,如果两侧距 i 最近的不相等邻居的值均大于 nums[i] ,则下标 i 是 nums 中某个谷的一部分。对于相邻下标 i 和 j ,如果 nums[i] == nums[j] , 则认为这两下标属于 同一个 峰或谷。

注意,要使某个下标所做峰或谷的一部分,那么它左右两侧必须 都 存在不相等邻居。

返回 nums 中峰和谷的数量。

 

模拟题,直接按题意来就行了,注意题中要找的是不相等的邻居。需要排除掉相等邻居的情况。

class Solution {
public:
    int countHillValley(vector<int>& nums) {
        int n=nums.size();
        int sumP=0,sumV=0;
        for(int i=1;i<n-1;i++){
            int j=i-1,k=i+1;
            if(nums[i]==nums[i-1])
                continue;
            if(nums[k]==nums[i]){
                while(k<n-1){
                    if(nums[k]!=nums[i])
                        break;
                    k++;
                }
            }
            if(nums[j]==nums[i]){
                while(j>0){
                    if(nums[j]!=nums[i])
                        break;
                    j--;
                }
            }
            if(nums[i]>nums[k]&&nums[i]>nums[j])
                sumP++;
            if(nums[i]<nums[k]&&nums[i]<nums[j])
                sumV++;
        }
        return sumV+sumP;
    }
};

2、6028. 统计道路上的碰撞次数 - 力扣(LeetCode) (leetcode-cn.com)

在一条无限长的公路上有 n 辆汽车正在行驶。汽车按从左到右的顺序按从 0 到 n - 1 编号,每辆车都在一个 独特的 位置。

给你一个下标从 0 开始的字符串 directions ,长度为 n 。directions[i] 可以是 'L'、'R' 或 'S' 分别表示第 i 辆车是向 左 、向 右 或者 停留 在当前位置。每辆车移动时 速度相同 。

碰撞次数可以按下述方式计算:

当两辆移动方向 相反 的车相撞时,碰撞次数加 2 。
当一辆移动的车和一辆静止的车相撞时,碰撞次数加 1 。
碰撞发生后,涉及的车辆将无法继续移动并停留在碰撞位置。除此之外,汽车不能改变它们的状态或移动方向。

返回在这条道路上发生的 碰撞总次数 。

 

这个题在周赛时没想明白,就一直卡在这里。。。其实就是个脑筋急转弯:在最左边的L和最右边的R永远不会发生碰撞,所以在排除最左侧的所有L和最右侧的所有R后,中间所有的车都会发生碰撞。

根据题意,“RL”碰撞次数+2————>有两辆车被撞停

                   ”RS“ or ”SL“碰撞次数+1——>有一辆车被撞停

所以我们直接统计中间的所有运动车辆即可。

 

class Solution {
public:
    int countCollisions(string directions) {
        int n=directions.length();
        int l=0,r=n-1;
        while(l<=r&&directions[l]=='L') l++;
        while(l<=r&&directions[r]=='R') r--;
        int res=0;
        for(int i=l;i<=r;++i){
            if(directions[i]=='R'||directions[i]=='L'){
                res++;
            }
        }
        return res;
    }
};

3、6029. 射箭比赛中的最大得分 - 力扣(LeetCode) (leetcode-cn.com)

所以说人不能在一棵树上吊死,这题其实方法之前我都见过,按道理应当可以拿下,结果却因为第二题没转过弯来导致这题没好好思考。。。周赛时一直在debug第二题,觉得自己方法没错。。。唉,得吸取教训。

方法一:0/1背包问题+路径还原

这道题可以看成是0/1背包问题——一共有12件物品,每一件物品i的权重为aliceArrows[i]+1,有一个大小为numsArrows的背包,求背包所能容纳的物品的最大权重和。

这道题还多了一步:要求我们回溯出路径,找到拿的哪几件物品,也算是一个小小的难点。

class Solution {
public:
    vector<int> maximumBobPoints(int numArrows, vector<int>& aliceArrows) {
        vector<vector<int>> dp(12,vector<int>(numArrows+1,0));
        for(int i=1;i<12;i++){   //正常的0/1背包求解,找到最大容量
            for(int j=1;j<=numArrows;j++){
                if(j>aliceArrows[i]){
                    dp[i][j]=max(dp[i-1][j],dp[i-1][j-aliceArrows[i]-1]+i);
                }
                else{
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        vector<int> ans(12,0);
        for(int i=11;i>0;--i){  //路径还原
            if(dp[i][numArrows]>dp[i-1][numArrows]){   //证明有过射箭行为
                ans[i]=aliceArrows[i]+1;
                numArrows-=ans[i];
            }
        }
        ans[0]=numArrows;  //统计完前面的所有有分的情况后,如果箭有剩余则证明全射在0区域,不得分
        return ans;
    }
};

方法二:二进制枚举

题目中射箭区域长度为12,可以使用一个二进制数来枚举出所有的情况,并不断更新最大分数以及对应的射箭情况。

 

class Solution {
public:
    vector<int> maximumBobPoints(int numArrows, vector<int>& aliceArrows) {
        int n=aliceArrows.size();
        int curScore;
        int maxScore=0;
        int usedArrows;
        vector<int> ans(12);
        for(int i=0;i<(1<<n);i++){  //枚举出所有的2048种情况
            curScore=0;
            usedArrows=0;
            vector<int> bob(12); //枚举所有情况
            for(int j=0;j<n;j++){
                if(((i>>j)&1)==1){  //若bob射在了aliceArrows[j]处
                    usedArrows+=aliceArrows[j]+1;
                    curScore+=j;
                    bob[j]=aliceArrows[j]+1;
                }
            }
            if(usedArrows<=numArrows&&curScore>maxScore){  //箭有剩余且当前分数大于已记录的最大分数
                ans=bob;
                maxScore=curScore;
                ans[0]+=numArrows-usedArrows;
            }
        }
        return ans;
    }
};

4、6030. 由单个字符重复的最长子字符串 - 力扣(LeetCode) (leetcode-cn.com)

给你一个下标从 0 开始的字符串 s 。另给你一个下标从 0 开始、长度为 k 的字符串 queryCharacters ,一个下标从 0 开始、长度也是 k 的整数 下标 数组 queryIndices ,这两个都用来描述 k 个查询。

第 i 个查询会将 s 中位于下标 queryIndices[i] 的字符更新为 queryCharacters[i] 。

返回一个长度为 k 的数组 lengths ,其中 lengths[i] 是在执行第 i 个查询 之后 s 中仅由 单个字符重复 组成的 最长子字符串 的 长度 。

 

本题由于使用到了线段树的有关思想,超出了笔者的知识范畴,所以不在此班门弄斧,在此附上大佬灵茶山艾府的题解,有兴趣的读者可以自行前去学习和字符集大小无关的线段树做法 - 由单个字符重复的最长子字符串 - 力扣(LeetCode) (leetcode-cn.com)

posted @ 2022-03-20 20:39  天涯海角寻天涯  阅读(134)  评论(0)    收藏  举报