zoukankan      html  css  js  c++  java
  • LeetCode 第 193 场周赛 解题报告

    5436. 一维数组的动态和

    • 时间复杂度:O(n)
    • 知识点:前缀和

    根据题目给出的公式 runningSum[i] = sum(nums[0]…nums[i]),可得:

    • 当 i > 0 时,runningSum[i] = runningSum[i-1] + nums[i]
    • 当 i = 0 时,runningSum[i] = nums[i]
    class Solution {
    public:
        vector<int> runningSum(vector<int>& nums) {
            for(int i = 1;i < nums.size();++i)nums[i] += nums[i - 1];
            return nums;
        }
    };
    

    5437. 不同整数的最少数目

    • 时间复杂度:O(n*logn)
    • 知识点:哈希,排序,贪心

    如果要删除 K 个数之后,剩余的数字种类最少
    那么就要移除尽可能多的类型的数字,
    那么就是要先删除那些出现次数最少的那些数字咯。

    可以先统计每个数字出现的次数,然后对次数进行升序排序,然后尝试删除头部的数字即可。

    class Solution {
    public:
        int findLeastNumOfUniqueInts(vector<int>& arr, int k) {
            unordered_map<int,int>hash;
            int len = arr.size();
            for(int i = 0;i < len;++i)hash[arr[i]]++;
            vector<int>num;
            for(auto it : hash)num.push_back(it.second);
            sort(num.begin(),num.end());
            int m = num.size();
            int ans = m;
            for(int i = 0;i < m;++i){
                if(k >= num[i]){
                    --ans;
                    k -= num[i];
                }else break;
            }
            return ans;
        }
    };
    

    5438. 制作 m 束花所需的最少天数

    • 时间复杂度:O(n*logm)。n为花的数量,m为1e9。
    • 知识点:二分

    首先最暴力的解法,从 1 开始暴力枚举天数 i ,然后检查前 i 天盛开的花是否能满足需求。这样的时间复杂度是 O(n*m)。
    不难发现,如果第 i 天可以满足要求,那么第 i 天之后盛开的花肯定也能满足需求。
    也就是说,答案具备二分的前置要求——单调性。
    接下来我们通过二分找到一个最小的 i,使其满足[0, i-1) 天盛开的花不能满足需求,[i, +∞) 天盛开的花都能满足需求。
    如果不存在这样的 i,那么答案就是 -1。
    设答案可能的取值范围为 [1, 1e9]。首先判断(1+1e9)/2 是否能满足需求。

    • 如果不能,说明答案不可能在[1, (1+1e9)/2] 中。
    • 如果能,说明答案不可能在 ((1+1e9)/2), 1e9] 中。

    依此类推,每次检查都能排除掉一半的候选值。所以做多需要检查约 30 次,即log(1e9) 次。

    image-20200616205547161
    class Solution {
    public:
        bool ok(int mid,vector<int>& b,int m,int k){
            int cnt = 0,num = 0;
            for(int i = 0;i < b.size();++i){
                if(b[i] <= mid)num++;
                else num = 0;
                if(num == k)++cnt,num = 0;
                if(cnt == m)return true;
            }
            return false;
        }
        int minDays(vector<int>& b, int m, int k) {
    		int n = b.size();
            if(n < m * k)return -1;
            int l = 0,r = 1e9;
            while(l < r){
                int mid = l + r >> 1;
                if(ok(mid,b,m,k)) r = mid;
                else l = mid + 1;
            }
            return l;
        }
    };
    

    5439. 树节点的第 K 个祖先

    这道题没接触过就没写了,赛后才知道是树的遍历 + 倍增

    学习评论区大佬的解法

    • 时间复杂度:O(n*logn)
    • 知识点:树的遍历,倍增
    • 如果通过预处理,可以知道每个节点的第 1,2,4,8,16…个祖先节点。那么对于每次询问,最多只会向上跳log(n)次。

      image-20200616205627222

      如上图所示,每个点最多会建立logn条向上的边。以寻找结点5的第5个祖先为例,可以转化为寻找结点1的第1个祖先,再转化为寻找结点0个第0个祖先,即结点0。

    倍增建边过程:

    如果结点 i 个所有祖先结点已经建边完成,那么可以询问 i 个第 1,2,4,8,16 … 个祖先结点,直到其某个祖先节点不存在。对于每次询问利用祖先结点已经建好的边可以O(logn)的时间复杂度完成。所以可以按照先序遍历的顺序来进行建边。

    class TreeAncestor {
        vector<int> anc[50000];
        bool mark[50000];
        void dfs(const vector<int> &parent, int id) {
            if(parent[id] == -1 || mark[id] == true) {
                return;
            }
            dfs(parent, parent[id]);
            for(int i = 1; ; i <<= 1) {
                int p = getKthAncestor(parent[id], i-1);
                if(p == -1) {
                    break;
                }
                anc[id].push_back(p);
            }
            mark[id] = true;
        }
    public:
        TreeAncestor(int n, vector<int>& parent) {
            memset(mark, false, sizeof(bool)*n);
            for(int i = 0; i < n; i++) {
                dfs(parent, i);
            }
        }
    
        int getKthAncestor(int node, int k) {
            if(node == -1) {
                return -1;
            }
            if(k == 0) {
                return node;
            }
            if(node == 0) {
                return -1;
            }
            int i = 1, pos = 0;
            while(i*2 <= k && pos+1 < anc[node].size()) {
                i *= 2;
                pos++;
            }
            return getKthAncestor(anc[node][pos], k-i);
        }
    };
    
    /**
     * Your TreeAncestor object will be instantiated and called as such:
     * TreeAncestor* obj = new TreeAncestor(n, parent);
     * int param_1 = obj->getKthAncestor(node,k);
     */
    
  • 相关阅读:
    BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
    BZOJ 2134: 单选错位( 期望 )
    BZOJ 1030: [JSOI2007]文本生成器( AC自动机 + dp )
    BZOJ 2599: [IOI2011]Race( 点分治 )
    BZOJ 3238: [Ahoi2013]差异( 后缀数组 + 单调栈 )
    ZOJ3732 Graph Reconstruction Havel-Hakimi定理
    HDU5653 Bomber Man wants to bomb an Array 简单DP
    HDU 5651 xiaoxin juju needs help 水题一发
    HDU 5652 India and China Origins 并查集
    HDU4725 The Shortest Path in Nya Graph dij
  • 原文地址:https://www.cnblogs.com/RioTian/p/13144767.html
Copyright © 2011-2022 走看看