【问题标题】:Reverse Polish to Infix Notation optimization in javajava中的反向波兰语到中缀表示法优化
【发布时间】:2018-09-01 16:30:54
【问题描述】:

我正在尝试解决涉及将反向波兰表示法转换为中缀表示法的编程挑战。例如: 1 3 + 2 4 5 - + / 将是:((1+3)/(2+(4-5))) 到目前为止,我的解决方案确实有效,但速度还不够快。所以我正在寻找任何优化建议。

public class betteralgo {
    public static void main(String[] args) throws IOException {
        BufferedReader bi = new BufferedReader(new InputStreamReader(System.in));
        String line = bi.readLine();
        String[] input = line.split(" ");
        StringBuilder builder = new StringBuilder();
        Stack<String> stack = new Stack<String>();

        for(String e:input) {
            switch(e){
                case("+"):
                case("-"):
                case("*"):
                case("/"):
                    String i = stack.pop();
                String k = stack.pop();
                stack.push("(" + k + e + i + ")");
                break;
                default:
                    stack.push(e);
                }
            }
        System.out.println(stack.pop());        
        }       
    }

【问题讨论】:

  • 如果代码有效,这个问题可能更适合代码审查
  • 您接受恕我直言的答案提供零加速。
  • 您是否考虑过直接解析字符串,而不是使用line.split?为什么在不使用时分配StringBuilderStringBuilder 在这种情况下不会帮助你。你确定这太慢了吗?你是怎么计时的?

标签: java algorithm optimization infix-notation


【解决方案1】:

由于使用越来越长的表达式,您的问题是二次复杂度。解决方案是构建一棵树。而不是

"(" + k + e + i + ")"

使用内容e 和子ki 创建一个新节点。然后通过树的简单传递允许您生成任何表示(中缀、前缀或后缀)。

【讨论】:

    【解决方案2】:

    出于好奇,这个递归解决方案是否更快?

    public static void main(String[] args)
    {
        String input = "1 3 + 2 4 5 - + /";
        List<String> terms = new ArrayList<>(Arrays.asList(input.split(" ")));      
        String result = build(terms);
        System.out.println(result);
    }
    
    static String build(List<String> terms)
    {
        String t = terms.remove(terms.size()-1);        
        if("+-/*".indexOf(t) >= 0)
        {
            String op2 = build(terms);
            String op1 = build(terms);
            return "(" + op1 + t + op2 + ")";
        }
        else return t;
    }
    

    【讨论】:

    • 我对此表示怀疑,因为O(n**2) 的复杂性仍然存在。
    【解决方案3】:

    您的代码在时间复杂度上是O(n),我认为这对于这个问题是最快的。但是您并没有利用StringBuilder,而是使用了耗时的字符串连接。

    这是优化后的版本:

    public static void main(String[] args) throws IOException {
        BufferedReader bi = new BufferedReader(new InputStreamReader(System.in));
        String line = bi.readLine();
        String[] input = line.split(" ");
        StringBuilder builder = new StringBuilder();
        Stack<String> stack = new Stack<String>();
    
        for(String e:input) {
            switch(e) {
                case("+"):
                case("-"):
                case("*"):
                case("/"):
                    String i = stack.pop();
                    String k = stack.pop();
                    builder.setLength(0);
                    builder.append("(");
                    builder.append(k).append(e).append(i);
                    builder.append(")");
                    stack.push(builder.toString());
                    break;
                default:
                    stack.push(e);
            }
        }
        System.out.println(stack.pop());  
    }
    

    【讨论】:

    • 您的优化毫无用处,因为您对StringBuilder 所做的正是 javac 所做的。为"(" + k + e + i + ")" 之类的东西手动编写StringBuilder 连接是没有意义的,只有在循环迭代中携带内容时才能获得。
    • 复杂度不是O(n),它是二次方,因为子表达式也随着n 增长。
    • 如果你要使用字符串生成器,你应该运行 setLength 来清除缓存,分配一个新的字符串生成器要慢得多。
    猜你喜欢
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-09
    相关资源
    最近更新 更多