Tính toán chuỗi con chung dài nhất của hai chuỗi bằng mảng hậu tố


15

Sau khi tôi học cách xây dựng một mảng hậu tố theo độ phức tạp O(N) , tôi thích khám phá các ứng dụng của mảng hậu tố. Một trong số đó là tìm chuỗi con chung dài nhất giữa hai chuỗi, trong thời gian O(N) . Tôi tìm thấy trên internet các thuật toán sau:

  1. hợp nhất hai chuỗi AB thành một chuỗi AB
  2. tính mảng hậu tố của AB
  3. tính toán mảng LCP (tiền tố chung dài nhất)
  4. câu trả lời là giá trị lớn nhất LCP[i]

Tôi đã cố gắng thực hiện nó, nhưng như nhiều chi tiết triển khai không được nói (nghĩa là khi nối các chuỗi, tôi có nên đặt một ký tự đặc biệt giữa chúng ( ) không?), Mã của tôi đã thất bại trong nhiều trường hợp thử nghiệm. Ai đó có thể giải thích nhiều hơn về thuật toán này?AcB

Cảm ơn trước.

Lưu ý: Tôi không đảm bảo tính chính xác của thuật toán này; Tôi đã tìm thấy nó trên một blog và tôi không chắc nó đang hoạt động. Nếu bạn nghĩ rằng nó không chính xác, xin vui lòng đề xuất một thuật toán khác.


3
Trước khi thực hiện thuật toán, hãy cố gắng hiểu tại sao nó hoạt động. Điều đó có thể giúp trả lời một câu hỏi như làm thế nào để nối hai chuỗi.
Yuval Filmus

3
Tôi nghi ngờ tính chính xác của thuật toán này. Lấy b c d , cách tôi đọc nó sẽ trả về a b c d , điều đó là sai. abcdabcdbcdabcd
Khaur

Câu trả lời:


19

Thuật toán của bạn không chính xác . Tôi giả sử bạn biết cách tính toán mảng hậu tố và mảng LCP của một chuỗi, nghĩa là triển khai hiệu quả của chúng. Như đã được chỉ ra trong các ý kiến, bạn nên cố gắng hiểu từng thành phần là gì và tại sao nó hoạt động.

Trước hết, là mảng hậu tố ( ) của một chuỗi. Một mảng hậu tố về cơ bản là tất cả các hậu tố của chuỗi S được sắp xếp theo thứ tự từ điển tăng dần. Cụ thể hơn, giá trị S A [ i ] chỉ ra rằng hậu tố của S bắt đầu từ vị trí S A [ i ] được xếp hạng iSASSA[i]SSA[i]i trong trật tự tự từ điển của tất cả các hậu tố của .S

Tiếp theo là mảng L C P [ i ] cho biết độ dài của tiền tố chung dài nhất giữa các hậu tố bắt đầu từ S A [ i - 1 ]S A [ i ] . Đó là, nó theo dõi độ dài của tiền tố chung dài nhất trong số hai hậu tố liên tiếp của S khi được sắp xếp theo thứ tự từ điển.LCPLCP[i]SA[i1]SA[i]S

Ví dụ, xem xét chuỗi . Các hậu tố theo thứ tự từ vựng sẽ là { a , a b b a b c a , a b c a , b a b c a , b b a b c a , b c a , c a } , vì vậy S , 4 , 3 , 2S=abbabca{a,abbabca,abca,babca,bbabca,bca,ca}SA=[7,1,4,3,2,5,6] for a 1-indexed array. The LCP array would be LCP=[,1,2,0,1,1,0].

Now, given two strings A and B, we concatenate them as S=A#B, where # is a character not present in both A and B. The reason for choosing such a character is so that when computing the LCP of two suffixes, say ab#dabd and abd, the comparison will break off at the end of the first string (since it only occurs once, two different suffixes will never have it in the same position), and won't "overflow" into the other string.

Bây giờ, có thể thấy rằng bạn sẽ có thể thấy lý do tại sao bạn chỉ cần xem các giá trị liên tiếp trong mảng (đối số dựa trên mâu thuẫn và thực tế là các hậu tố trong S A theo thứ tự từ điển). Tiếp tục kiểm tra mảng L C P để tìm giá trị tối đa sao cho hai hậu tố được so sánh không thuộc cùng một chuỗi gốc. Nếu chúng không thuộc cùng một chuỗi gốc (một chuỗi bắt đầu bằng A và chuỗi kia ở B ), thì giá trị lớn nhất như vậy là độ dài của chuỗi con chung lớn nhất.LCPSALCPAB

A=abcabcB=bcS=abcabc#bc{abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc}
SA=[4,1,8,5,2,9,6,3,7]LCP=[,3,0,2,2,0,1,1,0]

Now, the greatest value is LCP[2]=3, but it is for SA[1] and SA[2], both of which start in the string A. So, we ignore that. On the other hand, LCP[4]=2 is for SA[3] (corresponds to the suffix bc of B) and SA[4] (corresponding to suffix bcabc#bc of A). So, this is the longest common substring between the two strings. For getting the actual substring, you take a length 2 (value of the greatest feasible LCP) substring starting from either SA[3] or SA[4], which is bc.


1
Excellent explanation but I think that the example is a bit wrong, the sorted suffixes are : {#bc,abc#bc,abcabc#bc,bc,bc#bc,bcabc#bc,c,c#bc,cabc#bc}, SA=[7,4,1,8,5,2,9,6,3] and LCP=[−,0,3,0,2,2,0,1,1]
Saúl Martínez Vidals

1

The algorithm you found online is not entirely correct. As mentioned by Paresh, it will fail in the example given by him.

However, if you ensure that while checking the LCP, you only check the LCP of substrings of different strings. For example, if you are finding the LCS of strings A and B, then you need to ensure that the adjacent entries of the Suffix Array while checking for LCP are both not from the same string.

More details here.


1
When you say "This answer", do you mean your own answer or some other answer? Please only use the answer box to answer the question, not to comment on other answers. When you've picked up enough reputation, you'll be able to leave comments on other answers.
David Richerby

0

I think something like the algorithm you cite should indeed work if a character that is not part of the character set is used as a separator, and the suffix/prefix arrays are built to exclude all strings that contain the separator, probably the intention of the designer. this is basically equivalent to building suffix/prefix arrays for the two separate strings.

it would be helpful for future ref if you posted a link to the algorithm. note that wikipedia has the algorithm for this in pseudocode & many other algorithms. and there are implementations in most standard languages available online.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.