IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【LeetCode - Java】49. 字母异位词分组(中等) -> 正文阅读

[数据结构与算法]【LeetCode - Java】49. 字母异位词分组(中等)

1. 题目描述

在这里插入图片描述

2. 解题思路

这道题目的重点在于如何判断字母异位词,这时候我首先就想起了之前做过的一道题目【LeetCode - Java】46. 全排列(中等),在全排列中所有的组合都是相互的字母异位词,那么这样说我是不是可以把字符串数组中的值读取出来,生成他们所有的全排列,判断其是否在数组中从而得出答案呢?按道理来说这样做是肯定没有问题的,但求全排列是一个时间复杂度非常高的算法,并且这里字符串的长度可达 1 0 4 10^4 104,因此这种方法显然是不合适的。

字母异位词还有什么特征?各字母出现的次数一样!那么我们可以利用哈希表对每个字符串中出现的字符进行计数统计,把该频次表作为另一个哈希表的key,在value中存放同为字母异位词的字符串 。为什么可以这样做呢?这是哈希表的特性,相同内容的哈希表他们的内存地址也是相同的, 而对于数组来说就没有这个特性,自然而然这里也就不能使用数组代替哈希表进行字母频次统计了。

那…如果我非要用数组来进行频次统计呢?如何把相同内容的不同地址数组视为相等呢?这可以从【LeetCode - Java】38. 外观数列(中等)这道题目中找到灵感频次表核心内容是什么?总体来说他表达的就是多少个什么字母,那么我们可以构建一个类外观数列,按照α个β字母的形式生成字符串,为防止误判可以在不同字母计数中加分隔符

进一步简化,我可以不计数吗?如果不计数不算频次表,怎么才能够判断这个字符串中的字符个数是否一样呢?利用排序就可以实现这一想法,只需要把所有字符串预先进行排序,那么互为字母异位词的字符串排序后的结果必定是一致的

3. 代码实现

3.1 哈希表计数统计

public List<List<String>> groupAnagrams(String[] strs) {
        HashMap<Map<Character, Integer>, List<String>> mapListHashMap = new HashMap<>();
        for (String str : strs) {
            char[] chars = str.toCharArray();
            HashMap<Character, Integer> map = new HashMap<>();
            for (char aChar : chars) {
                map.put(aChar, map.getOrDefault(aChar, 0) + 1);
            }
            List<String> orDefault = mapListHashMap.getOrDefault(map, new ArrayList<>());
            orDefault.add(str);
            mapListHashMap.put(map,orDefault);
        }
        return new ArrayList<>(mapListHashMap.values());
    }

3.2 哈希表外观数列统计

public List<List<String>> groupAnagrams(String[] strs) {
        HashMap<String, List<String>> map = new HashMap<>();
        for (String str : strs) {
            char[] chars = str.toCharArray();
            int[] count = new int[26];
            for (char aChar : chars) {
                count[aChar - 'a']++;
            }
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < count.length; i++) {
                if (count[i] != 0)
                    sb.append(count[i]).append(i).append('.');
            }
            String s = sb.toString();
            List<String> orDefault = map.getOrDefault(s, new ArrayList<>());
            orDefault.add(str);
            map.put(s, orDefault);
        }
        return new ArrayList<>(map.values());
    }

3.3 哈希表排序统计

public List<List<String>> groupAnagrams(String[] strs) {
        HashMap<String, List<String>> map = new HashMap<>();
        for (String str : strs) {
            char[] chars = str.toCharArray();
            Arrays.sort(chars);
            String s = new String(chars);
            List<String> ans = map.getOrDefault(s, new ArrayList<String>());
            ans.add(str);
            map.put(s, ans);
        }
        return new ArrayList<>(map.values());
    }

3.4 对比

计数统计的时间复杂度是O(m*n)m为字符串数组的长度,n为字符串的最大长度外观数列的时间复杂度是O(m*(n+k))k为常数,值为26,代表英文字母的数量;排序的时间复杂度是O(mn*logn),其中进行排序的时间复杂度为O(nlogn)
在这里插入图片描述
看到这里是不是觉得很疑惑呢?明明这时间复杂度都是呈递增状态的,为什么实际的测试表现却是越来越优呢?首先来解释计数外观数列之间的差距,我曾经说到过,在一定情况下使用数组代替哈希表统计是可以大大提高速度的,其实这里本质上也是这个原因,至于那个k其实很小也可以忽略其对速度的影响,因此外观数列比计数快是合理现象

那么排序为什么比外观数列快呢?要符合这一现象时间复杂度之间的关系必须要满足n+k>n*logn,即n+26>n*logn,为此我专门画了两个函数图对比了一下:
在这里插入图片描述
显然,当n约处于0-15的位置上时,确实会出现这种状况的,这就表明本道题目的测试用例应该很大一部分是处于这个区间范围内的,因此出现该现象也就合理了。

纠结完时间复杂度再来看看空间复杂度计数外观数列的空间复杂度都是O(m*(n+k))排序的空间复杂度是O(mn),在现象上也表现合理

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:50:47  更:2022-03-10 22:52:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 13:39:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码