题目描述

给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, – 以及 * 。

示例 1:
输入: "2-1-1"
输出: [0, 2]
解释: 
((2-1)-1) = 0 
(2-(1-1)) = 2
示例 2:
输入: "2*3-4*5"
输出: [-34, -14, -10, -10, 10]
解释: 
(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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/different-ways-to-add-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解法1

这道题目采用分治法来解决,题目要求实现函数diffWaysToCompute,输入算数表达式input,输出不同的括号组合产生的计算结果列表ans。首先,我们扫描input寻找操作符即+、-和*。如果在input中找不到任何一个运算符,那么它就是操作数,我们将它转化为数字类型,加入到ans中返回即可。否则,input是包含运算符的表达式,情况变得复杂。

如果遇到了操作符,则将input分割成左右两部分,左右两部分可能还是一个计算表达式,我们继续将它送给函数diffWaysToCompute递归的处理,得到左右两部分返回值leftOpndsrightOpnds。我们将leftOpnds和rightOpnds按照操作符optr做笛卡尔积,将运算结果加入到ans中就完成了对运算符的处理,我们编写了函数calculate(char optr, List leftOpnds, List rightOpnds)来实现这个功能。

private List<Integer> calculate(char optr, List<Integer> leftOpnds, List<Integer> rightOpnds) {
    List<Integer> result = new ArrayList<>();
    for (Integer leftOpnd : leftOpnds) {
        for (Integer rightOpnd : rightOpnds) {
            switch (optr) {
                case '+':
                    result.add(leftOpnd + rightOpnd);
                    break;
                case '-':
                    result.add(leftOpnd - rightOpnd);
                    break;
                case '*':
                    result.add(leftOpnd * rightOpnd);
                    break;
            }
        }
    }
    return result;
}

举一个例子,对于表达式input = “2*3-4*5″,先处理第一个运算符*,将input分割成左右两个表达式”2″和”3-4*5″。假设我们已经知道了”3-4*5″能产生结果列表[-5, -17](后面会说怎么算出来的)。那么将2与[-5, -17]做乘法就能得到[-10, -34],这只是计算结果的一部分,我么还要继续处理input下一个运算符’-‘,直到整个input处理完毕。至于刚刚提到的”3-4*5″怎么算出来的[-10, -34],这又是一个子问题,按照相同的方法就能计算出来。

这是一种Top-down的解决问题方式,给定input就会递归的向下计算,这存在重复计算的问题。为了避免重复计算,需要使用Map<String, List<Integer>> cache来存储已经计算过的结果。全部代码如下:

class Solution {
    private Map<String, List<Integer>> cache = new HashMap<>();

    private List<Integer> calculate(char optr, List<Integer> leftOpnds, List<Integer> rightOpnds) {
        List<Integer> result = new ArrayList<>();
        for (Integer leftOpnd : leftOpnds) {
            for (Integer rightOpnd : rightOpnds) {
                switch (optr) {
                    case '+':
                        result.add(leftOpnd + rightOpnd);
                        break;
                    case '-':
                        result.add(leftOpnd - rightOpnd);
                        break;
                    case '*':
                        result.add(leftOpnd * rightOpnd);
                        break;
                }
            }
        }
        return result;
    }

    public List<Integer> diffWaysToCompute(String input) {
        if (input.length() == 0)
            return Collections.emptyList();
        List<Integer> ans = cache.get(input);
        if (ans != null)
            return ans;
        ans = new ArrayList<>();

        boolean hasOptr = false;
        for (int i = 0; i < input.length(); i++) {
            char currCh = input.charAt(i);
            if (currCh == '+' || currCh == '-' || currCh == '*') {
                List<Integer> leftOpnds = diffWaysToCompute(input.substring(0, i));
                List<Integer> rightOpnds = diffWaysToCompute(input.substring(i + 1));
                ans.addAll(calculate(currCh, leftOpnds, rightOpnds));
                hasOptr = true;
            }
        }

        if (!hasOptr) {
            ans.add(Integer.valueOf(input));
        }
        cache.put(input, ans);
        return ans;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *