日渐头秃的代码日记 -- 第317场周赛难度大为提升

126 阅读6分钟

这是我参与『掘金日新计划·10月更文挑战』的第5天。 难度大为提升,看不太懂,只能说大为震撼。

一、可被三整除的偶数的平均值

给你一个由正整数组成的整数数组 nums ,返回其中可被 3 整除的所有偶数的平均值。

注意:n 个元素的平均值等于 n 个元素 求和 再除以 n ,结果 向下取整 到最接近的整数。

 

示例 1:

输入: nums = [1,3,6,10,12,15]
输出: 9
解释: 6 和 12 是可以被 3 整除的偶数。(6 + 12) / 2 = 9

示例 2:

输入: nums = [1,2,4,7,10]
输出: 0
解释: 不存在满足题目要求的整数,所以返回 0 。

 

提示:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= 1000

解析

这道题我上来就Wrong了一次,哈哈,没仔细看,要求的是所有偶数,不是被3整除就行了,这不就是被6整除么。。。。。坑

代码

class Solution:
    def averageValue(self, nums: List[int]) -> int:
        n = [x for x in nums if x % 6 == 0]
        if len(n) == 0:
            return 0
        else:
            return sum(n) // len(n)

二、最流行的视频创作者

给你两个字符串数组 creators 和 ids ,和一个整数数组 views ,所有数组的长度都是 n 。平台上第 i 个视频者是 creator[i] ,视频分配的 id 是 ids[i] ,且播放量为 views[i] 。

视频创作者的 流行度 是该创作者的 所有 视频的播放量的 总和 。请找出流行度 最高 创作者以及该创作者播放量 最大 的视频的 id 。

  • 如果存在多个创作者流行度都最高,则需要找出所有符合条件的创作者。
  • 如果某个创作者存在多个播放量最高的视频,则只需要找出字典序最小的 id 。

返回一个二维字符串数组 **answer **,其中 **answer[i] = [creatori, idi] **表示 **creatori 的流行度 最高 且其最流行的视频 id 是 **idi **,可以按任何顺序返回该结果

 

示例 1:

输入: creators = ["alice","bob","alice","chris"], ids = ["one","two","three","four"], views = [5,10,5,4]
输出: [["alice","one"],["bob","two"]]
解释:
alice 的流行度是 5 + 5 = 10 。
bob 的流行度是 10 。
chris 的流行度是 4 。
alice 和 bob 是流行度最高的创作者。
bob 播放量最高的视频 id"two" 。
alice 播放量最高的视频 id"one""three" 。由于 "one" 的字典序比 "three" 更小,所以结果中返回的 id"one"

示例 2:

输入: creators = ["alice","alice","alice"], ids = ["a","b","c"], views = [1,2,2]
输出: [["alice","b"]]
解释:
id 为 "b""c" 的视频都满足播放量最高的条件。
由于 "b" 的字典序比 "c" 更小,所以结果中返回的 id 是 "b"

 

提示:

  • n == creators.length == ids.length == views.length
  • 1 <= n <= 105
  • 1 <= creators[i].length, ids[i].length <= 5
  • creators[i] 和 ids[i] 仅由小写英文字母组成
  • 0 <= views[i] <= 10^5

解析

说了一大堆,其实就按照题意模拟就行了,比较贴近实际业务场景,给个好评,不是为了难度而上难度

代码

from collections import defaultdict
class Solution:
    def mostPopularCreator(self, creators: List[str], ids: List[str], views: List[int]) -> List[List[str]]:
        # {
        #     creator: [(id, view), (id, view)]
        # }
        d = defaultdict(list)
        for i in range(len(creators)):
            creator = creators[i]
            d[creator].append(
                (ids[i], views[i])
            )
        m = 0
        v = []
        for creator, item in d.items():
            sv = sum([x[1] for x in item])
            v.append((creator, sv))
        maxv = max([m[1] for m in v ])
        answer = []
        for creator, item in d.items():
            sv = sum([x[1] for x in item])
            if sv == maxv:
                it = sorted(item)
                tm = max([p[1] for p in it])
                for i, y in it:
                    print(i, y, tm)
                    if y == tm:
                        answer.append([creator, i])
                        break
        return answer

三、美丽整数的最小增量

给你两个正整数 n 和 target 。

如果某个整数每一位上的数字相加小于或等于 target ,则认为这个整数是一个 美丽整数 。

找出并返回满足 n + x 是 美丽整数 的最小非负整数 x 。生成的输入保证总可以使 n 变成一个美丽整数。

 

示例 1:

输入: n = 16, target = 6
输出: 4
解释: 最初,n 是 16 ,且其每一位数字的和是 1 + 6 = 7 。在加 4 之后,n 变为 20 且每一位数字的和变成 2 + 0 = 2 。可以证明无法加上一个小于 4 的非负整数使 n 变成一个美丽整数。

示例 2:

输入: n = 467, target = 6
输出: 33
解释: 最初,n 是 467 ,且其每一位数字的和是 4 + 6 + 7 = 17 。在加 33 之后,n 变为 500 且每一位数字的和变成 5 + 0 + 0 = 5 。可以证明无法加上一个小于 33 的非负整数使 n 变成一个美丽整数。

示例 3:

输入: n = 1, target = 1
输出: 0
解释: 最初,n 是 1 ,且其每一位数字的和是 1 ,已经小于等于 target 。

 

提示:

  • 1 <= n <= 10^12
  • 1 <= target <= 150
  • 生成的输入保证总可以使 n 变成一个美丽整数。

解析

上来先不管三七二十一,暴力方法走一波,果然,超时了。还是得优化一下。

考虑到要像target 靠近,从高位到低位累计求和,超过target的那一瞬间,还剩下几位数,就凑出来几个0就行了.

直接用数学方法搞定。

代码

class Solution:
    def makeIntegerBeautiful(self, n: int, target: int) -> int:
        f = [int(x) for x in str(n)]
        s = sum(f)
        if s <= target:
            return 0
        t = 0
        for i in range(len(f)):
            t += f[i]
            if t > target-1:
                q = len(f) - i
                break
        a = 10 ** q
        res = a -  n % a
        return res

四、移除子树后的二叉树高度

给你一棵 二叉树 的根节点 root ,树中有 n 个节点。每个节点都可以被分配一个从 1 到 n 且互不相同的值。另给你一个长度为 m 的数组 queries 。

你必须在树上执行 m 个 独立 的查询,其中第 i 个查询你需要执行以下操作:

  • 从树中 移除 以 queries[i] 的值作为根节点的子树。题目所用测试用例保证 queries[i]  等于根节点的值。

返回一个长度为 m 的数组 **answer **,其中 **answer[i] **是执行第 i 个查询后树的高度。

注意:

  • 查询之间是独立的,所以在每个查询执行后,树会回到其 初始 状态。
  • 树的高度是从根到树中某个节点的 最长简单路径中的边数 。

 

示例 1:

输入: root = [1,3,4,2,null,6,5,null,null,null,null,null,7], queries = [4]
输出: [2]
解释: 上图展示了从树中移除以 4 为根节点的子树。
树的高度是 2(路径为 1 -> 3 -> 2)。

示例 2:

输入: root = [5,8,9,2,1,3,7,4,6], queries = [3,2,4,8]
输出: [3,2,3,2]
解释: 执行下述查询:
- 移除以 3 为根节点的子树。树的高度变为 3(路径为 5 -> 8 -> 2 -> 4)。
- 移除以 2 为根节点的子树。树的高度变为 2(路径为 5 -> 8 -> 1)。
- 移除以 4 为根节点的子树。树的高度变为 3(路径为 5 -> 8 -> 2 -> 6)。
- 移除以 8 为根节点的子树。树的高度变为 2(路径为 5 -> 9 -> 3)。

 

提示:

  • 树中节点的数目是 n
  • 2 <= n <= 105
  • 1 <= Node.val <= n
  • 树中的所有值 互不相同
  • m == queries.length
  • 1 <= m <= min(n, 10^4)
  • 1 <= queries[i] <= n
  • queries[i] != root.val

解析

周赛的时候这道题没有做出来,最后两个case超时了,回头研究了一下第一名大佬的代码,确实很厉害。

看讨论群,很多大佬都说是经典套路,只能说我见过的套路太少了一些。

代码

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def treeQueries(self, root: Optional[TreeNode], queries: List[int]) -> List[int]:
        height = defaultdict(int)  # 每棵子树的高度
        def get_height(node: Optional[TreeNode]) -> int:
            if node is None: return 0
            height[node] = 1 + max(get_height(node.left), get_height(node.right))
            print(node.val, height[node])
            return height[node]
        get_height(root)
        print("---")
        res = [0] * (len(height) + 1)  # 每个节点的答案
        def dfs(node: Optional[TreeNode], depth: int, rest_h: int) -> None:
            if node is None: return
            depth += 1
            print("nodevalue = %s depth = %s rest_h = %s" % (node.val, depth, rest_h))
            res[node.val] = rest_h
            dfs(node.left, depth, max(rest_h, depth + height[node.right]))
            dfs(node.right, depth, max(rest_h, depth + height[node.left]))
        dfs(root, -1, 0)

        for i, q in enumerate(queries):
            queries[i] = res[q]
        return queries

这里的精髓是dfs(node.left, depth, max(rest_h, depth + height[node.right]))这句代码,在对一个父节点的两个子节点进行遍历的时候,用的是父节点的rest_h,也就是始终可以把整棵树的最大深度携带,从root根节点开始,rest_h是0,但是他的left 和 right,有一个是整棵树的最大深度,而且这个深度会被一直携带到递归结束,真的是秀! 自己构造了一个特殊的例子,方便理解。

image.png