Home > Software engineering >  Reverse Odd-length Words in the given String in Java
Reverse Odd-length Words in the given String in Java

Time:12-03

I expect the User to provide a sentence.

And as an output, they will reverse a string with only the odd-length words reversed (i.e. even-length words should remain intact).

static String secretAgentII(String s) {
    StringBuffer sb = new StringBuffer();
    String[] newStr = s.split(" ");
    String result = "";

    for (int i = 0; i < newStr.length; i  ) {
        if (newStr[i].length() % 2 != 0) {
            sb.append(newStr[i]).reverse();
            result  = sb   " ";
        }

        result  = newStr[i]   " ";
    }

    return result;
}

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    String s = sc.nextLine();
    System.out.println(secretAgentII(s));
}

Input:

One two three Four

Expected Output:

enO owT eerhT Four

The actual Output:

enO One owtOne two eerhtenOtwo three Four

How can I fix that?

CodePudding user response:

I went ahead and wrote a method for what I think you are asking for.

    public static String secretAgentII(String input){
        StringBuilder returnValue = new StringBuilder();
        input = input.replaceAll("  ", " ");
        String[] tempArray = input.split(" ");
        for (int i = 0; i < tempArray.length; i  ) {
            String currentString = tempArray[i];
            if (currentString.length() % 2 == 1) {
                char[] tempArrayOfStringChars = currentString.toCharArray();
                for (int j = tempArrayOfStringChars.length - 1; j >= 0; j--) {
                    returnValue.append(tempArrayOfStringChars[j]);
                }
            } else {
                returnValue.append(currentString);
            }
            if (i != tempArray.length - 1) { //This prevents a leading space at the end of your string
                returnValue.append(' ');
            }
        }
        return returnValue.toString();
    }

From what I could tell, you only want the words of odd length to be reversed.

My sample input and output was as follows.

Input: One two three four five six seven eight nine ten
Output: enO owt eerht four five xis neves thgie nine net 

CodePudding user response:

Your problem is that you add to result the whole sb, instead of just the current reverse word. Meaning you need to "reset" (create a new) StringBurrer for each iteration.

You're also missing the else where you want to preserve the correct word's order

for (int i = 0; i < newStr.length; i  ) {
    if (newStr[i].length() % 2 == 1) {
        StringBuffer sb = new StringBuffer();
        sb.append(newStr[i]);
        result  = sb.reverse()   " ";
    }
    else {
        result  = newStr[i]   " ";
    }
}

CodePudding user response:

In your method secretAgentII the StringBuffer should have no other values so that it would not be concatenated to other strings.

I placed sb.replace(0, newStr[i].length(), newStr[i]).reverse(); inside the for loop so that it would replace the existing string in every use.

I also placed an else before the line result = newStr[i] " "; for the original string doesn't need to be concatenated when it is reversed.

static String secretAgentII(String s) {
    StringBuffer sb = new StringBuffer();
    String[] newStr = s.split(" ");
    String result = "";

    for (int i = 0; i < newStr.length; i  ) {
        if (newStr[i].length() % 2 != 0) {
            sb.replace(0, newStr[i].length(), newStr[i]).reverse();
            result  = sb   " ";
        } else
            result  = newStr[i]   " ";
    }
    return result;
}

Input: One Two Three Four

Output: enO owT eerhT Four

note: you are using too many spaces, try researching Java conventions on writing code.

CodePudding user response:

StringBuilder StringJoiner

Never use plain string concatenation the loop because in Java Strings are immutable. That means every s1 s2 produces new intermediate string, which don't need (since only the end result would be used). Concatenation in the loop effects performance and increase memory allocation.

Therefore, it's highly advisable to use StringBuilder, or other built-in mechanisms like static method String.join(), StringJoiner or Collector joining() when you need to combine multiple strings together.

To avoid bother about adding a white space after each word ourself, we can make use of the StringJoiner. Through its parameterized constructor we can provide the required delimiter " ".

That's how it might be implemented:

public static String reverseOdd1(String str) {
    StringJoiner result = new StringJoiner(" ");
    String[] words = str.split(" ");
    
    for (String word : words) {
        if (word.length() % 2 != 0) result.add(new StringBuilder(word).reverse());
        else result.add(word);
    }
    return result.toString();
}

Note that it's not advisable to use StringBuffer in single-threaded environment because its methods are synchronized to make it tread-safe (and synchronization doesn't come for free), and instead use it sibling StringBuilder which has the same methods.

Here's a couple of more advanced solutions.

Stream IPA - Collectors.joining()

You can generate a Stream of words, revers odd-length words using map() operation, and generate the resulting string using Collector joining().

public static String reverseOdd2(String str) {
    
    return Arrays.stream(str.split(" "))
        .map(s -> s.length() % 2 == 0 ? s : new StringBuilder(s).reverse().toString())
        .collect(Collectors.joining(" "));
}

Regex - Matcher.replaceAll()

Another option is to use regular expressions.

To capture a separate word we can use the following pattern:

public static final Pattern WORD = Pattern.compile("\\b(\\w )\\b");

Where \\b is a so-called boundary matcher denoting a word boundary (for more information, refer to the documentation).

We can create a Matcher instance using this patter and the given string and make use of the Java 9 method Matcher.replaceAll() to generate the resulting string.

public static String reverseOdd3(String str) {
    
    return WORD.matcher(str).replaceAll(matchResult -> {
        String group = matchResult.group(1);
        return group.length() % 2 == 0 ? group : new StringBuilder(group).reverse().toString();
    });
}

Usage Example

main

public static void main(String[] args) {
    System.out.println(reverseOdd1("One Two Three Four"));
    System.out.println(reverseOdd2("One Two Three Four"));
    System.out.println(reverseOdd3("One Two Three Four"));
}

Output:

enO owT eerhT Four
enO owT eerhT Four
enO owT eerhT Four
  • Related