LeetCode 第 193 场周赛

一维数组的动态和

给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] = sum(nums[0]…nums[i]) 。

请返回 nums 的动态和。

思路

前缀和模板即可

class Solution:
    def runningSum(self, nums: List[int]) -> List[int]:
        ret = [0] * len(nums)
        for idx, val in enumerate(nums):
            if idx == 0:
                ret[idx] += val
            else:
                ret[idx] = val + ret[idx - 1]
        return ret

不同整数的最少数目

给你一个整数数组 arr 和一个整数 k 。现需要从数组中恰好移除 k 个元素,请找出移除后数组中不同整数的最少数目。
示例:

输入:arr = [4,3,1,1,3,3,2], k = 3
输出:2
解释:先移除 4、2 ,然后再移除两个 1 中的任意 1 个或者三个 3 中的任意 1 个,最后剩下 1 和 3 两种整数。

思路

统计每个元素和出现次数, 按照出现次数从小到大排序, 然后删除 k 个元素即可.
优化: 可以通过小根堆优化. 简单来说, 如果当前剩余可移除元素个数大于堆顶的数字, 那么弹出, 燃火更新当前可移除元素个数, 最后统计堆的规模即可.
我没有考虑到优化, 直接放原始的代码

class Solution:
    def findLeastNumOfUniqueInts(self, arr: List[int], k: int) -> int:
        from collections import Counter
        counter = Counter(arr)
        kv = sorted(counter.items(), key = lambda x: x[1])
        ret = 0
        for idx, (key, v) in enumerate(kv):
            print(key, v)
            if v <= k:
                k -= v
            else:
                ret += 1
        return ret

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

给你一个整数数组 bloomDay,以及两个整数 m 和 k 。

现需要制作 m 束花。制作花束时,需要使用花园中 相邻的 k 朵花 。

花园中有 n 朵花,第 i 朵花会在 bloomDay[i] 时盛开,恰好 可以用于 一束 花中。

请你返回从花园中摘 m 束花需要等待的最少的天数。如果不能摘到 m 束花则返回 -1 。

示例:

输入:bloomDay = [1,10,3,10,2], m = 3, k = 1
输出:3
解释:让我们一起观察这三天的花开过程,x 表示花开,而 _ 表示花还未开。
现在需要制作 3 束花,每束只需要 1 朵。
1 天后:[x, _, _, _, _]   // 只能制作 1 束花
2 天后:[x, _, _, _, x]   // 只能制作 2 束花
3 天后:[x, _, x, _, x]   // 可以制作 3 束花,答案为 3

输入:bloomDay = [7,7,7,7,12,7,7], m = 2, k = 3
输出:12
解释:要制作 2 束花,每束需要 3 朵。
花园在 7 天后和 12 天后的情况如下:
7 天后:[x, x, x, x, _, x, x]
可以用前 3 朵盛开的花制作第一束花。但不能使用后 3 朵盛开的花,因为它们不相邻。
12 天后:[x, x, x, x, x, x, x]
显然,我们可以用不同的方式制作两束花。

思路

开始感觉是动态规划问题, 在给定数组里面找 m 个长为 k 的子数组, 然后超时了.
一个思路是枚举等待的天数, 从 1 开始, 当找到第一个符合要求的天数时, 肯定是最小的. 给定天数, 遍历数组就可以找到对应天数可以制作多少束花. 这个思路可以用二分来优化. 假设数组有 k 个元素, 数组中元素最大值为 n, 那么时间复杂度为 O ( n log ⁡ ( k ) ) O(n\log(k)) O(nlog(k))
代码如下:

class Solution:
    def minDays(self, bloomDay: List[int], m: int, k: int) -> int:
        def isValid(num):
            cnt = 0
            ret = 0
            for val in bloomDay:
                if val <= num:
                    cnt += 1
                else:
                    cnt = 0
                if cnt == k:
                    ret += 1
                    cnt = 0
                if ret == m:
                    return True
            return False
        
        lo, hi = 0, max(bloomDay)
        while lo <= hi:
            mid = (lo + hi) // 2
            if isValid(mid):
                hi = mid - 1
            else:
                lo = mid + 1
        if isValid(hi + 1): return hi + 1
        return -1

树节点的第 K 个祖先

给你一棵树,树上有 n 个节点,按从 0 到 n-1 编号。树以父节点数组的形式给出,其中 parent[i] 是节点 i 的父节点。树的根节点是编号为 0 的节点。

请你设计并实现 getKthAncestor(int node, int k) 函数,函数返回节点 node 的第 k 个祖先节点。如果不存在这样的祖先节点,返回 -1 。

树节点的第 k 个祖先节点是从该节点到根节点路径上的第 k 个节点。
示例:

输入:
["TreeAncestor","getKthAncestor","getKthAncestor","getKthAncestor"]
[[7,[-1,0,0,1,1,2,2]],[3,1],[5,2],[6,3]]

输出:
[null,1,0,-1]

解释:
TreeAncestor treeAncestor = new TreeAncestor(7, [-1, 0, 0, 1, 1, 2, 2]);

treeAncestor.getKthAncestor(3, 1);  // 返回 1 ,它是 3 的父节点
treeAncestor.getKthAncestor(5, 2);  // 返回 0 ,它是 5 的祖父节点
treeAncestor.getKthAncestor(6, 3);  // 返回 -1 因为不存在满足要求的祖先节点

思路

这是公共祖先问题的简化版本, 相关知识为倍增法. 如果常规方法来查, 比如查某个节点的第n个祖先节点, 那么需要查找 n 次, 多次查找时间复杂度过高.
例如给定 n=15, 常规方法要查 15 次, 但是有一种思路是这样: 先找到他的15 = 8 + 4 + 2 + 1, 那么先找到原始节点的第 8 个祖先节点, 在找其第 4 个祖先节点, 然后第 2 个, 第 1 个, 这样只需查找 4 次, 查找的复杂度就降下来了.
可以在写入数组的时候, 构造查找表pre[i][j] 表示第 i 个节点的第 2 j 2^j 2j 个祖先节点是谁 其递推关系为
p r e [ i ] [ j ] = p r e [ p r e [ i ] [ j − 1 ] ] [ j − 1 ] pre[i][j] = pre\left[pre[i][j- 1]\right][j - 1] pre[i][j]=pre[pre[i][j1]][j1]
例如, 第2 个节点的第 16(j - 1) 个祖先节点, 为第 2 个节点的第 8 个(i, j - 1)祖先的第 8(j - 1)个祖先
建表的时候, 时间复杂度是 O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n))
但查询快了很多
代码如下:

class TreeAncestor:

    def __init__(self, n: int, parent: List[int]):
        pre = [[-1] * 16 for _ in range(n)]
        for i, pi in enumerate(parent):
            pre[i][0] = pi
        for j in range(1, 16):
            for i in range(n):
                if pre[i][j - 1] == -1:
                    continue
                pre[i][j] = pre[pre[i][j - 1]][j - 1]
        self.pre = pre
        
    def getKthAncestor(self, node: int, k: int) -> int:
        for i in range(15, -1, -1):
            if (k >> i) & 1:
                node = self.pre[node][i]
            if node == -1:
                break
        return node
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值