Cari Substring Yang Merupakan Palindromes di Jawa

1. Gambaran keseluruhan

Dalam tutorial ringkas ini, kita akan melalui pendekatan yang berbeza untuk mencari semua substring dalam rentetan tertentu yang merupakan palindromes . Kami juga akan memperhatikan kerumitan masa setiap pendekatan.

2. Pendekatan Brute Force

Dalam pendekatan ini, kita akan melakukan iterasi pada rentetan input untuk mencari semua substring. Pada masa yang sama, kami akan memeriksa sama ada substring adalah palindrome atau tidak:

public Set findAllPalindromesUsingBruteForceApproach(String input) { Set palindromes = new HashSet(); for (int i = 0; i < input.length(); i++) { for (int j = i + 1; j <= input.length(); j++) { if (isPalindrome(input.substring(i, j))) { palindromes.add(input.substring(i, j)); } } } return palindromes; }

Dalam contoh di atas, kita hanya membandingkan substring dengan yang terbalik untuk melihat apakah itu palindrome:

private boolean isPalindrome(String input) { StringBuilder plain = new StringBuilder(input); StringBuilder reverse = plain.reverse(); return (reverse.toString()).equals(input); }

Sudah tentu, kita boleh memilih dari beberapa pendekatan lain dengan mudah.

Kerumitan masa pendekatan ini adalah O (n ^ 3). Walaupun ini mungkin dapat diterima untuk rentetan input kecil, kami memerlukan pendekatan yang lebih cekap jika kami memeriksa palindrom dalam jumlah teks yang banyak.

3. Pendekatan Pemusatan

Idea dalam pendekatan pemusatan adalah untuk mempertimbangkan setiap watak sebagai pivot dan berkembang ke dua arah untuk mencari palindromes .

Kami hanya akan berkembang jika watak-watak di sebelah kiri dan kanan sesuai, yang menjadikan rentetan menjadi palindrome. Jika tidak, kita teruskan ke watak seterusnya.

Mari lihat demonstrasi ringkas di mana kita akan menganggap setiap watak sebagai pusat palindrome:

public Set findAllPalindromesUsingCenter(String input) { Set palindromes = new HashSet(); for (int i = 0; i < input.length(); i++) { palindromes.addAll(findPalindromes(input, i, i + 1)); palindromes.addAll(findPalindromes(input, i, i)); } return palindromes; }

Dalam gelung di atas, kami memperluas ke dua arah untuk mendapatkan set semua palindromes yang berpusat pada setiap kedudukan. Kami akan menemui palindromes panjang dan ganjil dengan memanggil kaedah findPalindromes dua kali dalam gelung :

private Set findPalindromes(String input, int low, int high) { Set result = new HashSet(); while (low >= 0 && high < input.length() && input.charAt(low) == input.charAt(high)) { result.add(input.substring(low, high + 1)); low--; high++; } return result; }

Kerumitan masa pendekatan ini adalah O (n ^ 2). Ini adalah peningkatan berbanding pendekatan brute-force kami, tetapi kami dapat melakukan yang lebih baik lagi, seperti yang akan kami lihat di bahagian seterusnya.

4. Algoritma Manacher

Algoritma Manacher menemui substring palindromik terpanjang dalam masa linear . Kami akan menggunakan algoritma ini untuk mencari semua substring yang merupakan palindromes.

Sebelum kita menyelidiki algoritma, kita akan memulakan beberapa pemboleh ubah.

Pertama, kita akan menjaga rentetan input dengan watak sempadan pada awal dan akhir sebelum menukar rentetan yang dihasilkan ke array watak:

String formattedInput = "@" + input + "#"; char inputCharArr[] = formattedInput.toCharArray();

Kemudian, kami akan menggunakan jejari array dua dimensi dengan dua baris - satu untuk menyimpan panjang palindrom panjang ganjil, dan satu lagi untuk menyimpan panjang palindroma panjang genap:

int radius[][] = new int[2][input.length() + 1];

Seterusnya, kami akan melakukan iterasi pada array input untuk mencari panjang palindrome berpusat pada kedudukan i dan menyimpan panjang ini dalam radius [] [] :

Set palindromes = new HashSet(); int max; for (int j = 0; j <= 1; j++) { radius[j][0] = max = 0; int i = 1; while (i <= input.length()) { palindromes.add(Character.toString(inputCharArr[i])); while (inputCharArr[i - max - 1] == inputCharArr[i + j + max]) max++; radius[j][i] = max; int k = 1; while ((radius[j][i - k] != max - k) && (k < max)) { radius[j][i + k] = Math.min(radius[j][i - k], max - k); k++; } max = Math.max(max - k, 0); i += k; } }

Akhirnya, kami akan melintasi jejari array [] [] untuk mengira substring palindromik yang berpusat di setiap kedudukan:

for (int i = 1; i <= input.length(); i++) { for (int j = 0; j  0; max--) { palindromes.add(input.substring(i - max - 1, max + j + i - 1)); } } }

Kerumitan masa pendekatan ini adalah O (n).

5. Kesimpulan

Dalam artikel ringkas ini, kami membincangkan kerumitan waktu dari pendekatan yang berbeza untuk mencari substring yang merupakan palindrom.

Seperti biasa, kod sumber penuh contoh terdapat di GitHub.