力扣第 454 场周赛

本文最后更新于 2 分钟前,文中所描述的信息可能已发生改变。

3582. 为视频标题生成标签 - 力扣(LeetCode)

解题思路

用库函数实现首字母大写,其余小写

示例代码

python
class Solution:
    def generateTag(self, caption: str) -> str:
        ans = ['#']
        for i, c in enumerate(caption.split()):
            ans.append(c.title() if i else c.lower())
        return ''.join(ans)[:100]

3583. 统计特殊三元组 - 力扣(LeetCode)

解题思路

哈希表,或前后缀分解

示例代码

python
class Solution:
    def specialTriplets(self, nums: List[int]) -> int:
        mod = 10 ** 9 + 7
        d = defaultdict(int)
        cnt = defaultdict(int)
        ans = s = 0
        for i, x in enumerate(nums):
            if x == 0:
                s += 1
                continue
            d[(x * 2, x)] += cnt[x * 2]
            cnt[x] += 1
            ans += d[(x, x // 2)]
        return (ans + comb(s, 3)) % mod
python
class Solution:
    def specialTriplets(self, nums: List[int]) -> int:
        mod = 10 ** 9 + 7
        suf = Counter(nums)
        pre = defaultdict(int)
        ans = 0
        for x in nums:
            suf[x] -= 1
            ans += pre[x * 2] * suf[x * 2]
            pre[x] += 1
        return ans % mod

3584. 子序列首尾元素的最大乘积 - 力扣(LeetCode)

解题思路

前后缀最值,代码复用

或脑筋急转弯,见参考

参考:脑筋急转弯 + 枚举右维护左(Python/Java/C++/Go)

示例代码

python
class Solution:
    def maximumProduct(self, nums: List[int], m: int) -> int:
        n = len(nums)
        def cal(f, initial):
            pre = [initial] * (n + 1)
            suf = [initial] * (n + 1)
            for i, x in enumerate(nums):
                pre[i + 1] = f(pre[i], x)
            for i in range(n - 1, -1, -1):
                suf[i] = f(suf[i + 1], nums[i])
            ans = -inf
            for i in range(n - m + 1):
                ans = max(ans, pre[i + 1] * suf[i + m - 1])
            return ans
        return max(cal(max, -inf), cal(min, inf))
python
class Solution:
    def maximumProduct(self, nums: List[int], m: int) -> int:
        ans = mx = -inf
        mn = inf
        for i in range(m - 1, len(nums)):
            # 维护左边 [0,i-m+1] 中的最小值和最大值
            y = nums[i - m + 1]
            mn = min(mn, y)
            mx = max(mx, y)
            # 枚举右
            x = nums[i]
            ans = max(ans, x * mn, x * mx)
        return ans

3585. 树中找到带权中位节点 - 力扣(LeetCode)

解题思路

中心扩展,枚举每个节点,时间复杂度O(n*n),包超时的

带权 lca,判段左右路径权值,在沿路径寻找中位节点

参考:【模板】最近公共祖先 LCA(Python/Java/C++/Go)

示例代码

python
class Solution:
    def findMedian(self, n: int, edges: List[List[int]], queries: List[List[int]]) -> List[int]:
        g = LcaWithWeight(edges)
        ans = [0] * len(queries)
        for i, (u, v) in enumerate(queries):
            if u == v:
                ans[i] = u
                continue
            lca = g.get_lca(u, v)
            dis_uv = g.dis[u] + g.dis[v] - 2 * g.dis[lca]
            half = (dis_uv + 1) // 2
            if g.dis[u] - g.dis[lca] < half:
                ans[i] = g.upto_dis(v, dis_uv - half)
            else:
                to = g.upto_dis(u, half - 1)
                ans[i] = g.pa[to][0]
        return ans
py
from typing import List


class LcaWithWeight:
    __slots__ = ["depth", "dis", "pa", "m"]

    def __init__(self, edges: List[List[int]]) -> None:
        n = len(edges) + 1
        g = [[] for _ in range(n)]
        self.m = m = n.bit_length()
        self.depth = depth = [0] * n
        self.dis = dis = [0] * n
        self.pa = pa = [[-1] * m for _ in range(n)]

        for x, y, w in edges:
            g[x].append((y, w))
            g[y].append((x, w))

        q = [0]
        for u in q:
            for v, w in g[u]:
                if v == pa[u][0]:
                    continue
                pa[v][0] = u
                depth[v] = depth[u] + 1
                dis[v] = dis[u] + w
                q.append(v)

        for i in range(m - 1):
            for x in range(n):
                if (p := pa[x][i]) != -1:
                    pa[x][i + 1] = pa[p][i]

    def get_kth_ancestor(self, x: int, k: int) -> int:
        """返回 x 的第 k 个祖先"""
        for i in range(k.bit_length()):
            if k >> i & 1:
                x = self.pa[x][i]
                if x == -1:
                    break
        return x

    def get_lca(self, x: int, y: int) -> int:
        """返回 x 和 y 的最近公共祖先(节点编号从 0 开始)"""
        if self.depth[x] > self.depth[y]:
            x, y = y, x
        y = self.get_kth_ancestor(y, self.depth[y] - self.depth[x])
        if x == y:
            return x
        for i in reversed(range(len(self.pa[x]))):
            if self.pa[x][i] != self.pa[y][i]:
                x = self.pa[x][i]
                y = self.pa[y][i]
        return self.pa[x][0]

    def get_dis(self, x: int, y: int) -> int:
        """返回 x 和 y 之间的路径权值和(distance)"""
        return self.dis[x] + self.dis[y] - 2 * self.dis[self.get_lca(x, y)]

    def upto_dis(self, x: int, d: int) -> int:
        """返回 x 向上跳至多 d 距离能到达的最远节点"""
        dx = self.dis[x]
        for i in range(self.m - 1, -1, -1):
            p = self.pa[x][i]
            if p != -1 and dx - self.dis[p] <= d:
                x = p
        return x
LeetCode Weekly Contest 453
LeetCode Biweekly Contest 158