第 114 场 LeetCode 双周赛题解

A 收集元素的最少操作次数

在这里插入图片描述

模拟: 反序遍历数组,用一个集合存当前遍历过的不超过 k k k 的正数

class Solution {
public:
    int minOperations(vector<int> &nums, int k) {
        unordered_set<int> vis;
        int n = nums.size();
        int i = n - 1;
        for (;; i--) {
            if (nums[i] <= k && !vis.count(nums[i]))
                vis.insert(nums[i]);
            if (vis.size() == k)
                break;
        }
        return n - i;
    }
};

B 使数组为空的最少操作次数

在这里插入图片描述

计数:记录数组中各元素出现次数,若存在只出现一次的元素则无法使数组为空,否则,要将出现次数为 f f f 的某个元素全部删除最少需要的次数为:当 f % 3 = 0 f\%3=0 f%3=0 时为 f 3 \frac f 3 3f ,当 f % 3 ≠ 0 f\%3\ne 0 f%3=0 时为 ⌊ f 3 ⌋ + 1 \left \lfloor \frac f 3 \right \rfloor + 1 3f+1

class Solution {
public:
    int minOperations(vector<int> &nums) {
        unordered_map<int, int> cnt;
        for (auto x: nums)
            cnt[x]++;
        int res = 0;
        for (auto [_, f]: cnt) {
            if (f == 1)
                return -1;
            if (f % 3 == 0)
                res += f / 3;
            else
                res += f / 3 + 1;
        }
        return res;
    }
};

C 将数组分割成最多数目的子数组

在这里插入图片描述

模拟:遍历数组元素 n u m s [ i ] nums[i] nums[i] ,若 n u m s [ i ] nums[i] nums[i] 不是最后一个元素,则只有一种情况会使得最优解中 n u m s [ i ] nums[i] nums[i] 为其所在子数组的最后一个元素: n u m s [ i ] nums[i] nums[i] 所在的子数组分数已经为 0 0 0 n u m s [ i + 1 ] & ⋯ & n u m s [ n u m s . s i z e ( ) − 1 ] nums[i+1]\&\cdots\&nums[nums.size()-1] nums[i+1]&&nums[nums.size()1] 等于 0 0 0

class Solution {
public:
    int maxSubarrays(vector<int> &nums) {
        int n = nums.size();
        vector<int> sf(n);//“后缀与”数组
        sf[n - 1] = nums[n - 1];
        for (int i = n - 2; i >= 0; i--)
            sf[i] = nums[i] & sf[i + 1];
        int res = 0;
        for (int i = 0, cur = nums[0]; i < n; i++) {
            cur &= nums[i];
            if (i == n - 1 || cur == 0 && sf[i + 1] == 0) {//nums[i]为所在子数组的最后一个元素
                res++;
                if (i != n - 1)
                    cur = nums[i + 1];//下一个子数组的首个元素
            }
        }
        return res;
    }
};

D 可以被 K 整除连通块的最大数目

在这里插入图片描述
在这里插入图片描述

d f s dfs dfs:不妨以 0 0 0 为树根,通过 d f s dfs dfs s s s 数组: s [ i ] s[i] s[i] 为以 i i i 为根的子树的所有节点值之和。设 d f s dfs dfs 遍历到的当前节点为 c u r cur cur ,若遍历到 c u r cur cur 的子节点 j j j 时,有 s [ j ] % k = = 0 s[j]\%k==0 s[j]%k==0 ,则边 ( c u r , j ) (cur,j) (cur,j) 可以删除(即可以增加一个连通块)。

class Solution {
public:
    using ll = long long;

    int maxKDivisibleComponents(int n, vector<vector<int>> &edges, vector<int> &values, int k) {
        vector<int> e[n];//邻接表
        for (auto &ei: edges) {//建图
            e[ei[0]].push_back(ei[1]);
            e[ei[1]].push_back(ei[0]);
        }
        vector<ll> s(n);
        int res = 1;
        function<ll(int, int)> dfs = [&](int cur, int par) {//当前节点为cur,父节点为par
            s[cur] += values[cur];
            for (auto j: e[cur])
                if (j != par) {
                    s[cur] += dfs(j, cur);
                    if (s[j] % k == 0)
                        res++;
                }
            return s[cur];
        };
        dfs(0, -1);//以0为根跑dfs
        return res;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值