开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!
Leetcode学习之哈希表与字符串 (1)
1、哈希表基础知识
哈希表:(Hash table)根据关键字值(key)直接进行访问的数据结构,它通过把关键字值映射到表中一个位置(数组下标)来直接访问,以加快查找关键字值的速度。这个映射函数叫做哈希函数,存放记录的数组叫做哈希表。给定表M,存在函数
f
(
k
e
y
)
f(key)
f(key),对任意的关键字key,代入函数后若能得到包含该关键字的表中位置,称表M为哈希表,函数
f
(
k
e
y
)
f(key)
f(key)为哈希函数。
1、哈希-字符串
测试代码:
#include <stdio.h>
#include <string> //ASC2码,从0-127,故使用下标做映射,最大范围为128
using namespace std;
int main() {
int char_map[128] = { 0 };
string str = "abcdefgaaxy";
//统计字符串中,各个字符的数量
//char_map['a']++ 表示 char_map[97]++
for (int i = 0; i < str.length(); i++) {
char_map[str[i]]++;
}
for (int i = 0; i < 128; i++) {
if (char_map[i] > 0) {
printf("[%c][%d]:%d\n", i, i, char_map[i]);
}
}
system("pause");
return 0;
}
效果图:
2、哈希表排序整数
测试代码:
#include <stdio.h>
#include <string> //哈希表排序,使用数组的下标对正整数排序
using namespace std; // 哈希表的长度,需要超过最大待排序数组
int main() {
int random[10] = { 999,1,444,7,20,9,1,3,7,7 };
int hash_map[1000] = { 0 };
for (int i = 0; i < 10; i++) {
hash_map[random[i]]++;
}
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < hash_map[i]; j++) {
printf("%d\n", i);
}
}
system("pause");
return 0;
}
效果图:
3、任何元素的映射
测试代码:
#include <stdio.h>
#include <string> //哈希表排序,使用数组的下标对正整数排序
using namespace std; // 哈希表的长度,需要超过最大待排序数组
//直接对整数取余表长再返回
int int_func(int key, int table_len) {
return key%table_len;
}
//将字符串的字符的ASC2码相加得到整数再取余表长
int string_func(string key, int table_len) {
int sum;
for (int i = 0; i < key.length(); i++) {
sum = sum + key[i];
}
return sum % table_len;
}
int main() {
const int TABLE_LEN = 10;
int hash_map[TABLE_LEN] = { 0 };
hash_map[int_func(99999995, TABLE_LEN)]++;
hash_map[int_func(5, TABLE_LEN)]++;
hash_map[string_func("abc", TABLE_LEN)]++;
hash_map[string_func("bac", TABLE_LEN)]++;
for (int i = 0; i < TABLE_LEN; i++) {
printf("hash_map[%d] = %d \n", i, hash_map[i]);
}
system("pause");
return 0;
}
上段代码的出错原因为:不同的整数或者字符串,由于哈希函数的选择,被映射到了同一个下标处,产生了冲突!
=>拉链法,来构造哈希表!
测试代码:
#include <stdio.h>
#include <vector>
using namespace std;
struct ListNode{
int val;
ListNode *next;
ListNode(int x):val(x),next(NULL) { }
};
//整数哈希函数,直接取余
int hash_func(int key, int table_len) {
return key % table_len;
}
void insert(ListNode *hash_table[], ListNode *node, int table_len) {
int hash_key = hash_func(node->val, table_len); //取余
node->next = hash_table[hash_key]; //使用头插法插入节点
hash_table[hash_key] = node;
}
bool search(ListNode *hash_table[], int value, int table_len) {
int hash_key = hash_func(value, table_len); //整数直接取余
ListNode *head = hash_table[hash_key]; //关键词
while (head) {
if (head->val == value) {
return true;
}
head = head->next;
}
return false;
}
int main() {
const int TABLE_LEN = 11;
ListNode *hash_table[TABLE_LEN] = { 0 };
vector<ListNode *> hash_node_vec; //二叉树
int test[8] = { 1,1,4,9,20,30,150,500 };
for (int i = 0; i < 8; i++) { //二叉树
hash_node_vec.push_back(new ListNode(test[i]));
}
//将同一个加入hash_table中
for (int i = 0; i < hash_node_vec.size(); i++) {
insert(hash_table, hash_node_vec[i], TABLE_LEN);
}
printf("Hash table:\n");
for (int i = 0; i < TABLE_LEN; i++) {
printf("[%d]:", i);
ListNode *head = hash_table[i];
while (head){
printf("->%d", head->val);
head = head->next;
}
printf("\n");
}
printf("\n");
printf("Test search:\n");
for (int i = 0; i < 10; i++) {
if (search(hash_table, i, TABLE_LEN)) { //查找这个key里面是否有这个
printf("%d is in the hash table.\n",i);
}
else{
printf("%d is not in the hash table.\n",i);
}
}
system("pause");
return 0;
}
效果图:
4、哈希map与STL map
测试代码:
#include <stdio.h>
#include <map>
#include <string>
using namespace std;
struct ListNode {
string key;
int val;
ListNode *next;
ListNode(int x):val(x),next(NULL){}
};
int main() {
map<string, int> hash_map; //将字符串key映射为整数val
string str1 = "abc";
string str2 = "aaa";
string str3 = "xxxxx";
hash_map[str1] = 1;
hash_map[str2] = 2;
hash_map[str3] = 100;
if (hash_map.find(str1) != hash_map.end()) {
printf("%s is in hash_map, value is %d\n", str1.c_str(), hash_map[str1]);
}
map<string, int>::iterator it; //这边使用迭代器 注意用法 很常用
for (it = hash_map.begin(); it != hash_map.end(); it++) {
printf("hash_map[%s] = %d \n", it->first.c_str(), it->second);
}
system("pause");
return 0;
}
效果图:
2、最长回文串(字符哈希)LeetCode 409.
题目来源:
L
e
e
t
C
o
d
e
409.
L
o
n
g
e
s
t
P
a
l
i
n
d
r
o
m
e
LeetCode \ 409. \ Longest \ Palindrome
LeetCode 409. Longest Palindrome
回文字符串:除了中心字符之外,其余字符只要头部出现,尾部就要对应出现。
描述:已知一个只包括大小写字符的字符串,求用该字符串中的字符可以生成的最长回文字符串长度。
分析:根据回文字符串的特性,我们需要探讨字符数量为奇数和偶数的两种情况。
测试代码:
#include <stdio.h>
#include <map>
#include <string>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x):val(x),next(NULL){}
};
class Solution {
public:
int longestPalidrome(string s) {
int char_map[128] = { 0 }; //字符哈希
int max_length = 0; //回文串偶数部分的最大长度
int flag = 0; //是否有中心点
//key->value++
for (int i = 0; i < s.length(); i++) {
char_map[s[i]]++; //利用整数的数组下标实现字符哈希 统计字符个数
}
for (int i = 0; i < 128; i++) { //如果某字符为偶数,则均使用在回文串中
if (char_map[i] % 2 == 0) {
max_length = max_length + char_map[i];
}
else{ // 如果某字符为奇数个,则丢弃一个,其余的都使用在回文串里面
max_length = max_length + char_map[i] - 1;
flag = 1;
} //此时标记回文串里面有中心点
}
return max_length + flag;
}
}; //最终结果是偶数部分的最大长度+中心点字符
int main() {
string s = "abccccddaa";
Solution solve;
printf("%d\n", solve.longestPalidrome(s));
system("pause");
return 0;
}
效果图: