Onehot100-字母异位词

字母异位词C语言暴力解法思路

一、解题思路与步骤

  本题的解题思路:首先将strs字符串中的每个字符的ASCII码提取出来,对每个码进行从小到大的排序,再将排序后的ASCII码重新转换成对应的字符组成字符串,保存在新的字符串数组strs1中(大小与strs一样),然后两两比较strs1中的字符串strs1[i]、strs1[j],若strs1[i]==strs1[j],则将原字符串数组strs中的strs[i]、strs[j]存入返回的三维字符数组stsr2中.

   1、定义一个与传入数组strs大小一样的二维字符数组strs1,传入数组str的行数为strsSize,列数为cols

   2、定义qsort函数的排序顺序为从小到大(compare函数);

   3、循环取出传入字符串数组strs的每一个字符串(实际是该二维数strs的一行);
    ①创建一个与大小为cols-1的整数数组c,用来存储字符串中每个字符的ASCII码(例如:c[j]=(int)strs[i][j]);

    ②数组c获得第i行字符串的每一个字符的ASCII码后,用qsort函数对数组c进行排序;

    ③对于排序后的字符数组c,将其里面的每一个元素值即ASCII码,重新转成对应字符,存进数组strs1中(strs1[i][n]=c[n]);
     例如,字符数组为“eat",那么c[3]=[101,97,116],排序后c[3]=[97,101,116],重新转成字符再平常字符串为"aet";
     经过 (3)后,strs1中存的是strs中每个字符经过排序后的字符串:
                 strs[6][4]=[“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] 👉 strs1[6][4]=[“aet”, “aet”, “ant”, “aet”, “ant”, “abt”]

  4、先创建一个三维数组,其大小是strsSize个strsSize*cols的二维矩阵,后面若空间有多,再用realloc函数重新调整大小;
     ①创建一个used数组,大小是strsSize个整数大小,用来标识strs1中的元素是否已经被访问过, groupcount记录字母异      位词的组数;
     ②创建一个groupsize数组,用来辅助记录每类字母异位词的数量,大小是strsSize;
     ③创建一个used数组,用来标识strs1中的元素是否已经被访问过;
     ④每次循环前,先将取得的第一个字符串存进strs2[groupcount][0]中,然后使用字符串比较函数strcpy()比较strs1中的      strs1[t]和strs1[t+1]是否相等,若相等,则将原字符数组strs中的strs[t+1]存进strs2[grouncount][groupsize[groupcount]]      中,完成一次查找,重复循环,直至全部字母异位词均被查过;
     ⑤完成一组的查找后,根据字母异位词的组数以及每组字母异位词的个数,用realloc函数将三维数组中的未使用的二维      数组空间以及某个二维数组的剩下行的空间释放掉,避免浪费空间;

  5、最后将调整后的三维数组strs2以及统计到的字母异位词的组数groupcount返回,并且释放groupsize、used的空间.

具体的代码思路流程图如下:
在这里插入图片描述

二、具体知识点

  (1)多维数组的初始化、怎么理解数组名与指针的关系以及多级指针的使用;
  (2)malloc、calloc、realloc三种内存分配函数的使用与区别;
  (3)变量的作用范围、申请堆区与栈区的内存,其生命周期的区别;
  (4)数组名作为函数的参数、字符串函数strcpy与strcmp函数的使用、strcpy与strncpy的区别(详细看此链接);
  (5)continue与break的区别.

三、需要注意的地方

  (1)函数的参数是数组名时,不能在函数内部使用sizeof(数组名)来计算数组的长度,因为此时数组名退化为一个指针函数只会将其当作是一个指针,那么指针的大小在64位系统中大小是8个字节,但在main函数中,sizeof(数组名)是会计算整个数组所占内存空间的大小,此时在sizeof中,数组名并不表示数组首元素的地址,而表示整个数组。这就是数组名不表示数组首元素地址的例外情况
  (2)如何来动态调整返回三维数组的大小,以避免空间浪费;
  (3)提取字符串每个字符的ASCII码时,注意最后一个结束标志’\0’不要提取,否则排序后会出现错误;
  (4)如何更新strs2的数组下标,使得找到的每一组字母异位词都能正确的存进去.

四、具体代码

//(1)定义整数数组的排序属顺序(从小到大)
int compare(const void *a, const void *b) {
    return (*(int*)a - *(int*)b);
}

//(2)寻找字母异位词,并用三维字符数组返回
char*** groupAnagrams(int strsSize,int cols,char** strs,int* returnSize)  //strsSize是二维数组的行数[strsSize][cols]
{
    char strs1[strsSize][cols];
    //先对字符串的每个字符进行排序,得到一个新的字符数组
    for (int i = 0; i < strsSize; i++)
    {
        int c[cols-1];  //定义一个数组存储字符串的每个字符对应的ASCII码
        for (int j = 0; j < cols-1; j++)
        {
            c[j] = (int) strs[i][j];
        }

        //对数组c中的ASCII码进行从小到大排序
        qsort(c, cols-1, sizeof(int), compare);

        //将数组C中的ASCII码转成对应的字符,再拼接成对应的字符串,存回strs1[i]这个位置
        for (int n = 0; n <=cols-1; n++)
        {
            if(n==cols-1)
            {
                strs1[i][n]='\0';
            }
            else
            {
                strs1[i][n] = (char) c[n];
            }
        }
    }
    //上面已经完成:将字母的ASCII码排序后重新转成对应的字母,存到新的数组strs1中,

    //先申请内存来存储找到的字母异位词,申请内存使用malloc函数,否则内存在函数调用结束后会自动销毁
    char*** result=(char***)malloc(strsSize * sizeof(char**));
    if(result==NULL)
    {
        printf("nei cun bu zu \n");
        return  NULL;
    }

    //记录三维数组中每个的大小
    int* groupsize=(int*) calloc(strsSize,sizeof (int));
    if(groupsize==NULL)
    {
        printf("groupsize nei cun bu zu \n");
        free(result);
        return NULL;
    }

    //记录字母异位词的数量
    int groupcount=0;

    //标记某字符串是否已经被分组
    int* used=(int*)calloc(strsSize,sizeof (int ));
    if(used==NULL)
    {
        printf("used nei cun bu zu \n");
        free(result);
        free(groupsize);
        return NULL;
    }
    for(int t=0;t<strsSize;t++)
    {
        if(used[t])
        {
            continue;
        }
        result[groupcount]=(char **) malloc(strsSize*sizeof (char*));
        if(result[groupcount]==NULL)
        {
            printf("result groupcount nei cun bu zu");
            for (int k = 0; k < groupcount; k++)
            {
                free(result[k]);
            }
            free(result);
            free(groupsize);
            free(used);
            return NULL;
        }
        result[groupcount][0]=(char *) malloc(cols*sizeof (char ));
        strcpy(result[groupcount][0],strs[t]);
        groupsize[groupcount]=1;
        used[t]=1;
        for(int m=t+1;m<strsSize;m++)
        {
            if(used[m])
            {
                continue;
            }
            if(!strcmp(strs1[t],strs1[m]))
            {
                result[groupcount][groupsize[groupcount]] = (char*)malloc(cols * sizeof(char));
                strcpy(result[groupcount][groupsize[groupcount]], strs[m]);
                groupsize[groupcount]++;
                used[m] = 1;
            }
        }
       result[groupcount][groupsize[groupcount]] = NULL;

        //将三维数组中某个矩阵的剩下行的空间释放掉,避免浪费空间
        result[groupcount] = (char**)realloc(result[groupcount], (groupsize[groupcount] + 1) * sizeof(char*));

        /*for(int e=groupsize[groupcount]+1;e<strsSize;e++)
        {
            free(result[groupcount][e]);
        }*/
        groupcount++;
    }
    //调整结果数组的大小
    result=(char***) realloc(result,groupcount*sizeof (char**));

    // 更新返回的组数
    *returnSize = groupcount;

    // 释放不再需要的内存
    free(groupsize);
    free(used);

    return result;
}

//(3)主函数
int main() {
    int strsSize = 8;
    int maxLen = 4;
    char **strs = (char **) malloc(strsSize * sizeof(char *));
    if (strs == NULL) {
        printf("内存分配失败\n");
        return 1;
    }

    for (int i = 0; i < strsSize; i++) {
        strs[i] = (char *) malloc(maxLen * sizeof(char));
        if (strs[i] == NULL) {
            printf("内存分配失败\n");
            // 释放已分配的内存
            for (int j = 0; j < i; j++) {
                free(strs[j]);
            }
            free(strs);
            return 1;
        }
    }

    // 初始化二维数组
    char *words[] = {"eat", "tea", "tan", "ate", "nat", "bat", "tab","adc"};
    for (int i = 0; i < strsSize; i++) {
        strncpy(strs[i], words[i], maxLen);
    }
    int returnsize = 0;
    char ***result = groupAnagrams(strsSize, maxLen, strs, &returnsize);
    printf("%d\n", returnsize);
    if(result)
    {
        for (int i = 0; i < returnsize; i++) {
        printf("Group %d:\n", i + 1);
        for (int j = 0; result[i][j] != NULL; j++) {
            printf("%s ", result[i][j]);
            free(result[i][j]);
        }
        printf("\n");
        free(result[i]);
    }
    free(result);
    }
    return 0;
}

五、代码运行结果

4是找到了4组的字母异位词
在这里插入图片述

六、总结

  这个思路是比较容易理解的,但是代码读起来会比较难懂,其中涉及到了C语言比较细碎的知识点,后面将会更新C++版本的非暴力解法(使用哈希表、vector的解法).

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值