Java String Manipulation : Comparing adjacent Characters in Java
i have the following problem
Given a string, return a "cleaned" string where adjacent chars that are the same have been reduced to a single char. So"yyzzza"
yields "yza"
.
stringClean("yyzzza") → "yza"
stringClean("abbbc开发者_如何学运维dd") → "abcd"
stringClean("Hello") → "Helo"
Im trying my code for the input stringClean("abbbcdd") → "abcd"
My code is below.Im getting the partial appended string after doing the adjacent character comparison hence as of now im getting appended stringBuilder "sb=abc"
which is not the correct output i should get the output as "abcd"
,
class cleanString{
public static String stringClean(String str){
int startIndex = str.indexOf(str);
char startChar = '\u0000';
char adjacentChar = '\u0000';
System.out.println("startIndex-->" + startIndex);
final StringBuilder sb = new StringBuilder();
for(startIndex = 0; startIndex < str.length(); startIndex += 1){
startChar = str.charAt(startIndex);
System.out.println("startIndex ::" + startIndex);
System.out.println("startChar ::" + startChar);
final int adjacentPosition = startIndex + 1;
System.out.println("adjacentPosition ::" + adjacentPosition);
if(adjacentPosition != str.length()){
adjacentChar = str.charAt(adjacentPosition);
System.out.println("adjacentChar ::" + adjacentChar);
}
if(startChar == adjacentChar){
System.out.println("startChar ::" + startChar);
System.out.println("adjacentChar::" + adjacentChar);
System.out.println("Before Substring string --->" + str);
str = str.substring(1);
startIndex--;
System.out.println("After Substring string --->" + str);
System.out.println("IndexOf check ---->"
+ sb.toString().indexOf(startChar));
if(sb.toString().indexOf(startChar) != -1){
sb.append(adjacentChar);
System.out.println("Appended String in if part-->"
+ sb.toString());
}
} else{
str = str.substring(1);
startIndex--;
sb.append(startChar);
System.out.println("Appended String --->" + sb.toString());
}
}// end of for loop
return sb.toString();
}
//im getting output as abc...which is partial appended string
public static void main(String ...args){
String outputCleanString=new cleanString().stringClean("abbbcdd");
System.out.println("Cleaned String --->"+outputCleanString);
}
}
*Observation:*after i get the appended string "abc",and then when i move to compare the final set of characters "dd" im facing the problem in that part.
If a regex based solution is acceptable you can do:
str = str.replaceAll("(.)\\1+","$1");
Ideone Link
First of all, your code is overly complicated. There is absolutely no need to
str = str.substring(1);
startIndex--;
inside the loop - you are effectively keeping startIndex
at 0 and chopping off characters from the beginning of the string. Instead, you should just iterate through the characters of string (and print str.substring(startIndex)
if you want to see what's left to process).
Also, here
if(sb.toString().indexOf(startChar) != -1){
sb.append(adjacentChar);
System.out.println("Appended String in if part-->"
+ sb.toString());
}
you aim to prevent adding the same character again if it is repeated more than twice in a row - but the code actually prevents adding a character to the builder ever if it is already in there, i.e. an input like "aba" will yield the incorrect output "ab".
And actually, there is the source of your error too. The condition is wrong:
if(sb.toString().indexOf(startChar) != -1){
yields true
when startChar
is found in the string contained by sb
! If you change !=
to ==
, you will get your 'd' in the output (however, you will get an extra 'b' too).
Corrected algorithm
Your approach of always comparing the actual character to the next one fails when the same character is repeated more than twice in a row. The better approach is to just remember the last character appended to the buffer and skip until you find a character different from it:
public static String stringClean(String str){
final StringBuilder sb = new StringBuilder();
char lastAppendedChar = '\u0000';
for(int index = 0; index < str.length(); index += 1){
char actualChar = str.charAt(index);
if (actualChar != lastAppendedChar){
sb.append(actualChar);
lastAppendedChar = actualChar;
}
}// end of for loop
return sb.toString();
}
The problem in you code is that you append the char not when new is found but when adjetance is different then curent, so always last character would not be appended.
public static String stringClean(String str) {
if (str == null || "".equals(str)) {
return str;
}
char lastChar = str.charAt(0);
StringBuilder resultBuilder = new StringBuilder();
resultBuilder.append(lastChar);
for (int index = 1; index < str.length(); index++) {
char next = str.charAt(index);
if (lastChar != next) {
resultBuilder.append(next);
lastChar = next;
}
}
return resultBuilder.toString();
}
I would do it like this:
public static String stringClean(String str) {
if (str == null || "".equals(str))
return str;
StringBuffer buffer = new StringBuffer();
char[] chars = str.toCharArray();
buffer.append(chars[0]);
for (int i = 1; i < chars.length; i++) {
if (chars[i] != chars[i-1])
buffer.append(chars[i]);
}
return buffer.toString();
}
public static String stringClean(String str){
int startIndex = str.indexOf(str);
char startChar = '\u0000';
char adjacentChar = '\u0000';
boolean flag = false; // added
System.out.println("startIndex-->" + startIndex);
final StringBuilder sb = new StringBuilder();
for(startIndex = 0; startIndex < str.length(); startIndex++){
startChar = str.charAt(startIndex);
System.out.println("startIndex ::" + startIndex);
System.out.println("startChar ::" + startChar);
final int adjacentPosition = startIndex + 1;
System.out.println("adjacentPosition ::" + adjacentPosition);
if(adjacentPosition != str.length()){
adjacentChar = str.charAt(adjacentPosition);
System.out.println("adjacentChar ::" + adjacentChar);
} else {
flag = true;
}
if(startChar == adjacentChar){
System.out.println("startChar ::" + startChar);
System.out.println("adjacentChar::" + adjacentChar);
System.out.println("Before Substring string --->" + str);
str = str.substring(1);
startIndex--;
System.out.println("After Substring string --->" + str);
System.out.println("IndexOf check ---->"
+ sb.toString().indexOf(startChar));
if(sb.toString().indexOf(startChar) != -1){
sb.append(adjacentChar);
System.out.println("Appended String in if part-->"
+ sb.toString());
} else if(flag) { /* added */
sb.append(adjacentChar);
}
} else{
str = str.substring(1);
startIndex--;
sb.append(startChar);
System.out.println("Appended String --->" + sb.toString());
}
}// end of for loop
return sb.toString();
}
How about trying this one:
public String stringClean(String string){
char sc[] = string.toCharArray();
for(int i =0;i<sc.length;i++){
if(i!=sc.length-1){
if(sc[i]!=(sc[i+1])){
output+=sc[i];
}
}else {
output+=sc[i];
}
}
return output;
//System.out.println(output);
}
If you aren't restricted to use collections from java.util
I recommend to use Set
. See example below.
public static String stringClean(String input) {
Set<Character> result = new LinkedHashSet<Character>();
for (char c : input.toCharArray()) {
result.add(c);
}
StringBuilder sb = new StringBuilder();
for (char c : result)
sb.append(c);
return sb.toString();
}
For your code and the specific issue you have mentioned if the adjacent position is beyond the bounds of your string set adjacentChar to the null char as otherwise adjacentChar is seen as the last character in the string, which means that an append is not done.
if(adjacentPosition != str.length()){
adjacentChar = str.charAt(adjacentPosition);
System.out.println("adjacentChar ::" + adjacentChar);
}
else {
adjacentChar = '/u0000';
}
EDIT
I think that the second issue you have mentioned is in this piece of code
if(sb.toString().indexOf(startChar) != -1){
sb.append(adjacentChar);
System.out.println("Appended String in if part-->"
+ sb.toString());
}
As e and o are in the buffer from Hello they are being appended when Bookkeeper is being checked. I don't think you need that line so remove it and that should fix Hello Bookkeeper.
Although Mohoamed's answer will also work.
function cleanString(toClean){
return toClean.replace(/(\S)\1(\1)*/g,"$1")
}
Demo in jsFiddle
How about:
public String stringClean(String str) {
if (str.length() < 2)return str;
String nextStr = str.substring(1);
if (str.charAt(0) == str.charAt(1)) {
return stringClean(nextStr);
}
else return str.substring(0,1) + stringClean(nextStr);
}
Looks like you are solving codingbat problems, it is good,
I m a beginner too. This exercise is supposed to be just using recursion
This is my solution:
public String stringClean(String str) {
if (str.length() <= 1)
return str;
String adj1 = str.substring(0,1);
String adj2 = str.substring(1,2);
String rest = str.substring(1);
if (adj1.equals(adj2)) {
return stringClean(rest);
} else
return adj1 + stringClean(rest);
}
Hope it helps
精彩评论