力扣——第91场双周赛

118 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第8天,点击查看活动详情

力扣——第91场双周赛

2465. 不同的平均值数目 - 力扣(LeetCode)

问题解析

将数组排序后,用头尾双指针模拟数被删除,用哈希表记录下这两个数的平均值,最后返回哈希表大小即可。

AC代码

class Solution {
public:
    int distinctAverages(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int l=0,r=nums.size()-1;
        unordered_map<double,int>mymap;
        while(l<r)
        {
            
            mymap[((double)nums[l]+nums[r])/2.0]++;
            l++,r--;
        }
        return mymap.size();
    }
};

2466. 统计构造好字符串的方案数 - 力扣(LeetCode)

问题解析

一开始想组合数求解,后来发现动态规划更简单。

设置二维状态转移数组f,f[i] [0]表示长度为i且以0结尾的方案数个数,f[i] [1]表示长度为i且以1结尾的方案数个数。初始f[0] [0]为1。

  • 当i>=zero时,有状态转移方程:f[i] [0]=(f[i-zero] [0] + f[i-zero] [1]);
  • 当i>=one时,有状态转移方程:f[i] [1]=(f[i-one] [0] + f[i-one] [1]);

因为题目说长度在low和high之间的字符串都满足条件,所以我们记录长度在low和high之间的方案数。

AC代码

class Solution {
public:
    long long f[200050][2],MOD=1e9+7;
    int countGoodStrings(int low, int high, int zero, int one) {
        f[0][0]=1;
        long long sum=0;
        for(int i=1;i<=high;i++)
        {
            if(i>=zero)f[i][0]=(f[i-zero][0]+f[i-zero][1])%MOD;
            if(i>=one)f[i][1]=(f[i-one][0]+f[i-one][1])%MOD;
            if(i>=low&&i<=high)
            {
                sum=(sum+f[i][0]+f[i][1])%MOD;
            }
        }
        return sum;
    }
};

2467. 树上最大得分和路径 - 力扣(LeetCode)

问题解析

有意思的题。

首先我们应该知道,Alice从根节点0往下走可以有很多条不同的路,但是Bob从节点往根节点0走就只有一条路。那么我们可以先让Bob走完他走的路,用数组Bob记录下每个节点的状态:Bob[i]表示Bob走到节点i用了几步,为-1说明BOb没走到这个节点过。

然后Alice从根节点进行dfs,同时记录Alice走的步数,走到一个新的点x时,看一下Bob[x]的状态:

  • 如果Bob[x]为-1或Bob[x]大于Alice的步数,Alice可以获得这个点的全部分数,因为Bob走不到这个点,或者说Bob晚于Alice到达这个点;
  • 如果Bob[x]小于Alice的步数,Alice什么也得不到,因为这个门被Bob第一个打开了;
  • 如果Bob[x]等于Alice的步数,Alice和Bob共享这扇门的分数。

当到达叶子时,计算一下这条路径的总分数,并维护最大值。

最后返回最大值即可。

AC代码

class Solution {
public:
    vector<int>tree[100050];
    int deep[100050],Bob[100050],Alice[100050],mx=-1e9;
    vector<int>nums;
    //第一个dfs,记录每个节点的深度,方便判断Bob走路的方向
    void dfs(int x,int y,int u)
    {
        deep[x]=u;
        for(auto&i:tree[x])
        {
            if(i==y)continue;
            dfs(i,x,u+1);
        }
    }
    //第二个dfs,记录Bob的路径,因为是往上走,所以每次要走到深度比当前点小的点
    void dfs2(int x,int u)
    {
        Bob[x]=u;
        for(auto&i:tree[x])
        {
            if(deep[i]<deep[x])
                dfs2(i,u+1);
        }
    }
    //第三个dfs,Alice开始行动
    void dfs3(int x,int y,int num,int u)
    {
        bool flag=true;
        if(Bob[x]==u)
            num+=nums[x]/2;
        else if(Bob[x]!=-1&&Bob[x]<u)
            num+=0;
        else 
            num+=nums[x];
        for(auto&i:tree[x])
        {
            if(i==y)continue;
            dfs3(i,x,num,u+1);
            flag=false;
        }
        if(flag)
            mx=max(mx,num);
    }
    int mostProfitablePath(vector<vector<int>>& edges, int bob, vector<int>& amount) {
        nums=amount;
        for(auto&i:edges)
        {
            tree[i[0]].push_back(i[1]);
            tree[i[1]].push_back(i[0]);
        }
        memset(Bob,-1,sizeof Bob);
        dfs(0,-1,1);
        dfs2(bob,0);
        dfs3(0,-1,0,0);
        return mx;
    }
};

2468. 根据限制分割消息 - 力扣(LeetCode)

问题解析

很奇怪的题目。

主要就是咱们不知道字符串会分成多少部分,多少部分会影响每一部分的字符串长度(除去结尾的<a/b>)。

但是这个字符串的计算方式我们是知道的,就是每一部分都加上<a/b>罢了,我们很容易就算出多出来的这一部分的长度,即:a的长度+b的长度+3(“</>"的长度),我们可以一个个枚举b的大小(即枚举分成多少份能满足条件。

算出所有b部分的"<a/b>"的长度加上字符串本身的长度,如果小于等于b*limit并且大于等于(b-1) *limit,说明能满足题目要求(大于等于(b-1) *limit是因为除了最后一部分,其余的部分都要有limit个字符串),那么我们就按照b部分来分割它即可。

AC代码

class Solution {
public:
    int get_len(int x)
    {
        int len = 0;
        while (x)
        {
            x /= 10;
            len++;
        }
        return len;
    }
    vector<string> check(string s, int limit, int cnt)
    {
        vector<string>v;
        int n = s.size(), b = get_len(cnt), len = b + 4, a = 1;
        string str;
        for (int i = 0; i < n; i++)
        {
            str += s[i];
            if (str.size() + len == limit)
            {
                str += '<' + to_string(a) + '/' + to_string(cnt) + '>';
                a++;
                len = b + get_len(a) + 3;

                v.push_back(str);
                str.clear();
            }
        }
        if (str.size() != 0)
        {
            str += '<' + to_string(a) + '/' + to_string(cnt) + '>';
            v.push_back(str);
        }
        return v;
    }
    vector<string> splitMessage(string message, int limit) {
        int n = message.size(), len = 0;
        for (int i = 1; i <= n; i++)
        {
            if (i == 7)
            {
                cout << endl;
            }
            if (i == 10)
                len += 9;
            else if (i == 100)
                len += 99;
            else if (i == 1000)
                len += 999;
            else if (i == 10000)
                len += 9999;
            len += get_len(i) * 2 + 3;
            int x = len + n;
            if (i > 1 && x <= i * limit && x > (i - 1) * limit)
            {
                return check(message, limit, i);
            }
            else if (i == 1 && x <= limit)
            {
                return check(message, limit, i);
            }
        }
        return {};
    }
};