力扣:49. 字母异位词分组

知识点:

散列函数

散列函数能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位:

  1. 直接寻址法:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a*key + b,其中a和b为常数(这种散列函数叫做自身函数)

  2. 数字分析法:分析一组数据,比如一组员工的出生年月日,这时我们发现出生年月日的前几位数字大体相同,这样的话,出现冲突的几率就会很大,但是我们发现年月日的后几位表示月份和具体日期的数字差别很大,如果用后面的数字来构成散列地址,则冲突的几率会明显降低。因此数字分析法就是找出数字的规律,尽可能利用这些数据来构造冲突几率较低的散列地址。

  3. 平方取中法:取关键字平方后的中间几位作为散列地址。

  4. 折叠法:将关键字分割成位数相同的几部分,最后一部分位数可以不同,然后取这几部分的叠加和(去除进位)作为散列地址。通常针对较长的关键字。

  5. 随机数法:选择一随机函数,取关键字的随机值作为散列地址,通常用于关键字长度不同的场合。

  6. 除留余数法:取关键字被某个不大于散列表表长m的数p除后所得的余数为散列地址。即 H(key) = key MOD p, p<=m。不仅可以对关键字直接取模,也可在折叠、平方取中等运算之后取模。对p的选择很重要,一般取素数或m,若p选的不好,容易产生同义词。

查找效率

查找过程中,关键码的比较次数,取决于产生冲突的多少,产生的冲突少,查找效率就高,产生的冲突多,查找效率就低。因此,影响产生冲突多少的因素,也就是影响查找效率的因素。影响产生冲突多少有以下三个因素:

  1. 散列函数是否均匀;

  2. 处理冲突的方法;

  3. 散列表的装填因子。

  散列表的装填因子定义为:α= 填入表中的元素个数 / 散列表的长度

  α是散列表装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。

  实际上,散列表的平均查找长度是装填因子α的函数,只是不同处理冲突的方法有不同的函数。

加法哈希:

常用于字符串,将字符串中的每个字符转换为其对应的 ASCII 值,然后进行加法运算来生成哈希值。

int hash(char* str) {
    int hashValue = 0;
    for (int i = 0; str[i] != '\0'; i++) {
        hashValue += str[i];
    }
    return hashValue;
}

这里使用了一个简单的散列函数,它是一个基于质数的乘法散列函数。具体来说,散列函数的实现如下:

//对字符串进行哈希
int hash(char* str) {
    int hashValue = 0;
    for (int i = 0; str[i] != '\0'; i++) {
        hashValue = (hashValue * PRIME + str[i]) % 1000007;
    }
    return hashValue;
}

在这里,PRIME 是一个选择的质数,它有助于减少碰撞。我们遍历字符串的每个字符,并用它们更新 hashValue。由于我们对 hashValue 取模 1000007,所以返回的散列值会在 01000006 之间。

位运算哈希:

先移位,然后再进行各种位运算是这种类型Hash函数的主要特点。

int bitHash(char* str) {
    int hashValue = 0;
    for (int i = 0; str[i] != '\0'; i++) {
        hashValue = (hashValue << 5) + str[i] ^ hashValue;
    }
    return hashValue;
}

乘法哈希:

利用了乘法的不相关性(乘法的这种性质,最有名的莫过于平方取头尾的随机数生成算法,虽然这种算法效果并不好)。

FNV(Fowler–Noll–Vo)哈希算法是一个著名的乘法哈希算法,常用于字符串哈希。它是一种非常简单但效果很好的哈希算法。

#include <stdint.h>

uint32_t fnv1a(char* str) {
    uint32_t hash = 2166136261u; // FNV偏移基础值
    while (*str) {
        hash ^= (unsigned char)*str++;
        hash *= 16777619u; // FNV素数
    }
    return hash;
}

字符串操作:

#include<string.h>

字符串复制

strdup 是一个 C 语言函数,用于复制一个字符串。

strdup 函数会分配足够的内存来存储传入的字符串,并将原始字符串复制到新分配的内存中。然后返回指向新分配的字符串的指针。

char* copy = strdup(str);

free(copy);

strdup 可以用于创建字符串的副本,以便稍后使用和修改,而不影响原始字符串。

将malloc和赋值操作合二为一

排序:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

  • base:指向要排序的数组的指针。
  • nmemb:数组中元素的数量。
  • size:数组中每个元素的大小(以字节为单位)。
  • compar:用于比较两个元素的函数的指针。
int compare(const void* a, const void* b) {
    return *(char*)a - *(char*)b;
}
 char* str1 = strdup(strs[i]);
        int len = strlen(str1);
        //对 str1 中的字符进行排序,这样,具有相同字符的异位词会有相同的排序后的字符串。
        qsort(str1, len, sizeof(char), compare);

暴力求解:

超出时间限制。

*returnSize记录最终数组有多少个。

returnColumnSize记录最终数组中,每个数组的长度。一维数组。

        result[*returnSize] = (char**)malloc(strsSize * sizeof(char*));

        (*returnColumnSizes)[*returnSize] = 0;

        result[*returnSize][(*returnColumnSizes)[*returnSize]] = strs[i];

        (*returnColumnSizes)[*returnSize] += 1;

/**
 * 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().
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>



int compare(const void* a, const void* b) {
    return *(char*)a - *(char*)b;
}

char*** groupAnagrams(char** strs, int strsSize, int* returnSize, int** returnColumnSizes) {
    //记录strs中哪个词被找过了
    int* countstrs = (int*)malloc(strsSize * sizeof(int));
    //全置为0
    memset(countstrs, 0, strsSize * sizeof(int));
    *returnSize = 0;

    char*** result = (char***)malloc(strsSize * sizeof(char**));
    *returnColumnSizes = (int*)malloc(strsSize * sizeof(int));

    for (int i = strsSize-1; i >=0; i--) {
        if (countstrs[i] == 1) continue;
        
        char* str1 = strdup(strs[i]);
        int len = strlen(str1);
        //对 str1 中的字符进行排序,这样,具有相同字符的异位词会有相同的排序后的字符串。
        qsort(str1, len, sizeof(char), compare);
        
        result[*returnSize] = (char**)malloc(strsSize * sizeof(char*));
        (*returnColumnSizes)[*returnSize] = 0;

        result[*returnSize][(*returnColumnSizes)[*returnSize]] = strs[i];
        (*returnColumnSizes)[*returnSize] += 1;
        countstrs[i] = 1;

        for (int z = i-1; z >=0; z--) {
            if (countstrs[z] == 1) continue;

            char* str2 = strdup(strs[z]);
            if (len != strlen(str2)) {
                free(str2);
                continue;
            }
            
            qsort(str2, len, sizeof(char), compare);
            //现在都顺序排列了
            int flag=0;
            for (int j = 0; j < len; j++) {
                    if (str1[j] == str2[j] ) {
                        flag++;
                    }
                    else
                    break;
            }

            if (flag==len) {
                result[*returnSize][(*returnColumnSizes)[*returnSize]] = strs[z];
                (*returnColumnSizes)[*returnSize] += 1;
                countstrs[z] = 1;
            }

            free(str2);
        }
        *returnSize += 1;
        free(str1);
    }

    free(countstrs);
    return result;
}

哈希:

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

#define PRIME 31

typedef struct Node {
    char* key;
    char** values;
    int count;
    struct Node* next;
} Node;

int compare(const void* a, const void* b) {
    return *(char*)a - *(char*)b;
}

//对字符串进行哈希
int hash(char* str) {
    int hashValue = 0;
    for (int i = 0; str[i] != '\0'; i++) {
        hashValue = (hashValue * PRIME + str[i]) % 1000007;
    }
    return hashValue;
}

Node* createNode(char* key, char* value) {
    Node* newNode = (Node*)malloc(sizeof(Node));
    newNode->key = strdup(key);
    newNode->values = (char**)malloc(1000 * sizeof(char*));
    newNode->values[0] = strdup(value);
    newNode->count = 1;
    newNode->next = NULL;
    return newNode;
}

Node** createHashMap(int size) {
    Node** table = (Node**)malloc(size * sizeof(Node*));
    for (int i = 0; i < size; i++) {
        table[i] = NULL;
    }
    return table;
}

void insert(Node** table, char* key, char* value, int size) {
    int index = hash(key) % size;
    if (table[index] == NULL) {
        table[index] = createNode(key, value);
        return;
    }

    Node* current = table[index];
    while (current->next != NULL) {
        if (strcmp(current->key, key) == 0) {
            current->values[current->count++] = strdup(value);
            return;
        }
        current = current->next;
    }

    if (strcmp(current->key, key) == 0) {
        current->values[current->count++] = strdup(value);
    } else {
        current->next = createNode(key, value);
    }
}

char*** groupAnagrams(char** strs, int strsSize, int* returnSize, int** returnColumnSizes) {
    *returnSize = 0;
    Node** hashMap = createHashMap(1000007);
    *returnColumnSizes = (int*)malloc(strsSize * sizeof(int));
    char*** result = (char***)malloc(strsSize * sizeof(char**));

    for (int i = 0; i < strsSize; i++) {
        char* sortedStr = strdup(strs[i]);
        qsort(sortedStr, strlen(sortedStr), sizeof(char), compare);
        insert(hashMap, sortedStr, strs[i], 1000007);
        free(sortedStr);
    }

    for (int i = 0; i < 1000007; i++) {
        Node* current = hashMap[i];
        while (current != NULL) {
            result[*returnSize] = (char**)malloc(current->count * sizeof(char*));
            for (int j = 0; j < current->count; j++) {
                result[*returnSize][j] = strdup(current->values[j]);
            }
            (*returnColumnSizes)[*returnSize] = current->count;
            (*returnSize)++;
            current = current->next;
        }
    }

    for (int i = 0; i < 1000007; i++) {
        Node* current = hashMap[i];
        while (current != NULL) {
            for (int j = 0; j < current->count; j++) {
                free(current->values[j]);
            }
            free(current->values);
            Node* temp = current;
            current = current->next;
            free(temp->key);
            free(temp);
        }
    }

    free(hashMap);
    return result;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/548988.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

企业如何上百度百科

企业想要上百度百科&#xff0c;首先需要创建属于自己的词条。创建企业百度百科词条的步骤如下: 企业认证&#xff1a;企业需要提供营业执照等证明材料&#xff0c;以证明其合法性。此外&#xff0c;企业营业执照的注册时间必须满一年及以上&#xff0c;且在近一年内没有因为经…

如何在CentOS安装Firefox并结合内网穿透工具实现公网访问本地火狐浏览器

文章目录 1. 部署Firefox2. 本地访问Firefox3. Linux安装Cpolar4. 配置Firefox公网地址5. 远程访问Firefox6. 固定Firefox公网地址7. 固定地址访问Firefox Firefox是一款免费开源的网页浏览器&#xff0c;由Mozilla基金会开发和维护。它是第一个成功挑战微软Internet Explorer浏…

(Talk-Bot,ichat助手,ChatK,DGAL,NextChat,FreeGPT,动点原版chatgpt)分享7个好用ChatGPT

目录 目录 1、Talk-Bot 2、ichat助手 3、ChatK 4、DGAI 5、NextChat 6、Chkzh-Aink 7、FreeGPT | dongstop.vip 8、动点原版chatgpt 1、Talk-Bot https://vip.gptchatclub.org/?fromweb 2、ichat助手 https://chat.letdata.net/ichat/59w2x4n3pow https://ichat2019.com/ichat…

1231: 寻找出现次数最多的数

解法&#xff1a; #include<iostream> #include<algorithm> #include<vector> #include<unordered_map> #include<utility> using namespace std; int main() {int n, a;cin >> n;unordered_map<int, int> mp;while (n--) {cin >…

【Web】VS Code 插件

专栏文章索引&#xff1a;Web 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、安装步骤 二、插件 1.Chinese (Simplified) (简体中文) 2.open in browser 3.vscode-icons 4.Live Server 5.Live Server Preview 6.翻译(英汉词典) 一、安装步骤 点击 “扩…

Navicat 干货 | 了解 PostgreSQL 规则

PostgreSQL 是一个强大的开源关系型数据库管理系统&#xff0c;为增强数据管理和操作提供了丰富的功能。这些功能中包含了规则&#xff0c;这是一种用于控制数据库内部查询和命令处理方式的机制。本文将探讨 PostgreSQL 规则的工作原理&#xff0c;以及它们与触发器的区别&…

中东跨境电商平台Noon注册开店步骤详解

中东地区&#xff0c;素以“满地富豪”闻名&#xff0c;同时拥有发达的电子商务环境与较高的居民消费水平&#xff0c;吸引了大量跨境电商从业者前来寻求商机。其中&#xff0c;Noon作为中东地区颇具人气的电商平台&#xff0c;自然而然成为了众多卖家开拓中东市场的首选平台。…

关于Qt主窗口的菜单部件

前言 在介绍主窗口的两大部件之前&#xff0c;我们要先知道关于主窗口的一些知识。 主窗口 一个主窗口可以没有菜单条、工具条、状态条&#xff0c;但必须设置中心部件。在 Q 生成的 C头文件 ui_mainwindow.h 代码中,我们可以看到以下代码: centralWidget new Qwidget(MainWi…

节省时间和资源:了解如何最大化渲染农场的排队管理效率

在3D渲染领域&#xff0c;时间的价值无可替代。随著3D艺术家与制作工作室不断挑战技术极限&#xff0c;对高效计算资源的渴求空前增长&#xff0c;渲染农场因此成为了渲染任务中不可或缺的力量。其核心在于排队系统——这一动态且复杂的结构负责安排和最优化渲染任务的执行顺序…

剑指Offer题目笔记31(图的搜索)

面试题105&#xff1a; 解决方案&#xff1a; ​ 逐一扫描矩阵的每一个格子&#xff0c;如果遇到一个值为1的格子并且它不在已知的岛屿上&#xff0c;那么就到达了一个新的岛屿&#xff0c;于是搜索这个岛屿并且计算它的面积&#xff0c;在比较所有岛屿的面积之后就可以知道最…

高标准化及可扩展的产品能力,助力声通科技运营效率不断提升

高标准化及可扩展的产品能力对企业发展具有重要意义&#xff0c;有助于企业提高运营效率、增强市场竞争力&#xff0c;并推动企业实现规模化发展。上海声通信息科技股份有限公司&#xff08;下文称&#xff1a;声通科技或公司&#xff09;作为我国领先的企业级全栈交互式人工智…

C语言练习:变种水仙花数

今天让我们来看看变种的水仙花吧&#xff0c;话不多说&#xff0c;直入主题。 题目描述 变种水仙花数- Lily Number: 把任意的数字&#xff0c;从中间拆分成两个数字&#xff0c;比如1461可 以拆分成(1和461)&#xff0c;(14和61)&#xff0c;(146和1),如果所有拆分后的乘积之和…

Activity——绘制第一张流程图bpmn

文章目录 前言流程符号事件Event活动 Activity网关 GateWay流向 Flow 使用idea绘制第一张流程图设置流程图各节点属性流程图转换图片 问题原因与问题解决汇总问题一&#xff1a;流程乱码问题二&#xff1a;其他idea主题无左侧 Bpmn Editor 设置框问题三&#xff1a;idea右键xml…

DataGrip数据库管理工具安装使用

DataGrip数据库管理工具安装使用 DataGrip介绍 DataGrip是jetbrains旗下的一款数据库管理工具&#xff0c;相信做过java开发的同学都知道&#xff0c;idea就是这家公司发明的。 DataGrip 是JetBrains公司开发的数据库管理客户端工具&#xff08;操作数据库的IDE&#xff0c;…

imx6ull官方源码linux内核移植

1.尝试官方源码 在正点原子给的资料里找到NXP官方原版linux源码&#xff0c;路径为&#xff1a; 1、例程源码->4、 NXP 官方 原版 Uboot和 Linux->linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2。复制并解压。 修改顶层Makefile 编译一下 make -j16 出现以下错误 修改 就…

react17 + antd4 如何实现Card组件与左侧内容对齐并撑满高度

在使用antd进行页面布局时&#xff0c;经常会遇到需要将内容区域进行左右分栏&#xff0c;并在右侧区域内放置一个或多个Card组件的情况。然而&#xff0c;有时我们会发现右侧的Card组件并不能与左侧的栏目对齐&#xff0c;尤其是当左侧栏目高度动态变化时。本文将介绍如何使用…

基于SSM的游戏攻略管理系统

游戏攻略管理系统的构建与实现 一、系统概述二、系统架构与技术选型三、系统功能模块四、系统特点五、总结与展望 随着网络游戏的普及和发展&#xff0c;游戏攻略成为玩家们提升游戏技能、了解游戏机制的重要途径。为了更好地满足玩家需求&#xff0c;提高游戏攻略的管理效率和…

centos7离线安装postgresql13

**一.**安装存储库RPM yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm二.使用yumdownloader下载安装包 mkdir pg_yum cd pg_yum yumdownloader --resolve postgresql13-server**三.**上传rpm包到安…

Python的pytest框架(1)--基本概念、入门

按基础到进阶的顺序&#xff0c;学习Python的pytest框架&#xff0c;本篇文章先讲一讲pytest的基本概念、入门使用规则。 目录 一、pytest基础知识 1、安装 2、pytest框架主要做了什么工作 二、pytest的规则约定、运行方式以及参数详解 1、编写测试用例 模块&#xff08…

GitHub repository - commits - branches - releases - contributors

GitHub repository - commits - branches - releases - contributors 1. commits2. branches3. releases4. contributorsReferences 1. commits 在这里可以查看当前分支的提交历史。左侧的数字表示提交数。 2. branches 可以查看仓库的分支列表。左侧的数字表示当前拥有的分…