• [LeetCode周赛复盘] 第 361 场周赛20230906


    一、本周周赛总结

    • 幸好上周练习了倍增,否则T4就垮了。
    • T1 数位DP。
    • T2 贪心。
    • T3 同余+前缀和计数。
    • T4 树上前缀和+lca。
      在这里插入图片描述

    2843. 统计对称整数的数目

    2843. 统计对称整数的数目

    1. 题目描述

    在这里插入图片描述

    2. 思路分析

    这个数据范围实际上可以枚举。
    
    • 1
    • 当困难题用数位DP做,可以达到log2high。
    • 注意,两边的和可以合并成一个diff,如果不合并就是立方复杂度。
    • 递归时,只需要多传递一个填数起始点,就可以计算出这个数的长度,以及填数时是算左边还是右边。
    • 另外,这种high-low的以后一律写减法,尽量不考虑一个dfs同时搞上下界,思维量大很多。

    3. 代码实现

    class Solution:
        def countSymmetricIntegers(self, low: int, high: int) -> int:
    
            def f(s):
                n = len(s)
                @cache
                def f(i,p,st,is_limit):  # i,(suml-sumr),数字起点位置(代替is_num)
                    if p<0:return 0
                    if i == n:
                        return int(st!=-1 and p == 0)
                    ans = 0 
                    if st==-1:
                        ans += f(i+1,p,-1,False)
                    if st != -1 or (n-i)%2 == 0:  # 只有偶数长度有意义
                        up = int(s[i]) if is_limit else 9
                        down = 1 if st==-1 else 0
                        if st == -1:
                            st = i
                        mid = st+(n-st)//2
                        d = 1 if i < mid else -1
                        for j in range(down,up+1):                   
                            ans += f(i+1,p+j*d,st,is_limit and up == j)
                    return ans 
                return f(0,0,-1,True)
            return f(str(high)) - f(str(low-1))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    2844. 生成特殊数字的最少操作

    2844. 生成特殊数字的最少操作

    1. 题目描述

    在这里插入图片描述

    2. 思路分析

    • 能被25整除的数字,末两位一定是 00,25,50,75。
    • 那么从末尾依次找这几个字符即可,能找到第二个字符,就是途经的长度-1。
    • 另外,如果都没找到,至少可以把除了0的全删除,变成0也视为合法,即删除n-count(0)个。

    3. 代码实现

    class Solution:
        def minimumOperations(self, num: str) -> int:
            n = len(num)
            num = num[::-1]
            five = zero = -1
            for i,v in enumerate(num):
                if v == '5':
                    if zero != -1:
                        return i - 1
                    five = i
                elif v == '0':
                    if zero != -1:
                        return i-1
                    zero = i 
                elif v == '2' or v == '7':
                    if five != -1:
                        return i-1 
    
            return n - num.count('0')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2845. 统计趣味子数组的数目

    2845. 统计趣味子数组的数目

    1. 题目描述

    在这里插入图片描述

    2. 思路分析

    • 典题,同余计数。
    • 第一个条件可以看成nums全是01,那么题目变成问有多少子段,和 ≡ k(% mod)。
    • 那么可以用前缀和+计数,假设当前右端点和为s,需求s-x = k,变化得x = s-k。
    • 即它可以和所有(s-k)%mod的左端点组合,只需记录每个前缀和数量。

    3. 代码实现

    class Solution:
        def countInterestingSubarrays(self, nums: List[int], modulo: int, k: int) -> int:
            n = len(nums)
            a = [int(v%modulo==k) for v in nums]
            # cnt = [1]+[0]*n  # re 下标范围应该是module不是n
            cnt = Counter([0])
            s = ans = 0 
            for v in a:
                s += v 
                ans += cnt[(s-k)%modulo]
                cnt[s%modulo] += 1
            return ans
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2846. 边权重均等查询

    2846. 边权重均等查询

    1. 题目描述

    在这里插入图片描述
    在这里插入图片描述

    2. 思路分析

    • 设一条长为a的路径上最多的权出现b次,那么修改次数就是a-b。则本题转化成:求任意路径的长度和边权最大频次。
    • 看到边权值域只有26,考虑在值域上暴力计数。
    • 如何求子段上的一条路径贡献呢,如果是一维数组我们通常考虑前缀和。这里是树,也是可以的。
    • 有了快速计算子段的方法,还要考虑树的特殊计算方法。
    • 两个点可能分别在两个子树里,可以画图思考一下。
    • 计算时则可以先求出lca,画图发现:如果u是v的祖先,则可以套用普通的前缀和(祖先可以用lca==u来判断);否则,是两边加起来,再减去两次lca的前缀和;而第二种其实包含了第一种。

    3. 代码实现

    class Solution:
        def minOperationsQueries(self, n: int, edges: List[List[int]], queries: List[List[int]]) -> List[int]:
            g = [[] for _ in range(n)]
            for u,v,w in edges:
                g[v].append((u,w))
                g[u].append((v,w))
            m = n.bit_length()
            pa = [[-1]*m for _ in range(n)]
            pre=[[0]*27 for _ in range(n)]
            s = [0]*27
            depth = [0]*n
            def dfs(u,fa,ww):
                s[ww] += 1
                pre[u] = s[:]                                
                pa[u][0] = fa 
                for v,w in g[u]:
                    if v == fa:continue 
                    depth[v] = depth[u] + 1
                    dfs(v,u,w)
                s[ww] -= 1 
            dfs(0,-1,0)
            for j in range(m-1):
                for i in range(n):
                    p = pa[i][j]
                    pa[i][j+1] = pa[p][j]
    
            def get_kth_ancestor(u,k):
                for i in range(k.bit_length()):
                    if k>>i&1:
                        u = pa[u][i]
                return u
            def get_lca(u,v):
                if depth[u] > depth[v]:
                    u,v = v,u 
                v = get_kth_ancestor(v,depth[v]-depth[u])
                if u == v:
                    return u 
                for j in range(m-1,-1,-1):
                    pu,pv = pa[u][j],pa[v][j]
                    if pu != pv:
                        u,v = pu,pv 
                return pa[u][0]
            ans = []
            # for u,v in queries:
            #     p = [0]*27
            #     if depth[u] > depth[v]:
            #         u,v = v,u
            #     lca = get_lca(u,v)
            #     if lca == u:
            #         for i,(x,y) in enumerate(zip(pre[u],pre[v])):
            #             p[i] += y-x
            #     else:                
            #         for i,(x,y,z) in enumerate(zip(pre[u],pre[v],pre[lca])):
            #             p[i] += y+x-2*z
            #     p[0] = 0 
            #     ans.append(sum(p)-max(p))
            for u,v in queries:
                p = [0]*27           
                lca = get_lca(u,v)
                for i,(x,y,z) in enumerate(zip(pre[u],pre[v],pre[lca])):
                    p[i] += y+x-2*z
                
                ans.append(sum(p)-max(p))
            return ans    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    参考链接

  • 相关阅读:
    数据处理:一维数组转成树状结构(递归和非递归),树状结构转成扁平化数组(递归和非递归)
    CCF CSP认证 历年题目自练Day37
    VMware 配置记录
    HTML5Plus
    01科技文献
    【MATLAB】小波 MFE_SVM_LSTM 神经网络时序预测算法
    亚信科技AntDB数据库 高并发、低延迟、无死锁,深入了解AntDB-M元数据锁的实现
    【牛客刷题】每日一练——回文字符串
    01 顺序表
    LaTeX 数学公式常见问题及解决方案
  • 原文地址:https://blog.csdn.net/liuliangcan/article/details/132714729