1. Trang chủ
  2. » Luận Văn - Báo Cáo

ỨNG DỤNG MẢNG BĂM (HASH) ĐỂ GIẢI CÁC BÀI TOÁN VỀ SO KHỚP XÂU (CHUỖI)

29 2,4K 7

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 29
Dung lượng 96,5 KB

Nội dung

SỞ GIÁO DỤC VÀ ĐÀO TẠO NAM ĐỊNH TRƯỜNG THPT CHUYÊN LÊ HỒNG PHONGSÁNG KIẾN DỰ THI CẤP TỈNH BÁO CÁO SÁNG KIẾN ỨNG DỤNG MẢNG BĂM HASH ĐỂ GIẢI CÁC BÀI TOÁN VỀ SO KHỚP XÂU CHUỖI Tác giả: Ngô

Trang 1

SỞ GIÁO DỤC VÀ ĐÀO TẠO NAM ĐỊNH TRƯỜNG THPT CHUYÊN LÊ HỒNG PHONG

SÁNG KIẾN DỰ THI CẤP TỈNH BÁO CÁO SÁNG KIẾN

ỨNG DỤNG MẢNG BĂM (HASH) ĐỂ GIẢI CÁC BÀI

TOÁN VỀ SO KHỚP XÂU (CHUỖI)

Tác giả: Ngô Trung Tưởng Trình độ chuyên môn: Đại học Chức vụ: Giáo viên

Nơi công tác: Trường THPT chuyên Lê Hồng Phong

Trang 2

Nam Định, tháng 05 năm 2014

Trang 3

THÔNG TIN CHUNG VỀ SÁNG KIẾN

1 Tên sáng kiến:

ỨNG DỤNG MẢNG BĂM (HASH) ĐỂ GIẢI CÁC BÀI TOÁN VỀ SO KHỚP

XÂU (CHUỖI)

2 Lĩnh vực áp dụng sáng kiến:

Giảng dạy lớp 10, 11 chuyên tin, đội tuyển HSGQG môn tin học

3 Thời gian áp dụng sáng kiến:

Từ năm học 2012-2013 đến nay

4 Tác giả:

Họ và tên: Ngô Trung Tưởng

Năm sinh: 1982

Nơi thường trú: 22/34 Trần Thái Tông, P Thống Nhất, TP Nam Định

Trình độ chuyên môn: Đại học

Chức vụ công tác: Giáo viên

Nơi làm việc: Trường THPT chuyên Lê Hồng Phong

Địa chỉ liên hệ: 22/34 Trần Thái Tông, P Thống Nhất, TP Nam Định

Trang 4

I Điều kiện hoàn cảnh:

Trong lĩnh vực khoa học máy tính nói chung và trong thi cử nói riêng mộtlớp các bài toán rất được quan tâm đó là bài toán xử lý xâu chuỗi Một trong nhữngbài toán phổ biến mà chúng ta hay gặp là tìm kiếm xâu con trong xâu cho trước

II Thực trạng

Bài toán về xử lí xâu rất quen thuộc và thường gặp trong các bài tập về tinhọc, nhưng trong quá trình giảng các lớp chuyên tin và đội tuyển HSGQG môn Tinhọc, tôi nhận thấy các em học sinh giải quyết các bài toán này chưa thật sự thuầnthục và không hiệu quả, đặc biệt là trong thi cử Chính vì vậy, tôi viết chuyên đềnày để giúp các em giải quyết các bài toán về xâu hiệu quả hơn

III Nội dung chuyên đề

1 Phát biểu bài toán

- Cho một xâu T gồm m kí tự

- Cho một xâu mẫu P gồm n kí tự

- Yêu cầu: cho biết xâu mẫu P xuất hiện bao nhiêu lần trong T và chỉ ra các vị tríxuất hiện của P

2 Thuật toán

Có rất nhiều thuật toán khác nhau để giải bài toán này như Brute-force approach(vét cạn-độ phức tạp O(n*m)), KMP (độ phức tạp O(n+m)), Suffix Array…

Trong chuyên đề này tôi không đề cập đến các thuật toán trên mà chỉ tập trung vào

một thuật toán sử dụng mảng băm hay còn gọi một tên gọi khác là HASH Đây là

một thuật toán rất hiệu quả đặc biệt là trong thi cử vì tốc độ thực thi nhanh, linhhoạt trong xử lí và rất dễ cài đặt

Mô tả thuật toán HASH

a Các kí hiệu:

- Tập các chữ cái trong bảng chữ cái kí hiệu ∑

Trang 5

- Xâu T gồm m kí tự: T[1 m]

- Xâu mẫu P gồm n kí tự: P[1 n]

- Xâu con từ i đến j của xâu T là: T[i j]

- Chúng ta cần tìm tất cả các vị trí i thỏa mãn (1≤i≤m-n+1) mà T[i i+n-1]=P[1 n]

b Mô tả thuật toán

Để đơn giản, giả sử rằng Σ = {a, b,…, z}, nghĩa là Σ chỉ gồm các chữ cáiLatin in thường Để biểu diễn một xâu, thay vì dùng chữ cái, chúng ta sẽ chuyểnsang biểu diễn số ở hệ 26

Ví dụ: xâu ‘abcd’ biểu diễn hệ 26: ‘a’*263+ ‘b’*262+ ‘c’*261 + ‘d’*260 đổi ra số ở

hệ cơ số 10 tương ứng là: 65*263+66*262+67*26+68= 1188866

Dễ thấy rằng, muốn so sánh 2 xâu bằng nhau khi và chỉ khi biểu diễn của 2 xâu ở

hệ cơ số 10 giống nhau

Ví dụ xâu A=B ↔ Mã A = Mã B

Tuy nhiên nếu xâu quá dài thì Mã A, Mã B cũng rất lớn Chính vì thế, ta lấy mod cho 1 số base nguyên tố rất lớn nào đó ví dụ 109+7, hay 2.109+11…

A=B  Mã A mod base = Mã B mod base

Dễ dàng nhận thấy việc so sánh Mã A mod base với Mã B mod base rồi kết luận A

có bằng với B hay không là sai Mã A mod base = Mã B mod base chỉ là điều kiện

cần để A bằng B chứ chưa phải điều kiện đủ Tuy nhiên, chúng ta sẽ chấp nhận lập

luận sai này trong thuật toán Hash Và coi điều kiện cần như điều kiện đủ Trênthực tế, lập luận sai này có những lúc dẫn đến so sánh xâu không chính xác vàchương trình bị chạy ra kết quả sai Nhưng cũng thực tế cho thấy rằng, khi chọn

base là một số nguyên lớn, số lượng những trường hợp sai rất ít, và ta có thể coi

Hash là một thuật toán chính xác

Trở lại bài toán ban đầu, chúng ta cần chỉ ra P xuất hiện ở những vị trí nào trong T

Để làm được việc này, chúng ta chỉ cần duyệt qua mọi vị trí xuất phát có thể của Ptrong T

Trang 6

Giả sử vị trí đó là i, chúng ta sẽ kiểm tra T[i i + n − 1] có bằng với P hay không.

Để kiểm tra điều này, chúng ta cần tính được mã Hash của đoạn T[i i + n − 1] và

mã Hash của xâu P

Để tính mã Hash của xâu P chúng ta chỉ cần làm đơn giản như sau:

HashP=0;

for (i=1;i<=n;i++)

HashP = (HashP*26 + P[i]) % base;

Phần khó hơn của thuật toán Hash là: Tính mã Hash của một đoạn con từ i đến j T[i j] của xâu T (1 ≤ i ≤ j ≤ m)

Ví dụ sau: Xét xâu s= “cdeacx” và biểu diễn của nó dưới cơ số 26 Chúng ta cần

lấy mã Hash của đoạn con từ phần tử thứ 3 đến phần tử thứ 6, chỉ cần lấy mã Hash

của s[1 .6] trừ đi mã Hash của s[1 .2] nhân với 264

Để cài đặt ý tưởng này, chúng ta cần khởi tạo 26𝑥 mod base (0 ≤ i ≤ m) và mã Hash

của tất cả những tiền tố của s, cụ thể là mã Hash của những xâu s[1 i] (1 ≤ i ≤ m).

//tinh 26x mod base

POW[0]=1;

for (i=1;i<=m;i++)

POW[i] = POW[i-1]*26 % base;

//tinh ma Hash xau s[1 i]

HashT[0]=0;

for(i=1;i<=m;i++)

HashT[i]=(HashT[i-1]*26+T[i])%base;

Để lấy mã Hash của T[i j] ta viết hàm sau:

long long getHash(long i, long j){

return(HashT[j]-HashT[i-1]*POW[j-i+1]+ base*base)%base;

}

Trang 7

Bài toán chính được giải quyết như sau:

const long long base=1000000000+7;

long long hasha[1000005], hashb,POW[1000005];

Trang 8

for (long i=1; i<=m; i++)

hashb= (hashb*26 + b[i])% base;

for (long i=1; i<=n-m+1;i++)

if (hashb==gethash(i,i+m-1))

//cout<<i<<" ";

fo<<i<<" ";

Trang 9

4 Ứng dụng

Bài 1: Tiền tố và hậu tố

http://vn.spoj.com/problems/C11STR2/

Xâu a được gọi là tiền tố của xâu b nếu xâu a trùng với phần đầu của xâu b Ví

dụ pre là tiền tố củaprefix

Xâu a được gọi là hậu tố của xâu b nếu xâu a trùng với phần cuối của xâu b Ví

dụ fix là hậu tố củasuffix

yenthanh132 vừa mới học về tiền tố và hậu tố nên hôm nay anh ta sẽ đố các bạn

một bài toán đơn giản về tiền tố và hậu tố như sau:

 Cho 2 xâu a,b gồm các kí tự latin thường ('a' đến 'z')

 Tìm 1 xâu c thỏa mãng:

1 Xâu a là tiền tố của xâu c

2 Xâu b là hậu tố của xâu c

3 Độ xài xâu c là ngắn nhất. 

Input

 Dòng 1: Xâu a

Trang 10

 Dòng 2: Xâu b 

Output

 Một dòng duy nhất là xâu c

Giới hạn:

 40% số test có độ dài 2 xâu a,b <= 1000 kí tự

 Trong toàn bộ test, độ dài 2 xâu a,b <= 105 kí tự 

(2 xâu a,b không nhất thiết phải khác nhau)

Hướng dẫn giải thuật:

- Tìm hậu tố dài nhất xâu a có phần chung tiền tố xâu b:

+ Với xâu a gọi ha[i] là mã hash của xâu a gồm các kí tự từ 1 đến i

+ Với xâu b gọi hb[i] là mã hash cảu xâu b gồm các kí tự từ 1 đến i

+ Tìm vị trí x mà tiền tố xâu b chung hậu tố xâu a ta chỉ so sánh mã hash củaxâu con b[1],…,b[x] với a[n-x+1],…,a[n] với n là độ dài xâu a Duyệt x từ 1đến độ dài xâu b tìm ra kết quả

Trang 12

a.erase(0,1);//xoa ki tu @ them vao a

b.erase(0,1);//xoa ki tu @ them vao b

//cout<<res<<endl;

cout<<a+b.substr(res,b.size()-res);

//cin.get();

}

Trang 13

Bài 2: Sắp xếp Mã bài: VMSORT

Kì thi VM đang dần đi đến những vòng thi cuối cùng Trong khi các thí sinh hăngsay với những bài tập hóc búa, mang đậm tính chất Marathon thì các admin VNOIcũng phải đối mặt với những vấn đề rất nan giải, chẳng hạn như thống kê số lượngthí sinh, số lượng thí sinh giải được từng bài tập

Trong không khí căng thẳng của cuộc đua, ban tổ chức đã quyết định tặng một mónquà đặc biệt cho các bạn Và món quà đó chính là bài tập này!

Bạn sẽ phải giúp các admin làm một nhiệm vụ sau: Cho dữ liệu mô tả các thí sinh

tham gia mỗi một trong K vòng của cuộc thi VNOI Marathone 20xx, hãy tính xem

có bao nhiêu thí sinh tham gia ít nhất một vòng thi

Input

 Dòng 1: Ghi số nguyên dương K (1 ≤ K ≤ 5)

 K nhóm dòng sau: Mỗi nhóm thể hiện dữ liệu của một vòng thi: Dòng đầughi số nguyên N (1 ≤ N ≤ 200) là số lượng thí sinh tham gia vòng thi đó Ndòng sau, mỗi dòng ghi một nick của thí sinh, dưới dạng một xâu khác rỗng,

độ dài không quá 20 kí tự (đảm bảo xâu không chứa khoảng trống) Trongmỗi nhóm dòng mô tả một vòng thi, không có tên thí sinh nào được lặp lạihai lần

Output

 Ghi ra một số nguyên duy nhất là số thí sinh tham gia ít nhất một vòng thi

Example Input:

3

4

flashmt

ll931110

Trang 14

Hướng dẫn thuật toán:

- Mỗi xâu mã hóa dưới dạng số lưu vào một phần tử của mảng, sắp xếp lạimảng, đếm số lượng số khác nhau trong mảng

long long hash;

long long a[100005];

Trang 16

Bài 3 – Xâu con – COCI 2006-2007

Steve chiến thắng trong một lần cá cược và John phải mời anh ấy đi xem phim.Trong khi chờ đợi Steve, John để ý một thông báo trên màn hình quảng cáo phíatrên chỗ anh đang đứng

Steve đến muộn nên John đã để ý trên màn hình quảng cáo một thời gian và thấyrằng có một vài thông báo xuất hiện trên màn hình nhiều hơn một lần Tự nhiên,anh ấy viết tất cả các thông báo ra giấy John muốn biết chiều dài của xâu dài nhấtxuất hiện ít nhất hai lần (xuất hiện trong hai vị trí khác nhau trên trang giấy)?

Yêu cầu: Hãy giúp John trả lời câu hỏi đó.

Dữ liệu vào cho trong tệp SUBSTR.INP

- Dòng 1 chứa số nguyên L (1≤L≤200000) là độ dài mà Jonh đã viết trên giấy

- Dòng 2 chứa một xâu có độ dài L gồm các kí tự chữ thường trong bảng chữcái tiếng anh

Kết quả ghi ra tệp SUBSTR.OUT một số duy nhất là độ dài dài nhất của

xâu xuất hiện ít nhất hai lần trong xâu đã cho Nếu không tồn tạixâu con thỏa mãn đưa ra số 0

Trang 17

- Từ nhận xét trên ta sử dụng thuật toán tìm kiếm nhịphân theo độ dài xâu con cần tìm.

- Mỗi xâu con độ dài l, ta sẽ tính mã hash của tất cảcác xâu con lưu vào mảng

- Nếu mảng vừa tạo tồn tại ít nhất 2 phần tử giốngnhau tức là tồn tại ít nhất 2 xâu con có độ dài lthỏa mãn

- Tìm l có độ dài dài nhất thỏa

- Độ phức tạp của thuật toán Nlog 2 (N)

long long hash[200005],POW[200005],a[200005];

long long gethash(long i, long j){

return (hash[j]-hash[i-1]*POW[j-i+1]+

base*base)% base;

}

bool kt(long x){

Trang 18

for (long i=1;i<=n-x+1;i++)

Trang 19

return 0;}

Trang 20

Bài 4 - DTKSUB – Tìm chuỗi con dài nhất xuất hiện K lần

http://vn.spoj.com/problems/DTKSUB/

Sau những kỳ công trong những cuộc chinh phục các cấu trúc dữ liệu đặc biệt,

tình bạn giữa piratevà duyhung123abc ngày càng trở nên khăng khít Rồi bỗng một

ngày nọ, duyhung123abc bỗng ra đi không một lời từ biệt, chỉ để lại một mẫu giấy cho pirate Mẩu giấy viết rằng : "Em ơi, anh còn nặng nợ toán lý hóa anh, chưa thể

một lòng theo đuổi tin học Em hãy làm nốt công việc mà anh em ta còn dang

dở !". pirate đọc xong, nước mắt giàn giụa Nếu khi hai người gặp nhau, vui sướng

như khi Engels gặp Marx, thì trong giây phút chia ly này, lòng pirate đau đớn như

khi Đỗ Phủ tiễn người tri kỉ Lý Bạch lên đường

Mất đi người anh cả, pirate như con thuyền mất phương hướng Cuối cùng, sau

những đêm không ngủ, anh quyết định rằng mình sẽ đợi cho đến

khi duyhung123abc trả xong nợ công danh và quay trở về sẽ tiếp tục nghiên cứu

các cấu trúc dữ liệu đặc biệt Còn bây giờ, anh ta sẽ đi một con đường mới, đi vào

một thế giới mới, thế giới của các THUẬT TOÁN VỀ CHUỖI Tuy cô độc một

mình, nhưng với niềm tin của mình, pirate đã lên đường ngay mà không có chút do

dự

Nhưng trớ trêu thay, vạn sự khởi đầu nan Thử thách đầu tiên mà con người trẻtuổi này gặp phải thật đau đầu Anh ta được cho trước một chuỗi S có độ dài N vàmột số K Thử thách được hoàn thành chỉ khi anh ấy đưa ra được độ dài của chuỗi

dài nhất xuất hiện ít nhất K lần trong chuỗi S Làm sao đây ! Vừa vực dậy sau một

cú sốc lớn, pirate rất cần sự giúp đỡ của các bạn để không mất đi sự nhiệt huyết của

Trang 21

- Lưu ý: Một chuỗi A[1 m] được gọi là xuất hiện trong chuỗi B[1 n] K lần khi

và chỉ khi tồn tại K vị trí i phân biệt sao cho A[1 m] = B[i i+m-1].

Trang 22

long long gethash(long i, long j){

Trang 23

long l=1,r=n,g;

while (l<r){

g=(l+r+1)/2;

if (kt(g)) l=g; else r=g-1; }

if (kt(r)) cout<<r; else cout<<0;

cin.get();

return 0;

}

Trang 24

Bài 5 - Palindrome dài nhất – PALINY

- Từ nhận xét trên ta sử dụng thuật toán tìm kiếm nhịphân theo độ dài chẵn xâu con cần tìm

- Tương tự ta xét với độ dài xâu con độ dài lẻ

- Độ phức tạp của thuật toán Nlog(N)

Chương trình viết bằng C++

#include <iostream>

Trang 25

long long hashs[50002],hasht[50002],POW[50002];

long long gethash(long long x[],long a, long b){

Trang 26

for (long i=1;i<=n;i++){

hashs[i]=(hashs[i-1]*26 + s[i]-'a')% base; hasht[i]=(hasht[i-1]*26 + t[i]-'a')% base; }

Trang 27

so sánh mã Hash (ví dụ như dùng 3 modulo một lúc).

Trang 28

TÁC GIẢ SÁNG KIẾN

(Ký ghi rõ họ tên tên)

Ý KIẾN CỦA TỔ NHÓM CHUYÊN MÔN

CƠ QUAN ĐƠN VỊ ÁP DỤNG SÁNG KIẾN (xác nhận, đánh giá, xếp loại)

Trang 29

CÁC PHỤ LỤC KÈM THEO SÁNG KIẾNTài liệu tham khảo

- Hash: Thuật toán so khớp xâu - Le Khac Minh Tue

- http://vn.spoj.com/problems/SUBSTR/

- http://vn.spoj.com/problems/PALINY/

- http://vn.spoj.com/problems/DTKSUB/

- http://vn.spoj.com/problems/C11STR2/

Ngày đăng: 03/04/2015, 16:38

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w