12. Напишіть функцію для знаходження найдовшого паліндрому в даному рядку
Рядок може містити рядки-паліндроми, і знаходження найдовшого паліндрому - це питання програмування. Ключовим моментом тут є те, що з середини будь-якого паліндрому, якщо ми підемо праворуч і ліворуч на 1 символ, це завжди буде однаковим символом. Наприклад, 12321, середина тут 3, і якщо ми продовжимо рух з поточної позиції в обидві сторони, ми отримаємо 2, а потім 1. Ми використовуємо подібну логіку в нашій програмі Java для знаходження найдовшого паліндрому. Однак якщо довжина паліндрому парна, довжина середини теж парна, так що ми повинні переконатися, що в нашій програмі це так само передбачено, наприклад, 12333321, тут середина 33, і якщо ми продовжимо рух в обидва боки, ми отримаємо 3, 2 і 1. У нашій програмі ми проходимо по рядку з серединою на першому місці і перевіряємо лівий і правий символ. Також ми маємо дві глобальні змінні для зберігання початкової позиції паліндрому. Нам також необхідно перевірити наявність вже знайденого довшого паліндрому, оскільки ми можемо знайти кілька паліндромів у даному рядку. Нижче наведено приклад програми, яка добре працює у всіх випадках. Ми можемо вдосконалити наведений код, перемістивши цикл while в окремий метод, але я залишив цю частину для вас. Будь ласка, дайте мені знати, якщо у вас є вдала реалізація, або програма не спрацьовує в якомусь випадку. Ми можемо вдосконалити наведений код, перемістивши цикл while в окремий метод, але я залишив цю частину для вас. Будь ласка, дайте мені знати, якщо у вас є вдала реалізація, або програма не спрацьовує в якомусь випадку. Ми можемо вдосконалити наведений код, перемістивши цикл while в окремий метод, але я залишив цю частину для вас. Будь ласка, дайте мені знати, якщо у вас є вдала реалізація, або програма не спрацьовує в якомусь випадку.package com.journaldev.util;
public class LongestPalindromeFinder {
public static void main(String[] args) {
System.out.println(longestPalindromeString("1234"));
System.out.println(longestPalindromeString("12321"));
System.out.println(longestPalindromeString("9912321456"));
System.out.println(longestPalindromeString("9912333321456"));
System.out.println(longestPalindromeString("12145445499"));
}
public static String longestPalindromeString(String in) {
char[] input = in.toCharArray();
int longestPalindromeStart = 0;
int longestPalindromeEnd = 0;
for (int mid = 0; mid < input.length; mid++) {
// для случая нечетного палиндрома як 12321, 3 будет серединой
int left = mid-1;
int right = mid+1;
// нам необходимо двигаться влево и вправо на 1 позицию до конца
while (left >= 0 && right < input.length) {
// ниже проверка, является ли это палиндромом
if (input[left] == input[right]) {
// обновление глобальных позиций, только если палиндром длиннее имеющегося
if (right - left > longestPalindromeEnd
- longestPalindromeStart) {
longestPalindromeStart = left;
longestPalindromeEnd = right;
}
}
left--;
right++;
}
// для четного палиндрома у нас должна быть подобная логика с размером середины 2
// для этого мы начнем на одну позицию правее
left = mid-1;
right = mid + 2;// к примеру, для 12333321 мы выбрали 33 в качестве середины
while (left >= 0 && right < input.length)
{
if (input[left] == input[right]) {
if (right - left > longestPalindromeEnd
- longestPalindromeStart) {
longestPalindromeStart = left;
longestPalindromeEnd = right;
}
}
left--;
right++;
}
}
// теперь у нас есть позиции для самого длинного палиндрома
return in.substring(longestPalindromeStart, longestPalindromeEnd + 1);
}
}
Програма виведе наступне:
1
12321
12321
12333321
454454
13. Які відмінності між String, StringBuffer та StringBuilder
Рядок є незмінним і фіналізованим у Java, тому всі наші маніпуляції з рядком завжди будуть створювати новий рядок. Маніпуляції з рядками ресурсомісткі, тому Java забезпечує два корисні класи для маніпуляцій з рядками –StringBuffer
і StringBuilder
. StringBuffer
і StringBuilder
є змінними класами. Операції з StringBuffer
потокобезпечними та синхронізованими, а методи StringBuilder
не потокобезпечними. Тому коли кілька ниток працюють з одним рядком, ми повинні використовувати StringBuffer
, але в однопотоковому ми повинні використовувати StringBuilder
. StringBuilder
більш продуктивний, ніж StringBuffer
, оскільки не обтяжений синронізацією.
14. Чому рядок незмінний і фіналізований в Java
Є кілька переваг у незмінності рядків:-
Рядковий пул можливий тільки тому, що рядок незмінна в Java, таким чином віртуальна машина зберігає багато місця в пам'яті (heap space), оскільки різні рядкові змінні вказують на одну змінну в пулі. Якби рядок не був незмінним, тоді інтернування рядків не було б можливим, тому що якщо яка-небудь змінна змінить значення, це позначиться також і на інших змінних, що посилаються на цей рядок.
-
Якщо рядок буде змінним, тоді це стане серйозною загрозою безпеці програми. Наприклад, ім'я користувача бази даних та пароль передаються рядком для отримання з'єднання з базою даних та у програмуванні сокетів реквізити хоста та порту передаються рядком. Так як рядок незмінна, його значення не може бути змінено, в іншому випадку будь-який хакер може змінити значення посилання та викликати проблеми безпеки програми.
-
Так як рядок незмінна, вона безпечна для багато потоковості і один екземпляр рядка може бути спільно використаний різними нитками. Це дозволяє уникнути синхронізації для потокобезпеки, рядки повністю потокобезпечні.
-
Рядки використовуються в Java
classloader
і незмінність забезпечує правильність завантаження класу за допомогоюClassloader
. Наприклад, подумайте про екземплярі класу, коли ви намагаєтеся завантажитиjava.sql.Connection
клас, але значення посилання змінено наmyhacked.Connection
клас, який може здійснити небажані речі з базою даних. -
Оскільки рядок незмінний, його
hashcode
кешується в момент створення і немає необхідності розраховувати його знову. Це робить рядок відмінним кандидатом для ключаMap
і його обробка буде швидше, ніж інших ключівHashMap
. Це причина, чому рядок найбільш часто використовуваний об'єкт, який використовується як ключHashMap
.
15. Як поділити рядок на частини?
Ми можемо використовувати методsplit(String regex)
для поділу рядка на масив рядків, використовуючи як роздільник регулярний вираз.
import java.util.Arrays;
public class JavaSplitString {
public static void main(String[] args) {
String line = "I am a java developer";
String[] words = line.split(" ");
String[] twoWords = line.split(" ", 2);
System.out.println("String split with delimiter: "+Arrays.toString(words));
System.out.println("String split into two: "+Arrays.toString(twoWords));
//split string delimited with special characters
String wordsWithNumbers = "I|am|a|java|developer";
String[] numbers = wordsWithNumbers.split("\\|");
System.out.println("String split with special character: "+Arrays.toString(numbers));
}
}
Метод split(String regex, int numOfStrings)
є перевантаженим методом розділення рядка на задану кількість рядків. Ми можемо використовувати обернену рису для використання спеціальних символів регулярних виразів як звичайних символів. Програма виведе наступне:
String split with delimiter: [I, am, a, java, developer]
String split into two: [I, am a java developer]
String split with special character: [I, am, a, java, developer]
16. Чому масив рядків кращий за рядок для зберігання пароля?
Рядок незмінний в Java і зберігається в пулі рядків. З того часу, як вона була створена, вона залишається в пулі, поки не буде видалена збирачем сміття, тому коли ми думаємо, що закінчабо роботу з паролем, він залишається доступним у пам'яті деякий час, і немає способу уникнути цього. Це ризик безпеки, оскільки будь-хто, хто має доступ до дампи пам'яті, зможе знайти пароль у вигляді чистого тексту. Якщо ми використовуємо масив символів для зберігання пароля, ми можемо очистити його після завершення роботи. Таким чином, ми можемо контролювати, як довго він знаходиться в пам'яті, що дозволяє уникнути ризику безпеки, властивого рядку.17. Як ви перевірите два рядки на подібність у Java?
Є два способи перевірити, чи два рядки є еквівалентними – використовуючи оператор “==
”, або використовуючи метод equals
. Коли ми використовуємо оператор “ ==
”, він перевіряє значення рядка, як посилання, але у програмуванні більшу частину часу ми перевіряємо еквівалентність рядка лише значення. Тому ми повинні використовувати метод equals для перевірки двох рядків на еквівалентність. Є ще метод equalsIgnoreCase
, який ми можемо використовувати для ігнорування регістру.
String s1 = "abc";
String s2 = "abc";
String s3= new String("abc");
System.out.println("s1 == s2 ? "+(s1==s2)); //true
System.out.println("s1 == s3 ? "+(s1==s3)); //false
System.out.println("s1 equals s3 ? "+(s1.equals(s3))); //true
18. Що таке пул рядків?
Як підказує назва, пул рядків – це набір рядків, що зберігається у пам'яті Java heap. Ми знаємо, щоString
це спеціальний клас у Java, і ми можемо створювати об'єкти цього класу, використовуючи оператор new так само, як і створювати об'єкти, надаючи значення рядка в подвійних лапках. Діаграма нижче пояснює, як пул рядків розміщується в пам'яті Java heap і що відбувається, коли ми використовуємо різні способи створення рядків. Пул рядків можливий виключно завдяки незмінності рядків у Java та реалізації ідеї інтернування рядків. Пул рядків також є прикладом патерна Пристосуванець (Flyweight). Пул рядків допомагає заощаджувати великий обсяг пам'яті, але з іншого боку, створення рядка займає більше часу. Коли ми використовуємо подвійні лапки для створення рядка, спочатку шукається рядок у пулі з таким самим значенням, якщо знаходиться, то просто повертається посилання, інакше створюється новий рядок у пулі, а потім повертається посилання. Тим не менш, коли ми використовуємо оператор new, ми примушуємо клас String
створити новий об'єкт рядка, а потім ми можемо використовувати метод intern()
для того, щоб помістити рядок в пул, або отримати посилання з пула на інший об'єкт.String
з таким самим значенням. Нижче наведено приклад, який показує роботу пулу рядків.
public class StringPool {
public static void main(String[] args) {
String s1 = "Cat";
String s2 = "Cat";
String s3 = new String("Cat");
System.out.println("s1 == s2 :"+(s1==s2));
System.out.println("s1 == s3 :"+(s1==s3));
}
}
Програма виведе наступне:
s1 == s2 :true
s1 == s3 :false
19. Що робить метод intern()?
Коли методintern()
викликаний, якщо пул рядків вже містить рядок, еквівалентний нашому об'єкту, що підтверджується методом equals(Object)
, тоді повертається посилання на рядок з пула. В іншому випадку об'єкт рядка додається до пулу і посилання на цей об'єкт повертається. Цей метод завжди повертає рядок, який має те саме значення, що й поточний рядок, але гарантує, що це буде рядок з пулу унікальних рядків. Нижче наведено приклад роботи методу intern()
:
public class StringPool { public static void main(String[] args) { String a = "string a"; String b = new String("string a"); String c = b.intern(); System.out.println(a == b); System.out.println(b == c); System.out.println(a == c); } } Программа выведет следующее:
false false true
20. Чи є рядки потокобезпечними в Java?
Рядки є незмінними, тому ми не можемо змінити їх значення у програмі. Отже вони потокобезопасны і можуть благополучно використовуватися в мультипоточному оточенні.21. Чому рядок є популярним ключем у HashMap Java?
Оскільки рядки незмінні, їх хешкод кешується в момент створення і не вимагає повторного перерахунку. Це робить рядки відмінним кандидатом для ключаMap
і вони обробляються швидше, ніж інші об'єкти-ключі HashMap
. Ось чому рядки переважно використовуються як ключі HashMap
. Сподіваюся, що запитання, перелічені в цій статті, допоможуть вам на співбесідах, будь ласка, дайте мені знати, якщо я щось пропустив. Посилання на оригінальну статтю Автор: Pankaj Kumar