【问题标题】:setCharAt method not working as expected inside for loop (Java)setCharAt 方法在 for 循环(Java)中没有按预期工作
【发布时间】:2017-07-05 00:54:21
【问题描述】:

我正在尝试开发一种方法来反转字符串中的元音。为此,我开发了自己的小堆栈。我在字符串中向后迭代两次,一次是用我找到的每个元音填充堆栈,第二次用存储在堆栈顶部的元音替换元音。我添加了一堆打印语句来确定失败的地方,并且似乎在 setCharAt 方法上失败了。出于测试目的,我提供了一个字符串aeiou,我希望得到uoiea。这些字符在每次迭代中都会被替换,但不幸的是,它们不会保持这种状态。在下一次迭代中,在上一次迭代中被替换的字符恢复到它们之前的状态。结果,我返回了ueiou,其中只有字符串中的第一个字符符合预期(第三个字符是 noop)。这是我的代码。任何提示都表示赞赏。

import java.util.*;

public class Solution {

    static String result;

    static class StackOfVowels {
        static Node top;

        public StackOfVowels() {
            Node top = null;
        }

        static class Node {
            Node next = null; 
            char vowel = '\0';
            Node(char value) {
                this.vowel = value;
            }
        }

        public void push(char item) {
            Node node = new Node(item);
            if (top == null) {
                top = node;
            }
            else { 
                node.next = top;
                top = node;
            }
        }

        public char top() {
            if (top == null) throw new EmptyStackException();
            return top.vowel; 
        }

        public void pop() {
            int result = -1;
            if (top != null) {
                result = top.vowel;
                top = top.next;
            }
        }
    }

    public static String reverseVowels(String s) {

        StackOfVowels stackOfVowels = new StackOfVowels();

        for(int i = s.length()-1; i >= 0; i--) {
            char c = s.charAt(i);
            if ((c == 'a') || (c == 'e') || (c == 'i') || (c == 'o') || (c == 'u')) {
                System.out.println("Initial sequence of iterations identified vowel: " + c);
                stackOfVowels.push(c);
                System.out.println("Pushed to stack, current top is: " + stackOfVowels.top());
            }
        }

        for(int j = s.length()-1; j >= 0; j--) {
            char b = s.charAt(j);
            if ((b == 'a') || (b == 'e') || (b == 'i') || (b == 'o') || (b == 'u')) {
                System.out.println("Second sequence of iterations identified vowel: " + b);
                StringBuilder newstr = new StringBuilder(s);
                char d = stackOfVowels.top();
                System.out.println("Variable d set to top of: " + stackOfVowels.top());
                newstr.setCharAt(j, d);
                result = newstr.toString();
                System.out.println("Here is the new string: " + result);
                stackOfVowels.pop();
                System.out.println("Stack was popped");
            }
        }
        return result;
    }

    public static void main(String[] args) {
        String s = "aeiou";
        reverseVowels(s);
        System.out.println("Final result: " + result);
    }
}

【问题讨论】:

  • 也许摆脱静态的result 并使用从该方法返回的值 - 如果这不起作用,然后尝试调试它
  • 谢谢你的想法。我的打印语句告诉我,第二个 for 循环中的结果是错误的,然后在最后返回的结果也是错误的。
  • 每次循环您都执行new StringBuilder(s),这基本上会将您重置回初始字符串,因此只有您最后的更改才会生效。将它移到循环之外,它应该会更好地工作。
  • 为什么StringBuilder newstr = new StringBuilder(s); 在你的循环中?
  • 我注意到public StackOfVowels() { Node top = null; } 的其他事情毫无意义。 public void pop() { int result = -1;result有什么用?

标签: java string stack


【解决方案1】:

@Elliot 答案的轻微改进(值得商榷)是使用原始 String 创建 StringBuilder 并仅在必要时替换

    String vowels = new StringBuilder(s.replaceAll("[^AEIOUaeiou]", ""))
            .reverse().toString();
    StringBuilder sb = new StringBuilder(s);
    for (int i = 0, p = 0; i < s.length(); i++) {
        switch (Character.toLowerCase(s.charAt(i))) {
        // Note that these fall-through...
        case 'a': case 'e': case 'i': case 'o': case 'u':
            sb.setCharAt(i, vowels.charAt(p++));
            break;
        default:
            break;
        }
    }
    return sb.toString();

【讨论】:

    【解决方案2】:

    您总是在第二个循环中使用StringBuilder newstr = new StringBuilder(s); 生成一个新的 StringBuilder 但是您总是使用“s”而不是“结果”来构建新的 StringBuilder。

    最好不要在每次迭代中创建新的 StringBuilder 对象。

    同样令人困惑的是,您的方法有一个从未使用过的返回值。

    以下方法应该可以工作:

    public static String reverseVowels(String s) {
    
        StackOfVowels stackOfVowels = new StackOfVowels();
    
        for(int i = s.length()-1; i >= 0; i--) {
            char c = s.charAt(i);
            if ((c == 'a') || (c == 'e') || (c == 'i') || (c == 'o') || (c == 'u')) {
                System.out.println("Initial sequence of iterations identified vowel: " + c);
                stackOfVowels.push(c);
                System.out.println("Pushed to stack, current top is: " + stackOfVowels.top());
            }
        }
        StringBuilder result_builder = new StringBuilder(s);
        for(int j = s.length()-1; j >= 0; j--) {
            char b = s.charAt(j);
    
            if ((b == 'a') || (b == 'e') || (b == 'i') || (b == 'o') || (b == 'u')) {
                System.out.println("Second sequence of iterations identified vowel: " + b);
                char d = stackOfVowels.top();
                System.out.println("Variable d set to top of: " + stackOfVowels.top());
                result_builder.setCharAt(j, d);
                stackOfVowels.pop();
                System.out.println("Stack was popped");
            }
        }
        result = result_builder.toString();
        return result_builder.toString();
    }
    

    【讨论】:

      【解决方案3】:

      我会稍微不同地处理这个问题,首先我会使用一个正则表达式String 中删除所有辅音,以创建一个Stringvowels。然后我将遍历String 的字符,使用StringBuilder 来构建输出(传递辅音,但使用之前创建的vowels String 替换元音)。喜欢,

      public static String reverseVowels(String s) {
          // Match all consonants, and remove them. Reverse that String.
          String vowels = new StringBuilder(s.replaceAll("[^AEIOUaeiou]", ""))
                  .reverse().toString();
          StringBuilder sb = new StringBuilder();
          for (int i = 0, p = 0; i < s.length(); i++) {
              switch (Character.toLowerCase(s.charAt(i))) {
              // Note that these fall-through...
              case 'a': case 'e': case 'i': case 'o': case 'u':
                  sb.append(vowels.charAt(p++));
                  break;
              default:
                  sb.append(s.charAt(i));
              }
          }
          return sb.toString();
      }
      

      这是switch 和失败行为可以利用的地方之一。

      如果您使用的是 Java 8+,您可以使用 IntStream 表达相同的内容并映射字符;喜欢

      String vowels = new StringBuilder(s.replaceAll("[^AEIOUaeiou]", ""))
              .reverse().toString();
      int[] counter = new int[1]; // <-- A bit of a kludge really.
      return IntStream.range(0, s.length()).mapToObj(i -> {
          switch (Character.toLowerCase(s.charAt(i))) {
          case 'a': case 'e': case 'i': case 'o': case 'u':
              return Character.toString(vowels.charAt(counter[0]++));
          default:
              return Character.toString(s.charAt(i));
          }
      }).collect(Collectors.joining());
      

      【讨论】:

      • 似乎对大多数人都有效,但不适用于System.out.println(reverseVowels("scarywombat"));
      • @ScaryWombat "aoa"... :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-28
      • 2020-10-18
      • 1970-01-01
      • 2017-03-29
      • 1970-01-01
      相关资源
      最近更新 更多