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("abbbcdd") → "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
Related
I want to reverse a whole String. For example, "Cat is running" should give output "running is cat".
I have tried a lot but I am unable to do it. It shows "gninnur si taC". Kindly help me that it should take "cat" as a single character instead of taking 'c' as a single character.
Here is the code:
public static void main(String[] args) {
String str = "Cat is running";
System.out.println("Before recursion: " + str);
System.out.println("After recursion: " + reverse(str));
}
public static String reverse(String str) {
if(str.isEmpty())
return str;
String s = "";
for(int i = 0; i < str.length(); i++) {
s = s + str.charAt(i);
}
return reverse(s.substring(1)) + s.charAt(0);
}
You have to find the first word in the String, pass the rest of the String to the recursive call, and append the first word at the end:
public static String reverse(String str) {
if(str.isEmpty() || !str.contains(" "))
return str;
int sep = str.indexOf(' ');
return reverse(str.substring(sep+1)) + " " + str.substring(0,sep);
}
Output:
Before recursion: Cat is running
After recursion: running is Cat
BTW, the loop is your original code is pointless. You can simply use str directly instead of creating a copy of it.
You can make it even shorter with:
public static String reverse(String str) {
int sep = str.indexOf(' ');
return sep >= 0 ? reverse(str.substring(sep+1)) + " " + str.substring(0,sep) : str;
}
I think I made it a little less good than #Eran but I already wrote:
private static String reverse(String str) {
if (str.isEmpty() || !str.contains(" "))
return str;
StringBuilder sb = new StringBuilder(" ");
int i = 0;
while (i < str.length() && str.charAt(i) != ' ') {
sb.append(str.charAt(i));
i++;
}
return reverse(str.substring(i + 1)) + sb.toString();
}
I'm having a problem getting the unique letters and digits out of an array of strings, and then returning them. I am having a formatting issue.
The given input is: ([abc, 123, efg]) and is supposed to return abcefg123,
however, mine returns: abc123efg
how can I fix this since arrays.sort() will end up putting the numbers first and not last?
Here is my method so far:
public static String getUniqueCharsAndDigits(String[] arr) {
String str = String.join(",", arr);
String myString = "";
myString = str.replaceAll("[^a-zA-Z0-9]", "");
for(int i = 0; i < str.length(); i++) {
if(Character.isLetterOrDigit((i))){
if(myString.indexOf(str.charAt(i)) == -1) {
myString = myString + str.charAt(i);
}
}
}
return myString;
}
What you want to do is create two strings, one with the letters, one with the digits.
public static String getUniqueCharsAndDigits(String[] arr) {
String str = String.join("", arr);
String myLetters, myDigits;
myLetters = myDigits = "";
for(int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if(Character.isLetter(c)){
if(myLetters.indexOf(c) == -1) {
myLetters += c;
}
} else if(Character.isDigit(c)){
if(myDigits.indexOf(c) == -1) {
myDigits += c;
}
}
}
//if they need to be sorted, sort each one individually here
return myLetters + myDigits;
}
I've modified your code and deleted the unnecessary parts of it.
I'm trying to return strings in different lines given these conditions. Since I cannot use the += in Java with strings, how do I make one giant string that is spaced per line but "stacks?" In other words, how do I add a new string within a loop to an old string?
/**
Returns a String that concatenates all "offending"
words from text that contain letter; the words are
separated by '\n' characters; the returned string
does not contain duplicate words: each word occurs
only once; there are no punctuation or whitespace
characters in the returned string.
#param letter character to find in text
#return String containing all words with letter
*/
public String allWordsWith(char letter)
{
String result = "";
int i = 0;
while (i < text.length())
{
char newchar = text.charAt(i);
if (newchar == letter)
{
int index1 = text.lastIndexOf("",i);
int index2 = text.indexOf("",i);
String newstring = '\n' + text.substring(index2,index1);
}
i++;
}
return result;
}
Modify the result string, and fix your "word boundary" tests.
if (newchar == letter) {
int index1 = text.lastIndexOf(' ',i);
int index2 = text.indexOf(' ',i);
// TODO -- handle when index1 or index2 is < 0; that means it wasn't found,
// and you should use the string boundary (0 or length()) instead.
String word = text.substring( index2,index1);
result += "\n" + word;
}
If you were really concerned about performance you could use a StringBuilder and append(), but otherwise I strongly favour += for being concise & readable.
you are re-initializing your string in loop every time. Move the string declaration outsid eof loop:
Replace this
String newstring = '\n' + text.substring(index2,index1);
with
result = '\n' + text.substring(index2,index1);
First, use a StringBuilder.
Second, use System.getProperty("line.separator") to ensure proper line breaks are used.
Edited code:
public String allWordsWith(char letter)
{
StringBuilder sb = new StringBuilder();
int i = 0;
while (i < text.length())
{
char newchar = text.charAt(i);
if (newchar == letter)
{
int index1 = text.lastIndexOf("",i);
int index2 = text.indexOf("",i);
sb.Append(text.substring(index2,index1));
sb.Append(System.getProperty("line.separator"));
//I put the new line after the word so you don't get an empty
//line on top, but you can do what you need/want to do in this case.
}
i++;
}
return result;
}
Use StringBuilder as following:
public String allWordsWith(char letter){
//String result = "";
StringBuilder result = new StringBuilder();
int i = 0;
while (i < text.length()){
char newchar = text.charAt(i);
if (newchar == letter){
int index1 = text.lastIndexOf("",i);
int index2 = text.indexOf("",i);
result.append('\n' + text.substring(index2,index1));
}
i++;
}
return result.toString();
}
String text = "I have android code with many different java, bmp and xml files everywhere in my project that I used during the drafting phase of my project.";
String letter = "a";
Set<String> duplicateWordsFilter = new HashSet<String>(Arrays.asList(text.split(" ")));
StringBuilder sb = new StringBuilder(text.length());
for (String word : duplicateWordsFilter) {
if (word.contains(letter)) {
sb.append(word);
sb.append("\n");
}
}
return sb.toString();
result is:
android
have
java,
drafting
and
many
that
phase
I'm trying to make a function reverse a string of integers, but am only able to mirror it completely, with the following piece of code I found. (I want to translate it from string to string without arrays or lists, preferably recursively)
static String reverseMe(String s) {
if(s.length() == 0)
return "";
return s.charAt(s.length() - 1) + reverseMe(s.substring(0,s.length()-1));
}
So for example (1 2 41) returns (14 2 1) when I really want (41 2 1). I would like some way for Java to start reversing when it encounters a space (or any none-integer) and keep the integers themselves as they are.
A modified version of your function using String#lastIndexOf:
String reverseMe(String s)
{
if (s.length() == 0)
return "";
int index = s.lastIndexOf(" ");
if (index == -1) // not found, thus just return the string
return s;
else // found, thus concat last part with recursive call
return s.substring(index + 1) + " " + reverseMe(s.substring(0, index));
}
Or you can use String#split to separate by spaces and just loop through in reverse and concatenate.
String reverse(String s)
{
String reversed = "";
String[] split = s.split(" ");
reversed = split[split.length-1];
for (int i = split.length-2; i >= 0; i--)
{
reversed += " " + split[i];
}
return reversed;
}
Although StringBuilder would make for a more efficient option, since it doesn't require all that string copying.
You can also use StringTokenized
StringTokenizer st = new StringTokenizer("1 2 41");
StringBuilder sb = new StringBuilder();
while (st.hasMoreTokens()) {
if (sb.length() > 0) {
sb.insert(0, ' ');
}
sb.insert(0, st.nextToken());
}
System.out.println(sb.toString());
One another solution among these
static String reverseMe(String s) {
if(s.length() == 0)
return "";
String sa[] = s.split(" ");
List<String> newlist = Arrays.asList(sa);
Collections.reverse(newlist);
return newlist.toString();
}
Non recursive, guava present.
String input = "123 456 789 tt 012";
Iterable<String> tokens = Splitter.on(Pattern.compile("[^\\d]")).omitEmptyStrings().split(input);
for(String token: tokens){
StringBuilder builder = new StringBuilder(token);
System.out.println(builder.reverse().toString());
}
Or without guava:
String input = "123 456 789 tt 012";
String tokens [] = input.split("[^\\d]+");
for(String token:tokens){
StringBuilder builder = new StringBuilder(token);
System.out.println(builder.reverse().toString());
}
If you want to do it recursively,this would do it!
public static String reverseIt(final String inp,final int lastIndex,String out)
{
int i=lastIndex;
while(inp.charAt(i)!=' ' && i!=-1){i--;if(i==-1)break;}
out+=(inp.substring(i+1,lastIndex+1));if(i!=-1)out+=" ";
if(lastIndex!=0)return reverseIt(inp,i-1,out);
else return out;
}
You can now call it as
reverseIt(input,input.length-1,output);
If you are not particular with recursion, the below solution would work.
static String reversMe(String str) {
StringBuffer strBuf = new StringBuffer();
String strArray = str.split(" ");
for(int i = strArray.length();i>=0; i--) {
strBuf.append(strArray[i]).append(" ");
}
return strBuf.toString().trim();
}
It can be as simple as this.
String num="1 2 41";
StringTokenizer sTok=new StringTokenizer(num, " ");
String revnum="";
while(sTok.hasMoreTokens())
{
revnum=sTok.nextToken()+" "+revnum;
}
System.out.println(revnum);
Yet another recursive variant using Tail call recursion.
public static String reverseMe(String s) {
StringBuilder sb = new StringBuilder();
return reverseMe(s.split(" "), sb);
}
public static String reverseMe(String[] s, StringBuilder sb) {
if (s.length == 0) {
return sb.toString().trim();
} else {
return reverseMe(Arrays.copyOfRange(s, 1, s.length), sb.insert(0, " ").insert(0, s[0]));
}
}
I have this code:
String s = "A very long string containing " +
"many many words and characters. " +
"Newlines will be entered at spaces.";
StringBuilder sb = new StringBuilder(s);
int i = 0;
while ((i = sb.indexOf(" ", i + 20)) != -1) {
sb.replace(i, i + 1, "\n");
}
System.out.println(sb.toString());
The output of the code is:
A very long string containing
many many words and
characters. Newlines
will be entered at spaces.
The above code is wrapping the string after the next space of every 30 characters, but I need to wrap the string after the previous space of every 30 characters, like for the first line it will be:
A very long string
And the 2nd line will be
containing many
Please give some proper solution.
You can use Apache-common's WordUtils.wrap().
Use lastIndexOf instead of indexOf, e.g.
StringBuilder sb = new StringBuilder(s);
int i = 0;
while (i + 20 < sb.length() && (i = sb.lastIndexOf(" ", i + 20)) != -1) {
sb.replace(i, i + 1, "\n");
}
System.out.println(sb.toString());
This will produce the following output:
A very long string
containing many
many words and
characters.
Newlines will be
entered at spaces.
You can try the following:
public static String wrapString(String s, String deliminator, int length) {
String result = "";
int lastdelimPos = 0;
for (String token : s.split(" ", -1)) {
if (result.length() - lastdelimPos + token.length() > length) {
result = result + deliminator + token;
lastdelimPos = result.length() + 1;
}
else {
result += (result.isEmpty() ? "" : " ") + token;
}
}
return result;
}
call as wrapString("asd xyz afz","\n",5)
I know it's an old question, but . . . Based on another answer I found here, but can't remember the posters name. Kuddos to him/her for pointing me in the right direction.
public String truncate(final String content, final int lastIndex) {
String result = "";
String retResult = "";
//Check for empty so we don't throw null pointer exception
if (!TextUtils.isEmpty(content)) {
result = content.substring(0, lastIndex);
if (content.charAt(lastIndex) != ' ') {
//Try the split, but catch OutOfBounds in case string is an
//uninterrupted string with no spaces
try {
result = result.substring(0, result.lastIndexOf(" "));
} catch (StringIndexOutOfBoundsException e) {
//if no spaces, force a break
result = content.substring(0, lastIndex);
}
//See if we need to repeat the process again
if (content.length() - result.length() > lastIndex) {
retResult = truncate(content.substring(result.length(), content.length()), lastIndex);
} else {
return result.concat("\n").concat(content.substring(result.length(), content.length()));
}
}
//Return the result concatenating a newline character on the end
return result.concat("\n").concat(retResult);;
//May need to use this depending on your app
//return result.concat("\r\n").concat(retResult);;
} else {
return content;
}
}
public static void main(String args[]) {
String s1="This is my world. This has to be broken.";
StringBuffer buffer=new StringBuffer();
int length=s1.length();
int thrshld=5; //this valueis threshold , which you can use
int a=length/thrshld;
if (a<=1) {
System.out.println(s1);
}else{
String split[]=s1.split(" ");
for (int j = 0; j < split.length; j++) {
buffer.append(split[j]+" ");
if (buffer.length()>=thrshld) {
int lastindex=buffer.lastIndexOf(" ");
if (lastindex<buffer.length()) {
buffer.subSequence(lastindex, buffer.length()-1);
System.out.println(buffer.toString());
buffer=null;
buffer=new StringBuffer();
}
}
}
}
}
this can be one way to achieve
"\n" makes a wordwrap.
String s = "A very long string containing \n" +
"many many words and characters. \n" +
"Newlines will be entered at spaces.";
this will solve your problem