LeetCode228场周赛解题报告

LeetCode228场周赛解题报告

生成交替二进制字符串的最少操作数

原题链接

https://leetcode-cn.com/contest/weekly-contest-228/problems/minimum-changes-to-make-alternating-binary-string/

解题思路

直接进行暴力的将二进制字符串枚举,首个字符是0,还是1,枚举之后取最小值

AC代码

class Solution {
public:
    int minOperations(string s) {
        int res = 1e5, tmp;
        tmp = 0;
        for (int i = 0; i < s.size(); i ++ )
        {
            if (i % 2 == 0 && s[i] == '1')
                tmp ++;
            else if (i % 2 == 1 && s[i] == '0')
                tmp ++;
        }
        res = min(res, tmp);
        
        tmp = 0;
        for (int i = 0; i < s.size(); i ++ )
        {
            if (i % 2 == 1 && s[i] == '1')
                tmp ++;
            else if (i % 2 == 0 && s[i] == '0')
                tmp ++;
        }
        res = min(res, tmp);
        return res;
    }
};

统计同构子字符串的数目

原题链接

https://leetcode-cn.com/contest/weekly-contest-228/problems/count-number-of-homogenous-substrings/

解题思路

因为是子串,问题就很好解决了,首先我们将原数组看成 一下形式
a 0 , ⋅ ⋅ ⋅ , a 0 ⏟ n 0 , a 1 , ⋅ ⋅ ⋅ , a 1 ⏟ n 1 , ⋅ ⋅ ⋅ a i , ⋅ ⋅ ⋅ , a i ⏟ n i , ⋅ ⋅ ⋅ , a e d , ⋅ ⋅ ⋅ , a e d ⏟ n e d \underbrace{a_0, \cdot\cdot\cdot, a_0}_{n_0},\underbrace{a_1, \cdot\cdot\cdot, a_1}_{n_1},\cdot\cdot\cdot\underbrace{a_i, \cdot\cdot\cdot, a_i}_{n_i},\cdot\cdot\cdot,\underbrace{a_{ed}, \cdot\cdot\cdot, a_{ed}}_{n_{ed}} n0 a0,,a0,n1 a1,,a1,ni ai,,ai,,ned aed,,aed \quad 其中 ∀ i , a i ≠ a i + 1 \forall i, a_i \not= a_{i+1} i,ai=ai+1
对于第 i i i块, n i n_i ni他所能构成的同构子字符串的数目

  • 长度为1: n 1 n_1 n1
  • 长度为2: n 1 − 1 n_1 - 1 n11
  • 长度为3: n 1 − 2 n_1 - 2 n12
  • ···
    因此对于该块 有 ( n 1 + 1 ) ⋅ n 1 2 \frac {(n_1+1)\cdot n_1} 2 2(n1+1)n1个,将每个块加起来即可。

AC代码

typedef long long LL;
const int MOD = 1e9 + 7;
class Solution {
public:
    int countHomogenous(string s) {
        LL cnt = 1, ret = 0;
        s += '.';
        for (int i = 1; i < s.size(); i ++ )
        {
            if (s[i] == s[i - 1])
                cnt ++;
            else
            {
                ret += (cnt + 1) * cnt / 2;
                ret %= MOD;
                // printf("i=%d, tmp=%d\n", i, (cnt + 1) * cnt / 2);
                cnt = 1;
            }
        }
        return ret % MOD;
    }
};

袋子里最少数目的球

原题链接

https://leetcode-cn.com/contest/weekly-contest-228/problems/minimum-limit-of-balls-in-a-bag/

解题思路

一个简单的二分题目,假设最少的代价为 c c c
那么对于某一个含有 x x x求的袋子,那么他至少需要的操作次数为 ⌈ x c ⌉ − 1 \lceil \frac x c \rceil - 1 cx1,减一是因为自己那一份不需要分。那么我们二分最少代价,每次计算出他所需要的操作数量是否符合要求即可。

AC代码

typedef long long LL;
class Solution {
public:
    vector<int> v;
    int cnt;
    bool Check(int t)
    {
        LL ret = 0;
        for (auto x : v)
        {
            ret += x / t + (x % t != 0) - 1;
        }
        return ret <= cnt;
    }
    int minimumSize(vector<int>& nums, int maxOperations) {
        v = nums, cnt = maxOperations;
        int l = 1, r = v[0], mid;
        for (auto x : v)    
            r = max(r, x);
        
        while (l < r)
        {
            mid = l + r >> 1;
            if (Check(mid))
            {
                r = mid;
            }
            else
            {
                l = mid + 1;
            }
        }
        return l;       
    }
};

一个图中连通三元组的最小度数

原题链接

https://leetcode-cn.com/contest/weekly-contest-228/problems/minimum-degree-of-a-connected-trio-in-a-graph/

解题思路

因为 n ≤ 400 n \leq 400 n400,我们可以直接进行三重循环暴力枚举,不过要进行一些优化。
首先构造出邻接矩阵,并且计算出每个点连接边的个数(类似于有向图的入度,出度)
那么,对于三个点 i , j , k i, j, k i,j,k可是在 O ( 1 ) O(1) O(1)的时间内计算出是否是三元组,并且他的度数。
e[i][j],e[i][k],e[j][k]同时存在表示为三元组,他们的度数为 ind[i] + ind[j] + ind[k] - 6; 减去6是三元组相连的边计算了两遍。用该数字不断的更新答案即可。
本来以为可能被卡需要使用并查集试一下呢,结果发现不需要。

AC代码

const int N = 410;
int e[N][N];
int ind[N];
int par[N];

class Solution {
public:
    int minTrioDegree(int n, vector<vector<int>>& edges) {
        memset(ind, 0, sizeof ind); 
        memset(e, 0, sizeof e);
        for (int i = 0; i < edges.size(); i ++ )
        {
            ind[edges[i][0]] ++, ind[edges[i][1]] ++;
            e[edges[i][0]][edges[i][1]] = 1;
            e[edges[i][1]][edges[i][0]] = 1;
        }
        int ret = 1e9;
        for (int i = 1; i <= n && ret != 0; i ++ )
            for (int j = 1; j <= n; j ++ )
                for (int k = 1; k <= n; k ++ )
                {
                    if (e[i][j] && e[i][k] && e[j][k])
                    {
                        ret = min(ret, ind[i] + ind[j] + ind[k] - 6);
                    }
                }
        if (ret == 1000000000)  return -1;
        return ret;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值