So i'm making a program that removes duplicate letters in a string. The last step of it is updating the old string to the new string, and looping through the new string. I believe everything works besides the looping through the new string part. Any ideas what might be causing it to not work? It will work as intended for one pass through, and then after that it won't step through the new loop
public class homework20_5 {
public static void main(String[] arg) {
Scanner scanner = new Scanner(System.in);
String kb = scanner.nextLine();
int i;
for (i = 0; i < kb.length(); i ) {
char temp = kb.charAt(i);
if(temp == kb.charAt(i 1)) {
kb = kb.replace("" temp, "");
i = kb.length() i;
}
}
System.out.println(kb);
}
}
CodePudding user response:
Instead of using complex algorithms and loops like this you can just use HashSet
which will work just like a list but it won't allow any duplicate elements.
private static String removeDuplicateWords(String str) {
HashSet<Character> xChars = new LinkedHashSet<>();
for(char c: str.toCharArray()) {
xChars.add(c);
}
StringBuilder sb = new StringBuilder();
for (char c: xChars) {
sb.append(c);
}
return sb.toString();
}
CodePudding user response:
So you actually want to remove all occurrences that appear more than once entirely and not just the duplicate appearances (while preserving one instance)?
"Yea that’s exactly right "
In that case your idea won't cut it because your duplicate letter detection can only detect continuous sequences of duplicates. A very simple way would be to use 2 sets in order to identify unique letters in one pass.
public class RemoveLettersSeenMultipleTimes {
public static void main(String []args){
String input = "abcabdgag";
Set<Character> lettersSeenOnce = lettersSeenOnceIn(input);
StringBuilder output = new StringBuilder();
for (Character c : lettersSeenOnce) {
output.append(c);
}
System.out.println(output);
}
private static Set<Character> lettersSeenOnceIn(String input) {
Set<Character> seenOnce = new LinkedHashSet<>();
Set<Character> seenMany = new HashSet<>();
for (Character c : input.toCharArray()) {
if (seenOnce.contains(c)) {
seenMany.add(c);
seenOnce.remove(c);
continue;
}
if (!seenMany.contains(c)) {
seenOnce.add(c);
}
}
return seenOnce;
}
}
CodePudding user response:
There are a few problems here:
Problem 1
for (i = 0; i < kb.length(); i ) {
should be
for (i = 0; i < kb.length() - 1; i ) {
Because this
if (temp == kb.charAt(i 1))
will explode with an ArrayIndexOutOfBoundsException
otherwise.
Problem 2
Delete this line:
i = kb.length() i;
I don't understand what the intention is there, but nevertheless it must be deleted.
Problem 3
Rather than lots of code, there's a one-line solution:
String deduped = kb.replaceAll("[" input.replaceAll("(.)(?=.*\\1)|.", "$1") "]", "");
This works by:
- finding all dupe chars via
input.replaceAll("(.)(?=.*\\1)|.", "$1")
, which in turn works by consuming every character, either capturing it as group 1 if it has a dupe or just consuming it if a non-dupe - building a regex character class from the dupes, which is used to delete them all (replace with a blank)
CodePudding user response:
Say you feed the program with the input "AAABBC", then the expected output should be "ABC".
Now in the for-loop, i
gets incremented from 0 to 5.
After 1st iteration:
kb
becomes AABBC and i
becomes 5 0 = 5
and gets incremented to 6.
And now the condition for the for-loop is that i < kb.length()
which equates to 6 < 5
returning false. Hence the for-loop ends after just one iteration.
So the problematic line of code is i = kb.length() i;
and also the loop condition keeps changing as the size of kb
changes.
I would suggest using a while loop like the following example if you don't worry too much about the efficiency.
public static void main(String[] arg) {
String kb = "XYYYXAC";
int i = 0;
while (i < kb.length()) {
char temp = kb.charAt(i);
for (int j = i 1; j < kb.length(); j ) {
char dup = kb.charAt(j);
if (temp == dup) {
kb = removeCharByIndex(kb, j);
j--;
}
}
i ;
}
System.out.println(kb);
}
private static String removeCharByIndex(String str, int index) {
return new StringBuilder(str).deleteCharAt(index).toString();
}
Output: XYAC
EDIT: I misunderstood your requirements. So looking at the above comments, you want all the duplicates and the target character removed. So the above code can be changed like this.
public static void main(String[] arg) {
String kb = "XYYYXAC";
int i = 0;
while (i < kb.length()) {
char temp = kb.charAt(i);
boolean hasDup = false;
for (int j = i 1; j < kb.length(); j ) {
if (temp == kb.charAt(j)) {
hasDup = true;
kb = removeCharByIndex(kb, j);
j--;
}
}
if (hasDup) {
kb = removeCharByIndex(kb, i);
i--;
}
i ;
}
System.out.println(kb);
}
private static String removeCharByIndex(String str, int index) {
return new StringBuilder(str).deleteCharAt(index).toString();
}
Output: AC
Although, this is not the best and definitely not an efficient solution to this, I think you can get the idea of iterating the input string character by character and removing it if it has duplicates.
CodePudding user response:
Try:
for (i = 0; i < kb.length(); i ) {
for (int j = i 1; j < kb.length(); j ) {
char temp = kb.charAt(j);
// duplicate
if (temp == kb.charAt(i)) {
// remove all duplicate chars
kb = kb.replaceAll(String.valueOf(temp), "");
i--;
break;
}
}
}