LeetCode第274场周赛-2022/1/2

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

题目描述
检查是否所有A都在B之前
给你一个 仅 由字符 ‘a’ 和 ‘b’ 组成的字符串 s 。如果字符串中 每个 ‘a’ 都出现在 每个 ‘b’ 之前,返回 true ;否则,返回 false 。

  • 1 <= s.length <= 100
  • s[ i ] 为 ‘a’ 或 ‘b’

输入:s = “abab”
输出:false

题目分析
遍历完第一个 b b b 前的所有 a a a 后若已经遍历完整个串则直接返回 t r u e true true ,遍历 b b b,中间若出现 a a a 返回 f a l s e false false
字符串题目考虑子串往往更简单,本题可直接查找子串 b a ba ba,若没查到则说明所有 a a a b b b 前。


方法一:模拟

class Solution {
public:
    bool checkString(string s) {
        int count = 0;
        for (int i = 0; i < s.length(); i++) {
            count = i;
            if (s[i] == 'a') continue;
            else break;
        }
        if (count == s.length() - 1) return true;
        for (int i = count; i < s.length(); i++) {
            if (s[i] == 'b') continue;
            else return false;
        }
        return true;
    }
};


方法二:子串查找

class Solution {
public:
    bool checkString(string s) {
        return s.find("ba") == string::npos;
    }
};

银行中的激光束数量

题目描述
银行中的激光束数量
银行内部的防盗安全装置已经激活。给你一个下标从 0 开始的二进制字符串数组 bank ,表示银行的平面图,这是一个大小为 m x n 的二维矩阵。 bank[ i ] 表示第 i 行的设备分布,由若干 ‘0’ 和若干 ‘1’ 组成。‘0’ 表示单元格是空的,而 ‘1’ 表示单元格有一个安全设备。对任意两个安全设备而言,如果同时满足下面两个条件,则二者之间存在一个激光束:
1.两个设备位于两个不同行:r1 和 r2,其中 r1 < r2 。
2.满足 r1 < i < r2 的所有行 i ,都没有安全设备 。
激光束是独立的,也就是说,一个激光束既不会干扰另一个激光束,也不会与另一个激光束合并成一束。
返回银行中激光束的总数量。

  • m == bank.length
  • n == bank[ i ].length
  • 1 <= m, n <= 500
  • bank[ i ][ j ] 为 ‘0’ 或 ‘1’

输入:bank = [“011001”,“000000”,“010100”,“001000”]
输出:8

题目分析
用一个 c o u n t count count 数组记录每行的设备数,把相邻两行的 c o u n t count count 相乘后累加即可,相邻指两行之间没有设备。


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

摧毁小行星

题目描述
摧毁小行星
给你一个整数mass ,它表示一颗行星的初始质量。再给你一个整数数组asteroids ,其中 asteroids[ i ] 是第 i 颗小行星的质量。
你可以按任意顺序重新安排小行星的顺序,然后让行星跟它们发生碰撞。如果行星碰撞时的质量 大于等于小行星的质量,那么小行星被摧毁 ,并且行星会获得这颗小行星的质量。否则,行星将被摧毁。
如果所有小行星都能被摧毁,请返回 true ,否则返回 false 。

  • 1 <= mass <= 1 0 5 10^5 105
  • 1 <= asteroids.length <= 1 0 5 10^5 105
  • 1 <= asteroids[ i ] <= 1 0 5 10^5 105

输入:mass = 10, asteroids = [3,9,19,5,21]
输出:true

题目分析
注意 1 0 5 ∗ 1 0 5 10^5*10^5 105105 i n t int int 会溢出即可(2147483647)。


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

参加会议的最多员工数

题目描述
参加会议的最多员工数
一个公司准备组织一场会议,邀请名单上有 n 位员工。公司准备了一张圆形的桌子,可以坐下任意数目的员工。员工编号为 0 到 n - 1 。每位员工都有一位喜欢的员工,每位员工当且仅当他被安排在喜欢员工的旁边,他才会参加会议。每位员工喜欢的员工不会是他自己。
给你一个下标从 0 开始的整数数组 favorite ,其中 favorite[ i ] 表示第 i 位员工喜欢的员工。请你返回参加会议的最多员工数目 。

  • n == favorite.length
  • 2 <= n <= 1 0 5 10^5 105
  • 0 <= favorite[ i ] <= n - 1
  • favorite[ i ] != i

输入:favorite = [3,0,1,4,1]
输出:4

题目分析
图论题。若员工 i i i 喜欢员工 j j j ,则作有向弧 i → j i\to j ij,由于 f a v o r i t e [ i ] = j , i ≠ j , 0 ≤ i , j ≤ n − 1 favorite[ i ]=j,i\ne j,0\le i,j\le n-1 favorite[i]=j,i=j,0i,jn1,故得到一个 n n n n n n 边的有向图,因为点数等于边数所以图中必有环。
情况一
情况一:在大多数情况下,根据 f a v o r i t e favorite favorite 数组可以得到类似上图的基环树(内向),对于这个基环树可以证明中间的环就是可以选出的数量最多的出席会议员工。条件:每位员工当且仅当他被安排在喜欢员工的旁边,他才会参加会议。

  1. 由条件知任一点若被选中,则它指向的点必被选中;
  2. 若环中任一点被选中,由 1 知全环必被选中;
  3. 若环不被选中,则剩余点组成若干不连通的子图(树),由 1 知若其中有点被选中,则根必被选中(这些子图是并查集的结构),而根的出度为 0,根必不会被选中,则这些子树不可脱离环被单独选中;
  4. 若环被选中,由条件知环上任一点的左右必是环上与它相邻的两点,故除环以外的子树还是无法插入。
    情况二

情况二:基环树中的环只有两个点,则在情况一证明的 4 中,环上任一点的左右只有一个点也在环上,另外一点可取环外树的根,要使出席人数最多应选点为该基环树的最长轨。

在这里插入图片描述
然而 n n n n n n 边图不一定连通,情况一和二是各个连通分量的可能情况,对于 r i n g ring ring 而言取最大的那个 r i n g ring ring 即可,对于 c h a i n chain chain 而言,要取所有的 c h a i n chain chain 之和(如下图),因此最后的 m a x max max 才是最终答案。
在这里插入图片描述
代码思路就是把所有的子树剪枝(拓扑排序的做法),只留下环,如果环中 f a v o r i t e [ f a v o r i t e [ i ] ] = = i favorite[favorite[i]]==i favorite[favorite[i]]==i 说明是二元环, 则作最大链长累加 c h a i n + = c h a i n l e n [ i ] + c h a i n l e n [ f a v o r i t e [ i ] ] chain+=chainlen[i]+chainlen[favorite[i]] chain+=chainlen[i]+chainlen[favorite[i]],否则是多元环,取 r i n g = m a x ( r i n g , c o u n t ) ring=max(ring,count) ring=max(ring,count) 即可。
最后取 m a x ( r i n g , c h a i n ) max(ring,chain) max(ring,chain)

class Solution {
public:
    int maximumInvitations(vector<int>& favorite) {
        int n = favorite.size();
        vector<int> indegree(n), chain_len(n, 1), visited(n);
        for (int i = 0; i < n; i++) {
            indegree[favorite[i]]++;
        }
        queue<int> q;
        for (int i = 0; i < n; i++) {
            if (indegree[i] == 0) q.push(i);
        }
        while (!q.empty()) {
            int p = q.front();
            q.pop();
            visited[p] = true;
            int next = favorite[p];
            chain_len[next] = max(chain_len[next], chain_len[p] + 1);
            if (--indegree[next] == 0) {
                q.push(next);
            }
        }
        int ring = 0, chain = 0;
        for (int i = 0; i < n; i++) {
            if (!visited[i]) {
                if (favorite[favorite[i]] == i) {
                    chain += chain_len[i] + chain_len[favorite[i]];
                    visited[i] = visited[favorite[i]] = true;
                }
                else {
                    int cur = i, count = 0;
                    while(1) {
                        count++;
                        visited[cur] = true;
                        cur = favorite[cur];
                        if (cur == i) break;
                    }
                    ring = max(ring, count);
                }
            }
        }
        return max(ring, chain);
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值