leetcode第 317 场周赛

leetcode第 317 场周赛

2455. 可被三整除的偶数的平均值

难度简单3收藏分享切换为英文接收动态反馈

给你一个由正整数组成的整数数组 nums ,返回其中可被 3 整除的所有偶数的平均值。

注意:n 个元素的平均值等于 n 个元素 求和 再除以 n ,结果 向下取整 到最接近的整数。

示例 1:

输入:nums = [1,3,6,10,12,15]
输出:9
解释:6 和 12 是可以被 3 整除的偶数。(6 + 12) / 2 = 9 。

示例 2:

输入:nums = [1,2,4,7,10]
输出:0
解释:不存在满足题目要求的整数,所以返回 0 。

提示:

  • 1 <= nums.length <= 1000

  • 1 <= nums[i] <= 1000

    可被3整除的所有偶数其实就是可被6整除

class Solution {
public:
    int averageValue(vector<int>& nums) {
         int sum=0,n=0;
        for(int i=0;i<nums.size();i++)
            if(nums[i]%6==0)
            {
                sum+=nums[i];
                n++;
            }
        return sum==0?0:sum/n;
    }
};
2456. 最流行的视频创作者

难度中等15收藏分享切换为英文接收动态反馈

给你两个字符串数组 creatorsids ,和一个整数数组 views ,所有数组的长度都是 n 。平台上第 i 个视频者是 creator[i] ,视频分配的 id 是 ids[i] ,且播放量为 views[i]

视频创作者的 流行度 是该创作者的 所有 视频的播放量的 总和 。请找出流行度 最高 创作者以及该创作者播放量 最大 的视频的 id 。

  • 如果存在多个创作者流行度都最高,则需要找出所有符合条件的创作者。
  • 如果某个创作者存在多个播放量最高的视频,则只需要找出字典序最小的 id

返回一个二维字符串数组 answer ,其中 answer[i] = [creatori, idi] 表示 creatori 的流行度 最高 且其最流行的视频 id 是 idi ,可以按任何顺序返回该结果*。*

示例 1:

输入:creators = ["alice","bob","alice","chris"], ids = ["one","two","three","four"], views = [5,10,5,4]
输出:[["alice","one"],["bob","two"]]
解释:
alice 的流行度是 5 + 5 = 10 。
bob 的流行度是 10 。
chris 的流行度是 4 。
alice 和 bob 是流行度最高的创作者。
bob 播放量最高的视频 id 为 "two" 。
alice 播放量最高的视频 id 是 "one" 和 "three" 。由于 "one" 的字典序比 "three" 更小,所以结果中返回的 id 是 "one" 。

示例 2:

输入:creators = ["alice","alice","alice"], ids = ["a","b","c"], views = [1,2,2]
输出:[["alice","b"]]
解释:
id 为 "b" 和 "c" 的视频都满足播放量最高的条件。
由于 "b" 的字典序比 "c" 更小,所以结果中返回的 id 是 "b" 。

提示:

  • n == creators.length == ids.length == views.length
  • 1 <= n <= 105
  • 1 <= creators[i].length, ids[i].length <= 5
  • creators[i]ids[i] 仅由小写英文字母组成
  • 0 <= views[i] <= 105

这题当时做了好久最后还超时了,没有想到同时记录最大下标和总和

class Solution {
public:
    vector<vector<string>> mostPopularCreator(vector<string>& creators, vector<string>& ids, vector<int>& views) {
        int n = creators.size();

        // 记录每个作者的播放量总和
        unordered_map<string, long long> mp1;
        // 记录每个作者播放量最大视频的下标
        unordered_map<string, int> mp2;
        for (int i = 0; i < n; i++) {
            // 更新播放量总和
            mp1[creators[i]] += views[i];
            // 更新最大播放量下标
            if (mp2.count(creators[i])) {
                int &t = mp2[creators[i]];
                if (views[i] > views[t] || (views[i] == views[t] && ids[i] < ids[t])) t = i;
            } 
            else {
                mp2[creators[i]] = i;
            }
        }

        // 求最大播放量总和
        long long mx = -1;
        for (auto it = mp1.begin(); it != mp1.end(); it++) mx = max(mx, it->second);

        // 计算答案
        vector<vector<string>> ans;
        for (auto it = mp1.begin(); it != mp1.end(); it++) if (it->second == mx) ans.push_back({it->first, ids[mp2[it->first]]});
        return ans;
    }
};
2457. 美丽整数的最小增量

难度中等19收藏分享切换为英文接收动态反馈

给你两个正整数 ntarget

如果某个整数每一位上的数字相加小于或等于 target ,则认为这个整数是一个 美丽整数

找出并返回满足 n + x美丽整数 的最小非负整数 x 。生成的输入保证总可以使 n 变成一个美丽整数。

示例 1:

输入:n = 16, target = 6
输出:4
解释:最初,n 是 16 ,且其每一位数字的和是 1 + 6 = 7 。在加 4 之后,n 变为 20 且每一位数字的和变成 2 + 0 = 2 。可以证明无法加上一个小于 4 的非负整数使 n 变成一个美丽整数。

示例 2:

输入:n = 467, target = 6
输出:33
解释:最初,n 是 467 ,且其每一位数字的和是 4 + 6 + 7 = 17 。在加 33 之后,n 变为 500 且每一位数字的和变成 5 + 0 + 0 = 5 。可以证明无法加上一个小于 33 的非负整数使 n 变成一个美丽整数。

示例 3:

输入:n = 1, target = 1
输出:0
解释:最初,n 是 1 ,且其每一位数字的和是 1 ,已经小于等于 target 。

提示:

  • 1 <= n <= 1012
  • 1 <= target <= 150
  • 生成的输入保证总可以使 n 变成一个美丽整数。

得到当前数字的各位数字之和,如果<=target就直接返回0
当前值各位数之和大于了target,那么考虑进行进位,当前数大于,那么个位的数字往上变大更不可能满足条件
寻找最小值,末尾为0则最小 所以我们令此时的个位为0,十位进1,同理,如果计算后仍旧大于target,我们将十位变为0,百位进1
举个例子:123 3
123 和为6>3,那么124-129的各位数和不可能小于6,直到进位后130达到4才小于123的6
130 和为4>3 那么131-139也不可能小于4,也只有进位后200才小于130的4
200 和为2<3,所以200-123的差就是最小增量
当满足条件后,此时的值减去原值就是最小的数字

class Solution {
public:
    long long makeIntegerBeautiful(long long n, int target) {
        string str=to_string(n);
        int len=str.size();
        long long ten[64]={1};
           for(int i=1;i<=len;i++)
           ten[i]=ten[i-1]*10;
        int sum=0;
        for(int i=0;i<str.size();i++)
        sum=sum+str[i]-'0';
        if(sum<=target)
        return 0;
        long long num;
        for(int i=1;i<=len;i++)
        {
            num=n/ten[i]*ten[i]+ten[i];
            string s1=to_string(num);
            int sum1=0;
            for(int i=0;i<s1.size();i++)
            sum1+=s1[i]-'0';
            if(target>=sum1)
            return num-n;
        }
        return 0;
    }
};
2458. 移除子树后的二叉树高度

难度困难15收藏分享切换为英文接收动态反馈

给你一棵 二叉树 的根节点 root ,树中有 n 个节点。每个节点都可以被分配一个从 1n 且互不相同的值。另给你一个长度为 m 的数组 queries

你必须在树上执行 m独立 的查询,其中第 i 个查询你需要执行以下操作:

  • 从树中 移除queries[i] 的值作为根节点的子树。题目所用测试用例保证 queries[i] 等于根节点的值。

返回一个长度为 m 的数组 answer ,其中 answer[i] 是执行第 i 个查询后树的高度。

注意:

  • 查询之间是独立的,所以在每个查询执行后,树会回到其 初始 状态。
  • 树的高度是从根到树中某个节点的 最长简单路径中的边数

示例 1:

img

输入:root = [1,3,4,2,null,6,5,null,null,null,null,null,7], queries = [4]
输出:[2]
解释:上图展示了从树中移除以 4 为根节点的子树。
树的高度是 2(路径为 1 -> 3 -> 2)。

示例 2:

img

输入:root = [5,8,9,2,1,3,7,4,6], queries = [3,2,4,8]
输出:[3,2,3,2]
解释:执行下述查询:
- 移除以 3 为根节点的子树。树的高度变为 3(路径为 5 -> 8 -> 2 -> 4)。
- 移除以 2 为根节点的子树。树的高度变为 2(路径为 5 -> 8 -> 1)。
- 移除以 4 为根节点的子树。树的高度变为 3(路径为 5 -> 8 -> 2 -> 6)。
- 移除以 8 为根节点的子树。树的高度变为 2(路径为 5 -> 9 -> 3)。

提示:

  • 树中节点的数目是 n
  • 2 <= n <= 105
  • 1 <= Node.val <= n
  • 树中的所有值 互不相同
  • m == queries.length
  • 1 <= m <= min(n, 104)
  • 1 <= queries[i] <= n
  • queries[i] != root.val
解法一:

首先从用一个最简单的 dfs 去求每一个点的 高度 出发来思考:

int depth[N];
void dfs(TreeNode* root, int height) {
    depth[root->val] = height; // 因为每一个节点的值都不一样
    if (root->left) dfs(root->left, height + 1);
    if (root->right) dfs(root->right, height + 1);
}

我们想象对于某一个查询 ii,即我们要去除该节点及其子树。那么用 「先左后右」 这个方法来遍历到该节点时,由于它的子树是没有被遍历到的,所以如果我们用一个变量 max_heightmax_height 来表示遍历过程中的最大高度,那么当遍历到该节点时,如果其他节点(除了它本身和其子节点)都遍历过了,那么去掉该节点及其子树后的最大高度等于此时的 max_{height}max_height。

又因为这是「二叉树」,所以对于某一个节点来说,用「先左后右」 和 「先右后左」 两种遍历方式一定会有其中一种情况满足遍历到该节点时,其他节点(除了它本身和其子节点)都遍历过。

image.png

image.png

那么我们只用 「先左后右」 和 「先右后左」 两次遍历来记录遍历到当前节点的 max_heightmax_height 即可,最后去掉该节点后的整个树的最大高度就是两者中的较大值。

复杂度
时间复杂度: O(n),两次 dfs 的时间开销。

空间复杂度: O(n)。

const int N = 1e5 + 7;
class Solution {
public:
    int mp1[N]; // 先左后右到节点 i 的最大值
    int mp2[N]; // 先右后左到节点 i 的最大值
    int max_height; // 标记最大值
    void dfs1(TreeNode* root, int o) { // 先左后右
        mp1[root->val] = max_height;
        max_height = max(max_height, o);
        if (root->left) dfs1(root->left, o + 1);
        if (root->right) dfs1(root->right, o + 1);
    }
    void dfs2(TreeNode* root, int o) { // 先右后左
        mp2[root->val] = max_height;
        max_height = max(max_height, o);
        if (root->right) dfs2(root->right, o + 1);
        if (root->left) dfs2(root->left, o + 1);
    }
    vector<int> treeQueries(TreeNode* root, vector<int>& qs) {
        max_height = 0, dfs1(root, 0);
        max_height = 0, dfs2(root, 0);
        vector<int> res;
        for (auto& i : qs) {
            res.push_back(max(mp1[i], mp2[i]));
        }
        return res;
    }
};
解法二:

既然是求树的高度,我们可以先跑一遍 DFS,求出每棵子树的高度height(这里定义成最长路径的节点数)。

然后再 DFS 一遍这棵树,同时维护当前节点深度 depth(从 0 开始),以及删除当前子树后剩余部分的树的高度 restH(这里定义成最长路径的边数)。

具体做法如下:

往左走,递归前算一下从根节点到当前节点右子树最深节点的长度,即 depth +height[node.right],与 restH 取最大值,然后往下递归;
往右走,递归前算一下从根节点到当前节点左子树最深节点的长度,即 depth +height[node.left],与 restH 取最大值,然后往下递归。
每个节点的答案即为递归到该节点时的 restH 值。

代码实现时可以直接把答案覆盖到queries 数组中。

灵神的代码:

class Solution {
public:
    vector<int> treeQueries(TreeNode *root, vector<int> &queries) {
        unordered_map<TreeNode*, int> height; // 每棵子树的高度
        function<int(TreeNode*)> get_height = [&](TreeNode *node) -> int {
            return node ? height[node] = 1 + max(get_height(node->left), get_height(node->right)) : 0;
        };
        get_height(root);

        int res[height.size() + 1]; // 每个节点的答案
        function<void(TreeNode*, int, int)> dfs = [&](TreeNode *node, int depth, int rest_h) {
            if (node == nullptr) return;
            ++depth;
            res[node->val] = rest_h;
            dfs(node->left, depth, max(rest_h, depth + height[node->right]));
            dfs(node->right, depth, max(rest_h, depth + height[node->left]));
        };
        dfs(root, -1, 0);

        for (auto &q : queries) q = res[q];
        return queries;
    }
};


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值