算法竞赛>力扣>周赛 | weekly-contest-455

原文链接:算法竞赛>力扣>周赛 | weekly-contest-455

3591.检查元素频次是否为质数

解题思路

统计每个元素出现的次数,判断各次数是否为质数。由于次数<=100,可用试除法判断。

代码实现

bool isPrime(int x) {
    if (x < 2)return false;
    for (int i = 2, k = sqrt(x); i <= k; i++)
        if (x % i == 0)return false;
    return true;
}

bool checkPrimeFrequency(vector<int>& nums) {
    unordered_map<int, int> mp;
    for (int v : nums) mp[v]++;
    for (auto [k,v] : mp)
        if (isPrime(v))return true;
    return false;
}

时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( 1 ) O(1) O(1)

3592.硬币面值还原

解题思路

总金额 i 一定是由小于等于 i 的硬币凑成的。

已给出每种金额的方案数 numWays[i],如果集合存在,则一定是唯一的。那么,需要做的就是去构造这个集合。

不妨,从小到大考虑每种金额的硬币 i,是否需要硬币 i 呢?

设已考虑的硬币能凑成金额 i 的方案数为 dp[i],金额 i 的事实方案数为 numWays[i]。

如果 dp[i]<numWays[i],那么就需要将硬币 i 考虑进来(再挣扎一下,看能否达到 numWays[i],实际上金额 i 只会增加一种方案)。

将硬币 i 考虑进来后,需要更新各金额的方案数。

检查 dp[i] 与 numWays[i] 是否相等,如果不相等,说明不存在满足条件的集合。

  • 若 dp[i]<numWays[i],说明即便是挣扎后依旧无法满足要求。
  • 若 dp[i]>numWays[i],说明在满足 numWays[1:i-1] 的前提下,金额 i 的方案数已超过 numWays[i],后续更无法满足要求。

代码实现

vector<int> findCoins(vector<int>& numWays) {
    int n = numWays.size();
    vector<int> dp(n + 1, 0), &v = numWays, cs;
    dp[0] = 1;
    for (int i = 1; i <= n; i++) {
        if (v[i - 1] > dp[i]) {
            cs.push_back(i);
            for (int j = i; j <= n; j++)dp[j] += dp[j - i];
        }
        if (v[i - 1] != dp[i])return {};
    }
    return cs;
}

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

3593.使叶子路径成本相等的最小增量

解题思路

根节点已经固定为节点 0。

最终需要使得根节点到所有叶子节点的成本相等,记这个成本为目标成本,这个目标成本是多少呢?由于每个节点的成本不能减少,所以目标成本应该越小越好,小一点,需要增加成本的节点就可能少一点。由于每个节点的成本不能减少,目标成本不能小于根节点到叶子节点的最大成本。综上,目标成本为根节点到叶子节点的最大成本。换句话说,根节点的目标成本为根节点到叶子节点的最大成本。

最终,对于任意节点 i,其到其各叶子节点的成本均相等,记该成本为预期成本。特别的,根节点的预期成本即为上述目标成本。

成本应该尽可能加在上面的节点,这样可以作用于更多的路径。

对于节点 i,设其预期成本为 tc,节点 i 应该加多少成本呢?应尽可能多加,设加的成本为 ac,其各子节点到叶子节点的成本的最大值为
cc,则需要满足 cost[i]+cc+ac≤tc,故 ac 的最大值为 tc-(cost[i]+cc)。

综上所述,首先计算得到目标成本,再计算得到 cc,最终便可确定 ac,ac 为 0 说明当前节点不需要增加成本。

代码实现

int minIncrease(int n, vector<vector<int>>& edges, vector<int>& cost) {
    typedef long long ll;
    int m = edges.size();

    // 建图
    vector<int> h(n + 1, -1), e((m << 1) + 1), ne((m << 1) + 1);
    int idx = 0;
    auto add = [&](int a, int b) {
        e[idx] = b, ne[idx] = h[a], h[a] = idx++;
    };
    for (auto v : edges) add(v[0], v[1]), add(v[1], v[0]);

    // ms[i] 节点i的子节点到叶子节点的距离的最大值
    vector<ll> ms(n);
    // 计算每个节点到叶子节点的最大距离
    function<ll(int, int)> dfs1 = [&](int x, int p) {
        ll mc = 0;
        for (int i = h[x]; ~i; i = ne[i]) {
            if (e[i] == p)continue;
            mc = max(mc, dfs1(e[i], x));
        }
        ms[x] = mc;
        return cost[x] + mc;
    };
    // 根节点到叶子节点的距离的最大值
    ll mc = dfs1(0, -1);


    // 应该尽可能地往当前节点加,减轻子孙节点的压力
    int cnt = 0;
    function<void(int, int, ll)> dfs2 = [&](int x, int p, ll tc) {
        if (cost[x] + ms[x] < tc)cnt++;
        for (int i = h[x]; ~i; i = ne[i]) {
            if (e[i] == p)continue;
            dfs2(e[i], x, ms[x]);
        }
    };
    dfs2(0, -1, mc);

    return cnt;
}

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

你可能感兴趣的:(算法竞赛,算法,leetcode,职场和发展)