实操案例:字符串哈希表操作

软件工
• 阅读 2735
摘要:当遇到C语言库没有字符串哈希表的时候,该如何进行操作。

有考C语言可信编程认证的同事经常会问到,C语言库没有字符串哈希表操作,那考试遇到了怎么办。虽然历次考试的题目中没有必须要用到C语言哈希表的题目(至少我都能用常规C做出来),但是还需要防患未然,这里给出一道有代表性的题目,可以尝试做做看:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words/

给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
示例:
输入:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
输出:[0,9]
解释:
从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。

这题不考虑编程语言的话,用哈希表会比较简单,那要是用C语言的话,可以自己撸个哈希表用,对付这类题目还是绰绰有余的。

思路的话参考https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-6/中的解法二,这里只讲下怎么最简单构造一个哈希表。

首先是选取哈希函数,这里我用的是djb2算法,参考http://www.cse.yorku.ca/~oz/hash.html,碰撞率相当低,分布平衡,实现也很简单,就两三行代码,记住关键数字(5381和33)。

If you just want to have a good hash function, and cannot wait, djb2 is one of the best string hash functions i know. it has excellent distribution and speed on many different sets of keys and table sizes.

Language- 代码

unsigned long
hash(unsigned char *str)
{
    unsigned long hash = 5381;

    int c;

    while (c = *str++)

        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;

}

有了字符串哈希函数,就能够将大串字符串转换成数字,数字进而可以作为数组的下标(key)存储信息。那么哈希表的大小怎么取呢?一般大小要大于存储的数据个数,比如最多100个数据,存到哈希表的话大小肯定要大于100才行。对于这题而言,没有明确告诉你单词的最大个数,只能估值了,这里经过几轮提交测试,得到哈希表大小与通过用例个数的关系,说明这道题目最多的单词数可能在300左右,平均个数<50个吧:

5 -> 110/173
10 -> 143/173
50 -> 170/173
100 -> 170/173
300 -> 172/173
400 -> 173/173

这里给出我的解答:

实操案例:字符串哈希表操作

C 代码

// 字符串最大值,hash表大小,估值和实际数据个数有关

#define MAXWORDCOUNT 1000


static int wordCount[MAXWORDCOUNT];

static int currWordCount[MAXWORDCOUNT];



// ref: http://www.cse.yorku.ca/~oz/hash.html


unsigned long DJBHash(const char* s, int len) {

    unsigned long hash = 5381; // 经验值,hash冲突概率低,分布平衡


    while (len--) {

        hash = (((hash << 5) + hash) + *(s++)) % MAXWORDCOUNT; /* hash * 33 + c */


    }

    return hash;


}



int* findSubstring(char * s, char ** words, int wordsSize, int* returnSize){

    memset(wordCount, 0, sizeof(wordCount));


    *returnSize = 0;



    const int kSLen = strlen(s);

    if (kSLen == 0 || wordsSize == 0) return NULL;



    const int kWordLen = strlen(words[0]);


    // 将单词数量存到哈希表中,key: word, value: 单词数量

    for (int i = 0; i < wordsSize; ++i)


        ++wordCount[DJBHash(words[i], kWordLen)];



    int *result = malloc(sizeof(int) * kSLen);

    for (int i = 0; i < kWordLen; ++i) {


        for (int j = i; j + kWordLen * wordsSize <= kSLen; j += kWordLen) {

            // 统计当前窗口的单词数量


            for (int k = (j == i ? 0 : wordsSize - 1); k < wordsSize; ++k)

                ++currWordCount[DJBHash(s + j + k * kWordLen, kWordLen)];



            // 判断两个哈希表是否相等,即窗口中的单词是否和给定词典完全匹配


            if (memcmp(wordCount, currWordCount, sizeof(wordCount)) == 0)

                result[(*returnSize)++] = j;



            --currWordCount[DJBHash(s + j, kWordLen)];


        }

        // 哈希表清零操作


        memset(currWordCount, 0, sizeof(currWordCount));

    }


    return result;

}

点击关注,第一时间了解华为云新鲜技术~

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
待兔 待兔
1年前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Easter79 Easter79
3年前
sql注入
反引号是个比较特别的字符,下面记录下怎么利用0x00SQL注入反引号可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景,下面具体说下1)表名payload:select\from\users\whereuser\_id1limit0,1;!(https://o
Wesley13 Wesley13
3年前
030 SSM综合练习06
1.权限操作涉及的三张表(1)用户表信息描述users!(https://oscimg.oschina.net/oscnet/a4a2b1f943cbc2db1c8ddd613e7ed00a9ae.png)sql语句:CREATETABLEusers(idVARCHAR2(32)DEFAU
Stella981 Stella981
3年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
贾蔷 贾蔷
4星期前
手把手教你实现哈希表:从代码到原理的新手友好指南
一、简介和应用哈希表(HashTable)是一种高效的数据结构,通过哈希函数将键(Key)映射到存储位置,实现O(1)时间复杂度的查找、插入和删除操作。它广泛应用于缓存系统、数据库索引、字典查询等场景。例如,在编程中需要快速根据用户ID查找信息时,哈希表能
软件工
软件工
Lv1
几度思归还把酒,拂云堆上祝明妃。
文章
3
粉丝
0
获赞
0