0
点赞
收藏
分享

微信扫一扫

数据结构中数据有序性/ 单调性 ——二分查找

目录

C 语言实现字母异位词分组

在本篇博客中,我们将介绍如何用 C 语言实现力扣第 49 题——字母异位词分组(Group Anagrams)。题目要求将一组字符串分成多个组,其中每组字符串中的所有元素都是字母异位词。我们将逐行分析代码的实现过程,并详细解释每个部分的功能。

题目分析

字母异位词(Anagram)是指两个字符串包含相同的字符,且字符的频率相同。比如,"eat", "tea", "ate" 就是字母异位词组。我们的目标是将一组字符串分组,找到所有的字母异位词,并将它们归为一组。

代码实现

1. 包含必要的头文件

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_STR_LEN 100
  • stdio.h:提供输入输出函数,如 printf 用于打印结果。
  • stdlib.h:提供内存管理函数,如 mallocfree,以及排序函数 qsort
  • string.h:提供字符串操作函数,如 strlenstrcmp
  • MAX_STR_LEN:定义了字符串的最大长度,用于内存分配时的估算。

2. 排序比较函数

int compare(const void *a, const void *b) {
    return strcmp((char*)a, (char*)b);
}
  • 作用compare 是用于排序的比较函数。qsort 函数需要一个比较函数来确定排序规则。此函数使用 strcmp 来比较两个字符串的字典序。
  • 解释qsort 函数需要将传入的指针转换为 char* 类型,比较这两个字符串的字典序。

3. 字符串排序函数

void sort_string(char *str) {
    qsort(str, strlen(str), sizeof(char), compare);
}
  • 作用:此函数使用 qsort 对给定的字符串进行排序。排序后的字符串会帮助我们将字母异位词归类到一起。
  • 解释qsort 函数排序字符串时,使用字符串的长度 strlen(str) 来确定排序的长度,并以字符为单位排序。

4. 主函数 groupAnagrams

char*** groupAnagrams(char** strs, int strsSize, int* returnSize, int** returnColumnSizes) {
  • 作用:这是实现字母异位词分组的核心函数。该函数返回一个三维指针数组,表示不同字母异位词的组。
  • 参数
    • strs:输入字符串数组。
    • strsSize:字符串数组的大小。
    • returnSize:指向整数的指针,用于返回结果数组的大小(即异位词组的数量)。
    • returnColumnSizes:指向整数数组的指针,返回每个字母异位词组的大小。

5. 初始化变量

    char* hash_map[10000]; // 假设最多10000个不同的字母异位词
    int hash_map_size = 0;
    
    *returnSize = 0;
    *returnColumnSizes = (int*)malloc(sizeof(int) * strsSize);

    char*** ans = (char***)malloc(sizeof(char**) * strsSize);
  • 作用:初始化一些数据结构和变量:
    • hash_map:用于存储已排序的字符串,作为字母异位词的标识符。
    • hash_map_size:记录哈希表的大小,即当前已发现的异位词组数量。
    • returnSize:初始化返回的字母异位词组的数量。
    • returnColumnSizes:为每个字母异位词组分配内存,记录每组字符串的数量。
    • ans:动态分配内存来存储最终的分组结果。

6. 遍历所有字符串,排序并分组

    for (int i = 0; i < strsSize; i++) {
        char *sorted_str = strdup(strs[i]); // 复制当前字符串
        sort_string(sorted_str);
  • 作用:遍历输入字符串数组,为每个字符串进行排序。
  • 解释strdup 创建一个新的字符串副本,这样我们可以安全地对其进行排序,而不修改原始字符串。

7. 查找是否已存在该字母异位词组

        int found = -1;
        for (int j = 0; j < hash_map_size; j++) {
            if (strcmp(sorted_str, hash_map[j]) == 0) {
                found = j;
                break;
            }
        }
  • 作用:检查当前排序后的字符串是否已经出现在哈希表中。
  • 解释:如果找到匹配的字符串(即字母异位词组已存在),则将其索引保存到 found

8. 处理新发现的字母异位词组

        if (found == -1) {
            hash_map[hash_map_size] = sorted_str;
            ans[hash_map_size] = (char**)malloc(sizeof(char*) * strsSize);
            (*returnColumnSizes)[hash_map_size] = 0;
            found = hash_map_size;
            hash_map_size++;
        } else {
            free(sorted_str);  // 释放不再需要的内存
        }
  • 作用:如果找不到匹配的字母异位词组,说明这是一个新的字母异位词组。
  • 解释:我们将新发现的排序字符串添加到 hash_map 中,并在 ans 中为该组分配内存,初始化每组的大小。

9. 将当前字符串添加到字母异位词组中

        ans[found][(*returnColumnSizes)[found]++] = strs[i];
    }
  • 作用:将当前字符串加入到对应的字母异位词组中。
  • 解释:通过 found 找到对应的字母异位词组,增加该组的大小。

10. 返回结果

    *returnSize = hash_map_size;
    return ans;
}
  • 作用:将结果赋值给 returnSize,并返回字母异位词组的三维数组 ans

11. main 函数

int main() {
    char *param_1[] = {"eat", "tea", "tan", "ate", "nat", "bat"};
    int size_1 = 6;
  • 作用:在 main 函数中定义输入字符串数组 param_1 和其大小 size_1

12. 调用 groupAnagrams 并打印结果

    int ret_size, *ret_colsize;
    char ***ret = groupAnagrams(param_1, size_1, &ret_size, &ret_colsize);
    
    printf("Total Groups: %d\n", ret_size);
    for (int i = 0; i < ret_size; i++) {
        printf("Group %d: ", i + 1);
        for (int j = 0; j < ret_colsize[i]; j++) {
            printf("%s ", ret[i][j]);
        }
        printf("\n");
    }
  • 作用:调用 groupAnagrams 函数,获取分组结果,并打印每个字母异位词组。
  • 解释:输出字母异位词组的数量以及每组中的元素。

13. 内存释放

    for (int i = 0; i < ret_size; i++) {
        free(ret[i]);
    }
    free(ret_colsize);
    free(ret);
    return 0;
}
  • 作用:释放在 groupAnagrams 中动态分配的内存。
  • 解释:为了避免内存泄漏,在程序结束前释放所有分配的内存。

完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_STR_LEN 100

// 比较两个字符串的排序结果
int compare(const void *a, const void *b) {
    return strcmp((char*)a, (char*)b);
}

// 字符串排序函数
void sort_string(char *str) {
    qsort(str, strlen(str), sizeof(char), compare);
}

// 主解法,返回结果作为函数的返回值
char*** groupAnagrams(char** strs, int strsSize, int* returnSize, int** returnColumnSizes) {
    // 使用哈希表存储排序后的字符串和对应的字母异位词
    char* hash_map[10000]; // 假设最多10000个不同的字母异位词
    int hash_map_size = 0;
    
    *returnSize = 0;
    *returnColumnSizes = (int*)malloc(sizeof(int) * strsSize);

    // 临时存储每组字母异位词
    char*** ans = (char***)malloc(sizeof(char**) * strsSize);
    
    for (int i = 0; i < strsSize; i++) {
        // 排序当前字符串
        char *sorted_str = strdup(strs[i]); // 复制当前字符串
        sort_string(sorted_str);

        // 查找是否已存在该排序后的字符串
        int found = -1;
        for (int j = 0; j < hash_map_size; j++) {
            if (strcmp(sorted_str, hash_map[j]) == 0) {
                found = j;
                break;
            }
        }

        if (found == -1) {
            // 新的字母异位词组
            hash_map[hash_map_size] = sorted_str;
            ans[hash_map_size] = (char**)malloc(sizeof(char*) * strsSize);
            (*returnColumnSizes)[hash_map_size] = 0;
            found = hash_map_size;
            hash_map_size++;
        } else {
            free(sorted_str);  // 释放不再需要的内存
        }

        // 将当前字符串加入对应的字母异位词组
        ans[found][(*returnColumnSizes)[found]++] = strs[i];
    }

    *returnSize = hash_map_size;
    return ans;
}

int main() {
    // 输入
    char *param_1[] = {"eat", "tea", "tan", "ate", "nat", "bat"};
    int size_1 = 6;

    // 输出结果
    int ret_size, *ret_colsize;
    
    // 调用 groupAnagrams 并直接接收返回值
    char ***ret = groupAnagrams(param_1, size_1, &ret_size, &ret_colsize);
    
    // 打印结果
    printf("Total Groups: %d\n", ret_size);
    for (int i = 0; i < ret_size; i++) {
        printf("Group %d: ", i + 1);
        for (int j = 0; j < ret_colsize[i]; j++) {
            printf("%s ", ret[i][j]);
        }
        printf("\n");
    }

    // 释放内存
    for (int i = 0; i < ret_size; i++) {
        free(ret[i]);
    }
    free(ret_colsize);
    free(ret);

    return 0;
}
举报

相关推荐

0 条评论