第 364 场 LeetCode 周赛题解

A 最大二进制奇数

在这里插入图片描述

降序排序字符串,然后将最后一个 1 与最后一位交换

class Solution {
public:
    string maximumOddBinaryNumber(string s) {
        sort(s.begin(), s.end(), greater<>());
        for (int i = s.size() - 1;; i--)
            if (s[i] == '1') {
                swap(s[i], s.back());
                break;
            }
        return s;
    }
};

B 美丽塔 I

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

枚举: 枚举山状数组的最大值的下标 i i i,然后遍历两端 [ 0 , i ) [0,i) [0,i) ( i , n − 1 ] (i,n-1] (i,n1] ,求各位置能达到的最大高度

class Solution {
public:
    using ll = long long;

    long long maximumSumOfHeights(vector<int> &maxHeights) {
        int n = maxHeights.size();
        ll res = 0;
        for (int i = 0; i < n; i++) {
            ll cur = maxHeights[i];
            for (int j = i - 1, last = maxHeights[i]; j >= 0; j--) {
                last = min(last, maxHeights[j]);
                cur += last;
            }
            for (int j = i + 1, last = maxHeights[i]; j < n; j++) {
                last = min(last, maxHeights[j]);
                cur += last;
            }
            res = max(res, cur);
        }
        return res;
    }
};

C 美丽塔 II

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

单调栈+枚举:设 l [ i ] l[i] l[i] 为当 h e i g h t s [ i ] = m a x H e i g h t s [ i ] heights[i]=maxHeights[i] heights[i]=maxHeights[i] ∑ k = 0 i h e i g h t s [ k ] \sum_{k=0}^i heights[k] k=0iheights[k] 的最大值,类似地设 r [ i ] r[i] r[i] 为当 h e i g h t s [ i ] = m a x H e i g h t s [ i ] heights[i]=maxHeights[i] heights[i]=maxHeights[i] ∑ k = i h e i g h t s . s i z e ( ) − 1 h e i g h t s [ k ] \sum_{k=i}^{heights.size()-1} heights[k] k=iheights.size()1heights[k] 的最大值,用单调栈预先求出 l l l r r r 数组,答案即为: m a x { l [ i ] + r [ i ] − m a x H e i g h t s [ i ]    ∣    0 ≤ i < n } max\{ l[i]+r[i]-maxHeights[i] \; | \; 0\le i< n \} max{l[i]+r[i]maxHeights[i]0i<n}

class Solution {
public:
    using ll = long long;

    long long maximumSumOfHeights(vector<int> &maxHeights) {
        int n = maxHeights.size();
        vector<ll> l(n), r(n);
        stack<int> st;
        for (int i = 0; i < n; i++) {
            while (!st.empty() && maxHeights[st.top()] > maxHeights[i])//栈顶位置最大高度大于当前位置最大高度则需要出栈
                st.pop();
            l[i] = st.empty() ? 1LL * (i + 1) * maxHeights[i] : l[st.top()] + 1LL * (i - st.top()) * maxHeights[i];
            st.push(i);
        }
        st = stack<int>();
        for (int i = n - 1; i >= 0; i--) {
            while (!st.empty() && maxHeights[st.top()] > maxHeights[i])//栈顶位置最大高度大于当前位置最大高度则需要出栈
                st.pop();
            r[i] = st.empty() ? 1LL * (n - i) * maxHeights[i] : r[st.top()] + 1LL * (st.top() - i) * maxHeights[i];
            st.push(i);
        }
        ll res = 0;
        for (int i = 0; i < n; i++)
            res = max(res, l[i] + r[i] - maxHeights[i]);
        return res;
    }
};

D 统计树中的合法路径数目

在这里插入图片描述
在这里插入图片描述
计数+ d f s dfs dfs:设一个质数点 r o o t root root v v v 集合为: { 从 u 出发只通过非质数点能到达的非质数点的数目 ∣ u 是 r o o t 的邻接点 } \{ 从u出发只通过非质数点能到达的非质数点的数目 | u是root的邻接点 \} {u出发只通过非质数点能到达的非质数点的数目uroot的邻接点},例如下图中 r o o t root root v v v 集合为 { 1 , 2 , 3 } \{1,2,3 \} {1,2,3}
在这里插入图片描述
知道 r o o t root root v v v 集合后,则树中含 r o o t root root 的合法路径可分为两类:

  1. 一个端点为 r o o t root root 的路径,这类路径数为: ∑ v i ∈ v v i \sum_{v_i\in v} v_i vivvi
  2. 两个端点都不为 r o o t root root 的路径,这类路径数为: 1 2 ∑ v i ∈ v ∑ j ≠ i v i v j = 1 2 ( ( ∑ v i ∈ v v i ) 2 − ∑ v i ∈ v v i 2 ) \frac 1 2 \sum_{v_i\in v} \sum_{j\ne i} v_iv_j=\frac 1 2 \left ( ( \sum_{v_i\in v} v_i )^2 -\sum_{v_i\in v} v_i^2 \right ) 21vivj=ivivj=21((vivvi)2vivvi2)

不妨以 1 1 1 为树根,首先通过 d f s dfs dfs 计算 c n t _ n p cnt\_np cnt_np 数组: c n t _ n p [ i ] cnt\_np[i] cnt_np[i] 为以 i i i 为根的子树中从 i i i 出发只通过非质数点能到达的非质数点的数目。然后再次 d f s dfs dfs ,并在遍历过程中记录“从当前节点的父节点出发(且不经过当前节点)只通过非质数点能到达的非质数点的数目”,这样每到达一个质数点,就能求出它的 v v v 集合,从而计算含该点的合法路径数。

class Solution {
public:
    using ll = long long;

    long long countPaths(int n, vector<vector<int>> &edges) {
        vector<int> isp(n + 1, 1);//isp[i]:i是否是质数
        isp[1] = 0;
        for (int i = 2; i <= n; i++) {//预处理判断数是否是质数
            for (int j = 2; j * j <= i; j++)
                if (i % j == 0) {
                    isp[i] = 0;
                    break;
                }
        }
        vector<vector<int>> e(n + 1);
        for (auto &ei: edges) {//建图
            e[ei[0]].push_back(ei[1]);
            e[ei[1]].push_back(ei[0]);
        }
        vector<ll> cnt_np(n + 1);//以i为根的子树中从i出发只通过非质数点到达的非质数点的数目
        function<int(int, int)> comp_path = [&](int root, int p) {//当前点为root,父节点为p
            if (isp[root]) {//当前点为质数点
                cnt_np[root] = 0;
                for (auto j: e[root])
                    if (j != p)
                        comp_path(j, root);
            } else {//当前点非质数点
                cnt_np[root] = 1;
                for (auto j: e[root])
                    if (j != p)
                        cnt_np[root] += comp_path(j, root);
            }
            return cnt_np[root];
        };
        comp_path(1, 0);
        ll res = 0;
        function<void(int, int, int)> dfs = [&](int root, int p, int up) {//当前点为root,父节点为p,up:从p出发(且不经过当前节点)只通过非质数点能到达的非质数点的数目
            if (isp[root]) {//当前点为质数点
                vector<ll> v;// v集合
                if (up != 0)
                    v.push_back(up);
                for (auto j: e[root])
                    if (j != p) {
                        dfs(j, root, 0);
                        if (cnt_np[j])
                            v.push_back(cnt_np[j]);
                    }
                ll s = 0, s2 = 0;
                for (auto it: v) {
                    s += it;
                    s2 += it * it;
                }
                res += s + (s * s - s2) / 2;//+=含当前质数点的合法路径数目

            } else {//当前点非质数点
                ll s = up + 1;
                for (auto j: e[root])
                    if (j != p && cnt_np[j])
                        s += cnt_np[j];
                for (auto j: e[root])
                    if (j != p)
                        dfs(j, root, s - cnt_np[j]);
            }
        };
        dfs(1, 0, 0);
        return res;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值