Fjernelse af gentagne tegn fra en streng
1. Oversigt
I denne øvelse vil vi diskutere flere teknikker i Java til, hvordan man fjerner gentagne tegn fra en streng.
For hver teknik taler vi også kort om dens kompleksitet i tid og rum.
2. Bruger distinct
Lad os starte med at fjerne dubletterne fra vores streng ved hjælp af distinkt metode introduceret i Java 8.
Nedenfor får vi en forekomst af en Int S tream fra et givent strengobjekt. Så bruger vi distinkt metode til at fjerne dubletterne. Endelig kalder vi forEach metode til at sløjfe over de distinkte tegn og tilføje dem til vores StringBuilder :
StringBuilder sb = new StringBuilder();
str.chars().distinct().forEach(c -> sb.append((char) c));
Tidskompleksitet: O(n) – løkkens køretid er direkte proportional med størrelsen af inputstrengen
Auxiliary Space: O(n) – siden særskilt bruger et LinkedHashSet internt, og vi gemmer også den resulterende streng i en StringBuilder objekt
Opretholder orden: Ja – siden LinkedHashSet bevarer rækkefølgen af sine elementer
Og selvom det er rart, at Java 8 klarer denne opgave så godt for os, så lad os sammenligne det med bestræbelser på at rulle vores egen.
3. Bruger indexOf
Den naive tilgang til at fjerne dubletter fra en streng involverer simpelthen løkke over inputtet og bruge indexOf metode til at kontrollere, om det aktuelle tegn allerede findes i den resulterende streng :
StringBuilder sb = new StringBuilder();
int idx;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
idx = str.indexOf(c, i + 1);
if (idx == -1) {
sb.append(c);
}
}
Tidskompleksitet: O(n * n) – for hvert tegn, indexOf metoden løber gennem den resterende streng
Auxiliary Space: O(n) – lineært mellemrum er påkrævet, da vi bruger StringBuilder for at gemme resultatet
Opretholder orden: Ja
Denne metode har samme pladskompleksitet som den første tilgang, men virker meget langsommere.
4. Brug af et tegnarray
Vi kan også fjerne dubletter fra vores streng ved at konvertere den til en char array og derefter sløjfe over hvert tegn og sammenligne det med alle efterfølgende tegn .
Som vi kan se nedenfor, opretter vi to for loops, og vi tjekker, om hvert element gentages i strengen. Hvis der findes en dublet, føjer vi den ikke til StringBuilder :
char[] chars = str.toCharArray();
StringBuilder sb = new StringBuilder();
boolean repeatedChar;
for (int i = 0; i < chars.length; i++) {
repeatedChar = false;
for (int j = i + 1; j < chars.length; j++) {
if (chars[i] == chars[j]) {
repeatedChar = true;
break;
}
}
if (!repeatedChar) {
sb.append(chars[i]);
}
}
Tidskompleksitet: O(n * n) – vi har en indre og en ydre sløjfe, der begge krydser inputstrengen
Auxiliary Space: O(n) – lineært mellemrum er påkrævet, da tegnene variabel gemmer en ny kopi af strenginputtet, og vi bruger også StringBuilder for at gemme resultatet
Opretholder orden: Ja
Igen, vores andet forsøg klarer sig dårligt sammenlignet med Core Java-tilbuddet, men lad os se, hvor vi kommer hen med vores næste forsøg.
5. Brug af sortering
Alternativt kan gentagne tegn elimineres ved at sortere vores inputstreng for at gruppere dubletter. For at gøre det skal vi konvertere strengen til en char a rray og sorter det ved hjælp af Arrays .sortér metode. Til sidst gentager vi den sorterede char array.
Under hver iteration vil vi sammenligne hvert element i arrayet med det forrige element. Hvis elementerne er forskellige, føjer vi det aktuelle tegn til StringBuilder:
StringBuilder sb = new StringBuilder();
if(!str.isEmpty()) {
char[] chars = str.toCharArray();
Arrays.sort(chars);
sb.append(chars[0]);
for (int i = 1; i < chars.length; i++) {
if (chars[i] != chars[i - 1]) {
sb.append(chars[i]);
}
}
}
Tidskompleksitet: O(n log n) – sorteringen bruger en Quicksort med dobbelt pivot, som tilbyder O(n log n) ydeevne på mange datasæt
Auxiliary Space: O(n) – siden toCharArray metode laver en kopi af input String
Opretholder orden: Nej
Lad os prøve det igen med vores sidste forsøg.
6. Brug af et Set
En anden måde at fjerne gentagne tegn fra en streng på er ved at bruge et Set . Hvis vi er ligeglade med rækkefølgen af tegn i vores outputstreng, kan vi bruge et HashSet . Ellers kan vi bruge et LinkedHashSet for at opretholde indsættelsesrækkefølgen.
I begge tilfælde vil vi sløjfe over inputstrengen og tilføje hvert tegn til Sættet . Når tegnene er indsat i sættet, gentager vi det for at tilføje dem til StringBuilder og returner den resulterende streng:
StringBuilder sb = new StringBuilder();
Set<Character> linkedHashSet = new LinkedHashSet<>();
for (int i = 0; i < str.length(); i++) {
linkedHashSet.add(str.charAt(i));
}
for (Character c : linkedHashSet) {
sb.append(c);
}
Tidskompleksitet: O(n) – løkkens køretid er direkte proportional med størrelsen af inputstrengen
Auxiliary Space: O(n) – der kræves plads til sættet afhænger af størrelsen på inputstrengen; Vi bruger også StringBuilder for at gemme resultatet
Opretholder orden: LinkedHashSet – Ja, HashSet – Nej
Og nu har vi matchet Core Java-tilgangen! Det er ikke særlig chokerende at finde ud af, at dette minder meget om det distinkte allerede gør.
7. Konklusion
I denne artikel dækkede vi et par måder at fjerne gentagne tegn fra en streng i Java. Vi så også på kompleksiteten af tid og rum for hver af disse metoder.
Som altid kan kodestykker findes over på GitHub.