反转字符串中单词中的字母

时间:2017-07-06 07:25:13

标签: string java-8

我编写了以下解决方案,除了有标点符号外,它有效。我想知道是否有O(1)空间复杂度和O(字符串长度)时间复杂度解决方案,不使用reverse()方法,或类似的任何使得这个任务太容易。任何能够正确处理标点符号的答案都会很棒。

示例:

给出字符串:"我喜欢巧克力"

返回字符串应该是:"我evol etalocohc"

为清楚起见,当我说正确处理标点符号时,我的意思是标点符号不应移动。

 // reverse the letters of every word in a sentence (string), and return the result

 public static String reverse(String x)
 {
     String[] str = x.split(" ");

     StringBuilder rev = new StringBuilder("");

     for (int i = 0; i < str.length; i++)
     {
         for (int s = str[i].length()-1; s >= 0; s--)
         {
             rev.append(str[i].charAt(s));
         }
         rev.append(" ");
     }

     return rev.toString();
 }

这是我的一些测试的输出:

     public static void main(String[] args)
     {
         System.out.println(reverse("I love chocolate"));//this passes
         System.out.println(reverse("Geeks for Geeks"));//this passes
         System.out.println(reverse("You, are awesome"));//not handling puncutation mark correctly, gives me ",uoY era emosewa", instead of "uoY, era emosewa"
         System.out.println(reverse("Geeks! for Geeks."));//not handling puncutation marks correctly, gives me "!skeeG rof .skeeG", instead of "skeeG! rof skeeG."
     }

4 个答案:

答案 0 :(得分:1)

这可能适用于标点符号:

public static String reverse(String x)
{
     String[] str = x.split("\\W"); //Split on non-word characters.

     StringBuilder rev = new StringBuilder("");
     int currentPosition = 0;
     for (int i = 0; i < str.length; i++)
     {
         for (int s = str[i].length()-1; s >= 0; s--)
         {
             rev.append(str[i].charAt(s));
             currentPosition++;
         }
         while (currentPosition < x.length() && Character.toString(x.charAt(currentPosition)).matches("\\W")) 
            rev.append(x.charAt(currentPosition++)); //Add the actual character there.
     }

     return rev.toString();
 }

Haven现在用Java编写了一段时间,所以我知道这可能不是最好的做法。

复杂性是O(n)(空间和时间)。

如果您从字符串构建器开始,您可以通过使用就地字符交换而不是附加来降低空间复杂性,但是您需要抢先找到所有非字字符的位置。< / p>

答案 1 :(得分:1)

这是一种使用仅需要O(1)存储的单词的就地反转的实现。此外,反转算法本身为O(N),其长度为字符串。

基本算法是沿着弦向下走,直到撞到一个空格。然后,调用swap()方法来反转该特定单词。它只需要一个额外的角色。

由于大量使用StringBuilder操作,这种方法可能不如接受的答案那样高效。但是,在像Android应用程序这样空间非常宝贵的环境中,这可能需要考虑。

 public static void swap(StringBuilder input, int start, int end) {
    for (int i=0; i <= (end - start) / 2; ++i) {
        char ch = input.charAt(start + i);
        input.setCharAt(start + i, input.charAt(end - i));
        input.setCharAt(end - i, ch);
    }
}

public static void main(String[] args) {
    StringBuilder sb = new StringBuilder("I love chocolate");

    int start = 0;
    int end = 0;

    while (true) {
        while (end <= sb.length() - 1 && sb.charAt(end) != ' ') {
            ++end;
        }
        swap(sb, start, end - 1);
        start = end + 1;
        end = start;
        if (end > sb.length() - 1) {
            break;
        }
    }

    System.out.println(sb);
}

在这里演示:

Rextester

答案 2 :(得分:1)

我刚刚更改了代码,而不是其他方法或循环,只是一些变量和条件。

/* Soner - The methods reverse a string with preserving punctiations */
public static String reverse(String x) {
    String[] str = x.split(" ");
    boolean flag = false;
    int lastCharPosition;
    StringBuilder rev = new StringBuilder("");

    for (int i = 0; i < str.length; i++) {
        flag = false;
        lastCharPosition = str[i].length()-1;
        if (str[i].charAt(lastCharPosition) == '.' || str[i].charAt(lastCharPosition) == '!'
                || str[i].charAt(lastCharPosition) == ',') {  // you can add new punctiations
            flag = true;
            lastCharPosition = str[i].length()-2;
        }
        for (int s = lastCharPosition; s >= 0; s--) {
            rev.append(str[i].charAt(s));
        }
        if (flag) rev.append(str[i].charAt(lastCharPosition + 1));
        rev.append(" ");
    }

    return rev.toString();
}

答案 3 :(得分:1)

紧凑型解决方案

public static String reverse(String x) {
    Matcher m = Pattern.compile("\\w+").matcher(x);
    if(!m.find()) return x;
    StringBuffer target = new StringBuffer(x.length());
    do m.appendReplacement(target, new StringBuilder(m.group()).reverse().toString());
    while(m.find());
    return m.appendTail(target).toString();
}

Matcher上的appendReplacement循环+ appendTail是等效于String.replaceAll(regex)的手册,旨在支持替换比简单字符串更复杂的情况使用占位符,例如反转找到的单词。

不幸的是,我们必须在这里使用过时的StringBuffer,因为API早于StringBuilderJava 9 is going to change that

可能更有效的替代方案是

public static String reverse(String x) {
    Matcher m = Pattern.compile("\\w+").matcher(x);
    if(!m.find()) return x;
    StringBuilder target = new StringBuilder(x.length());
    int last=0;
    do {
        int s = m.start(), e = m.end();
        target.append(x, last, s).append(new StringBuilder(e-s).append(x, s, e).reverse());
        last = e;
    }
    while(m.find());
    return target.append(x, last, x.length()).toString();
}

这在整个操作中使用StringBuilder并使用该功能附加部分字符序列,而不是为匹配和替换创建中间字符串。它也没有在替换中搜索占位符,appendReplacement在内部进行。