I am trying to reverse a String word by word using recursion. (Ex: "Hello my friend" is reversed to "friend my Hello") This is the code I have attempted to write for this method. I have tried multiple similar variations but the output is only ever the first or last word of the String. I believe the part that is "broken" is the first if statement, but I am not quite sure.
public static String reverse (String words) {
Scanner sc = new Scanner(words);
String backwards = "";
if (sc.hasNext()) {
String currentWord = sc.next();
reverse(sc.nextLine());
backwards = backwards + " " + currentWord;
} //end if
else {
backwards = words;
} //end else
return backwards;
}
I am aware that a few similar questions exist, but their answers have not seemed to help me understand my mistake(s).
Thanks!
You shouldn't call nextLine()
because your input is all on one line. Your logic is much clearer if you begin by creating a simple helper method, it should take an array of words
and a position; from there you can recursively build your desired output with something like
private static String reverse(String[] words, int p) {
if (p + 1 < words.length) {
return reverse(words, p + 1) + " " + words[p];
} else if (p < words.length) {
return words[p];
}
return "";
}
Then your public
method is easy to implement, just split
the original input on white space and call reverse
starting at 0
(remembering to return
the result). Like,
public static String reverse(String words) {
return reverse(words.split("\\s+"), 0);
}
And then, I tested it like
public static void main(String[] args) {
System.out.println(reverse("Hello my friend"));
}
Which outputs (as requested)
friend my Hello
Alternatively , you could make that helper take your Scanner
instead like
private static String reverse(Scanner sc) {
if (sc.hasNext()) {
String currentWord = sc.next();
if (sc.hasNext()) {
return reverse(sc) + " " + currentWord;
}
return currentWord;
}
return "";
}
And then your public method is
public static String reverse(String words) {
return reverse(new Scanner(words));
}
Instead of using a Scanner
, you can make use of an overload of String.split
to split words
around the first space:
public static String reverse(String words) {
String[] wordArr = words.split(" ", 2); // split into a maximum of 2 Strings
if (wordArr.length > 1) { // If there is more than 1 word
// return the first word (wordArr[0]),
// behind the reverse of the rest of the String (wordArr[1])
return reverse(wordArr[1]) + " " + wordArr[0];
}
return wordArr[0]; // else, just return the one word
}
As stated in the comments, you could use a StringBuilder
instead of Scanner class.
This example sends the same words, splits them by spaces each time you enter the method and you send the index of the word to be added in the next iteration.
For example:
public class RecursiveReverse {
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) {
String stringToReverse = "Hello my friend!";
System.out.println(reverse(stringToReverse, stringToReverse.split(" ").length - 1));
}
public static String reverse(String words, int i) {
if (i >= 0) { //If the index of the words is greater or equals the first word
sb.append(words.split(" ")[i]); //We split it and append it to our StringBuilder
sb.append(" "); //We append a space
reverse(words, --i); //We do this again
}
return sb.toString(); //When the above condition doesn't match we return the StringBuilder object as a String (which contains the words reversed)
}
}
Which produces this output:
friend! my Hello
A better method would be passing a String array as parameter so you split only once (when sending the words as an array to the method) the String.
public class RecursiveReverse {
static StringBuilder sb = new StringBuilder();
public static void main(String[] args) {
String stringToReverse = "Hello my friend!";
String words[] = stringToReverse.split(" ");
System.out.println(reverse(words, words.length - 1));
}
public static String reverse(String words[], int i) {
if (i >= 0) {
sb.append(words[i]);
sb.append(" ");
reverse(words, --i);
}
return sb.toString();
}
}
You throw away the recursion results:
reverse(sc.nextLine());
backwards = backwards + " " + currentWord;
Instead, use this:
backwards = reverse(sc.nextLine());
backwards = backwards + " " + currentWord;
Better yet:
backwards = reverse(sc.nextLine()) + " " + currentWord;
public static String reverseSentence(String sentence) {
StringBuilder sb = new StringBuilder();
int firstSpace = sentence.indexOf(' ');
if (firstSpace == -1) {
return sb.append(sentence.strip()).append(" ").toString();
}
String secondPart = sentence.substring(firstSpace + 1);
String firstPart = sentence.substring(0, firstSpace);//similar to merger sort
return sb.append(reverseSentence(secondPart)).append(reverseSentence(firstPart)).toString();
}
Do you must use recursion? You can do that without it.
public static String reverse(String words) {
String[] list = words.split(" ");
Collections.reverse(list);
String reversed = String.join(" ", list);
return reversed;
}
You must keep hold of the extracted words between calls in an accumulator. Here is an example.
public static String reverse(String words, String acc){
Scanner sc = new Scanner(words);
if(!sc.hasNext()){
return acc;
}
return reverse(sc.nextLine(), acc) + " " + sc.next();
}
You would call it like this.
reverse("Hello my friend", "");
It's not the most efficient implementation in the world, but yeah... It must work!
If you want a more efficient one, use a StringBuilder
as the accumulator.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.