AcWing 137. 雪花雪花雪花 138. 兔子与兔子

这篇博客探讨了如何使用哈希表和字符串哈希技术来解决AcWing上的两个问题:雪花问题中判断两朵雪花是否相同,以及兔子问题中通过DNA序列判断兔子是否相同。对于雪花问题,博主提出利用雪花六个角长度的和与乘积作为哈希规则;而在兔子问题中,通过预处理字符串所有前缀的哈希值来快速查询任意字串的哈希值,以提高效率。
摘要由CSDN通过智能技术生成

在这里插入图片描述
在这里插入图片描述

雪花

题意:

根据雪花六个角的长度判断两朵雪花是否相同。

思路:

属于hash表内容,根据值域建立一个一样大小的数组进行映射查找,这是hash表的关键,比如本题就可以用长度的和与乘积作为hash的规则,用这个值来归类这些雪花,如果hash值相同,再将两片雪花做精细化比对顺序是否相同。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int maxn = 1e6+10;
const int mod = 99991;
int head[maxn],nxt[maxn],snow[maxn][6];
int n,tot;
int Hash(int *a) {//产生hash值
	int sum = 0,mul = 1;
	for(int i=0;i<6;i++) {
		sum = (sum+a[i])%mod;
		mul = (ll)mul*a[i]%mod;
	}
	return (sum+mul)%mod;
}
bool equal(int *a,int *b) {//看是否循环同构
	for(int i=0;i<6;i++) {
		for(int j=0;j<6;j++) {
			bool flag = true;
			for(int k=0;k<6;k++) {//正着循环一遍看是否相同
				if(a[(i+k)%6] != b[(j+k)%6]) {
					flag = false;
				}
			}
			if(flag) return true;
			flag = true;
			for(int k=0;k<6;k++) {//再逆着判断一波
				if(a[(i+k)%6] != b[(j-k+6)%6]) {
					flag = false;
				}
			}
			if(flag) return true;
		}
		return false; 
	}
}
bool insert(int *a) {
	int val = Hash(a);//获取hash值
	for(int i=head[val];i;i = nxt[i]) {//遍历相同hash值的雪花
		if(equal(snow[i],a)) return true;//如果相等直接返回true
	}
	++tot;//类似前向星存边
	memcpy(snow[tot],a,6*sizeof(int));
	nxt[tot] = head[val];
	head[val] = tot;
	return false;
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) {
	    int a[10];
		for(int j=0;j<6;j++) cin>>a[j];
		if(insert(a)) {
		    cout<<"Twin snowflakes found."<<endl;
		    return 0;
		}
	}
	cout<<"No two snowflakes are alike."<<endl;
}

兔子

题意:

兔子相同与否靠他的DNA序列来区分,即比对指定区域的两端字符是否相等。

思路:

本题属于字符串hash的内容,对于两个字符串比较他们是否相等,如果我们通过遍历比较当比较次数多、字符串长时效率偏低,字符串hash就是将一个字符串映射成一个非负整数,并且冲突的概率几乎为0。取一固定值P,将字符串中的每一个字符用数字代表,那么这个字符串就会变成一个P进制的数,当我们将P取131或13331这类数时冲突概率较低。所以我们可以先O(n)预处理出字符串所有前缀的hash值,再O(1)查询任意字串的hash值(类似前缀和内味)。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
char s[maxn];
int f[maxn],p[maxn];

int main()
{
	scanf("%s",s+1);
	int n;
	scanf("%d",&n);
	p[0] = 1;
	int len = strlen(s+1);
	for(int i=1;i<=len;i++) {
		f[i] = f[i-1]*131+s[i]-'a'+1;
		p[i] = p[i-1]*131;
	}
	for(int i=1;i<=n;i++) {
		int l1,r1,l2,r2;
		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
		if(f[r1]-f[l1-1]*p[r1-l1+1] == f[r2]-f[l2-1]*p[r2-l2+1]) {
			cout<<"Yes\n";
		} else {
			cout<<"No\n";
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值