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

news2025/1/24 1:33:40

知识点:

散列函数

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

  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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CentOS 7安装Zookeeper

说明&#xff1a;本文介绍如何在CentOS 7操作系统下使用Zookeeper 下载安装 首先&#xff0c;去官网下载所需要安装的版本&#xff0c;我这里下载3.4.9版本&#xff1b; 上传到云服务器上&#xff0c;解压 tar -xvf zookeeper-3.4.9.tar.gz修改配置 进入Zookeeper目录下的co…

ssm049基于Vue.js的在线购物系统的设计与实现+vue

在线购物系统 摘 要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于在线购物系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了在线购物系统&#xff0c;它彻底改…

设计模式代码实战-外观模式

1、问题描述 小明家的电源总开关控制了家里的三个设备&#xff1a;空调、台灯和电视机。每个设备都有独立的开关密码&#xff0c;分别用数字1、2和3表示。即输入1时&#xff0c;空调关闭&#xff0c;输入2时&#xff0c;台灯关闭&#xff0c;输入3时&#xff0c;电视机关闭&am…

排序总结Java

文章目录 排序算法复杂度总结插入排序希尔排序归并排序快速排序堆排序 排序算法复杂度总结 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 插入排序 public class Sort {// 插入排序public int[] inserSort(int[] nums){for (int i 1; i < nums.length;…

科技助力输电线安全隐患预警,基于YOLOv8全系列【n/s/m/l/x】参数模型开发构建电力设备场景下输电线安全隐患目标检测预警系统

电力的普及让我们的生活变得更加便利&#xff0c;四通八达的电网连接着生活的方方面面&#xff0c;电力能源主要是依托于庞大复杂的电网电力设备进行传输的&#xff0c;有效地保障电网场景下输电线的安全对于保障我们日常生活所需要的电力有着重要的意义&#xff0c;但是电力设…

Redis报错:CROSSSLOT Keys in request don‘t hash to the same slot的解决方案

最近&#xff0c;项目上线的时候&#xff0c;出现了一个Redis的报错&#xff1a;CROSSSLOT Keys in request dont hash to the same slot&#xff0c;这个在内网环境下无法复现&#xff0c;因为正式环境的Redis是cluster集群模式&#xff0c;而我们内网环境是单机模式。(后面我…

Django第三方功能的使用

Django第三方功能的使用 Django REST framework前言1、Django--Restframework--coreapi版文档BUG:AssertionError: coreapi must be installed for schema support.How to run Django with Uvicorn webserver?2、序列化类 Serializer的使用模型序列化类 ModelSerializer的使用…

再写-全景拼接

全景拼接 1. 将读取进行灰度转化&#xff0c;并且输出图像&#xff0c;关键点和计算描述 import cv2 import numpy as np# 将读取进行灰度转化&#xff0c;并且输出图像&#xff0c;关键点和计算描述 image_left cv2.imread("C:\\Users\\HONOR\\Desktop\\image\\pinjie…

001_IoT/物联网通信协议基础: HTTP、Websocket、MQTT、AMQP、COAP、LWM2M一文搞懂

001_IoT/物联网通信协议基础: HTTP、Websocket、MQTT、AMQP、COAP、LWM2M一文搞懂 文章目录 001_IoT/物联网通信协议基础: HTTP、Websocket、MQTT、AMQP、COAP、LWM2M一文搞懂创作背景通信模型ISO/OSI七层模型 和 TCP/IP四层模型网络通信数据包格式&#xff08;Ethernet II&…

【微信小程序——案例——本地生活(列表页面)】

案例——本地生活&#xff08;列表页面&#xff09; 九宫格中实现导航跳转——以汽车服务为案例&#xff08;之后可以全部实现页面跳转——现在先实现一个&#xff09; 在app.json中添加新页面 修改之前的九宫格view改为navitage 效果图&#xff1a; 动态设置标题内容—…

【5G PHY】5G无线链路监测原理简述

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

车载电子电器架构 —— 平行开发策略

车载电子电器架构 —— 平行开发策略 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己…

架构师系列-搜索引擎ElasticSearch(八)- 集群管理故障恢复

故障转移 集群的master节点会监控集群中的节点状态&#xff0c;如果发现有节点宕机&#xff0c;会立即将宕机节点的分片数据迁移到其它节点&#xff0c;确保数据安全&#xff0c;这个叫做故障转移。 下图中node1是主节点&#xff0c;其他两个节点是从节点 节点故障 此时node1…

【LeetCode】回溯算法类题目详解

所有题目均来自于LeetCode&#xff0c;刷题代码使用的Python3版本 回溯算法 回溯算法是一种搜索的方法&#xff0c;在二叉树总结当中&#xff0c;经常使用到递归去解决相关的问题&#xff0c;在二叉树的所有路径问题中&#xff0c;我们就使用到了回溯算法来找到所有的路径。 …

计算机网络 实验指导 实验17

实验17 配置无线网络实验 1.实验拓扑图 Table PC0 和 Table PC1 最开始可能还会连Access Point0&#xff0c;无影响后面会改 名称接口IP地址网关地址Router0fa0/0210.10.10.1fa0/1220.10.10.2Tablet PC0210.10.10.11Tablet PC1210.10.10.12Wireless互联网220.10.10.2LAN192.16…

CSS-布局

display display 属性是用于控制 布局 的最重要的 CSS 属性。display 属性规定是否/如何显示元素。 每个 HTML 元素都有一个默认的 display 值&#xff0c;具体取决于它的元素类型。大多数元素的默认 display 值为 block 或 inline。 block block&#xff1a;块级元素。块级…

STL--list双向链表

功能 将数据进行链式存储 链表&#xff08;list&#xff09;是一种物理存储单元上非连续的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接实现的 链表的组成&#xff1a;链表由一系列结点组成 结点的组成&#xff1a;一个是存储数据元素的数据域&#xff0…

Java应用中文件上传安全性分析与安全实践

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 一. 文件上传的风险 二. 使用合适的框架和库 1. Spr…

Tomcat服务器入门介及用postman工具简单接收数据 2024详解

Tomcat服务器 简介 Tomcat是一个开源的Servlet容器&#xff0c;也是一个支持Java Servlet和JSP技术的Web服务器。它由Apache软件基金会开发和维护。Tomcat的主要作用是将Java Servlet和JavaServer Pages&#xff08;JSP&#xff09;等动态网页技术部署到服务器上&#xff0c;…

Linux操作系统中关于用户管理的操作

创建新用户 useradd 【选项】 用户名 在/etc/passwd中以追加的方式在passwd的最后一行添加用户信息。 可以使用命令tail -n 1/etc/passwd查看文件的最后一行内容。 ls /home/首先/home/这是普通用户的家目录&#xff0c; 在/home/下会有一个跟用户名同名的家目录&#xf…