[python 刷题] 49 Group Anagrams

2023-09-18 02:22:15

[python 刷题] 49 Group Anagrams

题目:

Given an array of strings strs, group the anagrams together. You can return the answer in any order.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

这里 Anagram 的定义就是可以通过重新排序获得的单词,如 cat 可以获得 act 这种,所以这道题需要按需将所有 Anagram 组合在一起,如:

["eat","tea","tan","ate","nat","bat"] 中包含

  • {'a': 1, 'e': 1, 't': 1} 为 key 的 [eat, tea, ate]
  • {'b': 1, 'a': 1, 't': 1} 为 key 的 [bat]
  • {'t': 1, 'a': 1, 'n': 1} 为一组的 [tan, nat]

所以,最终的答案就是 [["bat"],["nat","tan"],["ate","eat","tea"]]

我最初的写法是:

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        # if no list, return empty
        if len(strs) == 0:
            return strs

        ana_dict = {}

        for str in strs:
            key = {}
            for c in str:
                key[c] = key.get(c, 0) + 1

            frozen_key = frozenset(key.items())
            if frozen_key in ana_dict:
                ana_dict[frozen_key].append(str)
            else:
                ana_dict[frozen_key] = [str]

        res = []
        for _, value in ana_dict.items():
            res.append(value)

        return res

这个写法的逻辑为:

  1. 便利每一个 key,将其转换为对应的 dict
  2. 因为 dict 可变(mutable),python 的 dict 要求 key 不可变,因此将其转化为 immutable 的 frozenset
  3. 遍历 dict 生成最终结果

这是一个可以实行的方法,大 O 是 O ( n × k ) O(n \times k) O(n×k),其中 n n n 为数组的长度, k k k 为字符串的长度

随后我又看了一下别人是怎么写的,然后发现了更妙的两个写法:

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        # if no list, return empty
        if len(strs) == 0:
            return strs

        ana_dict = {}

        for str in strs:
            key = ''.join(sorted(list(str)))
            ana_dict[key] = ana_dict.get(key, [])
            ana_dict[key].append(str)

        res = []
        for _, value in ana_dict.items():
            res.append(value)

        return res

这个就不把遍历的 str 转换成 dict,而是直接通过排序的方式获得 Anagram,理论上来说这个写法的时间复杂度为 O ( n × k l o g ( k ) ) O(n \times k log(k)) O(n×klog(k)),不过我实际提交了几次,发现 leetcode 上这个写法的平均用时比第一个写法要短,可能有三个原因:

  • dict 转 frozenset 太耗时了
  • python 内部对 sort 的优化
  • leetcode 的案例比较极端

第二个写法更妙一些,它最终的时间复杂度还是 O ( n × k ) O(n \times k) O(n×k),不过写法更简洁:

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        ans = collections.defaultdict(list)

        for str in strs:
            count = [0] * 26
            for c in str:
                count[ord(c) - ord('a')] += 1
            ans[tuple(count)].append(str)

        return ans.values()

这里主要用了一些比较妙的点:

  • 使用了 collections.defaultdict

    collections.defaultdict 和 dict 主要的区别就在于,前者当遇到当前 dict 中不存在的 key,会使用提供的默认值,而 dict 就会直接报错

    以本题为例,ans = collections.defaultdict(list) 代表着所有 key 的默认初始值为 [],也就可以直接使用 append 方法

  • 与其使用 dict 去创建 k-v 对,不如直接使用 array,毕竟英文就 26 个字母

  • 没有 frozenset 去创建不可变的 key,而是使用了 tuple

    对于数量比较小——这里就 26 个字母——的 iterable 来说,tuple 一般来说会比 frozenset 快一些

  • 直接使用内置的 values() 进行返回,而没有做一个新的迭代

当然,实际运行上,这个跑法还是比用 sort 的要慢一点,但是比我之前写的那个方法要快一点点,不过写法则是干净很多

更多推荐

vue基础知识十二:双向数据绑定是什么

一、什么是双向绑定我们先从单向绑定切入单向绑定非常简单,就是把Model绑定到View,当我们用JavaScript代码更新Model时,View就会自动更新双向绑定就很容易联想到了,在单向绑定的基础上,用户更新了View,Model的数据也自动被更新了,这种情况就是双向绑定举个栗子当用户填写表单时,View的状态就被

第 113 场 LeetCode 双周赛题解

A使数组成为递增数组的最少右移次数数据范围小直接模拟…classSolution{public:intminimumRightShifts(vector<int>&nums){for(intop=0;op<nums.size();op++){if(is_sorted(nums.begin(),nums.end()))/

udp的简单整理

最近思考udp处理的一些细节,根据公开课,反复思考,终于有所理解,做整理备用。0:简单汇总1:udp是基于报文传输的,接收方收取数据时要一次性读完。2:借助udp进行发包,发大包也是没有问题的,借助IP层ip分片。===》ip分片可以发生在原始主机上,也可以发生在中间路由器上(MTU值)===》ip分片后,可以再分片,

Swift 5.5之Continuation

Continuation是Swift5.5中引入的一种新的编程模型,用于管理异步任务的结果。它允许您在异步任务完成后使用结果继续执行代码,可以与Async/Await一起使用,以简化异步编程。下面是使用Continuation的基本步骤:导入Continuation模块在使用Continuation之前,需要在代码文件

mysql知识大全

MySQL知识大全(2)MySqL基础为1—7(增删改查基础语法),MySQL进阶知识为8—11(约束、数据库设计、多表查询、事务)1、数据库相关概念以前我们做系统,数据持久化的存储采用的是文件存储。存储到文件中可以达到系统关闭数据不会丢失的效果,当然文件存储也有它的弊端。假设在文件中存储以下的数据:姓名年龄性别住址张

Python案例实现|租房网站数据表的处理与分析

在综合实战项目中,“北京链家网”租房数据的抓取任务已在上一篇完成,得到了数据表bj_lianJia.csv,如图1所示。该数据表包含ID、城区名(district)、街道名(street)、小区名(community)、楼层信息(floor)、有无电梯(lift)、面积(area)、房屋朝向(toward)、户型(mo

leetcode 10. 正则表达式匹配

2023.9.20感觉是目前做过dp题里最难的一题了...本题首要的就是需要理解题意,翻了评论区我才发现之前一直理解的题意是错的。我原来理解的“*匹配0次”是指:*直接消失,不会影响到前面的字符。但是*和前一个字符其实是连体的,所以说:*如果匹配0次,那么前一个字符就没了,消失了;*如果匹配1次,那么才相当于*消失了,

【Python】PySpark 数据处理 ① ( PySpark 简介 | Apache Spark 简介 | Spark 的 Python 语言版本 PySpark | Python 语言场景 )

文章目录一、PySpark简介1、ApacheSpark简介2、Spark的Python语言版本PySpark3、PySpark应用场景4、Python语言使用场景一、PySpark简介1、ApacheSpark简介Spark是Apache软件基金会顶级项目,是开源的分布式大数据处理框架,专门用于大规模数据处理,是一款

Windows11系统C盘用户文件夹下用户文件夹为中文,解决方案

说明:1.博主电脑为Windows11操作系统,亲测有效,修改后无任何影响,软件都可以正常运行!2.Windows10系统还不知道可不可行,因为Windows11的计算机管理中没有本地用户和组,博主在csdn上看到很多博主有发Windows10的解决方案,有通过“注册表”的,也有通过“本地用户和组”的,大家可以自己去小

OpenCV实现“蓝线挑战“特效

原理算法原理可以分为三个流程:1、将视频(图像)从(顶->底)或(左->右)逐行(列)扫描图像。2、将扫描完成的行(列)像素重新生成定格图像。3、使用原帧图像像素填充未扫描到的像素。图像扫描首先第一步,拿到一个视频(很多帧图像)可以简单的看成图像处理。我们需要将图像从顶到底逐行进行像素扫描,当然也可以从左到右逐列扫描,

在服务器上创建git仓库

1、在服务器上创建git仓库选择一个创建文件夹的地方,这个地方不会将源码存放在这里,只用于版本控制#创建一个专门放置git的文件夹,也可以叫其它名mkdirgit&&cdgit#创建自己项目的文件夹,文件夹后面要带.gitmkdirmy_object.git&&cdmy_object.git#初始化gitinit--b

热文推荐