【Leetcode】天堂硅谷·数字经济算法编程大赛(虚拟)

感受

题目清单
https://leetcode.cn/contest/hhrc2022/
周末比较忙,两场比赛都没有参加,打的虚拟赛。

题解

A.化学反应

实验室内有一些化学反应物,其中的任意两种反应物之间都能发生反应,且质量的消耗量为 1:1。
已知初始 material[i] 表示第 i 种反应物的质量,每次进行实验时,会选出当前 质量最大 的两种反应物进行反应,假设反应物的重量分别为 i 和 j ,且 i <= j。反应的结果如下:

  • 如果 i == j,那么两种化学反应物都将被消耗完;
  • 如果 i < j,那么质量为 i 的反应物将会完全消耗,而质量为 j 的反应物质量变为 j - i 。

最后,最多只会剩下一种反应物,返回此反应物的质量。如果没有反应物剩下,返回 0。
直接利用。

直接用STL进行模拟就可以了。

class Solution {
public:
    int lastMaterial(vector<int>& m) {
        priority_queue<int> q;
        
        for (auto c: m)
            q.push(c);
        
        while(q.size() > 1)
        {
            int a = q.top();
            q.pop();
            if (q.size() >= 1)
            {
                a -= q.top();
                q.pop();
                q.push(a);
            }
            cout << a << endl;
        }
        return q.top();
    }
};

B.销售出色区间

给你一份销售数量表 sales,上面记录着某一位销售员每天成功推销的产品数目。
我们认为当销售员同一天推销的产品数目大于 8 个的时候,那么这一天就是「成功销售的一天」。
所谓「销售出色区间」,意味在这段时间内,「成功销售的天数」是严格 大于「未成功销售的天数」。
请你返回「销售出色区间」的最大长度。

思路:求出满足f[i] < f[j]且最小的i,ans = j - i

  1. 利用前缀和计算前[0, i]天的成功销售天数(允许为负数)。
  2. 将成功销售天数进行分组,key为成功销售天数,value存储成功销售天数为key的区间,由于区间左下表都是0,所以只存储右下标i就可以了,存储的时候也要保证成功销售天数从小到大存储。
  3. 枚举找到满足f[i] < f[j]且最小的i
class Solution {
public:
    int longestESR(vector<int>& sales) {
        
        int len = sales.size();
        
        vector<int> v(len + 1, 0);
        
        for (int i = 1; i <= len; i ++)
        {
            v[i] = v[i - 1] + (sales[i - 1] > 8 ? 1 : -1);
        }
        
        map<int, vector<int>> m;
        
        for (int i = 0; i <= len ; i ++) m[v[i]].push_back(i);
        
        int minl = 1e9, ans = 0;
        for (auto it = m.begin(); it != m.end(); it ++)
        {
            for (auto c : it->second)
            {
                ans = max(ans, c - minl);
            }
            for (auto c : it->second)
            {
                minl = min(minl, c);
            }
        }
        return ans;
    }
};

C.重复的彩灯树

有一棵结构为二叉树的圣诞树 root 挂满了彩灯,各节点值表示彩灯的颜色。
如果两棵子树具有 相同的结构 和 相同的彩灯颜色分布,则它们是 重复 的。
请返回这棵树上所有 重复的子树。

寻找重复的子树,leetcode原题。

寻找重复的子树-https://leetcode.cn/problems/find-duplicate-subtrees/

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    unordered_map<string, int> m;
    vector<TreeNode*> ans;
    vector<TreeNode*> lightDistribution(TreeNode* root) {
        m.clear();
        
        solve(root);
        
        return ans;
    }
    
    string solve(TreeNode* root) {
        
        if (root == nullptr) return "#";
        
        string l = solve(root -> left) + "," +  solve(root -> right) + "," + to_string(root -> val);
        
        if (m[l] == 1) ans.push_back(root);
        
        m[l] ++;
        
        return l;
    }
};

D.补给覆盖

已知有一片呈二叉树的道路,我们要在道路上的一些节点设置补给站支援。
补给站可以设置在任意节点上,每个补给站可以使距离自身小于等于 1 个单位的节点获得补给。
若要使道路的所有节点均能获得补给,请返回所需设置的补给站最少数量。

树形DP问题

对于某一个节点i来说,要让他获得补给,有以下三种情况:

  1. f[i][0]: 自己没有补给站,父亲要有。即那么i的儿子都不能有补给站,i的儿子只能由i的孙子来覆盖。
  2. f[i][1]: 自己没有,儿子有。
  3. f[i][2]: 自己有

状态转移方程:
f[i][0] = f[l][1] + f[r][1];
f[i][1] = min(f[l][2] + f[r][2], f[l][1] + f[r][2], f[l][2] + f[r][1]);
f[i][2] = min(f[son][0], f[son][1], f[son][2]) + 1;

Ps: 赋初值{0, 0, INF},f[i][0] = 0, f[i][1] = 0, f[i][2] = INF

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    const int INF = 1e9;
    int minSupplyStationNumber(TreeNode* root) {
        auto ans = dfs(root);
        return min(ans[1], ans[2]);
    }
    // 对于某一个节点i来说,要让他获得补给,有以下三种情况:
    // 1.f[i][0]: 自己没有补给站,父亲要有。即那么i的儿子都不能有补给站,i的儿子只能由i的孙子来覆盖。 
    // 2.f[i][1]: 自己没有,儿子有。
    // 3.f[i][2]: 自己有
    /**
     * 状态转移方程:
     * f[i][0] = f[l][1] + f[r][1];
     * f[i][1] = min(f[l][2] + f[r][2], f[l][1] + f[r][2], f[l][2] + f[r][1]);
     * f[i][2] = min(f[son][0], f[son][1], f[son][2]) + 1;
     **/
    /**
    * 赋初值{0, 0, INF},f[i][0] = 0, f[i][1] = 0, f[i][2] = INF。
    * 
    **/

    vector<int> dfs(TreeNode* root) {
        // 如果该节点为null,
        if (root == nullptr) return {0, 0, INF};
        
        auto l = dfs(root -> left);
        auto r = dfs(root -> right);
        
        int ans = INF;
        for (int i = 0; i < 3; i ++)
            for (int j = 0; j < 3; j ++)
                ans = min(ans, l[i] + r[j] + 1);
        
        return {min(INF, l[1] + r[1]), min({INF, l[2] + r[2], l[1] + r[2], l[2] + r[1]}), ans};
    }
};
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Honyelchak

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值