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();
}
Related
I want to return each character just after its consecutive occurrences
For example:
Input : GeeeEEKKKss
Output : 1G3e2E3K2s
Input : ccccOddEEE
Output : 4c1O2d3E
I have developed this piece of code and it works fine but I am looking if I can fix this problem with java 8 with lambda expression or if there is a better solution for this.
public static String encode(String plaintext ) {
String str = "";
for (int i = 0; i < plaintext.length(); i++) {
// Counting occurrences of s[i]
int count = 1;
while (i + 1 < plaintext.length()
&& plaintext.charAt(i)
== plaintext.charAt(i + 1)) {
i++;
count++;
}
str += String.valueOf(count) + plaintext.charAt(i);
}
return str;
}
Here is one solution using regex and lambda expression, but it requires Java 9 or later.
public static String encode(String plaintext) {
return Pattern.compile("(.)\\1*").matcher(plaintext)
.replaceAll(m -> m.group().length() + m.group(1));
}
For full Unicode support, incl. emojis and grapheme clusters, it should be:
public static String encode(String plaintext) {
return Pattern.compile("(\\X)\\1*").matcher(plaintext)
.replaceAll(m -> (m.end() - m.start()) / (m.end(1) - m.start(1)) + m.group(1));
}
As an alternative to Andreas' answer (even if you should only need that):
public static String encode(String input) {
String output = "";
String[] cArray = input.replaceAll("(\\w)(?!\\1)", "$1 ").split(" ");
for (String s : cArray) {
output += (s.length() + s.substring(0, 1));
}
return output;
}
/*
input = GeeeEEKKKss
cArray = ["G", "eee", "EE", "KKK", "ss"]
output = 1G3e2E3K2s
*/
Stream version:
public static String encode(String input) {
return Arrays.stream(
input.replaceAll("(\\w)(?!\\1)", "$1 ").split(" ")
)
.map(s -> s.length() + s.substring(0, 1))
.collect(Collectors.joining());
}
public class PrintElements {
public static void printReverse (String str)
{
if ((str==null)||(str.length() <= 1))
System.out.print(str);
else
{
System.out.print(str.charAt(str.length()-1));
printReverse(str.substring(0,str.length()-1));
}
}
/**
* #param args
*/
public static void main(String[] args) {
String str="this function reverse";
printReverse(str);
}
}
In this method, I am trying to just change the place the words not letters place with using recursion.
For example, if "this function reverse" is the input, the output should be "Reverse function this".
But my current output is : "esrever noitcnuf siht"
Do it as follows:
import java.util.Arrays;
public class Main {
public static void printReverse(String str) {
if (str == null || !str.contains(" ")) {
System.out.print(str);
return;
}
String[] words = str.split("\\s+");// Split str on space(s)
System.out.print(words[words.length - 1] + " ");// Print the last element
// Call the method recursively by passing a new string with all but last word
printReverse(String.join(" ", Arrays.asList(words).subList(0, words.length - 1)));
}
public static void main(String[] args) {
String str = "this function reverse";
printReverse(str);
}
}
Output:
reverse function this
Try this. It traverses the input string and finds out each word and then merges them into the reversed string by reversing the order of the words.
public static void printReverse (String str)
{
if ((str == null) || (str.equals("")))
return ;
str = str + " "; //to add a space at the end. this will help in detecting the last word
String revStr = "", word = "";
char c;
for (int i=0; i < str.length(); i++)
{
c = str.charAt(0);
if (c != ' ')
{
word = word + c;
}
else
{
revStr = word + " " + revStr;
}
}
System.out.println(revStr.Trim()); //removes the extra space from the end
}
}
public static String reverseString(String str) {
if (str == null)
return "";
if (!str.contains(" "))
return str;
int whitespacePos = str.indexOf(" ");
String firstWord = str.substring(0, whitespacePos);
return reverseString(str.substring(whitespacePos + 1)) + " " + firstWord;
}
public static void main(String[] args) {
String str = "this function reverse";
System.out.println(reverseString(str));
}
I tested this code and it works
It is (most of the time) cleaner to return a String, and then print this String if you want to.
If you use charAt(), you are only getting individual characters. Therefore it will be difficult to not also reverse the letters of the words. It is easier to find the whitespaces between the words and then to retrieve whole words with subString()
the subString() method can take two parameters, startIndex and endIndex, or just one parameter, only the startIndex. It then returns the subString from this startIndex up to the end of the String.
Note: I know you can use split(), I wanted to show how it can be done with indexes. If you already use split(), you might aswell not use recursion.
public static void reverseWords(String str){
if(str=="" || str==null){
return;
}else {
String[] _str = str.split(" ");
System.out.println(_str[_str.length-1]);
String[] newArr = Arrays.copyOf(_str,_str.length-1);
reverseWords(String.join(" ", newArr));
}
}
dont forget to import
import java.util.Arrays;
public String reverseString(String str){
if(str.lastIndexOf(32) ==-1){ //32 is an ASCII value for space
return str;
}
return str.substring(str.lastIndexOf(32)+1)+" "+reverseString(str.substring(0,str.lastIndexOf(32)));
//Here lastIndexOf() method get the last element of space so that method substring takes the String after last space because is used lastIndexOf(32)+1 and
//reverseString() method continuously takes up to n-1 from nth string until lastIndexOf() return -1 i.e no more whitespace avaliable
}
Here's a solution:
public String reverseString(final String str){
//Using ternary operator
return (str.lastIndexOf(32) == -1)
? str
: str.substring(str.lastIndexOf(32) + 1) + " " + reverseString(str.substring(0, str.lastIndexOf(32)));
}
or with if-else:
public String reverseString(final String str){
if (str.lastIndexOf(32) == -1))
return str;
else
return str.substring(str.lastIndexOf(32) + 1) + " " + reverseString(str.substring(0, str.lastIndexOf(32)));
}
32 is the space character. So if there's no space in the string it just returns the string (word). If there is one it recursively swaps the tail after the and the word before it.
I need to reverse 5 or more character long words in a given string. For example:
* Given string: My name is Michael.
* Output: My name is leahciM.
Rest of the sentence stays the same, just those long words get reversed.
So far I came up with this:
public static String spinWords(String sentence) {
String[] splitWords = sentence.split(" ");
String reversedSentence = "";
String reversedWord = "";
for (String str : splitWords) {
if (str.length() >= 5) {
for (int i = str.length() - 1; i >= 0; i--)
reversedWord += (str.charAt(i) + " ");
}
}
}
And I have reversed those words, but
1) they are in one string, without a space
2) I dont know how to put them back into their places in string
Here is a suggestion:
write a method that reverses a string:
private static String reverse(String s) { ... }
then in your main method, call it when necessary:
if (str.length() >= 5) str = reverse(str);
you then need to put the words back together, presumably into the reversedSentence string:
reversedSentence += str + " "; //you will have an extra space at the end
Side notes:
using a StringBuilder may prove more efficient than string concatenation for longer sentences.
you could put all the words back into a List<String> within the loop and call reversedSentence = String.join(" ", list) after the loop
reversing a string can be done in one line - you should find numerous related Q&As on stackoverflow.
You can use StringBuilder
public static String spinWords(String sentence) {
String[] splitWords = sentence.split(" ");
StringBuilder builder = new StringBuilder();
for (String str : splitWords) {
if (str.length() < 5) {
builder.append(str);
else
builder.append(new StringBuilder(str).reverse().toString());
builder.append(" ");
}
return builder.toString().trim();
}
No need to use anything else you almost had it, just check your "for" loops and remember to add the unreversed string.
public static String spinWords(String sentence) {
String[] splitWords = sentence.split(" ");
String reversedSentence = "";
String reversedWord;
for (String str : splitWords) {
if (str.length() >= 5) {
reversedWord = "";
for (int i = str.length() - 1; i >= 0; i--) {
reversedWord += (str.charAt(i));
}
reversedSentence += " " + reversedWord;
} else {
reversedSentence += " " + str;
}
}
return reversedSentence;
}
Use StringBuilder to build the answer as you process the elements in splitWords.
You may also find the idiom of space with special first-time value (being "") useful.
There was also a bug in your original code.
So here is what I would do:
public class ReverseLongWord {
public static void main(String[] args) {
String testInput = "My name is Michael";
System.out.println(spinWords(testInput));
}
public static String spinWords(String sentence) {
String[] splitWords = sentence.split(" ");
String reversedSentence = "";
StringBuilder sb = new StringBuilder();
String space = ""; // first time special
String reversedWord = "";
for (String str : splitWords) {
if (str.length() >= 5) {
for (int i = str.length() - 1; i >= 0; i--) {
reversedWord += (str.charAt(i)); // Bug fixed
}
sb.append(space + reversedWord);
} else {
sb.append(space + str);
}
space = " "; // second time and onwards
}
return sb.toString();
}
}
The output of this program is the following, as you have specified:
My name is leahciM
I think the reverse method as some people suggest would be the easiest way, here I share my implementation
public static void main(String[] args) {
System.out.println(concatenatePhrase("My name is Michael"));
System.out.println(concatenatePhrase("Some randoms words with differents sizes and random words"));
}
private static String concatenatePhrase(String phrase) {
StringBuilder completePhrase = new StringBuilder();
String[] phrases = phrase.split(" ");
for (String word : phrases) {
if (word.length() >= 5) {
completePhrase.append(reverseWord(word).append(" "));
} else {
completePhrase.append(word).append(" ");
}
}
return completePhrase.toString().trim();
}
private static StringBuilder reverseWord(String wordPassed) {
StringBuilder word = new StringBuilder(wordPassed);
return word.reverse();
}
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 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