《算法笔记》4.2小节——算法初步->哈希

整数HASH

1.直接定址法
2.除留余数法
怎么解决冲突?
使用标准模板库的map来解决冲突

字符串HASH
将字符串映射为一个整数

1.26进制转换为十进制(A-Z)
2.52进制转换为十进制(A-Z a-z)
3.62进制转换为十进制(A-Z a-z 0-94.如果数字有确定的个数,末尾的数字直接拼接

问题 A: 谁是你的潜在朋友
问题描述: “臭味相投”——这是我们描述朋友时喜欢用的词汇。两个人是朋友通常意味着他们存在着许多共同的兴趣。然而作为一个宅男,你发现自己与他人相互了解的机会 并不太多。幸运的是,你意外得到了一份北大图书馆的图书借阅记录,于是你挑灯熬夜地编程,想从中发现潜在的朋友。
首先你对借阅记录进行了一番整理,把N个读者依次编号为1,2,…,N,把M本书依次编号为1,2,…,M。同时,按照“臭味相投”的原则,和你喜欢读同一本书的人,就是你的潜在朋友。你现在的任务是从这份借阅记录中计算出每个人有几个潜在朋友。

  • 输入
  每个案例第一行两个整数N,M,2 <= N ,M<= 200。接下来有N行,第i(i = 1,2,,N)行每一行有一个数,表示读者i-1最喜欢的图书的编号P(1<=P<=M)
  • 输出
  每个案例包括N行,每行一个数,第i行的数表示读者i有几个潜在朋友。如果i和任何人都没有共同喜欢的书,则输出“BeiJu”(即悲剧,^ ^
  • 样例输入
4 5
2
3
2
1
  • 样例输出
1
BeiJu
1
BeiJu

这题注意选潜在朋友的时候要排除自己

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 210;
int hashtable[maxn] = { 0 };
int main()
{
	int N, M;
	int i;
	int num;
	int reader[2000];//表示每位读者喜欢的书的编号
	while (scanf("%d %d", &N, &M) != EOF)
	{
		for (i = 0; i < N; i++)
		{
			scanf("%d", &num);
			reader[i] = num;//num表示喜欢的书的编号
			hashtable[num]++;
		}
		for (i = 0; i < N; i++)
		{
			if (hashtable[reader[i]]>=2)
				printf("%d\n", hashtable[reader[i]]-1);
			else
				printf("BeiJu\n");
		}
		memset(hashtable, 0, sizeof(hashtable));//进行下一轮,清零
	}	
	return 0;
}

⭐⭐问题 B: 分组统计
问题描述:先输入一组数,然后输入其分组,按照分组统计出现次数并输出,参见样例。

  • 输入
输入第一行表示样例数m,对于每个样例,第一行为数的个数n,接下来两行分别有n个数,第一行有n个数,第二行的n个数分别对应上一行每个数的分组,n不超过100
  • 输出
输出m行,格式参见样例,按从小到大排。
  • 样例输入
1
7
3 2 3 8 8 2 3
1 2 3 2 1 3 1
  • 样例输出
1={2=0,3=2,8=1}
2={2=1,3=0,8=1}
3={2=1,3=1,8=0}

这题用二维数组实现,需要注意数组的第二维下标表述数字,这个维度不可以取得太小,否则会答案错误
另外注意到输出的结果中每组数字是从小到大排列的,这个对sort排序有一定的启发。

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
	int m, n;
	int i,j,k;
	int b[110];//暂时存放输入的数字
	int c[110];//暂时存放数字对应的分组
	
	while (scanf("%d", &m) != EOF)
	{
		for (i = 0; i < m; i++)
		{
			int a[110][2000] = {0};//存放对应分组下的数字个数,一维表示分组的,二维表示分组中的某数字
			scanf("%d", &n);
			for (j = 0; j < n; j++)
			{
				scanf("%d", &b[j]);
			}
			for (j = 0; j < n; j++)
			{
				scanf("%d", &c[j]);
				a[c[j]][b[j]]++;//c[j]分组下b[j]数字+1
			}
			sort(b, b + n);
			sort(c, c + n);
			for (j = 0; j < n; j++)
			{
				if ((j == 0) || ((j > 0) && (c[j] != c[j - 1])))
				{
					printf("%d={", c[j]);
					for (k = 0; k < n; k++)
					{
						if ((k == 0) || ((k > 0) && (b[k] != b[k - 1])))
						{
							printf("%d=%d", b[k], a[c[j]][b[k]]);
							if ((k != (n - 1)) && b[k] != b[n - 1])//当不是最后一个数的时候,输出,
								printf(",");
						}
					}
					printf("}\n");
				}
			}
		}
	}	
	return 0;
}

问题 C: ⭐Be Unique (20)
问题描述:对火星上的人来说,独一无二非常重要,以至于他们的彩票也是以独特的方式设计的。获胜规则很简单:从 [1, 10 4 ] 中选择一个数字下注。第一个下注唯一号码的人获胜。例如,如果有 7 个人下注 5 31 5 88 67 88 17,那么下注 31 的第二个人获胜。

  • 输入
每个输入文件包含一个测试用例。每个案例都包含一行,以正整数 N (<=10 5 ) 开头,然后是 N 个赌注。数字之间用空格分隔。
  • 输出
对于每个测试用例,在一行中打印中奖号码。如果没有获胜者,则打印“None”。
  • 样例输入
7 5 31 5 88 67 88 17
5 888 666 666 888 888
  • 样例输出
31
None

判断元素在数组中是不是第一次出现有两种方法,第一种是写个函数判断(本题),第二种是sort排序之后通过if((i==0)||((i>0)&&(a[i]!=a[i-1])))判断,即要不是第一个元素,如果不是第一个元素就要和前面的元素不相等(上一题)

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100010;
int func(int b[],int i)//此函数用来判断数组b中第i个元素是不是第一次出现,如果是,就返回1,否则返回0
{
	int j;
	for (j = 0;j < i; j++)
	{
		if (b[j] == b[i])
			return 0;
	}
	return 1;
}
int main()
{
	int N;
	int i;
	int num;
	int flag;
	while (scanf("%d", &N) != EOF)
	{
		flag = 0;
		int a[maxn] = {0};
		int b[maxn] = { 0 };
		for (i = 0; i < N; i++)
		{
			scanf("%d",&num);
			a[num]++;
			b[i] = num;
		}
		for (i = 0; i < N; i++)
		{
			if (func(b,i))
			{	
				if (a[b[i]] == 1)
				{
					printf("%d\n", b[i]);
					flag = 1;
					break;//注意找到要找的元素后就Break退出循环
				}					
			}
		}
		if (flag == 0)//最终没有找到符和的元素,输出none
			printf("None\n");
	}
	return 0;
}

问题 D: String Subtraction (20)
题目描述:
Given two strings S1 and S2, S = S1 - S2 is defined to be the remaining string after taking all the characters in S2 from S1. Your task is simply to calculate S1 - S2for any given strings. However, it might not be that simple to do it fast.
就是把S2字符串里的字符从S1中摘出来

  • 输入
Each input file contains one test case. Each case consists of two lines which gives S1 and S2, respectively. The string lengths of both strings are no more than 104. It is guaranteed that all the characters are visible ASCII codes and white space, and a new line character signals the end of a string.
//输入的字符串长度小于10的4次方,以\0结尾,中间可能有空格
  • 输出
For each test case, print S1 - S2 in one line.
//输出S1-S2
  • 样例输入
They are students.
aeiou
  • 样例输出
Thy r stdnts.

基础题

#define _CRT_SECURE_NO_WARNINGS 1
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 10010;
bool hashtable[300] = { 0 };
int main()
{
	char str1[maxn];
	char str2[maxn];
	int i,j;
	gets(str1);
	gets(str2);
	
	
	for (i = 0; i < strlen(str2); i++)
	{
		hashtable[str2[i]] = 1;
	}
	for (i = 0; i < strlen(str1); i++)
	{
		if (hashtable[str1[i]] == 1)//如果是str2里出现过的字符
			for (j = i; j < strlen(str1); j++)
				str1[j] = str1[j + 1];
	}
	printf("%s",str1);

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值