[LeetCode周赛复盘] 第 306 场周赛20220814

[LeetCode周赛复盘] 第 306 场周赛20220814

    • 一、本周周赛总结
    • 二、 [Easy] 6148. 矩阵中的局部最大值
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 三、[Medium] 6149. 边积分最高的节点
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 四、[Medium] 6150. 根据模式串构造最小数字
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现
    • 五、[Hard] 6151. 统计特殊整数
      • 1. 题目描述
      • 2. 思路分析
      • 3. 代码实现

一、本周周赛总结

  • 几乎全是模拟题,除了第二题是一道同向双指针。
  • 第二次打力扣周赛就ak了,这周的题好水啊。
  • 前排的大佬真就做阅读理解呗,读完题=会了。
    [LeetCode周赛复盘] 第 306 场周赛20220814_第1张图片

二、 [Easy] 6148. 矩阵中的局部最大值

链接: 6148. 矩阵中的局部最大值

1. 题目描述

[LeetCode周赛复盘] 第 306 场周赛20220814_第2张图片

2. 思路分析

定级Easy。
按题意暴力模拟即可。

3. 代码实现

class Solution:
    def largestLocal(self, grid: List[List[int]]) -> List[List[int]]:
        m,n = len(grid),len(grid[0])
        ans = [[0]* n for _ in range(m)]
        for i in range(1,m-1):
            for j in range(1,n-1):
                ans[i][j] = max(grid[i-1][j-1:j+2]+grid[i][j-1:j+2]+grid[i+1][j-1:j+2])
        
        return [ans[i][1:n-1] for i in range(1,m-1)]

三、[Medium] 6149. 边积分最高的节点

链接: 6149. 边积分最高的节点

1. 题目描述

[LeetCode周赛复盘] 第 306 场周赛20220814_第3张图片

2. 思路分析

一开始看成所有路径指向它的点,其实是直接指向,看邻边累加即可。

3. 代码实现

class Solution:
    def edgeScore(self, edges: List[int]) -> int:
        n = len(edges)
        f = [0] * n
        vis = [0] * n
        for u,v in enumerate(edges):
            f[v] += u
        # print(f)
        ans = 0
        for i in range(1,n):
            if f[i]>f[ans]:
                ans = i
        return ans

四、[Medium] 6150. 根据模式串构造最小数字

链接: 6150. 根据模式串构造最小数字

1. 题目描述

[LeetCode周赛复盘] 第 306 场周赛20220814_第4张图片

2. 思路分析

定级Medium。

  • dp预处理一个r数组,r[i]代表数i右边有多少个D。
  • 遇到I则直接置0.
  • 然后用有序集合维护剩余的数字,如果当前位置右边有x个D,则代表它最小只能取当前第x小的数字。

3. 代码实现

class Solution:
    def smallestNumber(self, pattern: str) -> str:
        n = len(pattern)+1
        from sortedcontainers import SortedList
        s = SortedList(range(1,n+1))
        
        r = [0]*n
        for i in range(n-2,-1,-1):
            if pattern[i] == 'D':
                r[i] = r[i+1] +1
            else:
                r[i] = 0
        ans=[0]*n
        for i in range(n):
            if r[i]<=0:
                ans[i] = s.pop(0)
                # s.popleft()
            else:
                ans[i] = s.pop(r[i])
        return ''.join(map(str,ans))

五、[Hard] 6151. 统计特殊整数

链接: 6151. 统计特殊整数

1. 题目描述

[LeetCode周赛复盘] 第 306 场周赛20220814_第5张图片

2. 思路分析

定级Hard
数位dp,参考力扣 357. 统计各位数字都不同的数字个数.

  • 记录一下灵神的数位dp通用模板。
  • 先把数字x转化成字符串s。
  • 定义一个记忆化函数@cache def f(i,mask,is_limit,is_num):
  • 函数返回:在前边用了mask的集合后,约束从左开始第i位后边的数字能构造出的数目。
  • 其中i代表现在运算到第几位。
  • mask代表用了哪些数字,有的题目用不到,或者是其他约束。
  • is_limit代表当前位是否受到了对应s串上对应位数字的约束,比如针对’123’这个串,当前两位填了’12’,那么第3位只能填0123.
    • 也就是说,当is_limit==True,则当前位最多填int(s[i];否则能填到9
  • is_num,也叫is_not_lead,代表当前位的前一位是否填了数字,本题如果没填数字,即本位是开头,那么等于本位也可以跳过,相当于多一种情况。

3. 代码实现

数位DP通用模板

class Solution:
    def countSpecialNumbers(self, x: int) -> int:
        s = str(x)
        n = len(s)
        @cache
        def f(i,mask,is_limit,is_num):
            if i == n:
                return int(is_num)
            ans = 0
            if not is_num:
                ans += f(i+1,mask,False,False)
            r = int(s[i]) if is_limit else 9
            l = 0 if is_num else 1
            for j in range(l,r+1):
                if not mask>>j&1:
                    ans += f(i+1,mask|(1<<j),is_limit and j == r,True)
            return ans 
        return f(0,0,True,False)


class Solution:
    def countSpecialNumbers(self, x: int) -> int:
        f = [[0]*10 for _ in range(10)]
        for i in range(1,10):
            for j in range(1,10):
                cur = 1
                for k in range(i,j+1):
                    cur *= k
                f[i][j] = cur
        
        t = x
        nums = []
        while t:
            nums.append(t%10)
            t //= 10
        n = len(nums)
        if n<=1:
            return x
        ans = 0
        p = 1
        s = 0
        for i in range(n-1,-1,-1):
            cur = nums[i]
            cnt = 0
            for j in range(cur-1,-1,-1):
                if i == n-1 and j == 0:
                    continue
                if ((s>>j)&1) == 0:
                    cnt += 1
            a = 10-p
            b = a-(n-p)+1
            ans +=  (cnt * f[b][a] if b<=a else cnt)
            if ((s>>cur)&1) == 1:
                break
            s |= 1<<cur
            if i == 0:
                ans += 1            
            
            p+=1
            
        ans += 10
        last = 9
        for i in range(2,n):
            cur = last*(10-i+1)
            ans += cur
            last = cur
        return ans-1                                                                      

你可能感兴趣的