LeetCode-第99场周赛题解

第一题-2578. 最小和分割

2578. 最小和分割

【贪心】

  • 把num各位数字取出放到vec里,升序排列
    • 对于新组成的两个数(设为a、b),每次从vec里拿取两个最小的数分别拼接到它们后面形成新的数
      • 借助x = x*10 + vec[i]
      • 因为最后形成的两个数位数要么一样,要么位数之差为1
        • 取决于原数num的位数是奇还是偶
          • 若为偶,a、b位数一样,拿取的两个最小数放置顺序无所谓
            • 因为当前最小的两个数一定在同一位上,交换放和也不会变
          • 若为奇,a、b位数差1,应该把拿取的两个最小数中更小的那个放在a、b中更小的那个数后面
            • 这样保证每次都把当前未访问过最小数字给到位数多的那个数,从而使得生成的两数和最小
    int splitNum(int num) {
        vector<int> vec;
        while(num){
            vec.push_back(num%10);
            num/=10;
        }
        int len = vec.size();
        sort(vec.begin(), vec.end());
        int num1 = 0, num2 = 0;
        int i = 0;
        for(; i < len; i+=2){
            num1 = num1*10 + vec[i];
            if(i+1 < len) num2 = num2*10 + vec[i+1];
        }
        return num1+num2;
    }
};

第二题-2579. 统计染色格子数

2579. 统计染色格子数

【数学, 找规律】

  • n=k时,
    • 把图形分为上下两部分,其中上半部分包括中间的那行
    • 中间那行:2k-1
    • 上半部分:形成{1, 3, …, 2k-1}的等差数列
      • 首项为1,公差为2,末项为(2k-1),项数为k
      • 总数(即和)= ( 1 + ( 2 k − 1 ) ) ∗ k 2 = k 2 \frac{(1+ (2k-1))*k}{2}=k^2 2(1+(2k1))k=k2
    • 下半部分:形成{1,3,…}的等差数列
      • 比起上半部分,就少了(2k-1)这一项
      • 所以和减掉(2k-1),即 k 2 − ( 2 k − 1 ) k^2-(2k-1) k2(2k1)
    • 总和 = 2 k 2 − 2 k + 1 =2k^2-2k+1 =2k22k+1
    long long coloredCells(int n) {
        return 2ll * n * n - 2ll * n + 1;
    }

第三题-2580. 统计将重叠区间合并成组的方案数

2580. 统计将重叠区间合并成组的方案数

【贪心】

  • 合并区间
    • 贪心:左端点升序排序
      • 从头遍历,记录当前比较过的最大右端点值
      • 对第i个区间:
        • 若区间左端点>right,说明不相交
          • ++cnt
          • 更新right = max(right, interval.right)
        • 若区间左端点<=right,说明相交
          • 更新right = max(right, interval.right)
      • 设合并后的区间有cnt个
  • 因为要分成两组,所以对于每个合并后的区间,有2种选择
    • 去第1组还是去第2组
    • 所以答案为 2 c n t 2^{cnt} 2cnt
    const int mod = 1e9+7;
    int countWays(vector<vector<int>>& ranges) {
        sort(ranges.begin(), ranges.end(), cmp);

        int cnt = 0, right = -1;
        for(vector<int> interval: ranges){
            if(interval[0] > right) ++cnt;
            right = max(right, interval[1]);
        }

        int ans = 1;
        for(int i = 1; i <= cnt; i++){
            ans = (2ll *ans)%mod;
        }
        return ans;
    }
    static bool cmp(vector<int>&a, vector<int>&b){
        return a[0] == b[0]? a[1] > b[1] : a[0] < b[0];
    }

第四题-2581. 统计可能的树根数目

2581. 统计可能的树根数目

【树形DP-换根DP】

节点编号0~(n-1)

  • 换根DP,需要两次DFS
    • 第一次:
      • 求出以0为根的树的guess正确个数
      • BFS:设当前节点为u
        • $cnt[u] = \sum_{v为u的子节点}{cnt[v] + ifExitGuess(u->v)} $
          • 其中ifExitGuess(u->v)
            • =1:存在一个u->v的guess
            • =0:不存在一个u->v的guess
    • 第二次:
      • 换根,求出以i为根的数的guess正确个数
        • i为0~(n-1)
      • 求状态转移:
        • 设u为根,v为其子节点
          • dp[v] = dp[u] + ifExitGuess(u->v) - ifExitGuess(v->u)
        • 从第一次DFS的根节点0开始,递归地往下求
        • 答案就是count{dp[i]>=k} (0<=i<=n-1)
    • tips:
      • 标记gusses(u->v)是否存在
        • 除了可以用map<pair<int, int>, bool>外,
          • 注意unordered_map的key不能用pair
        • 还可以set<long> st; //或unordered_map<long, bool> mp;
          • u和v都是int型,占4字节
          • long占8字节,前4字节标记u,后四字节标记v
            • 状态压缩
          • 用法:st.insert(((long)u << 32 | v));
          • 若求gusses(u->v)出现的次数:
            • unordered_map<long,int> mp;

使用set+状态压缩来标记:

    set<long> st;
    int rootCount(vector<vector<int>>& edges, vector<vector<int>>& guesses, int k) {
        int n = edges.size()+1;

        vector<int> dp(n, 0);
        vector<vector<int>> graph(n);
        for(int i = 0; i <edges.size(); i++){
            int u = edges[i][0], v = edges[i][1];
            graph[u].push_back(v);
            graph[v].push_back(u);
        }
        for(int i = 0; i < guesses.size(); i++){
            int u = guesses[i][0], v = guesses[i][1];
            st.insert((long)u << 32 | v);
        }
        
        dp[0] = dfs(0, graph, -1);
        rootCnt(0, graph, dp, -1);
        
        int cnt = 0;
        for(int i = 0; i < n; i++){
            if(dp[i] >= k) ++cnt;
        }
        return cnt;
    }
    
    int dfs(int u, vector<vector<int>>&graph, int fa){
        int cnt = 0;
        for(int i = 0; i < graph[u].size(); i++){
            int v = graph[u][i];
            if(v == fa) continue;
            cnt += dfs(v, graph, u) + st.count((long)u << 32 | v);
        }
        return cnt;
    }
    void rootCnt(int u, vector<vector<int>>&graph, vector<int>& dp, int fa){
        for(int i = 0; i < graph[u].size(); i++){
            int v = graph[u][i];
            if(v == fa) continue;
            dp[v] = dp[u] + st.count((long)v << 32 | u) - st.count((long)u << 32 | v);
            rootCnt(v, graph, dp, u);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值