简体   繁体   中英

How to reverse all the words in a string, without changing symbol position?

i have to write a program which will reverse all words in a string, but all symbols should stay on previous position for example: " a1bcd efg!h " => " d1cba hgf!e ". I wrote a simple program which can reverse all words/symbols, but I have no idea how to make it like in example

public void reverseWordInMyString(String str) {
    String[] words = str.split(" ");
    String reversedString = "";

    for (int i = 0; i < words.length; i++) {

        String word = words[i];
        String reverseWord = "";

        for (int j = word.length()-1; j >= 0; j--) {

            reverseWord = reverseWord + word.charAt(j);
        }

        reversedString = reversedString + reverseWord + " ";
    }
    System.out.println(reversedString);
}

It's a good start. The question is just that tricky.

Your current approach uses a single 'accumulator' which starts at the end of the string and moves back to the start: The j in for (int j =...) .

You'll need two accumulators to complete this homework assignment: One going from the front to the back, which steadily increments (so, that'll be for (int i = 0; i < word.length(); i++) ), and one which starts at the end and decrements, but not steadily.

The idea is: As you go forward, you inspect the character you find at position i . Then, you use an if , as the question asks you to do different things depending on a condition:

  • if the character at i is a special character, just add it.
  • else, add the last non-special character in the string we haven't yet added.

the if case is trivial. The else case is not. That's where your second accumulator comes in: This one will track where you're at in the string, from the end. This is a loop-in-loop. What you'll need to:

repeat the following algorithm:

  • If the character at 'j' (which goes from end to start) is a special character, decrement j, and restart this algorithm
  • Otherwise, that's the 'last non-special character we havent yet added', so add that, decrement j, and escape this algorithm.

The above can be done with, for example, a while or do/while loop. It'll be inside your for loop.

Good luck!

NB: This isn't the only way to do it. For example, you could also eliminate all special characters from the input, do a basic reverse on every word inside, which is a lot simpler than what you have now, as string has a .reverse() method these days, and then, after all that, go through your original input character by character, and for each special character you find, insert that character at that position in your output string. That works too. Whichever strategy you prefer!

according to www.geeksforgeeks.org

The Problem:

Given a string, that contains special character together with alphabets ('a' to 'z' and 'A' to 'Z'), reverse the string in a way that special characters are not affected.

Solution:

  1. Create a temporary character array say temp[].
  2. Copy alphabetic characters from given array to temp[].
  3. Reverse temp[] using standard string reversal algorithm. Now traverse input string and temp in a single loop. Wherever there is alphabetic character is input string, replace it with current character of temp[].

Algorithm:

1) Let input string be 'str[]' and length of string be 'n'
2) l = 0, r = n-1
3) While l is smaller than r, do following
    a) If str[l] is not an alphabetic character, do l++
    b) Else If str[r] is not an alphabetic character, do r--
    c) Else swap str[l] and str[r]

Java Code:

    public static void main(String[] args){
        String s = "Thi!s is a sa5mpl?e sentence.";
        String[] words = s.split("\\s+");
        System.out.println("Result:" + reverse(s));
        //Output: sih!T si a el5pma?s ecnetnes.
    }

    public static String reverse(String input)
    {
        String[] words = input.split("\\s+");
        String last_str = "";

        for(int j=0;j<words.length;j++){
            char[] str = words[j].toCharArray();
            int r = str.length - 1, l = 0;

            // Traverse string from both ends until
            // 'l' and 'r'
            while (l < r)
            {
                // Ignore special characters
                if (!Character.isAlphabetic(str[l]))
                    l++;
                else if(!Character.isAlphabetic(str[r]))
                    r--;

                    // Both str[l] and str[r] are not spacial
                else
                {
                    str[l] ^= str[r];//swap using triple XOR
                    str[r] ^= str[l];
                    str[l] ^= str[r];
                    l++;
                    r--;
                }
            }
            last_str = last_str + new String(str) + " ";
        }
        // Initialize left and right pointers

        return last_str;
    }

}

I would approach this as follows:

  1. Keep track of where the current word starts (or, equivalently, where the last non-word character was). This will be updated as we go along.
  2. Scan the input string. Every time a non-word character (special character or space) is found, output the reverse of the current word and then the non-word character. You can output the reverse of the current word by indexing backwards from just before the non-word character to the start of the current word. (Note that the current word might be empty; for example, two special characters in a row).

For the output area, I recommend a StringBuilder rather than a String; this will be more efficient.

In code, it might look something like this (where I've changed the method to return the result rather than print it to the console):

public String reverseWordInMyString(String str) {
    StringBuilder output = new StringBuilder(str.length()); // initialize full capacity
    int curWordStart = 0;
    // scan the input string
    for (int i = 0; i < str.length(); i++) {
        char curLetter = str.charAt(i);
        if (!Character.isLetter(char)) {
            // the current word has ended--output it in reverse
            for (int j = i-1; j >= curWordStart; j--) {
                output.append(str.charAt(j));
            }
            // output the current letter
            output.append(curLetter);
            // the next current word starts just after the current letter
            curWordStart = i + 1;
        }
    }
    // The last current word (if any) ends with the end of string,
    // not a special character, so add it (reversed) as well to output
    for (int j = str.length() - 1; j >= curWordStart; j--) {
        output.append(str.charAt(j));
    }

    return output.toString();
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM