Gặp vấn đề khi giải bài trả về vị trí của chuỗi con trong chuỗi dùng thuật toán Rabin-Karp

Xin chào mọi người, em đang học đến Hash-table, cụ thể là đang học đến giải thuật Rabin-Karp, và nó khá khó, em đã hiểu được ý tưởng bài toán, và giải thuật hoạt động thế nào. Song khi thực hiện giải thuật thì gặp kết quả sai.
Cụ thể, đề bài là, trả về vị trí của chuỗi con trong chuỗi.
Ví dụ:
aba
abacaba
Output: 0 4.
Ví dụ này thì thuật toán chạy đúng kết quả.
Ví dụ 2:
Test
testTesttesT
Output: 4
Kết quả: pHash(Test) :118188920
H[4] (Test) : 957396881
Lúc này khi tính hàm preComputeHashes thì nó ra sai kết quả. Em đang phân vân không biết hàm polyHash tính sai hay là hàm preComputeHashes tính sai nữa. Mọi người xem và góp ý giúp em với. Em xin cảm ơn nhiều.

// Assignment3Problem3.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
// Assignment3Problem3.cpp : This file contains the 'main' function. Program execution begins and ends there.
#include "pch.h"
#include <iostream>
#include <string>
#include <vector>

using namespace std;
typedef unsigned long long ull;
struct Data {
	string pattern, text;
};
Data read_input() {
	Data data;
	cin >> data.pattern >> data.text;
	return data;
}
void print_occurrences(const vector<int>& output) {
	for (size_t i = 0; i < output.size(); ++i)
		cout << output[i] << " ";
	cout << "\n";
}
long long polyHash(string &p, int prime, int x)
{
	long long hash = 0;
	for (int i = p.length() - 1; i >= 0; i--)
	{
		hash = ((hash*x + p[i])%prime+prime)%prime;
	}
	return hash;
}
vector<long long> preComputeHashes(string t, int pLength, int prime, int x)
{
	vector<long long> H(t.length() - pLength + 1);
	string s = t.substr(t.length() - pLength, t.length() - 1);
	H[H.size() - 1] = polyHash(s, prime, x);
	int y = 1;
	for (int i = 1; i <= pLength; i++)
		y = ((y*x) % prime + prime) % prime;
	for (int i = t.length() - pLength - 1; i >= 0; i--)
		H[i] = ((x*H[i + 1] + t[i] - y * t[i + pLength]) % prime + prime) % prime;
	return H;
}
vector<int> get_occurrences(const Data& input) {
	string p = input.pattern, t = input.text;
	vector<int> result;
	int prime = 1000000007, x = 1;
	long long pHash = polyHash(p, prime, x);
	vector<long long> H = preComputeHashes(t, p.length(), prime, x);
	for (size_t i = 0; i <= t.length() - p.length(); i++)
	{
		if (pHash != H[i])
			continue;
		bool isSame = true;
		for (int j = i; j < i + p.length(); j++)
		{
			if (t[j] != p[j - i])
			{
				isSame = false;
				break;
			}
		}
		if (isSame == true)
			result.push_back(i);
	}
	return result;
}

int main() {
	ios_base::sync_with_stdio(false);
	print_occurrences(get_occurrences(read_input()));
	
	return 0;
}


Thay x=1 thì nó lại pass được một vài test case đơn giản, có lẽ vẫn đề nằm ở preComputeHashes tính số quá lớn.

sao trong hình thuật toán ghi tính y*x mod prime thôi mà có +prime nữa à :V

y*x có thể bị tràn số, cast y thành long long là được :V

5 Likes

Tại vì mod prime nó có thể ra số âm nữa ấy, nên + prime)%prime kết quả là số dương :3.
bài này còn sai ở chỗ, trường hợp biên nó sẽ ra sai đáp án.

3 Likes

Tính modulo nên dùng unsigned :slight_smile: hay uint64_t. Đỡ đau đầu vì số âm.

4 Likes

Không được nha, em mới thử, đáp án sai ngay. Cái này hình như là do ngôn ngữ lập trình c++ không hỗ trợ nên 3%5!=-2%5

Sửa lại thành + (prime - y * t[i + pLength]) % prime) là ổn.

6 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?