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) {
        vector<int> res(nums.size());
        res[0] = nums[0];
        for(int i = 1; i < nums.size(); i++) {
            res[i] = nums[i] + res[i-1];
        }
        return res;
    }
};

5437. 不同整数的最少数目

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

如果要删除 K 个数之后,剩余的数字种类最少
那么就要移除尽可能多的类型的数字,
那么就是要先删除那些出现次数最少的那些数字咯。
LeetCode 第 193 场周赛_第1张图片
可以先统计每个数字出现的次数,然后对次数进行升序排序,然后尝试删除头部的数字即可。

class Solution {
public:
    int findLeastNumOfUniqueInts(vector<int>& arr, int k) {
        unordered_map<int, int> pos;
        int count[100000] = {0};
        for(int i = 0; i < arr.size(); i++) {
            auto it = pos.find(arr[i]);
            if(it == pos.end()) {
                it = pos.insert(make_pair(arr[i], pos.size())).first;
            }
            count[it->second]++;
        }
        sort(count, count+pos.size(), less<int>());
        int anw = pos.size();
        for(int i = 0; i < pos.size() && k >= count[i]; i++) {
            k -= count[i];
            anw--;
        }
        return anw;
    }
};

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) 次。
LeetCode 第 193 场周赛_第2张图片

bool mark[100000];
class Solution {
    bool check(const vector<int> &bloomDay, int m, int k, int day) {
        int pre = -1;
        for(int i = 0; i < bloomDay.size(); i++) {
            mark[i]= bloomDay[i] <= day;
            if(mark[i] == true) {
                if(i - pre >= k) {
                    if(--m == 0) {
                        return true;
                    }
                    pre = i;
                }
            } else {
                pre = i;
            }
        }
        return false;
    }
public:
    int minDays(vector<int>& bloomDay, int m, int k) {
        int L = 1, R = 1000000000;
        int anw = -1;
        while(L <= R) {
            int mid = (L+R)>>1;
            if(check(bloomDay, m, k, mid)) {
                anw = mid;
                R = mid-1;
            } else {
                L = mid+1;
            }
        }
        return anw;
    }
};

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

  • 时间复杂度:O(n*logn)
  • 知识点:树的遍历,倍增
    LeetCode 第 193 场周赛_第3张图片
    如果通过预处理,可以知道每个节点的第 1,2,4,8,16…个祖先节点。那么对于每次询问,最多只会向上跳log(n)次。
    LeetCode 第 193 场周赛_第4张图片
    如上图所示,每个点最多会建立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);
 */

LeetCode 第 193 场周赛_第5张图片

你可能感兴趣的:(题解给力,数据结构,算法)