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);
     */
    
  • 相关阅读:
    互联网公司做智能硬件要注意什么?
    移动GPU全解读(二)
    java JDK设置环境变量
    hive load文件第一个字段为NULL
    网页版微信和微信公共号扫码登陆原理分析
    Java&amp;Xml教程(九)Java中通过XSD校验XML合法性
    47.Android 自己定义PopupWindow技巧
    ArcGIS中数据之间的转换接口IFeatureDataConverter2
    怎样衡量代码质量?
    iOS -读书笔记-网络请求
  • 原文地址:https://www.cnblogs.com/RioTian/p/13144767.html
Copyright © 2011-2022 走看看