《算法笔记》4.2散列

一.整数的散列
把输入的数作为数组下标来对这个数的性质进行统计;
示例1:

#include<cstdio>
const int maxn = 100010 ;
bool hashTable[maxn] = {false} ;
int main() {
	int n , m , x ;
	scanf("%d%d",&n,&m) ;
	for(int i = 0 ; i < n ; i ++) {
		scanf("%d",&x) ;
		hashTable[x] = true ;
	}
	for(int i = 0 ; i < m ; i ++) {
		scanf("%d",&x) ;
		if(hashTable[x] == true) printf("YES\n") ;
		else printf("NO\n") ; 
	}
	return 0 ;
}

二.其他元素的散列
将元素通过 散列函数H 转换成整数,使该整数尽量唯一代表此元素;
1.散列函数:
1).直接定址法:H(i)=i 或 H(i)=k* i+b;
2).除留余数法:H(i)=i%mod;
2.冲突解决:
1).线性探查法:检查下一个位置是否被占,若超过表长则回到表的首位继续检查,此做法导致扎堆;
2).平方探查法:按以下顺序:H(i)+1* 1、H(i)-1* 1、H(i)+2* 2、H(i)-2* 2;
3).链地址法:造一条单链表;

三.字符串的散列
示例1:S由大写字母构成
e.g.字符串BCD等于26进制下的234,将(234)转换为10进制

int hashFunc(char S[] , int len) {
	int id = 0 ;
	for(int i = 0 ;i < len ; i ++) id = id * 26 + (S[i] - 'A') ;
	return id ;
}

示例2:S由大小写字母构成

int hashFunc(char S[] , int len) {
	int id = 0 ;
	for(S[i] >= 'A' && S[i] <= 'Z') id = id * 52 + (S[i] - 'A') ;
	else if(S[i] >= 'a' && S[i] <= 'z') id = id * 52 + (S[i] - 'a') + 26 ;
	return id ;
}

示例3:S末尾是确定个数的数字

int hashFunc(char S[] , int len) {
	int id = 0 ;
	for(int i = 0 ; i < len - 1 ; i ++) id = id * 26 + (S[i] - 'A') ;
	id = id * 10 + (S[len - 1] - '0') ;
	return id ;
}

四.题目
1.PAT A1084
思路:
枚举查此键是否损坏,利用hashTable记录是否已经输出过;

注意:
1).bool hashTable[128] = {false} ;
2).循环里的 i、j 的值只在此循环内有效,需要在 for 外定义才能在全局有效,并且不能两次用 int;

代码:

#include<cstdio>
#include<cstring>
int main() {
	bool hashTable[128] = {false} ;
	char str1[100] , str2[100] ;
	scanf("%s",str1) ;
	scanf("%s",str2) ;
	int len1 = strlen(str1) ;
	int len2 = strlen(str2) ;
	for(int i = 0 ; i < len1 ; i ++) {
		char c1 , c2 ;
		int j ;
		for(j = 0 ; j < len2 ; j ++) {
			c1 = str1[i] ;
			c2 = str2[j] ;
			if(c1 >= 'a' && c1 <= 'z') c1 -= 32 ;
			if(c2 >= 'a' && c2 <= 'z') c2 -= 32 ;
			if(c1 == c2) break ;
		}
		if(j == len2 && hashTable[c1] == false) {
			printf("%c",c1) ;
			hashTable[c1] = true ;
		}
	}
	return 0 ;
}

2.PAT B1033
思路:
hashTable保存损坏的键(小写),枚举输入的字符串;

注意:
bool hashTable[256] = {true} ;错误,什么都不输出;
bool hashTable[256] ; memset(hashTable , true , sizeof(hashTable)) ;正确;
因为第一种赋值方法只能用于初值为0(false)的情况;若为其他值,则只给数组第一个 hashTable[0] 赋值

代码:

#include<cstdio>
#include<cstring>
using namespace std ;
const int maxn = 100000 + 10 ;
int main() {
	bool hashTable[256] ;
	memset(hashTable , true , sizeof(hashTable)) ;
	char str1[maxn] , str2[maxn] ;
	scanf("%s",str1) ;
	scanf("%s",str2) ;
	int len1 = strlen(str1) ;
	int len2 = strlen(str2) ;
	for(int i = 0 ; i < len1 ; i ++) {
		if(str1[i] >= 'A' && str1[i] <= 'Z') str1[i] += 32 ;
		hashTable[str1[i]] = false ;
	}
	for(int i = 0 ; i < len2 ; i ++) {
		if(str2[i] >= 'A' && str2[i] <= 'Z') {
			int c2 = str2[i] + 32 ;
			if(hashTable[c2] == true && hashTable['+'] == true) printf("%c",str2[i]) ;
		}
		else if(hashTable[str2[i]] == true) printf("%c",str2[i]) ;
	}
	printf("\n") ;
	return 0 ;
}

3.PAT B1039
思路:
1).怎么计算缺少的珠子:hashTable --,若 <0 则缺少的珠子数 miss 加 1,最后通过判断 miss 的正负确定是 Yes 或 No;
2).算多出的珠子时,直接将两串长度相减;

注意:
最后输出时不是YES NO,是Yes No;(我是白痴?多看看其他博客,也有人犯和我一样的错误);

代码:

#include<cstdio>
#include<cstring>
using namespace std ;
const int maxn = 1010 ;
int main() {
	char str1[maxn] , str2[maxn] ;
	int hashTable[128] = {0} ;
	scanf("%s",str1) ;
	scanf("%s",str2) ;
	int len1 = strlen(str1) ;
	int len2 = strlen(str2) ;
	for(int i = 0 ; i < len1 ; i ++) {
		hashTable[str1[i]] ++ ;
	} 
	int miss = 0 ;
	for(int i = 0 ; i < len2 ; i ++) {
		hashTable[str2[i]] -- ;
		if(hashTable[str2[i]] < 0) miss ++ ;
	}
	if(miss == 0) printf("Yes %d\n",len1 - len2) ;
	else printf("No %d\n",miss) ;
	return 0 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值