[LeetCode周赛复盘] 第 298 场周赛20220619

一、本周周赛总结

  • 好难啊,我好菜。
  • 第四题12:01想出思路,12:19写完提交通过,要是早点想到就好了。
  • 过了3题,我是憨批。
    在这里插入图片描述

二、 [Easy] 5242. 兼具大小写的最好英文字母

链接: 5242. 兼具大小写的最好英文字母

1. 题目描述

给你一个由英文字母组成的字符串 s ,请你找出并返回 s 中的 最好 英文字母。返回的字母必须为大写形式。如果不存在满足条件的字母,则返回一个空字符串。

最好 英文字母的大写和小写形式必须 都 在 s 中出现。

英文字母 b 比另一个英文字母 a 更好 的前提是:英文字母表中,b 在 a 之 后 出现。

2. 思路分析

定级Easy。
按题意模拟即可。
大小写转换技巧:

  • a^32:互相转换
  • a|32:转小写
  • a&-33:转大写

3. 代码实现

class Solution:
    def greatestLetter(self, s: str) -> str:
        ans = ''
        visited = set(s)
        for c in s:
            d = chr(ord(c)^32)
            if d in visited:
                ans = max(ans,chr(ord(d)&-33))
        
        if len(ans) ==0:
            return ans
        return ans

三、[Medium] 5218. 个位数字为 K 的整数之和

链接: 5218. 个位数字为 K 的整数之和

1. 题目描述

给你两个整数 numk ,考虑具有以下属性的正整数多重集:

  • 每个整数个位数字都是 k
  • 所有整数之和是 num
    返回该多重集的最小大小,如果不存在这样的多重集,返回 -1 。

注意:

  • 多重集与集合类似,但多重集可以包含多个同一整数,空多重集的和为 0 。
  • 个位数字 是数字最右边的数位。

2. 思路分析

定级Medium。

  • 因为数字任选,因此我们用个位数乘倍数找复合的尾数即可,这个倍数就是答案。
  • 先做一遍乘法表,记下k的倍数中,目标尾数出现时最少要乘几。
  • 最后如果num小于这个倍数*k,那么是不行的。
  • 如果num大于等于倍数*k,则k可以任意调整十位数百位数,一定可以满足题意。

3. 代码实现

class Solution:
    def minimumNumbers(self, num: int, k: int) -> int:
        if num == 0:
            return 0
        w = num%10
        cnt = defaultdict(lambda :10**9)  # k的倍数尾数最小倍数
        min_mul = defaultdict(lambda :10**9)
        for i in range(1,11):
            wei = k*i%10
            cnt[wei] = min(cnt[wei],i)
            min_mul[wei] = min(min_mul[wei],k*i)
        if w not in cnt:
            return -1
        if num < k * cnt[w]:
            return -1
        return cnt[w]

四、[Medium] 6099. 小于等于 K 的最长二进制子序列

链接: 6099. 小于等于 K 的最长二进制子序列

1. 题目描述

给你一个二进制字符串 s 和一个正整数 k 。

请你返回 s 的 最长 子序列,且该子序列对应的 二进制 数字小于等于 k 。

注意:

  • 子序列可以有 前导 0 。
  • 空字符串视为 0 。
  • 子序列 是指从一个字符串中删除零个或者多个字符后,不改变顺序得到的剩余字符序列。

2. 思路分析

定级Medium。

  • 因为是找子序列,而不是子串,那么所有0组成的串一定满足(题干保证k>=1)。
  • 而所有前导的0也是需要的。
  • 假设我们找到一个位置i,它右边可以找到一个最大的子串,十进制值j<=k,那么它i左边的所有0都应该计算,再加上这个子串本身的长度就可以拿来更新答案。
  • 提前预处理一个数组,a[i]代表i前边有几个0.

3. 代码实现

class Solution:
    def longestSubsequence(self, s: str, k: int) -> int:
        n = len(s)
        a = [0]*(n+1)
        for i in range(1,n+1):
            a[i] = a[i-1]
            if s[i-1] == '0':
                a[i] += 1
        # print(a)
        ans = max(a)
        t = ''
        for i in range(n-1,-1,-1):
            t = s[i] + t
            while t and int(t,2)>k:
                t = t[:-1]
            if int(t,2)<=k:
                ans = max(ans,len(t)+a[i])
        return ans

五、[Hard] 5254. 卖木头块

链接: 5254. 卖木头块

1. 题目描述

给你两个整数 m 和 n ,分别表示一块矩形木块的高和宽。同时给你一个二维整数数组 prices ,其中 prices[i] = [hi, wi, pricei] 表示你可以以 pricei 元的价格卖一块高为 hi 宽为 wi 的矩形木块。

每一次操作中,你必须按下述方式之一执行切割操作,以得到两块更小的矩形木块:

  • 沿垂直方向按高度 完全 切割木块,或
  • 沿水平方向按宽度 完全 切割木块
    在将一块木块切成若干小木块后,你可以根据 prices 卖木块。你可以卖多块同样尺寸的木块。你不需要将所有小木块都卖出去。你 不能 旋转切好后木块的高和宽。

请你返回切割一块大小为 m x n 的木块后,能得到的 最多 钱数。

注意你可以切割木块任意次。

2. 思路分析

定级Hard
这题把我卡没了。
比赛结束一瞬间想到模拟思路:
令dfs(wood)为一块大小m,n的木头的最大价值

  • 对每块木头进行所有切割可能的划分:
  • 横着切,有m-1种切法,那么这块木头的最大价值一定是dfs(left)+dfs(right)
  • 竖着切,有n-1种切法,那么这块木头的最大价值一定是dfs(top)+dfs(bottom)
  • 具体实现时,dfs参数传入长宽,然后记忆化即可。
  • 边界:
  • 如果m,n有0,价值是0
  • 如果m,n组合在price里,可尝试不切。
  • 尝试切块的类数可以只搜到中间(左右对称),剪掉另一半,比赛就不纠结这点了。

3. 代码实现

class Solution:
    def sellingWood(self, m: int, n: int, prices: List[List[int]]) -> int:
        p = {(a,b):c for a,b,c in prices}
       
        @cache
        def dfs(x,y):
            if x == 0 or y == 0:
                return 0
            
            s = 0
            if (x,y) in  p:
                s = p[(x,y)]
            for i in range(1,x):
                s = max(s,dfs(i,y)+dfs(x-i,y))
            for i in range(1,y):
                s = max(s,dfs(x,i)+dfs(x,y-i))
            
            return s
        
        return dfs(m,n)
           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值