242. 有效的字母异位词

一、题目

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。

示例 1:

输入: s = "anagram", t = "nagaram"
输出: true

示例 2:

输入: s = "rat", t = "car"
输出: false

说明:你可以假设字符串只包含小写字母。

进阶:如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?


二、解法

方法1:排序

算法:通过将 s 的字母重新排列成 t 来生成变位词。因此,如果 T 是 S 的变位词,对两个字符串进行排序将产生两个相同的字符串。此外,如果 s 和 t 的长度不同,t 不能是 s 的变位词,我们可以提前返回。
代码如下

void swap(char* a, char* b)
{
    char tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

void strSort(char* str)
{
    int len = strlen(str);
    char* pf = str;

    for (int i = 0; i < len - 1; i++)
    {
        for (int j = 0; j < len - i - 1; j++)
        {
            if (*(pf+j) > *(pf+j+1))            
                swap(pf + j, pf + j + 1);           
        }        
    }
    puts(str);
}

bool isAnagram(char* s, char* t)
{
    int s_len = strlen(s);
    int t_len = strlen(t);
    if (s_len != t_len)
        return false;
    strSort(s);
    strSort(t);
    if (strcmp(s, t) == 0)
        return true;
    else
        return false;
}

上述代码是没有问题的,但是提交时却给出了“超出时间限制”错误提示,如下图所示。
在这里插入图片描述
确实,上述算法本身没问题,出问题的应该是排序算法,由于使用的冒泡排序,使得时间复杂度达到 O ( n 2 ) O(n^2) O(n2),因此考虑采用效率更高的归并排序。为什么选用归并而不是选择排序呢?因为归并排序的性能不受输入数据的影响,并且表现比选择排序好的多,因为归并始终都是 O ( n l o g n ) O(nlogn) O(nlogn) 的时间复杂度。而代价则是需要额外的内存空间。(注:关于归并排序算法的相关介绍,请出门左转看我下篇论述
采用归并排序后的代码如下(通过):

int min(int a, int b)
{
    return a < b ? a : b;
}

void merge_sort(char* str)
{
    int len = strlen(str);
    char* ptr = str;
    char* newStr = (char*)malloc(len * sizeof(char));

    for (int seg = 1; seg < len; seg += seg)
    {
        for (int start = 0; start < len; start += seg * 2)
        {
            int low = start, mid = min(start + seg, len), high = min(start + seg * 2, len);
            int k = low;
            int start1 = low, end1 = mid;
            int start2 = mid, end2 = high;
            while (start1 < end1 && start2 < end2)            
                newStr[k++] = (ptr[start1] < ptr[start2]) ? ptr[start1++] : ptr[start2++];       
            
            while (start1 < end1)
                newStr[k++] = ptr[start1++];

            while (start2 < end2)
                newStr[k++] = ptr[start2++];
        }
        char* temp = ptr;
        ptr = newStr;
        newStr = temp;
    }
    if (ptr != str)
    {
        for (int i = 0; i < len; i++)
            newStr[i] = ptr[i];
        newStr = ptr;
    }
    free(newStr);
}

bool isAnagram(char* s, char* t)
{
    int s_len = strlen(s);
    int t_len = strlen(t);
    if (s_len != t_len)
        return false;
    merge_sort(s);
    // puts(s);
    merge_sort(t);
    if (strcmp(s, t) == 0)
        return true;
    else
        return false;
}

emmm……虽然通过了,但是结果好像并不感人啊
在这里插入图片描述
尤其是内存占用,简直了!
在这里插入图片描述
没有比这个更糟糕的了。当然了,大家也可以用快排来做,但是结果应该不会很理想。

那有没有更好地方法呢?
答案是:有的!

方法2:哈希表(模拟实现)

思路

  • 首先判断两个字符串长度是否相等,不相等则直接返回 false
  • 若相等,则初始化 26 个字母哈希表,遍历字符串 s 和 t
  • s 负责在对应位置增加,t 负责在对应位置减少
  • 如果哈希表的值都为 0,则二者是字母异位词

代码如下:

bool isAnagram(char* s, char* t)
{
    int s_len = strlen(s);
    int t_len = strlen(t);
    if (s_len != t_len)
        return false;
    int alpha[26] = { 0 };
    for (int i = 0; i < s_len; i++)
    {
        alpha[s[i] - 'a']++;
        alpha[t[i] - 'a']--;
    }
    for (int i = 0; i < 26; i++)
    {
        if (alpha[i] != 0)
            return false;
    }
    return true;
}

代码执行用时图如下:
在这里插入图片描述
复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)。时间复杂度为 O ( n ) O(n) O(n) 因为访问计数器表是一个固定的时间操作。
  • 空间复杂度: O ( 1 ) O(1) O(1)。尽管我们使用了额外的空间,但是空间的复杂性是 O ( 1 ) O(1) O(1),因为无论 N 有多大,表的大小都保持不变。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值