Leetcode 第274场周赛题解

这篇博客分享了LeetCode第274场周赛的四道编程题目,包括检查字符串中'a'是否都在'b'之前、计算银行中的激光束数量、判断能否摧毁所有小行星以及求解参加会议的最大员工数。通过C++代码详细解析了解题思路和实现方法。

Leetcode 第274场周赛题解(C++版)

Problem A - 检查是否所有 A 都在 B 之前

题意
问字符串中是否所有’a’都在’b’之前
思路
检查最后一个’a’前面是否有’b’即可
代码

class Solution {
public:
    bool checkString(string s) {
        int a=0,n=s.size();
        for(int i=0;i<n;i++)
            if(s[i]=='a') a=i;
        for(int i=0;i<n;i++)
            if(s[i]=='b'&&i<a) return false;
        return true;
    }
};

Problem B - 银行中的激光束数量

题意

给定一个01矩阵,0为空,1表示其所在位置有一个安全设备,对任意两个安全设备而言,如果同时满足下面两个条件,则二者之间存在 一个激光束

  1. 两个设备位于两个不同行: r 1 r_1 r1 r 2 r_2 r2 ,其中 r 1 < r 2 r_1 < r_2 r1<r2
  2. 满足 r 1 < i < r 2 r1 < i < r2 r1<i<r2的所有行 i i i,都没有安全设备 。
    问有多少条激光束

思路

我们只需记录含’1’的行和其含’1’的数量,对于两个满足条件的行来说,它们之间的激光束数量就等于它们’1’的数量的乘积。

代码

class Solution {
public:
    int numberOfBeams(vector<string>& bank) {
        int m=bank.size(),n=bank[0].size();
        vector<int> v;
        for(int i=0;i<m;i++){
            int sum=0;
            for(int j=0;j<n;j++)
                sum+=(bank[i][j]=='1');
            if(sum) v.push_back(sum);
        }
        if(v.size()<=1) return 0;
        int sz=v.size(),ans=0;
        for(int i=0;i<sz-1;i++){
            ans+=(v[i]*v[i+1]);
        }
        return ans;
    }
};

Problem C - 摧毁小行星

题意

给定一个整数表示初始小行星质量,小行星能摧毁质量小于等于它的其它行星,并获得其质量,现在给你一堆小行星的质量,问你能否全部摧毁。

思路

显然我们可以按照质量从小到大来摧毁小行星,类似于球球大作战哈哈,我们当然是需要尽量让自己变大,当前能变得最大的就是把比自己质量小的都吃掉,我们可以贪心地从小到大去摧毁小行星,因为这样可以保证能把质量小于等于自己的小行星先摧毁了,再去碰大的。
需要注意的点是质量需要用long long 来存,否则会超过int的范围。

代码

class Solution {
public:
    bool asteroidsDestroyed(int mass, vector<int>& a) {
        sort(a.begin(),a.end());
        long long sum=mass;
        for(int i=0;i<a.size();i++){
            if(sum>=a[i]) sum+=a[i];
            else return false;
        }
        return true;
        
    }
};

Problem D - 参加会议的最多员工数

题意

给定一个有向图,边 { u , v } \{u,v\} {u,v}代表的是 u u u喜欢 v v v,现在让你从 n n n个点选取 m m m个点围成一个圈,圈上的每个点都必须至少和它相邻的一个点有"喜欢"的关系,问最大的 m m m

思路

首先我们显然能想到该问题和环有关,对于长度大于2的环,显然能够恰好将环上所有点围成一个符合题意的圈,且无法再加入其他的点;但是对于长度等于2的环,由于围成环之后每个点的旁边只被占据了一个位置,所以能够加入其它的点,故而我们对上述两种情况做如下思考:

  1. 对于所有长度大于2的环,取最大值,若没有长度等于2的环,则答案就是最大环的点数
  2. 对于所有长度等于2的环,设上面两个点分别为 x 1 , x 2 x_1,x_2 x1,x2,显然,我们可以选取一条终点为 x 1 x_1 x1的链,让上面的点依次排在 x 1 x_1 x1的旁边,同时,也可以选取一条终点为 x 2 x_2 x2的链,让上面的点依次排在 x 1 x_1 x1的旁边,具体可以看看下面的示意图, x 2 − n o d e 1 − n o d e 2 x_2-node_1-node_2 x2node1node2显然是可以排在一起的,那么我们只需要分别找到以 x 1 , x 2 x_1,x_2 x1,x2为终点的最长链,并按照上面说的方法排在一起即可。
    1.png
    于是,我们可以分别讨论上述两种情况,取最大值即可。

代码

class Solution {
public:
    vector<int> vis;//记录访问情况
    /*
        在寻找环的dfs中,-1表示已访问,0表示未访问,1表示正在访问
        在寻找链的dfs中,1表示已访问,0表示未访问
    */
    vector<int> cyc,c1;//记录当前环、最大环
    vector<pair<int,int>> p2;//记录长度为2的环
    int ans,res,mx;
    vector<int> G[100005];//反向建图,方便从长度为2的环找最长链
    void dfs(int now,vector<int>& a){
        vis[now]=1;
        cyc.push_back(now);
        if(vis[a[now]]==0)//目标点
            dfs(a[now],a);
        else if(vis[a[now]]==1){
            int cnt=0;
            int m=cyc.size();
            for(int i=m-1;;i--){//当前环
                //cout<<cyc[i]<<' ';
                cnt++;
                if(cyc[i]==a[now]) break;
            }
            //cout<<endl;
            if(cnt==2)//记录长度为2的环
                p2.push_back({cyc[m-1],cyc[m-2]});
            if(cnt>mx){//更新最大环并用c1存储
                mx=cnt;//最大环长度
                c1=cyc;
            }
        }
        vis[now]=-1;
        cyc.pop_back();
    }
    void dfs1(int now,int len){//寻找与长度为2的环相连的最长链
        vis[now]=1;
        res=max(res,len);//记录最大链长度
        for(int i=0;i<G[now].size();i++)
            if(!vis[G[now][i]]) dfs1(G[now][i],len+1);
    }
    
    int maximumInvitations(vector<int>& a) {
        int n=a.size();
        vis.resize(n);
        mx=0;//最大环长度
        for(int i=0;i<n;i++)//初始化
            G[i].clear(),vis[i]=0;
        for(int i=0;i<n;i++)
            G[a[i]].push_back(i);
        for(int i=0;i<n;i++)//dfs最大环
            if(vis[i]!=-1) dfs(i,a);
        //c1存储最大环
        ans=0;
        if(!p2.empty()){//处理长度为2的环
            int tmp=0;
            for(auto p:p2){
                for(int i=0;i<n;i++) vis[i]=0;
                vis[p.first]=vis[p.second]=1;
                res=1;
                dfs1(p.first,1);
                tmp+=res;

                for(int i=0;i<n;i++) vis[i]=0;
                vis[p.first]=vis[p.second]=1;
                res=1;
                dfs1(p.second,1);
                tmp+=res;
            }
            ans=max(tmp,ans);//更新所有与长度为2的环有关的答案,取最大值
        }
        return max(ans,mx);
    }
};
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值