实操案例:字符串哈希表操作
有考C语言可信编程认证的同事经常会问到,C语言库没有字符串哈希表操作,那考试遇到了怎么办。虽然历次考试的题目中没有必须要用到C语言哈希表的题目(至少我都能用常规C做出来),但是还需要防患未然,这里给出一道有代表性的题目,可以尝试做做看:https://leetcode-cn.com/problems/substring-with-concatenation-of-all-words/
给定一个字符串 s 和一些长度相同的单词 words。找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置。
注意子串要与 words 中的单词完全匹配,中间不能有其他字符,但不需要考虑 words 中单词串联的顺序。
[code]示例: 输入: 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- 代码
[code] 01 unsigned long 02 hash(unsigned char *str) 03 { 04 unsigned long hash = 5381; 05 int c; 06 07 while (c = *str++) 08 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 09 10 return hash; 11 }
有了字符串哈希函数,就能够将大串字符串转换成数字,数字进而可以作为数组的下标(key)存储信息。那么哈希表的大小怎么取呢?一般大小要大于存储的数据个数,比如最多100个数据,存到哈希表的话大小肯定要大于100才行。对于这题而言,没有明确告诉你单词的最大个数,只能估值了,这里经过几轮提交测试,得到哈希表大小与通过用例个数的关系,说明这道题目最多的单词数可能在300左右,平均个数<50个吧:
[code]5 -> 110/173 10 -> 143/173 50 -> 170/173 100 -> 170/173 300 -> 172/173 400 -> 173/173
这里给出我的解答:
C 代码
[code]01 // 字符串最大值,hash表大小,估值和实际数据个数有关 02 #define MAXWORDCOUNT 1000 03 static int wordCount[MAXWORDCOUNT]; 04 static int currWordCount[MAXWORDCOUNT]; 05 06 // ref: http://www.cse.yorku.ca/~oz/hash.html 07 unsigned long DJBHash(const char* s, int len) { 08 unsigned long hash = 5381; // 经验值,hash冲突概率低,分布平衡 09 while (len--) { 10 hash = (((hash << 5) + hash) + *(s++)) % MAXWORDCOUNT; /* hash * 33 + c */ 11 } 12 return hash; 13 } 14 15 int* findSubstring(char * s, char ** words, int wordsSize, int* returnSize){ 16 memset(wordCount, 0, sizeof(wordCount)); 17 *returnSize = 0; 18 19 const int kSLen = strlen(s); 20 if (kSLen == 0 || wordsSize == 0) return NULL; 21 22 const int kWordLen = strlen(words[0]); 23 // 将单词数量存到哈希表中,key: word, value: 单词数量 24 for (int i = 0; i < wordsSize; ++i) 25 ++wordCount[DJBHash(words[i], kWordLen)]; 26 27 int *result = malloc(sizeof(int) * kSLen); 28 for (int i = 0; i < kWordLen; ++i) { 29 for (int j = i; j + kWordLen * wordsSize <= kSLen; j += kWordLen) { 30 // 统计当前窗口的单词数量 31 for (int k = (j == i ? 0 : wordsSize - 1); k < wordsSize; ++k) 32 ++currWordCount[DJBHash(s + j + k * kWordLen, kWordLen)]; 33 34 // 判断两个哈希表是否相等,即窗口中的单词是否和给定词典完全匹配 35 if (memcmp(wordCount, currWordCount, sizeof(wordCount)) == 0) 36 result[(*returnSize)++] = j; 37 38 --currWordCount[DJBHash(s + j, kWordLen)]; 39} 40 // 哈希表清零操作 41 memset(currWordCount, 0, sizeof(currWordCount)); 42 } 43 return result; 44 }
- 学习笔记(03):21天通关Python(视频课)-案例实操:使用事务控制数据库操作
- 学习笔记(01):实用主义学Python(小白也容易上手的Python实用案例)-实操:为背景去除程序添加操作界面...
- python实操(5):python数据类型及常用操作,数字、字符串、元组、列表、字典、集合
- 关于Excel操作编写的一个软件设计构思案例[连载] --如何实现从字符串中提取需要的字符并赋值给指定单元格内
- python用字符串操作20行代码简单爬虫入门+案例(爬取一章《三体》小说)
- 项目案例:二进制文件与十六进制字符串转化常用操作
- linux shell 字符串操作(长度,查找,替换)详解
- 《Windows Via C/C++》边学习,边翻译(四)操作字符和字符串-3
- LeetCode OJ ZigZag Conversion ”之“字符串变化 string操作
- C语言数据结构(16)--使用数组实现字符串常用操作实例
- Js字符串操作函数大全
- 第十三周项目5字符串操作(1)
- symbian s60 字符串操作
- Linux c 开发 - 常用字符串操作全集
- python基础学习6----字符串操作
- Spark 2.2.1 JSON 数据集操作的案例与解读
- solr的修改操作案例
- java操作html字符串
- Python字符串操作的性能测试
- javascript中对字符串的操作总结