12. Napisz funkcję znajdującą najdłuższy palindrom w podanym ciągu znaków
Ciąg może zawierać ciągi palindromowe, a znalezienie najdłuższego palindromu jest kwestią programowania. Kluczową kwestią jest to, że jeśli od środka dowolnego palindromu przejdziemy w prawo i w lewo o 1 znak, zawsze będzie to ten sam znak. Na przykład 12321, środek to 3 i jeśli będziemy kontynuować przesuwanie się od bieżącej pozycji w obu kierunkach, otrzymamy 2, a następnie 1. Używamy podobnej logiki w naszym programie Java, aby znaleźć najdłuższy palindrom. Jeśli jednak długość palindromu jest parzysta, długość środka również jest parzysta, więc musimy się upewnić, że jest to również uwzględnione w naszym programie, np. 12333321, środek wynosi 33 i jeśli będziemy kontynuować ruch w obu kierunkach otrzymamy 3, 2 i 1. W naszym programie przechodzimy przez wynikowy ciąg ze środkiem w pierwszej kolejności i sprawdzamy lewy i prawy znak. Mamy również dwie zmienne globalne do przechowywania początkowej pozycji palindromu. Musimy także sprawdzić, czy nie znaleziono już dłuższego palindromu, ponieważ w danym ciągu możemy znaleźć wiele palindromów. Poniżej znajduje się przykładowy program, który działa dobrze we wszystkich przypadkach. Możemy ulepszyć powyższy kod, przenosząc pętlę while do osobnej metody, ale tę część pozostawię Tobie. Proszę dać mi znać, jeśli masz lepszą implementację lub jeśli program zawodzi w jakiś sposób.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++) {
// для случая нечетного палиндрома Jak 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);
}
}
Program wyświetli następujące informacje:
1
12321
12321
12333321
454454
13. Jakie są różnice pomiędzy String, StringBuffer i StringBuilder
Ciąg jest niezmienny i sfinalizowany w Javie, więc wszystkie nasze manipulacje ciągami zawsze spowodują utworzenie nowego ciągu. Manipulowanie ciągami wymaga dużych zasobów, dlatego Java udostępnia dwie przydatne klasy do manipulacji ciągami —StringBuffer
i StringBuilder
. StringBuffer
i StringBuilder
są klasami modyfikowalnymi. Operacje za pomocą StringBuffer
są bezpieczne dla wątków i zsynchronizowane, ale metody StringBuilder
nie są bezpieczne dla wątków. Zatem gdy wiele wątków pracuje na tym samym ciągu znaków, powinniśmy użyć StringBuffer
, ale w środowisku jednowątkowym powinniśmy użyć StringBuilder
. StringBuilder
bardziej produktywny niż StringBuffer
dlatego, że nie jest obciążony synchronizacją.
14. Dlaczego ciąg znaków jest niezmienny i sfinalizowany w Javie?
Niezmienność ciągów ma kilka zalet:-
Łączenie ciągów jest możliwe tylko dlatego, że ciąg jest niezmienny w Javie, dlatego maszyna wirtualna oszczędza dużo miejsca na stercie, ponieważ różne zmienne łańcuchowe wskazują na tę samą zmienną w puli. Jeśli ciąg znaków nie byłby niezmienny, wówczas internowanie ciągów nie byłoby możliwe, ponieważ jeśli jakakolwiek zmienna zmieni swoją wartość, będzie to miało wpływ również na inne zmienne odwołujące się do tego ciągu.
-
Jeśli ciąg znaków można modyfikować, stanowi to poważne zagrożenie bezpieczeństwa aplikacji. Na przykład nazwa użytkownika i hasło bazy danych są przekazywane jako ciąg znaków w celu uzyskania połączenia z bazą danych, a podczas programowania gniazd szczegóły hosta i portu są przekazywane jako ciąg znaków. Ponieważ ciąg znaków jest niezmienny, nie można zmienić jego wartości, w przeciwnym razie każdy haker może zmienić wartość łącza i spowodować problemy z bezpieczeństwem aplikacji.
-
Ponieważ ciąg jest niezmienny, jest bezpieczny dla wątków i jedno wystąpienie ciągu może być współużytkowane przez różne wątki. Pozwala to uniknąć synchronizacji dla bezpieczeństwa wątków, ciągi znaków są całkowicie bezpieczne dla wątków.
-
W Javie używane są ciągi znaków,
classloader
a niezmienność gwarantuje, że klasa zostanie poprawnie załadowana przy użyciuClassloader
. Weźmy na przykład instancję klasy, gdy próbujesz załadowaćjava.sql.Connection
klasę, ale wartość referencyjna zostaje zmieniona namyhacked.Connection
klasę, która może zrobić niepożądane rzeczy z twoją bazą danych. -
Ponieważ ciąg znaków jest niezmienny,
hashcode
jest on buforowany w momencie tworzenia i nie ma potrzeby ponownego obliczania go. To sprawia, że ciąg znaków jest doskonałym kandydatem na klucz,Map
a jego przetwarzanie będzie szybsze niż w przypadku innych kluczyHashMap
. To jest powód, dla którego string jest najczęściej używanym obiektem używanym jako kluczHashMap
.
15. Jak podzielić ciąg na części?
Możemy użyć metodysplit(String regex)
podziału ciągu na tablicę ciągów, używając wyrażenia regularnego jako ogranicznika.
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));
}
}
Metoda split(String regex, int numOfStrings)
jest przeciążoną metodą dzielenia ciągu na określoną liczbę wierszy. Możemy użyć ukośnika odwrotnego, aby używać znaków specjalnych wyrażeń regularnych jako znaków zwykłych. Program wyświetli następujące informacje:
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. Dlaczego do przechowywania hasła lepsza jest tablica ciągów niż ciąg znaków?
Ciąg znaków jest niezmienny w Javie i jest przechowywany w puli ciągów. Raz utworzone pozostaje w puli aż do momentu wyrzucenia go do śmieci, więc gdy uznamy, że już z hasłem skończyliśmy, pozostaje ono przez jakiś czas dostępne w pamięci i nie da się tego uniknąć. Stanowi to zagrożenie bezpieczeństwa, ponieważ każdy, kto ma dostęp do zrzutu pamięci, będzie mógł znaleźć hasło w postaci zwykłego tekstu. Jeśli do przechowywania hasła użyjemy tablicy znaków, możemy je wyczyścić po zakończeniu. W ten sposób możemy kontrolować, jak długo pozostaje on w pamięci, unikając zagrożeń bezpieczeństwa związanych z ciągiem znaków.17. Jak sprawdzić podobieństwo dwóch ciągów w Javie?
Istnieją dwa sposoby sprawdzenia, czy dwa ciągi znaków są równoważne — używając==
operatora „ ” lub używając operatora equals
. Kiedy używamy ==
operatora „ ”, sprawdza on wartość ciągu jako odniesienie, ale w programowaniu przez większość czasu sprawdzamy równoważność ciągu tylko pod względem wartości. Dlatego musimy użyć metody równości, aby przetestować dwa ciągi pod kątem równości. Istnieje również metoda, equalsIgnoreCase
której możemy użyć do ignorowania wielkości liter.
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. Co to jest pula ciągów?
Jak sama nazwa wskazuje, pula ciągów to zbiór ciągów przechowywanych na stercie Java. Wiemy, żeString
jest to specjalna klasa w Javie i możemy tworzyć obiekty tej klasy za pomocą operatora new, tak samo jak możemy tworzyć obiekty, podając wartość ciągu znaków w cudzysłowie. Poniższy diagram wyjaśnia, w jaki sposób pula ciągów jest alokowana na stercie Java i co się dzieje, gdy używamy różnych sposobów tworzenia ciągów. Pulowanie ciągów jest możliwe wyłącznie dzięki niezmienności ciągów w Javie i realizacji idei internowania ciągów. Pula strun jest również przykładem wzorca wagi muszej. Pula ciągów pomaga zaoszczędzić dużo pamięci, ale z drugiej strony utworzenie wiersza zajmuje więcej czasu. Kiedy używamy podwójnych cudzysłowów do utworzenia ciągu, najpierw szuka w puli ciągu o tej samej wartości, a jeśli zostanie znaleziony, po prostu zwraca referencję. W przeciwnym razie w puli tworzony jest nowy ciąg, a następnie zwraca referencję. Jednakże, gdy używamy operatora new, zmuszamy klasę String
do utworzenia nowego obiektu typu string, a następnie możemy użyć tej metody intern()
do umieszczenia ciągu znaków w puli lub uzyskania referencji z puli do innego obiektu String
o tej samej wartości. Poniżej znajduje się przykład pokazujący, jak działa pula ciągów.
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));
}
}
Program wyświetli następujące informacje:
s1 == s2 :true
s1 == s3 :false
19. Do czego służy metoda intern()?
Po wywołaniu metodyintern()
, jeśli w puli ciągów znajduje się już ciąg znaków odpowiadający naszemu obiektowi, co zostało zweryfikowane metodą equals(Object)
, zwracane jest odwołanie do ciągu znaków z puli. W przeciwnym razie obiekt typu string jest dodawany do puli i zwracane jest odwołanie do tego obiektu. Ta metoda zawsze zwraca ciąg znaków, który ma taką samą wartość jak bieżący ciąg, ale gwarantuje, że będzie to ciąg z puli unikalnych ciągów. Poniżej znajduje się przykład działania metody 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. Czy ciągi znaków są bezpieczne w Javie?
Stringi są niezmienne, więc nie możemy zmienić ich wartości w programie. Dlatego są bezpieczne dla wątków i można ich bezpiecznie używać w środowisku wielowątkowym.21. Dlaczego String jest popularnym kluczem w HashMap w Javie?
Ponieważ ciągi znaków są niezmienne, ich kod skrótu jest buforowany w momencie tworzenia i nie wymaga ponownego obliczania. To sprawia, że ciągi znaków są doskonałym kandydatem na kluczMap
i są przetwarzane szybciej niż inne kluczowe obiekty HashMap
. Z tego powodu jako klucze używane są głównie ciągi znaków HashMap
. Mam nadzieję, że pytania wymienione w tym artykule pomogą Ci w rozmowach kwalifikacyjnych. Daj mi znać, jeśli coś pominąłem. Link do oryginału artykułu Autor: Pankaj Kumar
GO TO FULL VERSION