Leetcode第91场双周赛

T1:LeetCode 2465. 不同的平均值数目

 第一题比较简单,排个序后开个哈希表存总和就行

class Solution {
public:
    int distinctAverages(vector<int>& nums) {
        unordered_set<int> hash;
        sort(nums.begin(), nums.end());
        for(int i = 0, j = nums.size() - 1; i < j; i ++ , j --)
            hash.insert(nums[i] + nums[j]);
        return hash.size();
    }
};

T2:LeetCode 2466. 统计构造好字符串的方案数

 简单dp问题

f(i)就表示长度为 i 的字符串有多少个,我们可以将f(i)分为两类:

一类是以one个1结尾,那我们就只要统计f(i-one)

另一类是以zero个0结尾,同理我们就只要统计f(i - zero)

所以最后f(i) = f(i - one)+ f(i - zero)

class Solution {
public:
    int countGoodStrings(int low, int high, int zero, int one) {
       const int MOD = 1e9 + 7;//先定义个取模数
       vector<int> f(high + 1);

       f[0] = 1;//初始一个都没有也是个方案
       int res = 0;
       for(int i = 1; i <= high; i ++ )
       {
           if(i >= zero) f[i] = f[i - zero];
           if(i >= one) f[i] = (f[i] + f[i - one]) % MOD;
           if(i >= low) res = (res + f[i]) % MOD;
       }
       return res;
    }
};

 T3:LeetCode 2467. 树上最大得分和路径

 无向树

先分析一下题意:

Alice不断向下的路径并不是唯一的。

我们可以发现Bob每次走的路径是唯一的,我们是可以知道Bob每次走到哪里的,那这样我们就可以预处理一下每个点Bob到达的时间,根据样例给出个图

Bob从0那一点开始走,一直往上

然后我们看看Alice是怎么走的

首先Alice从根节点下来,之后开始分叉。

可以看出Alice能得到的分值是唯一确定的,不管是往左右走,左走的话不用说,右走的话也是唯一确定的只是有了Bob的影响不好算,但也还是唯一确定的。

所以我们就可以算出Alice往左右走的分值最大的是多少,所以Alice走的路径的话就是每次取最大的儿子方向走就可以了,难点就在算Alice的分数

接下来分析一下,如何算Alice的分数

 在这里我们用At表示Alice到达的时间,Bt表示Bob到达的时间。

下面在代码中展示吧

const int N = 100010, M = N * 2;

int n;
int h[N], w[N], e[M], ne[M], idx;
int bt[N], p[N];

class Solution {
public:

    void add(int a, int b)//建立一个无向图,加边函数
    {
        e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
    }

    void dfs1(int u, int fa)
    {
        for(int i = h[u]; ~i; i = ne[i]){
            int j = e[i];   
            if(j == fa) continue;
            p[j] = u;
            dfs1(j, u);
        }
    }

    int dfs2(int u, int fa, int t)
    {
        int val = 0;//权值
        //这里分类讨论
        if(bt[u] == -1 || t < bt[u]) val = w[u];
        else if(t == bt[u]) val = w[u] / 2;

        int mx = -2e9;//定义最大值
        for(int i = h[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if(j == fa) continue;
            mx = max(mx, dfs2(j, u, t + 1));
        }
        if(mx == -2e9) mx = 0;//没有儿子,没有儿子结点
        return val + mx;//返回答案
    }
    int mostProfitablePath(vector<vector<int>>& edges, int bob, vector<int>& amount) {
        memset(h, -1, sizeof h);
        idx = 0;
        n = amount.size();
        for(int i = 0; i < n; i ++ ) w[i] = amount[i];//求权值
        for(auto& edge: edges){//加边
            int a = edge[0], b = edge[1];
            add(a, b), add(b, a);
        }

        dfs1(0, -1);//这里直接枚举每个点的父节点

        memset(bt, -1, sizeof bt);//每个点到达的时间都初始化成-1
        int t = 0;
        while(true)
        {
            bt[bob] = t;//每次往上走一个就 ++ 
            t ++ ;
            if(!bob) break;
            bob = p[bob];//bob要走到父节点的位置
        }

        return dfs2(0, -1, 0);
    }
};

 T4:LeetCode 2468. 根据限制分割消息

 推公式:

class Solution {
public:
    int get(int k, int limit)
    {
        int len = to_string(k).size();
        int res = (limit - 3 - len) * k;
        int s = 0;
        for(int i = 1, t = 9; i < len; i ++, t *= 10)
        {
            res -= i * t;
            s += t;
        }
        res -= len * (k - s);
        return res;
    }
    vector<string> splitMessage(string message, int limit) {
        int n = message.size();
        for(int i = 1; i <= n; i ++ ){
            if(get(i, limit) >= n){
                vector<string> res;

                for(int j = 1, k = 0; j <= i && k < n; j ++ ){
                    string str = "<" + to_string(j) + "/" + to_string(i) + ">";
                    int len = min(n - k, limit - (int)str.size());
                    res.push_back(message.substr(k, len) + str);
                    k += len;
                }
                return res;
            }
        }
        return {};
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值