알고리즘 학습 - > 문자열 hash
Hash, 일반적으로 '해시' 로 번역 되 고 '해시' 로 직접 음역 되 는 것 도 있 습 니 다. 즉, 임의의 길이 의 입력 (프 리 맵 pre - image 라 고도 함) 을 해시 알고리즘 을 통 해 고정 길이 의 출력 으로 바 꾸 는 것 입 니 다. 이 출력 은 해시 값 입 니 다.이러한 전환 은 압축 맵 이다. 즉, 해시 값 의 공간 은 보통 입력 공간 보다 훨씬 작 고 서로 다른 입력 은 같은 출력 으로 해시 될 수 있 기 때문에 해시 값 에서 유일한 입력 값 을 확정 할 수 없다.쉽게 말 하면 임의의 길이 의 메 시 지 를 일정한 길이 의 메시지 요약 으로 압축 하 는 함수 입 니 다.
모든 해시 함 수 는 다음 과 같은 기본 적 인 특성 을 가지 고 있 습 니 다. 만약 에 두 개의 해시 값 이 다르다 면 이 두 개의 해시 값 의 원시 입력 도 같 지 않 습 니 다.이 특성 은 산열 함수 가 확정 적 인 결 과 를 가지 고 있다.그러나 다른 한편, 해시 함수 의 입력 과 출력 은 일일이 대응 하 는 것 이 아니다. 만약 에 두 개의 해시 값 이 같다 면 두 개의 입력 값 은 같 을 수 있 지만 두 사람 이 반드시 같다 는 것 은 확실 하지 않다 (해시 충돌 이 발생 할 수 있다).
문자열 hash, 즉 모든 문자열 hash 를 하나의 숫자 로 하여 숫자 를 비교 합 니 다.
다음 문자열 의 hash 값 을 보 여 드 리 겠 습 니 다.
1. 요구: 현재 우 리 는 모든 문자열 이 하나의 정수 에 매 핑 될 수 있 도록 hash 함 수 를 찾 고 싶 습 니 다. 예 를 들 어 hash [i] = (hash [i - 1] * p + idx (s [i])% mod
2. 문자열: abc, bbc, aba, aadaabac, 문자열 아래 표 시 는 0 부터 시작 합 니 다.
3. 매 핑: 먼저 a 매 핑 을 1 로 하고 b 매 핑 을 2, c - > 3, d - > 4, 즉 idx (a) = 1, idx (b) = 2, idx (c) = 3, idx (d) = 4 로 한다.
4. 수치: 우리 가 p = 13, mod = 101 을 취한 다 고 가정 합 니 다.
5. 방법: 먼저 abc 를 하나의 정수 hash [0] = 1 로 표시 하고 a 맵 을 1 (주의 점) hash [1] = (hash [0] * p + idx (b)% mod = 15 로 표시 하 며 ab 맵 을 15 hash [2] = (hash [1] * p + idx (c)% mod = 97 로 표시 합 니 다. 그러면 abc 를 97 이라는 숫자 로 표시 합 니 다. 즉, hash [abc] = 97 입 니 다.
• 같은 방법 으로 우 리 는 BBc, aba, aadaabac 를 모두 하나의 정수 에 투사 할 수 있 습 니 다. 같은 hash 함수 로 다음 과 같은 결 과 를 얻 을 수 있 습 니 다. abc - > 97, 즉 hash [abc] = 97 · BBc - > 64, 즉 hash [BBc] = 64 · aba - > 95, 즉 hash [aba] = 95 · aadaabac - > 35, 즉 hash [aadaabac] = 35
• 그러면 우 리 는 이것 이 정수 에 대한 문자열 의 맵 이라는 것 을 알 게 되 었 습 니 다. 그러면 우 리 는 모든 문자열 에 대응 하 는 정 수 를 기록 할 수 있 습 니 다. 현재 이미 나타 난 문자열 이 나 타 났 을 때 정수 가 나 타 났 는 지 확인 하면 문자열 이 중복 되 었 는 지 여 부 를 알 수 있 습 니 다.이제 두 문자열 이 일치 하 는 지 판단 하려 면 어떻게 해 야 합 니까?hash 값 으로 직접 판단 하면 됩 니 다. hash 값 이 일치 하면 문자열 이 일치 하 다 고 생각 합 니 다.hash 값 이 일치 하지 않 으 면 다른 문자열 이 라 고 생각 합 니 다.우 리 는 두 문자열 이 일치 하 는 지 여 부 를 판단 해 야 합 니 다. 그렇게 번 거 롭 지 않 습 니 다. 길이 가 일치 하 는 지 직접 판단 한 다음 에 모든 문자 가 일치 하 는 지 판단 하면 됩 니 다.그러나 여러 문자열 에 몇 개의 다른 문자열 이 있 는 지 판단 하려 면 어떻게 해 야 합 니까?두 문자열 을 모두 비교 합 니까?시간 복잡 도가 너무 높 습 니 다. 모든 문자열 hash 를 하나의 정수 로 만 든 다음 에 모든 정 수 를 다시 조작 하면 답 을 알 수 있 습 니 다.충돌 이 발생 했 을 때, 우 리 는 p 와 mod 를 조정 하여 충돌 확률 을 작 게 줄 일 수 있다.우 리 는 일반적으로 p 와 mod 는 일반적으로 소 수 를 취하 고 p 는 비교적 큰 소 수 를 취하 면 된다 고 생각한다 (6 위 에서 8 위). mod 는 큰 소 수 를 취한 다. 예 를 들 어 1e9 + 7 또는 1e9 + 9 이다.
어떻게 하위 문자열 의 hash 값 을 구 합 니까?그 전에 우 리 는 hash [i] 를 구 했 고 i 번 째 접두사 의 hash 값 을 표시 했다.이제 각 하위 문자열 의 hash 값 을 어떻게 구 합 니까?
• hash 의 공식 을 살 펴 보 겠 습 니 다.hash[i]=(hash[i-1]*p+idx(s[i]))%p; •그럼, S [l... r] 이 하위 문자열 의 hash 값 • hash [l. r] = (hash [r] - hash [l - 1] * (p ^ (r - 1 + 1)% mod (문자열 아래 표 시 는 1 부터) 를 요구 합 니 다.hash [l. r] = (hash [r] - hash [l - 1] * (p ^ (r - 1 + 1))% mod · hash [l. r] 마이너스 가 있 을 수 있 지 않 습 니까?어 떡 하지?hash [l. r] < 0 을 얻 었 을 때 hash [l. r] + = mod 를 얻 었 으 면 좋 겠 습 니 다.이렇게 하면 모든 하위 문자열 의 hash 값 이 [0, mod - 1] 범위 내 에서 hash 값 으로 문자열 을 정확하게 처리 할 수 있 습 니 다.
2. 문자열 해시 의 세 가지 맵 함수
1. 자동 모드
unsigned long long hash[N];
hash[i]=hash[i-1]*p( )
설명: unsigned long hash [N];
unsigned long 형식의 변 수 를 정의 합 니 다. 그 범 위 는 [0, 2 ^ 64) 내 에 있 습 니 다. 이 는 숫자 가 2 ^ 64 - 1 을 초과 하면 넘 치 는 것 과 같 습 니 다. 이것 은 하나의 모드 2 ^ 64 의 과정 에 해당 합 니 다.
그러면 hash 함 수 는 다음 과 같이 이해 할 수 있 습 니 다.
hash[i]=(hash[i-1]*p)%(2^64)
P 는 큰 소 수 를 취하 고, 일반적으로 1e9 + 7 또는 1e9 + 9 를 취한 다.
안전 지수: 삼 성 (그래서 안전 하지 않다)
2. 문자열 문자
hash[i]=(hash[i-1]*p+idx(s[i]))%mod
설명: 이것 은 전에 이미 언급 한 적 이 있다.
hash[i]=(hash[i-1]*p+idx(s[i]))%mod
p. 6 ~ 8 비트 의 소 수 를 취하 고 mod 는 큰 소 수 를 취하 고 보통 1e9 + 7 또는 1e9 + 9 안전 지수: 4 성 (괜 찮 습 니 다) 을 취한 다.
3. 더 블 해시
hash1[i]=(hash1[i-1]*p+idx(s[i]))%mod1
hash2[i]=(hash2[i-1]*p+idx(s[i]))%mod2
pair<hash1,hash2> !
double hash 는 두 개의 mod 값 을 가 져 옵 니 다. mod1 과 mod2 hash 1 [i] = (hash 1 [i - 1] * p + idx (s [i])% mod 1
hash2[i]=(hash2[i-1]*p+idx(s[i]))%mod2
mod 1 은 보통 1e9 + 7 을 취하 고, mod 2 는 보통 1e9 + 9 를 취하 는데 왜 이렇게 합 니까?
1000000007 과 1000000009 는 쌍둥이 소수 로 그들 을 취하 면 충돌 할 확률 이 매우 낮다!
안전 지수: 5 성! (매우 안정 적!)
소결: 이렇게 말 할 수 있 습 니 다. hash 는 어느 정도 에 난 장 판 입 니 다. hash 함 수 를 불규칙 하 게 할 수록 좋 습 니 다. 충돌 확률 이 작 아서 대부분의 데이터 가 끊 기지 않 습 니 다.ash 는 해 킹 당 할 수 있 지만, double hash 는 해 킹 당 하기 가 매우 어렵 습 니 다. double hash 로 문 제 를 해결 할 수 있 습 니 다.
3. 연습 문제 및 AC 코드
1、A - Crazy Search
Many people like to solve hard puzzles some of which may lead them to madness. One such puzzle could be finding a hidden prime number in a given text. Such number could be the number of different substrings of a given size that exist in the text. As you soon will discover, you really need the help of a computer and a good algorithm to solve such a puzzle. Your task is to write a program that given the size, N, of the substring, the number of different characters that may occur in the text, NC, and the text itself, determines the number of different substrings of size N that appear in the text.
As an example, consider N=3, NC=4 and the text “daababac”. The different substrings of size 3 that can be found in this text are: “daa”; “aab”; “aba”; “bab”; “bac”. Therefore, the answer should be 5.
Input
The first line of input consists of two numbers, N and NC, separated by exactly one space. This is followed by the text where the search takes place. You may assume that the maximum number of substrings formed by the possible set of characters does not exceed 16 Millions.
Output
The program should output just an integer corresponding to the number of different substrings of size N found in the given text.
Sample Input
3 4 daababac
Sample Output
5
Hint
Huge input,scanf is recommended.
AC 코드:
#include
#include
#include
#include
using namespace std;
int has[16000003],cnt=0,vis[500];
char str[16000003];
int n,nc,ans=0;
int main(){
while(~scanf("%d%d%s",&n,&nc,str)){
ans=0;cnt=0;
int le=strlen(str);
// memset(has,0,sizeof(has));
// memset(vis,0,sizeof(vis));
for(int i=0;iif(vis[str[i]]==0){
vis[str[i]]=cnt++;
}
}
for(int i=0;i<=le-n;i++){
int sum=0;
for(int j=0;jsum=sum*cnt+vis[str[j+i]];
}
if(has[sum]==0){
has[sum]=1;
ans++;
}
}
printf("%d
",ans);
}
return 0;
}
2. 저주 사전
해 리포터 의 마법 학교 필수 과목 중 하 나 는 징 크 스 를 배 우 는 것 이다. 마법 의 세 계 는 100000 가지 서로 다른 징 크 스 가 있다 고 한다. 해 리 는 모두 기억 하기 어렵 지만 강적 에 대항 하기 위해 서 는 위급 할 때 필요 한 징 크 스 를 사용 해 야 하기 때문에 도움 이 필요 하 다.
주문 사전 을 드 리 겠 습 니 다. 해 리 는 주문 을 들 었 을 때, 당신 의 프로그램 은 그 에 게 그 주문 의 기능 을 알려 야 합 니 다. 해 리 는 어떤 기능 이 필요 하지만 어떤 주문 을 써 야 할 지 모 를 때, 당신 의 프로그램 은 그 에 게 해당 하 는 주문 을 찾 아야 합 니 다. 만약 그 가 원 하 는 주문 이 사전에 없다 면, "what?" 를 출력 해 야 합 니 다.
Input
먼저 사전 에 100000 개가 넘 지 않 는 서로 다른 저주 단 어 를 보 여 줍 니 다. 각 형식 은 다음 과 같 습 니 다.
[저주] 대응 기능
그 중에서 '저주' 와 '대응 기능' 은 각각 길이 가 20 과 80 을 초과 하지 않 는 문자열 로 문자열 에 문자 '[' 와 ']' 가 포함 되 지 않 고 ']' 와 뒤의 문자열 사이 에 빈 칸 만 있 음 을 보증 합 니 다.사전 의 마지막 줄 은 '@ END @' 으로 끝 납 니 다. 이 줄 은 사전 의 단어 에 속 하지 않 습 니 다.사전 뒤의 한 줄 은 정수 N (< = 1000) 을 포함 하고 그 다음은 N 개의 테스트 용례 이다.각 테스트 용례 가 한 줄 을 차지 하거나 '[저주]' 를 주거 나 '대응 기능' 을 제시한다.
Output
모든 테스트 용례 의 출력 은 한 줄 을 차지 하고 출력 저주 에 대응 하 는 기능 이나 기능 에 대응 하 는 저주 입 니 다.저주 가 사전 에 없 으 면 "what?" 를 출력 합 니 다.
Sample Input
[expelliarmus] the disarming charm [rictusempra] send a jet of silver light to hit the enemy [tarantallegra] control the movement of one’s legs [serpensortia] shoot a snake out of the end of one’s wand [lumos] light the wand [obliviate] the memory charm [expecto patronum] send a Patronus to the dementors [accio] the summoning charm @END@ 4 [lumos] the summoning charm [arha] take me to the sky
Sample Output
light the wand accio what? what?
AC 코드:
#include
#include
#include
using namespace std;
typedef unsigned long long ull;
typedef unsigned int ui;
const int nmax = 150 ;
const int INF = 0x3f3f3f3f;
const ui MOD1 = 1e9 + 9;
const ui MOD2 = 1e9 + 9;
const ui p = 131;
int n, mcnt, fcnt;
char str[105];
char mis[100005][22], fun[100005][82];
mapint > mp1, mp2;
inline ui hash1(char s[]) {
int len = strlen(s);
ui ans = s[0];
for (int i = 1; i < len; ++i) ans = ((ans * p) + s[i] ) ;
return ans;
}
inline ui hash2(char s[]) {
int len = strlen(s);
ui ans = s[0];
for (int i = 1; i < len; ++i) ans = ((ans * p) + s[i] ) ;
return ans;
}
int main() {
while (gets(str)) {
if (str[0] == '@') break;
int len = strlen(str), pos;
for (int i = 0; i < len; ++i) if (str[i] == ']') {pos = i; str[pos] = '\0'; break;}
strcpy(mis[mcnt], str + 1); strcpy(fun[fcnt], str + pos + 2);
mp1[hash1(mis[mcnt])] = fcnt;
mp2[hash2(fun[fcnt])] = mcnt;
fcnt++; mcnt++;
}
scanf("%d", &n); getchar();
char str[100];
for (int i = 1; i <= n; ++i) {
gets(str);
if (str[0] == '[') {
int len = strlen(str); str[len - 1] = '\0';
int ans = hash1(str + 1);
if (mp1[ans] == 0) printf("what?
");
else printf("%s
", fun[mp1[ans]]);
} else {
int ans = hash2(str);
if (mp2[ans] == 0) printf("what?
");
else printf("%s
", mis[mp2[ans]]);
}
}
return 0;
}
더 많은 연습 문제:https://vjudge.net/contest/242212#overview
해석: 이상 의 이론 설명 은 대부분 다른 블 로그 에서 왔 습 니 다. 저 는 단지 학습 정 리 를 했 을 뿐 입 니 다.원문 은 다음 과 같다.https://www.cnblogs.com/–ZHIYUAN/p/7445842.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
【좌절하기 전에】Ruby 배열 오브젝트와 해시 오브젝트의 이미지이 기사에서는 배열 객체와 해시 객체의 차이점은 무엇입니까? 라는 방향으로 해설해 가고 싶습니다. 배열 객체와 해시 객체의 차이를 잘 알지 못하는 사람 배열 객체와 해시 객체의 이미지를 잡을 수없는 사람 우선 해시 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.