2022-01-30 每日打卡:Leetcode第278场周赛

2022-01-30 每日打卡:Leetcode第278场周赛

写在前面

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

T1~T2

  • T1:思路定了以后对于循环的退出位置其实细想一下就好,不要懒的直接去试,这次一次过了,但比较慢,下次争取控制在1min内。
  • T2:计算【不确定的最值对应的列表】也可以通过一遍遍历,无须借助字典完成,以最大值为例,如果大于的时候一定是第一次出现,此时新建列表,如果等于最大值,此时列表一定存在。
  • T2:【10^5次方】不要尝试遍历了,使用前缀和或者滑动窗口差不多。

5994. 查找给定哈希值的子串(T3)

2022-01-30 每日打卡:Leetcode第278场周赛_第1张图片

  • 指数运算非常非常慢,尤其是 **pow() 的时间复杂度为 O ( l o g n ) O(logn) O(logn)。所以尽量把指数运算的部分作为常量,或者使用累乘的方法,比如题目中需要计算这个公式: h a s h ( s , p , m ) = ( v a l ( s [ 0 ] ) ∗ p 0 + v a l ( s [ 1 ] ) ∗ p 1 + . . . + v a l ( s [ k − 1 ] ) ∗ p k − 1 ) m o d m hash(s, p, m) = (val(s[0]) * p0 + val(s[1]) * p1 + ... + val(s[k-1]) * pk-1) mod m hash(s,p,m)=(val(s[0])p0+val(s[1])p1+...+val(s[k1])pk1)modm
    • 使用while循环中一个变量单独表示exp,每次循环 exp *= p 也远远快于 pow(p, _)
    • 使用等比数列计算公式,但是注意大数取余问题!取余公式。顺便复习了一下两种常用的指数取余方法(T14),循环取余和快速幂。
  • 很有趣的一点是我发现前面的几位都是使用的都是【倒序计算】,从最后一位开始计算最后一个窗口的。明白过来是因为这个题中虽然滑动窗口【一定能整除】,但是涉及大数问题的除法时,往往会有这么一个报错 OverflowError: integer division result too large for a float
    • python中整数没有位数限制,但浮点数有,这也是为什么inf写在了float中,所以【一定能整除的可以直接使用//而不是/
    • 更严谨的做法就是反向推导,从前往后需要除,那从后往前就好了,把除法变成乘法

5995. 字符串分组(T4)

2022-01-30 每日打卡:Leetcode第278场周赛_第2张图片
思路比较简单,就是并查集+二进制状态压缩。不过相对于可能面临的 1 0 4 10^4 104 数据,两两检查是否match显然是不科学的,所以采用对于每一个未检查的结点,【枚举+哈希表查找】其可能衍生的词是否在words中,因为衍生的可能性是常数级别:

class Solution:
    def groupStrings(self, words: List[str]) -> List[int]:
        # 使用哈希映射统计每一个二进制表示出现的次数
        wordmasks = Counter()
        for word in words:
            mask = 0
            for ch in word:
                mask |= (1 << (ord(ch) - ord("a")))
            wordmasks[mask] += 1
        
        # 辅助函数,用来得到 mask 的所有可能的相邻节点
        def get_adjacent(mask: int) -> List[int]:
            adj = list()
            # 将一个 0 变成 1,或将一个 1 变成 0
            for i in range(26):
                adj.append(mask ^ (1 << i))
            # 将一个 0 变成 1,且将一个 1 变成 0
            for i in range(26):
                if mask & (1 << i):
                    for j in range(26):
                        if not (mask & (1 << j)):
                            adj.append(mask ^ (1 << i) ^ (1 << j))
            return adj
        
        used = set()
        best = cnt = 0
        for mask, occ in wordmasks.items():
            if mask in used:
                continue
            
            # 从一个未搜索过的节点开始进行广度优先搜索,并求出对应连通分量的大小
            q = deque([mask])
            used.add(mask)
            # total 记录联通分量的大小
            total = occ

            while q:
                u = q.popleft()
                for v in get_adjacent(u):
                    if v in wordmasks and v not in used:
                        q.append(v)
                        used.add(v)
                        total += wordmasks[v]
            
            best = max(best, total)
            cnt += 1
            
        return [cnt, best]

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/groups-of-strings/solution/zi-fu-chuan-fen-zu-by-leetcode-solution-a8dr/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(algorithm,leetcode,算法,职场和发展)