Pisahkan string menjadi string kata yang valid menggunakan Pemrograman Dinamis

Saya perlu menemukan algoritma pemrograman dinamis untuk menyelesaikan masalah ini. Saya mencoba tetapi tidak dapat menemukannya. Inilah masalahnya:

Anda diberikan serangkaian n karakter s[1...n], yang Anda yakini sebagai dokumen teks rusak yang semua tanda bacanya telah hilang (sehingga terlihat seperti "itwasthebestoftimes..."). Anda ingin merekonstruksi dokumen menggunakan kamus, yang tersedia dalam bentuk fungsi Boolean dict(*) sehingga, untuk setiap string w, dict(w) memiliki nilai 1 jika w adalah kata yang valid, dan memiliki nilai 0 jika tidak.

  1. Berikan algoritma pemrograman dinamis yang menentukan apakah string s[*] dapat disusun kembali sebagai rangkaian kata yang valid. Waktu berjalan paling banyak harus O(n^2), dengan asumsi bahwa setiap panggilan ke dict membutuhkan waktu satuan.
  2. Jika string tersebut valid, buat algoritme Anda mengeluarkan urutan kata yang sesuai.

person Pet    schedule 15.03.2011    source sumber
comment
Ya, ini adalah latihan dari buku teks. Saya tidak memiliki solusi untuk latihan ini, dan saya tidak yakin bagaimana menyelesaikan masalah ini.   -  person Pet    schedule 15.03.2011
comment
Hal pertama yang terlintas dalam pikiran adalah ambiguitas. Misalkan kamus Anda mempunyai kata 'was', 'her' dan 'washer'. Namun, Anda bisa memilih kata-kata yang paling pendek. Tunggu, tidak... Anda dapat memotong sebagian dari kata dan menjadikan string tidak valid - seperti menangkap 'otomatis' dari 'otomatis'.   -  person alxx    schedule 15.03.2011
comment
Apakah Anda mencoba mencari jawabannya terlebih dahulu? Sudah ada beberapa pertanyaan tentang masalah ini di SO - stackoverflow.com/questions /4755157/split-string-into-words , stackoverflow.com/questions/3553958/ , stackoverflow.com/questions/3466972/ . Beberapa di antaranya menyebutkan solusi pemrograman dinamis.   -  person hoha    schedule 15.03.2011


Jawaban (6)


Misalkan panjang dokumen yang dipadatkan adalah N.

Misalkan b(n) adalah boolean: true jika dokumen dapat dipecah menjadi kata-kata yang dimulai dari posisi n dalam dokumen.

b(N) benar (karena string kosong dapat dipecah menjadi 0 kata). Diketahui b(N), b(N - 1), ... b(N - k), Anda dapat membuat b(N - k - 1) dengan mempertimbangkan semua kata yang dimulai pada karakter N - k - 1. Jika ada kata apa pun, w, dengan himpunan b(N - k - 1 + len(w)), lalu atur b(N - k - 1) menjadi true. Jika tidak ada kata seperti itu, setel b(N - k - 1) ke false.

Akhirnya, Anda menghitung b(0) yang memberi tahu Anda apakah seluruh dokumen dapat dipecah menjadi kata-kata.

Dalam kode semu:

def try_to_split(doc):
  N = len(doc)
  b = [False] * (N + 1)
  b[N] = True
  for i in range(N - 1, -1, -1):
    for word starting at position i:
      if b[i + len(word)]:
        b[i] = True
        break
  return b

Ada beberapa trik yang dapat Anda lakukan untuk mendapatkan 'kata yang dimulai pada posisi i' secara efisien, tetapi Anda diminta untuk algoritma O(N^2), sehingga Anda dapat mencari setiap string yang dimulai pada i di kamus.

Untuk menghasilkan kata-kata, Anda dapat memodifikasi algoritme di atas untuk menyimpan kata-kata yang baik, atau cukup membuatnya seperti ini:

def generate_words(doc, b, idx=0):
  length = 1
  while true:
    assert b(idx)
    if idx == len(doc): return
    word = doc[idx: idx + length]
    if word in dictionary and b(idx + length):
       output(word)
       idx += length
       length = 1

Di sini b adalah array boolean yang dihasilkan dari bagian pertama algoritma.

person Community    schedule 15.03.2011
comment
Bukankah tidak efisien jika memperhitungkan semua kata yang dimulai dengan karakter N - k - 1. Metode yang lebih baik adalah b[i] = true if there exists i <= j < N such that dict(s[i..j]) and b[j+1..N-1] - person Minh Pham; 07.03.2013

Untuk meresmikan apa yang disarankan @MinhPham.

Ini adalah solusi pemrograman dinamis.

Diberikan sebuah string str, biarkan

b[i] = true jika substring str[0...i] (inklusif) dapat dipecah menjadi kata-kata yang valid.

Tambahkan beberapa karakter awal ke str, katakanlah!, untuk mewakili kata kosong. str = "!" + str

Kasus dasarnya adalah string kosong, jadi

b[0] = benar.

Untuk kasus berulang:

b[j] = benar jika b[i] == benar dan str[i..j] adalah kata untuk semua i ‹ j

person mingxiao    schedule 03.07.2013

O(N^2) Dpnya jelas tetapi jika Anda mengetahui kata-kata dalam kamus, saya rasa Anda dapat menggunakan beberapa perhitungan awal untuk mendapatkannya lebih cepat di O(N). Aho-Corasick

person mariusgherman    schedule 15.03.2011

Solusi dp di c++:

int main()
{
    set<string> dict;
    dict.insert("12");
    dict.insert("123");
    dict.insert("234");
    dict.insert("12345");
    dict.insert("456");
    dict.insert("1234");
    dict.insert("567");
    dict.insert("123342");
    dict.insert("42");
    dict.insert("245436564");
    dict.insert("12334");

    string str = "123456712334245436564";

    int size = str.size();
    vector<int> dp(size+1, -1);
    dp[0] = 0;
    vector<string > res(size+1);
    for(int i = 0; i < size; ++i)
    {
        if(dp[i] != -1)
        {
            for(int j = i+1; j <= size; ++j)
            {
                const int len = j-i;
                string substr = str.substr(i, len);
                if(dict.find(substr) != dict.end())
                {
                    string space = i?" ":"";
                    res[i+len] = res[i] + space + substr;
                    dp[i+len] = dp[i]+1;
                }
            }
        }
    }
    cout << *dp.rbegin() << endl;
    cout << *res.rbegin() << endl;

    return 0;
}
person hidayat    schedule 15.03.2011
comment
Mengapa Anda tidak memberikan gambaran apa yang telah Anda lakukan dan menjelaskan mengapa Anda melakukannya? - person Minh Pham; 07.03.2013
comment
@tobias bisakah Anda menjelaskan algonya - person EmptyData; 21.05.2014
comment
Hanya beberapa kode acak tidak membantu siapa pun. Anda harus memberikan penjelasan. - person adijo; 13.06.2014

String s[] berpotensi dapat dipecah menjadi lebih dari satu cara. Metode di bawah ini mencari jumlah kata maksimum yang dapat kita pisahkan s[]. Di bawah ini adalah sketsa/pseudocode dari algoritma tersebut

bestScore[i] -> Menyimpan jumlah maksimum kata yang dapat memisahkan i karakter pertama (jika tidak, akan menjadi MINUS_INFINITY)

for (i = 1 to n){
     bestScore[i] = MINUS_INFINITY
     for (k = 1 to i-1){
        bestScore[i] = Max(bestSCore[i], bestScore[i-k]+ f(i,k))
     }
 }

Dimana f(i,k) didefinisikan sebagai:

f(i,k) = 1 : if s[i-k+1 to i] is in dictionary
       = MINUS_INFINITY : otherwise

bestScore[n] akan menyimpan jumlah maksimum kata yang s[] dapat dipecah (jika nilainya MINUS_INFINIY, s[] tidak dapat dipecah)

Jelas waktu berjalannya adalah O(n^2)

Karena ini terlihat seperti latihan di buku teks, saya tidak akan menulis kode untuk merekonstruksi posisi split yang sebenarnya.

person Mahak Patidar    schedule 15.03.2011

Di bawah ini adalah solusi O(n^2) untuk masalah ini.

void findstringvalid() {
string s = "itwasthebestoftimes";
set<string> dict;
dict.insert("it");
dict.insert("was");
dict.insert("the");
dict.insert("best");
dict.insert("of");
dict.insert("times");

vector<bool> b(s.size() + 1, false);
vector<int> spacepos(s.size(), -1);
//Initialization phase
b[0] = true; //String of size 0 is always a valid string
for (int i = 1; i <= s.size(); i++) {
    for (int j = 0; j <i; j++) {
       //string of size s[ j... i]
       if (!b[i]) {
           if (b[j]) {
              //check if string "j to i" is in dictionary
              string temp = s.substr(j, i - j);
              set<string>::iterator it = dict.find(temp);
              if (it != dict.end()) {
                  b[i] = true;
                  spacepos[i-1] = j;
              }
           }
        }
    }
}
if(b[s.size()])
    for (int i = 1; i < spacepos.size(); i++) {
        if (spacepos[i] != -1) {
            string temp = s.substr(spacepos[i], i - spacepos[i] + 1);
            cout << temp << " ";
    }
    }
}
person Pankaj Mistry    schedule 27.09.2016
comment
Kamus Anda tidak menyertakan semua kemungkinan kata dalam string. Misalnya a, as dan dia semua adalah kata-kata valid yang dapat ditemukan di substring ini. - person Phil Glau; 17.05.2019