R1NQFAQDH3EG9

I_R_W14_M35_Java Programowanie dynamiczne - znajdowanie spójnego podciągu

Źródło: Gerd Altman, from Pixabay, domena publiczna.

Zadanie 2. Najdłuższy spójny podciąg palindromiczny

Spójny podciąg to taki, którego każde dwa sąsiednie wyrazy były sąsiednimi wyrazami pierwotnego ciągu. Natomiast spójny podciąg palindromiczny to taki podciąg, który czytany w obu kierunkach (czyli od lewej do prawej, jak i wspak) jest identyczny.

W pliku napisy.txt znajduje się 100 ciągów znaków oddzielonych znakiem nowej linii.

Przykładowe dane:

  • ySSyQTffTQcEWWEc

  • ZBdUUdBZzPPz

  • VbbV

R9U2XF8ALKKN4

Plik TXT o rozmiarze 1.02 KB w języku polskim

Napisz program znajdujący najdłuższy spójny podciąg palindromiczny danego ciągu znaków. Wykorzystaj programowanie dynamiczne.

Specyfikacja problemu:

Dane:

  • n – długość wejściowego ciągu znaków; liczba naturalna

  • S[] – ciąg znaków, w którym należy znaleźć najdłuższy podciąg palindromiczny

Wynik:

  • najdluzszy_palindrom – znaleziony najdłuższy podciąg palindromiczny; ciąg znaków

Użyj napisanego programu do znalezienia najdłuższych podciągów palindormicznych dla każdego z ciągów znaków w pliku napisy.txt. Wyniki zapisz do pliku palindromy.txt, każdy w osobnej linii.

1.

Jedno z bezpośrednich rozwiązań polegałoby na sprawdzeniu każdego spójnego podciągu. Niech n będzie długością wejściowego ciągu znaków. Wszystkich takich spójnych podciągów jest wtedy O(nIndeks górny 2 Indeks górny koniec). Sprawdzenie czy ciąg długości n jest palindromiczny zajmuje O(n) czasu. Tak określony prosty algorytm siłowy działa w czasie O(nIndeks górny 3 Indeks górny koniec) . Szybsze rozwiązanie działające w czasie O(nIndeks górny 2 Indeks górny koniec) może opierać się na programowaniu dynamicznym

2. 

Niech d będzie tablicą dwuwymiarową rozmiaru n x n. Wyraz d[i][j] jest równy 1, jeśli spójny podciąg pomiędzy indeksami i oraz j jest palindromiczny.

Np. dla wyrazu „1abdedba254” podciąg „bdedb” jest palindromiczny, zatem wyraz d[2][6]musi być równy 1. Tak samo d[3][5] („ded”) i d[1][7] („abdedba”) też będą równe 1. Z drugiej strony podciąg „1abdedb” nie jest palindromiczny, więc podciąg d[0][6] jest równy 0.

3.

Zapisanie pseudokodu rozpoczniemy od zdefiniowania nagłówka funkcji będącej implementacją algorytmu. Jako argument wymagany jest tylko ciąg znaków S i długość ciągu n.

Linia 1. funkcja najdluzszySpojnyPalindrom otwórz nawias okrągły S otwórz nawias kwadratowy zamknij nawias kwadratowy przecinek n zamknij nawias okrągły dwukropek.

4.

Następnie zdefiniujemy dwuwymiarową tablicę d o rozmiarze n x n, którą wypełniamy 0. Będziemy wypełniać wyłącznie jej część ponad przekątną. Łatwo zauważyć, że d[i][j] będzie zawsze równe d[j][i], więc nie ma potrzeby wypełniać całej tablicy. Dodatkowo określimy zmienną maks_dlugosc przechowującą dotychczas największą długość palindromicznego spójnego podciągu.

Linia 1. funkcja najdluzszySpojnyPalindrom otwórz nawias okrągły S otwórz nawias kwadratowy zamknij nawias kwadratowy przecinek n zamknij nawias okrągły dwukropek. Linia 2. d otwórz nawias kwadratowy n zamknij nawias kwadratowy otwórz nawias kwadratowy n zamknij nawias kwadratowy ← tablica n x n przecinek wypełniona 0. Linia 3. maks podkreślnik dlugosc ← 1.

5.

Na początku wypełniamy przekątną tablicy d[]. Pojedynczy znak jest zawsze palindromem, dlatego wszystkie pola d[i][i] dla 0 < = i < n powinny mieć wartość 1.

Linia 1. funkcja najdluzszySpojnyPalindrom otwórz nawias okrągły S otwórz nawias kwadratowy zamknij nawias kwadratowy przecinek n zamknij nawias okrągły dwukropek. Linia 2. d otwórz nawias kwadratowy n zamknij nawias kwadratowy otwórz nawias kwadratowy n zamknij nawias kwadratowy ← tablica n x n przecinek wypełniona 0. Linia 3. maks podkreślnik dlugosc ← 1. Linia 5. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus 1 wykonuj dwukropek. Linia 6. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy i zamknij nawias kwadratowy ← 1.

6.

Następnie zdefiniujemy zmienną pomocniczą start, która będzie przechowywać indeks, od którego rozpoczyna się najdłuższy znaleziony podciąg palindromiczny. W pojedynczej pętli, iterując po ciągu S, będziemy poszukiwać palindromów długości 2.Znajdując taki palindrom pomiędzy S[i]oraz S[i + 1] zapiszemy w d[i][i+1] wartość 1.

Linia 1. funkcja najdluzszySpojnyPalindrom otwórz nawias okrągły S otwórz nawias kwadratowy zamknij nawias kwadratowy przecinek n zamknij nawias okrągły dwukropek. Linia 2. d otwórz nawias kwadratowy n zamknij nawias kwadratowy otwórz nawias kwadratowy n zamknij nawias kwadratowy ← tablica n x n przecinek wypełniona 0. Linia 3. maks podkreślnik dlugosc ← 1. Linia 5. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus 1 wykonuj dwukropek. Linia 6. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy i zamknij nawias kwadratowy ← 1. Linia 8. start ← 0. Linia 9. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus 1 wykonuj dwukropek. Linia 10. jeżeli S otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości S otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy dwukropek. Linia 11. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy ← 1. Linia 12. start ← i. Linia 13. maks podkreślnik dlugosc ← 2.

7.

Kolejnym krokiem jest utworzenie dwóch zagnieżdżonych pętli, które pozwolą nam wypełnić pozostałe pola w tablicy d[]. Zmienna i będzie wskazywała na początek sprawdzonego podciągu, zmienna k będzie określała jego długość natomiast zmienna j będzie zmienną pomocniczą, której przypiszemy końcowy indeks sprawdzanego podciągu.

Linia 1. funkcja najdluzszySpojnyPalindrom otwórz nawias okrągły S otwórz nawias kwadratowy zamknij nawias kwadratowy przecinek n zamknij nawias okrągły dwukropek. Linia 2. d otwórz nawias kwadratowy n zamknij nawias kwadratowy otwórz nawias kwadratowy n zamknij nawias kwadratowy ← tablica n x n przecinek wypełniona 0. Linia 3. maks podkreślnik dlugosc ← 1. Linia 5. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus 1 wykonuj dwukropek. Linia 6. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy i zamknij nawias kwadratowy ← 1. Linia 8. start ← 0. Linia 9. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus 1 wykonuj dwukropek. Linia 10. jeżeli S otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości S otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy dwukropek. Linia 11. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy ← 1. Linia 12. start ← i. Linia 13. maks podkreślnik dlugosc ← 2. Linia 15. dla k znak równości 3 przecinek 4 przecinek kropka kropka kropka przecinek n wykonuj dwukropek. Linia 16. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus k wykonuj dwukropek. Linia 17. j ← i plus k minus 1.

8.

W każdej iteracji pętli będziemy chcieli sprawdzić, czy podciąg pomiędzy indeksem i oraz j jest palindromem. Aby tak było, muszą być spełnione dwa warunki: podciąg pomiędzy i + 1 oraz j - 1 musi być palindromem oraz S[i]==S[j]. Jeżeli został znaleziony nowy palindrom musimy również sprawdzić, czy nie jest on nowym najdłuższym znalezionym rozwiązaniem. W takim wypadku ustawiamy zmienną start na indeks i natomiast maks_dlugosc na k.

Linia 1. funkcja najdluzszySpojnyPalindrom otwórz nawias okrągły S otwórz nawias kwadratowy zamknij nawias kwadratowy przecinek n zamknij nawias okrągły dwukropek. Linia 2. d otwórz nawias kwadratowy n zamknij nawias kwadratowy otwórz nawias kwadratowy n zamknij nawias kwadratowy ← tablica n x n przecinek wypełniona 0. Linia 3. maks podkreślnik dlugosc ← 1. Linia 5. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus 1 wykonuj dwukropek. Linia 6. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy i zamknij nawias kwadratowy ← 1. Linia 8. start ← 0. Linia 9. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus 1 wykonuj dwukropek. Linia 10. jeżeli S otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości S otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy dwukropek. Linia 11. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy ← 1. Linia 12. start ← i. Linia 13. maks podkreślnik dlugosc ← 2. Linia 15. dla k znak równości 3 przecinek 4 przecinek kropka kropka kropka przecinek n wykonuj dwukropek. Linia 16. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus k wykonuj dwukropek. Linia 17. j ← i plus k minus 1. Linia 19. jeżeli d otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy otwórz nawias kwadratowy j minus 1 zamknij nawias kwadratowy ORAZ S otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości S otwórz nawias kwadratowy j zamknij nawias kwadratowy dwukropek. Linia 20. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy ← 1. Linia 22. jeżeli k zamknij nawias ostrokątny maks podkreślnik dlugosc dwukropek. Linia 23. start ← i. Linia 24. maks podkreślnik dlugosc ← k.

9.

Na koniec definiujemy tablicę najdluzszy_palindrom[] o długości maks_dlugosc, która pozwoli nam zwrócić znalezione rozwiązanie. Zapiszemy do niej w pętli podciąg zaczynający się na indeksie start, a kończący na start + maks_dlugosc‑1, a następnie zwrócimy.

Linia 1. funkcja najdluzszySpojnyPalindrom otwórz nawias okrągły S otwórz nawias kwadratowy zamknij nawias kwadratowy przecinek n zamknij nawias okrągły dwukropek. Linia 2. d otwórz nawias kwadratowy n zamknij nawias kwadratowy otwórz nawias kwadratowy n zamknij nawias kwadratowy ← tablica n x n przecinek wypełniona 0. Linia 3. maks podkreślnik dlugosc ← 1. Linia 5. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus 1 wykonuj dwukropek. Linia 6. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy i zamknij nawias kwadratowy ← 1. Linia 8. start ← 0. Linia 9. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus 1 wykonuj dwukropek. Linia 10. jeżeli S otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości S otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy dwukropek. Linia 11. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy ← 1. Linia 12. start ← i. Linia 13. maks podkreślnik dlugosc ← 2. Linia 15. dla k znak równości 3 przecinek 4 przecinek kropka kropka kropka przecinek n wykonuj dwukropek. Linia 16. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek n minus k wykonuj dwukropek. Linia 17. j ← i plus k minus 1. Linia 19. jeżeli d otwórz nawias kwadratowy i plus 1 zamknij nawias kwadratowy otwórz nawias kwadratowy j minus 1 zamknij nawias kwadratowy ORAZ S otwórz nawias kwadratowy i zamknij nawias kwadratowy znak równości S otwórz nawias kwadratowy j zamknij nawias kwadratowy dwukropek. Linia 20. d otwórz nawias kwadratowy i zamknij nawias kwadratowy otwórz nawias kwadratowy j zamknij nawias kwadratowy ← 1. Linia 22. jeżeli k zamknij nawias ostrokątny maks podkreślnik dlugosc dwukropek. Linia 23. start ← i. Linia 24. maks podkreślnik dlugosc ← k. Linia 26. najdluzszy podkreślnik palindrom otwórz nawias kwadratowy maks podkreślnik dlugosc zamknij nawias kwadratowy ← tablica znaków o rozmiarze maks podkreślnik dlugosc. Linia 27. dla i znak równości 0 przecinek 1 przecinek kropka kropka kropka przecinek maks podkreślnik dlugosc minus 1 wykonuj dwukropek. Linia 28. najdluzszy podkreślnik palindrom otwórz nawias kwadratowy i zamknij nawias kwadratowy ← S otwórz nawias kwadratowy start plus i zamknij nawias kwadratowy. Linia 30. zwróć najdluzszy podkreślnik palindrom.

Odpowiedź do zadania

Odpowiedź dla danych z pliku napisy.txt znajduje się w załączniku:

RF2RN53OC6JK5

Plik TXT o rozmiarze 553.00 B w języku polskim