2022-01-09 每日打卡:力扣周赛第 275 场

2022-01-09 每日打卡:力扣周赛第 275 场

写在前面

“这些事儿在熟练之后,也许就像喝口水一样平淡,但却能给初学者带来巨大的快乐,我一直觉得,能否始终保持如初学者般的热情、专注,决定了在做某件事时能走多远,能做多好。” 该系列文章由python编写,所刷题目共三个来源:之前没做出来的 ;Leetcode中等,困难难度题目; 周赛题目;某个专题的经典题目,所有代码已AC。每日1-3道,随缘剖析,希望风雨无阻,作为勉励自己坚持刷题的记录。

5976. 检查是否每一行每一列都包含全部整数

在这里插入图片描述
第一道,简单题,充分利用题目信息即可。每次判断不仅仅要满足和的关系,还有去重。

class Solution:
    def checkValid(self, matrix: List[List[int]]) -> bool:
        n = len(matrix)
        return all(len(set(row)) == n 
        			for row in matrix) and 
        		all(len(set(col)) == n 
        			for col in zip(*matrix))

5977. 最少交换次数来组合所有的 1 II

在这里插入图片描述
想的思路一定要经过每个测试用例的验证!再开始编码!

统计1的个数,最开始想的是统计连缀的1的个数,其实应该是统计滑动窗口中1的个数。窗口大小为1的总个数,最后结果就是总个数-窗口中1个数的最大值
关于成环的问题,比较典型的两个解决方法:

  • 后缀添加相同数组
  • 切片

而不是模拟,模拟可能带来边界处理的麻烦。

class Solution:
    def minSwaps(self, nums: List[int]) -> int:
        n, cnt, size = len(nums), 0, nums.count(1)
        for _ in range(size):
            cnt+=nums[_]
        l, r, ans = 0, size, 0
        nums += nums
        while l<n:
            if nums[l]:
                cnt-=1
            if nums[r]:
                cnt+=1
            l+=1
            r+=1
            ans=max(cnt,ans)
            
        return size-ans

5978. 统计追加字母可以获得的单词数

在这里插入图片描述
类似于从一组原材料到另一组目标的问题,一般做法有两种:

  • 为原材料进行哈希编码,组成目标(常常会用到拓扑排序)
  • 为目标进行哈希编码,从原材料中选取所需要的
class Solution:
    def wordCount(self, startWords: List[str], targetWords: List[str]) -> int:
        all_set = set(''.join(sorted(w)) for w in startWords)
        ans = 0
        for w in targetWords:
            w2 = ''.join(sorted(w))
            if any((w2[:i] + w2[i+1:]) in all_set 
            				for i in range(len(w2))):
                ans += 1
        return ans

比完赛学习了一下别人写的,思路大概是两条

  • 状态压缩: 因为题目说每个字符串不包含重复的字母,因此可以用一个25位的位图来表示一个字符串
  • 反向查找: 在确认一个target是否可以由start集合中的字符串变换得到时,不要遍历start集合,因为这个集合可能非常大;我们可以通过删除target中的一个字母来看集合中是否存在相等的字符串来反向查找。因为字母的个数最多26个,而startSet可能非常非常大。

然后位运算的状态压缩原理是这样的:用一位数代表一个字母,26个字母对应的分别是把1左移0~26位。比如a是1(1),那b就是10(2),c是100(4)… 这样我们只需要关注一个字符串中出现过的字母(题目已经给了这些字母互不重复),而不受其顺序的影响。
在这里插入图片描述

class Solution:
    def wordCount(self, startWords: List[str], targetWords: List[str]) -> int:
        s = set()
        # 状态压缩存储出现的字符串
        # 譬如abc将存储为"000...000111",即26位中后三位为1
        # 每一个mask都是列表中的一项
        for word in startWords:
            mask = 0
            for ch in word:
                mask |= 1 << (ord(ch) - ord('a'))
            s.add(mask)
        ans = 0
        for word in targetWords:
            mask = 0
            # 每一个mask都是列表中的一项,计算要匹配的状态压缩后的数
            for ch in word:
                mask |= 1 << (ord(ch) - ord('a'))
            for ch in word:
                # 遍历当前项,按顺序去掉一个字符
                if mask ^ (1 << (ord(ch) - ord('a'))) in s:  
                    ans += 1
                    # 防止重复计算
                    break
        return ans
        

5979. 全部开花的最早一天

在这里插入图片描述
大概知道是贪心算法,但是这个题将一盆花分为了两个阶段,可以发现,无论怎么种,前面的播种时间都是无法重合的,也就是说种植时间是一定的。
那么我们就尽可能的使得生长时间保持最短,使用贪心策略即可。下面是比较严谨的理论证明。可以简单理解为,每个活动的开始时间不同了,但开始时间取决于种植时间,渴望总时间最短,将 时间可以重合 的部分安排为最长的最先开始重合即可。

在这里插入图片描述
下面这个图是模拟了[1,2]和[3,2]两盆花的种植情况,可以发现,种植顺序并不影响最后的结尾,因为种植时长一定,爱种哪个种哪个,让长的慢的先长就可以啦:
请添加图片描述

class Solution:
    def earliestFullBloom(self, plantTime: List[int], growTime: List[int]) -> int:
        N = len(growTime)
        grow_sort = sorted(range(N), key=lambda x: growTime[x], reverse=True)
        s = 0
        ans = 0
        for i in grow_sort:
            s += plantTime[i]
            ans = max(ans, s + growTime[i])
        return ans
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值