力扣第49题 字母异位词分组

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
char *** groupAnagrams(char ** strs, int strsSize, int* returnSize, int** returnColumnSizes){
    // 存储各个字符串的归类情况以及同类别的下一个字符串的下标,初始化为0,因为初始就从下标为0的字符串开始遍历,无需从position得知,故初始化为0不影响结果。特殊情况数值下面会讲到。
    int position[10000] = {0};
    // 存储各个类别下字符串数目,以动态分配空间时使用
    int word_num[10000] = {0};
    // 存储字符串各个字母的数目
    int words[26] = {0};
    // 存储字符串各个字母数目的临时数组
    int temp[26] = {0};
    // 当前类别数目,动态变化
    int num = 0;

    // 开始遍历所有字符串,寻找字母异位词并分类
    for (int i = 0; i < strsSize; i++) {
        // position[i]为0说明该字符串还没有归类处理
        if (position[i] == 0) {
            // 重置words数组
            for (int j = 0; j < 26; j++) {
                words[j] = 0;
            }
            int length = strlen(strs[i]);
            // 对字符串各字母计数
            for (int j = 0; j < length; j++) {
                int pos = strs[i][j] - 'a';
                words[pos]++;
            }

            // first记录不与position[i]同类的首个字符串下标,遍历完一遍strs后下一轮遍历将直接从first开始
            // left记录当前检测到的同类字符串的上一个字符串下标,实时更新,初始化为i。如一开始从第0个字符开始,若检测到下标为2的字符串为第一个与第0个字符串字母异位的字符串,则position[left],也就是position[0]置为2,left更新为2,然后继续往strs右边推进。
            int first = -1, left = i;
            // num1记录当前种类下的字符串数目,初始化为1因为此时已经至少有一个字符串在这一类中(即i)。
            int num1 = 1;
            // 开始遍历检查字符串是否归属于当前类别
            for (int j = i + 1; j < strsSize; j++) {
                // 仅对还没有归类的字符串进行检查
                if (position[j] == 0) {
                    int length1 = strlen(strs[j]);
                    if (length != length1) {
                        // 字符串长度都不同,显然不属于同一类别,此时若不属于同一类别的首个字符串下标变量还没有更新,则在这里更新,下同。
                        if (first < 0) {
                            first = j;
                        }
                        continue;
                    }
                    // 复刻当前类别字符串字母数目的信息到临时数组
                    for (int k = 0; k < 26; k++) {
                        temp[k] = words[k];
                    }
                    // 当前字符串是否归属于当前类别的标志,1为真,初始化为1
                    int flag = 1;
                    // 检查
                    for (int k = 0; k < length1; k++) {
                        int pos = strs[j][k] - 'a';
                        temp[pos]--;
                        // 检查到某字母数目超出,表明该字符串不属于当前类别
                        if (temp[pos] < 0) {
                            if (first < 0) {
                                first = j;
                            }
                            flag = 0;
                            break;
                        }
                    }
                    // flag没有置0,当前字符串满足条件,更新当前类别字符串数目,此时该类别中上一个字符串的下标为left(上面说过),更新position[left]为j,这样到时候从小标为i的字符串寻找下一个该类别下的字符串下标时可直接从position[i]获取。
                    //更新left为最新的j
                    if (flag) {
                        num1++;
                        position[left] = j;
                        left = j;
                    }
                }
            }
            // 此时已经退出循环,即该类别的字符串已经全部获取,若first仍然小于零,表明strs中已经没有还没归类的字符串,则可以直接将position[left]置为10001,一个肯定大于strs长度的值表示分类结束。
            if (first < 0) {
                position[left] = 10001;
            }
            // first大于等于零(实际上肯定大于0),表示strs中仍然有没有归类的字符串,且这些字符串中下标最小的为first,则可以将position[left]置为first,这样的话再将上一类别的字符串分类写入到ans数组中后可以直接将下标定位到first处开始下一类别的字符串写入答案
            else {
                position[left] = first;
                i = first - 1;
            }
            // 更新存储每一类别下字符串数目的数组,同时类别数num加一
            word_num[num++] = num1;
        }
    }
    *returnSize = num;
    *returnColumnSizes = (int*)malloc(sizeof(int) * (*returnSize));
    char*** ans = (char***)malloc(sizeof(char**) * num);
    // 初始化init为0,表示答案从第0个字符串开始写入
    int init = 0;
    for (int i = 0; i < num; i++) {
        (*returnColumnSizes)[i] = word_num[i];
        ans[i] = (char**)malloc(sizeof(char*) * word_num[i]);
        int length2 = strlen(strs[init]) + 1;
        for (int j = 0; j < word_num[i]; j++) {
            ans[i][j] = (char*)malloc(sizeof(char) * length2);
            for (int k = 0; k < length2 - 1; k++) {
                ans[i][j][k] = strs[init][k];
            }
            ans[i][j][length2 - 1] = '\0';
            // 更新下一个要写入ans的字符串的下标
            init = position[init];
        }
    }
    return ans;
}

代码有点复杂,时间复杂度也比较高,但还是可以过的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值