0
点赞
收藏
分享

微信扫一扫

云原生周刊:CNCF 宣布 Falco 毕业|2024.3.4

前行的跋涉者 2024-03-08 阅读 10

代码训练(4)LeetCode之字母异位词

Author: Once Day Date: 2024年3月6日

漫漫长路,才刚刚开始…

全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客

参考文章:

  • 242. 有效的字母异位词 - 力扣(LeetCode)
  • 力扣 (LeetCode) 全球极客挚爱的技术成长平台

文章目录

1. 原题

例如对于carraw,就不是字母异位词,因为cw没有对上。

2. 分析

该问题是一个简单的编程题目,用C语言来实现,只要要求性能较高(速度90%),一般不浪费内存即可。

题目要求我们编写一个函数,这个函数需要判断两个字符串 st 是否是字母异位词。如果一个字符串的字母重新排列后能够得到另一个字符串,那么这两个字符串互为字母异位词。换句话说,两个字符串有相同的字母和相同数量的每个字母。

解决这个问题,核心思路是检查两个字符串中每个字母的数量是否完全相同。

  1. 哈希表法:我们可以使用一个哈希表(或称为字典)来记录字符串 s 中每个字符出现的次数,然后遍历字符串 t,减少哈希表中对应字符的计数。如果最后哈希表中所有字符的计数都是零,则说明 ts 的字母异位词。
  2. 数组法:由于题目只提到了字母,我们可以假设输入是 ASCII 字符串,因此可以使用一个大小为 26 的整数数组来代替哈希表。数组的每个位置对应一个字母,值为该字母在字符串 s 中出现的次数。这种方法在空间上更加高效,因为它不需要额外的哈希表结构。
  3. 排序法:将两个字符串分别排序,如果它们相等,则它们是字母异位词。

如果题目支持大量字符(比如宽字符unicode字符),那么Hash方法更合适。

这里只考虑26个字母,使用数组法解决效率更高,如下:

  1. 如果 st 的长度不同,则它们不能是字母异位词,返回 false
  2. 创建一个大小为 26 的整数数组来存储每个字母的频率。
  3. 遍历字符串 s,对于每个字符 c,在数组中 c - 'a' 的位置增加 1。
  4. 遍历字符串 t,对于每个字符 c,在数组中 c - 'a' 的位置减少 1。
  5. 遍历整数数组,如果所有位置的值都是 0,则返回 true;否则,返回 false

假设我们有两个字符串 s = "anagram"t = "nagaram"

  1. 两个字符串长度相同,继续。
  2. 创建频率数组 freq[26]
  3. 遍历 s,更新频率数组:freq['a' - 'a'] = 3, freq['n' - 'a'] = 1, 等等。
  4. 遍历 t,更新频率数组:每个对应字符的频率减 1。
  5. 最后检查频率数组,所有值都是 0,所以 ts 的字母异位词。

性能优化关键点

  • 执行速度:直接使用长度为 26 的数组来存储每个字母频率是相当快的操作,因为数组的访问时间是常数时间。

  • 内存使用:使用静态大小的数组,而不是动态数据结构如哈希表,可以减少内存开销。

3. 代码实现
bool isAnagram(char* s, char* t) {
    int16_t s1[26] = {0};

    while (*s != '\0') {
        s1[*s - 'a']++;
        s++;
    }
    while (*t != '\0') {
        if (--s1[*t - 'a'] < 0) {
            return false;
        }
        t++;
    }
    for (int i = 0; i < 26; i++) {
        if (s1[i]) {
            return false;
        }
    }

    return true;
}

这段代码定义了一个函数 isAnagram,它用来检测两个输入的字符串 st 是否为字母异位词。字母异位词是指由相同的字母以不同的顺序组成的单词或短语。

函数的工作原理如下:

  1. 定义并初始化一个整型数组 s1 用于计数26个英文字母在字符串 s 中出现的次数。数组的每个索引对应一个字母(0索引对应 ‘a’,1索引对应 ‘b’,以此类推)。
  2. 第一个 while 循环遍历字符串 s,通过递增 s1 数组相应的计数器来记录每个字母出现的次数。
  3. 第二个 while 循环遍历字符串 t,同时递减 s1 数组中相应字母的计数器。如果某个字母的计数器在递减前已经是0或在递减后变为负数,这意味着字符串 t 中这个字母出现的次数多于字符串 s 中的次数,或者字符串 s 中没有这个字母,因此可以判断两个字符串不是字母异位词,函数返回 false
  4. 第三个 for 循环检查 s1 数组中的计数器是否都回到了0。如果有任何计数器的值不为0,这意味着字符串 s 中有字母没有在字符串 t 中出现相同的次数,或字符串 t 较短而未能消除 s 中的某些字母计数,因此两个字符串也不是字母异位词,函数同样返回 false
  5. 如果所有的计数器最终都是0,这意味着两个字符串有相同的字母和相同的字母出现次数,函数返回 true,表示字符串 st 是字母异位词。

运行截图如下所示,可以看到运行效率和内存使用还是非常好的,这里有个注意点,C语言strlen函数开销很大,不能频繁调用,这和Python等动态语言是完全不同的。

在这里插入图片描述

在这里插入图片描述

4. 总结

这个题目考查了对字符串的基本操作,以及对哈希表和数组数据结构的理解和应用。为了提升解决此类问题的能力,可以加强对数据结构的学习和实践,特别是了解如何根据不同的问题选择合适的数据结构来优化性能。此外,对字符串的常见操作如遍历、比较、哈希编码等的掌握也是非常关键的。

理解和应用。为了提升解决此类问题的能力,可以加强对数据结构的学习和实践,特别是了解如何根据不同的问题选择合适的数据结构来优化性能。此外,对字符串的常见操作如遍历、比较、哈希编码等的掌握也是非常关键的。







Alt

Once Day

也信美人终作土,不堪幽梦太匆匆......

如果这篇文章为您带来了帮助或启发,不妨点个赞👍和关注,再加上一个小小的收藏⭐!

(。◕‿◕。)感谢您的阅读与支持~~~

举报

相关推荐

0 条评论