码迷,mamicode.com
首页 > 其他好文 > 详细

表达式求值(from leetcode 241)

时间:2015-07-27 23:18:16      阅读:387      评论:0      收藏:0      [点我收藏+]

标签:

给定一个正确的表达式(不用担心不规范的输入),比如2-1-1, 通过在不同位置添加左右括号,改变求值的优先级顺序,求出所有的这些值;

Example 1

Input: "2-1-1".

((2-1)-1) = 0
(2-(1-1)) = 2

Output: [0, 2]

Example 2

Input: "2*3-4*5"

(2*(3-(4*5))) = -34
((2*3)-(4*5)) = -14
((2*(3-4))*5) = -10
(2*((3-4)*5)) = -10
(((2*3)-4)*5) = 10

Output: [-34, -14, -10, -10, 10]

这个题目应该没有便捷的解法,只能全部的都尝试一遍;当然仅仅需要暴力的枚举一遍,也没有什么有趣的地方,我觉得有趣的地方体现在下面两点:

1. 这个题目可以用递归的方法求解,因为,假设遇到某个操作符,如果知道了左边的结果,再计算出右边的结果,那么只要把左右两边的结果合并起来,就可以了;

2. 当然如果直接按照递归去做,会出现一个问题,(大概会超时,我没有提交这样的代码);假设在得到了某个操作符两边的结果后,到了下一个操作符,递归计算的时候,任然会需要前面一个操作符(左边的)的结果,所以必须要把已经计算过的结果要cache起来;

最后的代码如下:

private final static long base = 100001;
private Map<Long, List<Integer>> cache = new HashMap<>();

private List<Integer> diffWaysToCompute(char[] cs, int start, int end) {
    long key = base * start + end;
    if (cache.containsKey(key)) {
        return cache.get(key);
    }

    boolean isNumber = true;

    for (int i = start; i < end; i++) {
        if (isOperator(cs[i])) {
            isNumber = false;
            break;
        }
    }

    List<Integer> result = new ArrayList<>();
    if (isNumber) {
        result.addAll(toNum(cs, start, end));
    } else {

        for (int i = start; i < end; i++) {
            if (isOperator(cs[i])) {
                List<Integer> prev = diffWaysToCompute(cs, start, i);
                List<Integer> suff = diffWaysToCompute(cs, i + 1, end);
                result.addAll(combineResult(prev, suff, cs[i]));
            }
        }

        return result;
    }

    cache.put(key, result);
    return result;
}

private List<Integer> combineResult(List<Integer> prev, List<Integer> suff, char op) {
    List<Integer> result = new ArrayList<>();

    for (int x : prev) {
        for (int y : suff) {
            result.add(calculate(x, y, op));
        }
    }

    return result;
}

private int calculate(int x, int y, char op) {
    switch (op) {
        case ‘+‘:
            return x + y;
        case ‘-‘:
            return x - y;
        case ‘*‘:
            return x * y;
    }
    return 0;
}

private List<Integer> toNum(char[] cs, int start, int end) {
    int num = 0;

    for (int i = start; i < end; i++) {
        if (cs[i] == ‘ ‘) {
            continue;
        }
        num = num * 10 + (cs[i] - ‘0‘);
    }
    List<Integer> result = new ArrayList<>(1);
    result.add(num);
    return result;
}

private boolean isOperator(char c) {
    return c == ‘+‘ || c == ‘-‘ || c == ‘*‘;
}

public List<Integer> diffWaysToCompute(String input) {
    return diffWaysToCompute(input.toCharArray(), 0, input.length());
}

public static void main(String[] args) {
    Solution solution = new Solution();
    System.out.println(solution.diffWaysToCompute("2-4").stream().map(x -> "" + x).collect(Collectors.joining(",")));
}

再仔细想想,这种需要cache之前结果的递归算法,应该是可以用动态规划的方式表达出来的。可惜我不擅长动态规划,就不费脑力了~~~

表达式求值(from leetcode 241)

标签:

原文地址:http://my.oschina.net/u/922297/blog/484437

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!