Намерете поднизове, които са палиндроми в Java

1. Общ преглед

В този бърз урок ще преминем през различни подходи за намиране на всички поднизове в даден низ, които са палиндроми . Ще отбележим и сложността във времето на всеки подход.

2. Подход на грубата сила

При този подход ние просто ще прегледаме входния низ, за ​​да намерим всички поднизове. В същото време ще проверим дали поднизът е палиндром или не:

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; }

В горния пример просто сравняваме подниза с обратната му страна, за да видим дали е палиндром:

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

Разбира се, можем лесно да избираме измежду няколко други подхода.

Сложността във времето на този подход е O (n ^ 3). Въпреки че това може да е приемливо за малки входни низове, ще ни е необходим по-ефективен подход, ако проверяваме за палиндроми в големи обеми текст.

3. Подход за централизация

Идеята в подхода за централизация е да се разглежда всеки знак като опора и да се разширява в двете посоки, за да се намерят палиндроми .

Ще се разширим само ако символите от лявата и дясната страна съвпадат, квалифицирайки низа като палиндром. В противен случай продължаваме към следващия знак.

Нека видим бърза демонстрация, в която ще разглеждаме всеки знак като център на палиндрома:

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; }

В рамките на цикъла по-горе се разширяваме в двете посоки, за да получим набора от всички палиндроми, центрирани във всяка позиция. Ще намерим палиндроми с четна и нечетна дължина, като извикаме метода findPalindromes два пъти в цикъла :

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; }

Сложността във времето на този подход е O (n ^ 2). Това е подобрение спрямо нашия груб подход, но можем да направим още по-добре, както ще видим в следващия раздел.

4. Алгоритъм на Manacher

Алгоритъмът на Manacher намира най-дългия палиндромен подниз в линейно време . Ще използваме този алгоритъм, за да намерим всички поднизове, които са палиндроми.

Преди да се потопим в алгоритъма, ще инициализираме няколко променливи.

Първо ще защитим входния низ с граничен символ в началото и в края, преди да преобразуваме получения низ в символен масив:

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

След това ще използваме двуизмерен радиус на масив с два реда - единият за съхраняване на дължините на палиндроми с нечетна дължина, а другият за съхраняване на дължини на палиндроми с четна дължина:

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

След това ще повторим входния масив, за да намерим дължината на палиндрома, центриран в позиция i, и ще съхраним тази дължина в радиус [] [] :

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; } }

И накрая, ще преминем през радиуса на масива [] [], за да изчислим палиндромните поднизове, центрирани във всяка позиция:

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)); } } }

Сложността във времето на този подход е O (n).

5. Заключение

В тази бърза статия обсъдихме времевата сложност на различните подходи за намиране на поднизове, които са палиндроми.

Както винаги, пълният изходен код на примерите е достъпен в GitHub.