Diberikan dan string, apakah salah satu dari mereka adalah substring dari yang lain?

9

Misalkan kita diberi koleksi string, . Saya ingin tahu apakah salah satu dari string tersebut adalah substring dari string lain dalam koleksi. Dengan kata lain, saya ingin algoritma untuk tugas berikut:nS1,,Sn

Input:S1,,Sn

Output: sehingga adalah substring dari S_j dan i \ ne j , atau None jika tidak ada i, j adai,jSiSjiji,j

Apakah ada algoritma yang efisien untuk ini?

Jika kita mengganti "substring" dengan "awalan", ada algoritma yang efisien (mengurutkan string, lalu melakukan pemindaian linier untuk membandingkan string yang berdekatan; pengurutan akan memastikan bahwa substring berbatasan). Tetapi tampaknya lebih menantang untuk menguji apakah string adalah substring dari string lain. Algoritma naif adalah untuk mengulangi semua pasangan i,j , tetapi ini membutuhkan tes substring Θ(n2) . Apakah ada algoritma yang lebih efisien?

Saya kira kita bisa menyebut ini "all-pair substring testing", atau sesuatu seperti itu.

Tujuan utama saya adalah memangkas koleksi sehingga tidak ada string yang merupakan substring dari yang lain, dengan menghapus masing-masing yang merupakan substring dari sesuatu yang lain dalam koleksi.

DW
sumber
Petunjuk: Susunan sufiks.
Nama samaran
Sebagai catatan tambahan, tidak benar jika Anda menghapus substring saat Anda menemukannya. Itu akan lebih sedikit. Anda juga harus mengurutkan berdasarkan panjang karena string yang lebih panjang tidak dapat muncul dalam string yang lebih pendek. Lagi salah di sini. Θ(n2)Θ(n2)
Alexis Wilke
@AlexisWilke, benar: itulah jumlah tes substring dalam kasus terburuk (kasus terburuk adalah di mana tidak ada string yang merupakan substring dari yang lain). Mengurutkan berdasarkan panjang hanya memberi Anda faktor dua, yang tidak memengaruhi asimptotik. Θ(n2)
DW

Jawaban:

6

Anda dapat membangun pohon sufiks dalam waktu linier dan memeriksa apakah ada simpul dalam yang terkait dengan string penuh (waktu konstan per simpul).

Secara lebih rinci, anggap kita diberi string .s1,,snΣ

  1. Buat pohon sufiks (umum) dari dengan n penanda terminal berbeda berpasangan $ 1 , , $ nΣ .s1$1,s2$2,,sn$nn$1,,$nΣ

    Menggunakan algoritma Ukkonen , ini dapat dilakukan dalam waktu linier; linear dalam jumlah semua panjang string.

  2. Dengan asumsi bahwa Anda memberi label daun dengan jika mereka mewakili akhiran s i [ j . . | s i | ] dari(i,j)si[j..|si|] , lintasi pohon dan temukan n daun yang berlabel ( i , 0 ) , yaitu daun yang sesuai dengan string penuh.sin(i,0)

    Ini membutuhkan waktu linier dalam ukuran pohon, yang itu sendiri linier dalam ukuran input.

  3. Daun turunan dari induk (yang dicapai oleh tepi berlabel $ i ) mewakili semua kecocokan dari set; ini mengikuti dari invarian dasar pohon suffix. Temukan satu kecocokan dengan turun ke daun apa pun (tapi ( i , 0 ) ).(i,0)$i(i,0)

    Ini lagi membutuhkan waktu linier.

Penanda terminal yang berbeda tidak benar-benar diperlukan; satu yang digunakan untuk mengakhiri semua string cukup memadai selama Anda mengizinkan beberapa label per daun.

Raphael
sumber