【问题标题】:Reversing the characters of each individual word of a sentence without reversing the word order在不颠倒单词顺序的情况下颠倒句子中每个单词的字符
【发布时间】:2016-04-21 09:54:35
【问题描述】:

我有这段代码应该做标题所说的,颠倒字符顺序而不改变单词的顺序:

package stackTests;

import java.util.Scanner;
import java.util.Stack;


public class StackTest
{
  Stack<Character> stack;

  public StackTest()
  {
    stack = new Stack<Character>();
  }

  public String reverseString(String str)
  {
    int start = 0;
    int start2 = 0;
    int size;
    char space = ' ';
    char[] cArr;
    Scanner scan = new Scanner(str);
    cArr = str.toCharArray();
    for (; start < cArr.length; start++)
    {
      if(cArr[start] == space || start == cArr.length - 1)
      {
        for (; start2 < stack.size(); start++)
        {
          System.out.print(stack.pop());
        }
      }
      else
      {
        stack.push(cArr[start]);
      }
      start2 = 0;
    }
    return str;
  }
}

如果我输入一个像“Hello”这样的单词,它会正常工作——它会输出“olleH”——但是一旦它变得比一个单词更复杂,它就会开始输出一些奇怪的东西。“你好,我的名字是" 输出 "ollehem"。我对Stacks 真的很陌生,这是我第一次使用它们。我不确定Stacks是否存在逻辑错误或使用不当。

【问题讨论】:

  • 那不可读。以可读的方式格式化您的代码。
  • 你真的必须使用堆栈吗?这是作业的一部分吗?
  • 你知道如何使用调试器吗?
  • 可能相关(代码打高尔夫球):codegolf.stackexchange.com/questions/11142/…
  • 我看不出堆栈适合您的问题。我想 1) 使用 String#split 将句子拆分为单词,2) 反转每个元素并将其按顺序添加到列表中,3) 将单词放回一起。

标签: java arrays loops stack


【解决方案1】:

如果你必须使用堆栈,我会遵循这样的算法:

String myString = "Hello World";
Stack<Character> stack = new Stack<Character>();
StringBuilder sb = new StringBuilder();
String[] splitString = myString.split(" ");

//Iterate through each word in the string
for(String s : splitString){

    //Push each character of the word into LIFO stack
    for(char c : s.toCharArray()){
        stack.push(c);
    }

    //Build new string with reverse ordered characters
    while(!stack.isEmpty()){
        sb.append(stack.pop());
    }

    //Append a space as long as it's not the last word of the original string
    if(!s.equals(splitString[splitString.length - 1]))
        sb.append(" ");
}

//Print the new string
System.out.println(sb.toString());

我不确定效率是否对你很重要,但这个算法可以在线性时间内工作,其中 n 是字符串中的字符数。

【讨论】:

  • 由于我对 StringBuilder 不太熟悉,您能否为我分解一下您的流程,所以我有点迷茫。
  • 当然。 java中的字符串是不可变对象。这意味着当您添加到字符串时,它实际上是在内存中创建一个全新的字符串,而不仅仅是添加到前一个字符串上。 StringBuilder 是一个对象,它允许您安全地(内存)将新字符串附加到您的 StringBuilder 对象。出于您的目的,您还可以使用普通的 String 对象(只需将 StringBuilder 替换为 String myString = "",并将 append 语句替换为 myString += stack.pop())。
  • 好的,我明白了,谢谢你的解释,彻底搞清楚了!
【解决方案2】:

您没有输出原始空格,这就是您看到奇怪结果的原因

这里是固定版本:

public static void reverseString(final String str) {
    final Stack<Character> stack = new Stack<>();
    for (int i = 0; i < str.length(); i++) {
        final char c = str.charAt(i);
        if (c == ' ') {
            while (!stack.isEmpty())
                System.out.print(stack.pop());
            System.out.print(' ');
        } else
            stack.push(c);
    }
    while (!stack.isEmpty())
        System.out.print(stack.pop());
}

另一个没有堆栈的版本,就地替换:

public static void reverseString(final String str) {
    final char[] chars = str.toCharArray();
    int start = 0;
    for (int i = 0; i < chars.length; i++) {
        if (chars[i] == ' ') {
            reverse(chars, start, i - 1);
            start = i + 1;
        }
    }
    reverse(chars, start, chars.length - 1);
    System.out.println(new String(chars));
}

private static void reverse(final char[] chars, int s, int e) {
    while (s < e) {
        final char t = chars[s];
        chars[s] = chars[e];
        chars[e] = t;
        s++;
        e--;
    }
}

【讨论】:

  • 我想我只是在考虑使用数组,不知道为什么我认为这是个好主意。
【解决方案3】:

以下是如何在不使用任何额外空间的情况下就地执行此操作(不使用堆栈):

public class ReverseWordsInplace {

    public static void main(String[] args) {
        reverseWords(new StringBuilder("This is a test"));
    }

    public static void reverseWords(StringBuilder s) {
        StringBuilder str = new StringBuilder(s);
        int startWordIndex = 0;
        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) == ' ' || str.length() - 1 == i) {
                int x = 0;
                int endWordIndex = str.charAt(i) == ' ' ? i - 1 : i;
                while (endWordIndex - x > startWordIndex + x) {
                    char c1 = str.charAt(startWordIndex + x);
                    char c2 = str.charAt(endWordIndex - x);
                    str.setCharAt(startWordIndex + x, c2);
                    str.setCharAt(endWordIndex - x, c1);
                    x++;
                }
                startWordIndex = i + 1;
            }
        }
        System.out.println(str);
    }
}

输出:

sihT si a tset

【讨论】:

    最近更新 更多