241. Different Ways to Add Parentheses

```java
class Solution {
    public List<Integer> diffWaysToCompute(String expression) {
        Map<String, List<Integer>> memo = new HashMap<>();
        return dfs(expression, memo);
    }
    private List<Integer> dfs(String expression, Map<String, List<Integer>> memo) {
        if (memo.containsKey(expression)) {
            return memo.get(expression);
        }

        List<Integer> result = new ArrayList<>();
        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            if (c == '+' || c == '-' || c == '*') {
                List<Integer> left = diffWaysToCompute(expression.substring(0, i));
                List<Integer> right = diffWaysToCompute(expression.substring(i+1));

                for (int l : left) {
                    for (int r : right) {
                        int calResult = calculate(l, r, c);
                        result.add(calResult);
                    }
                }
            }
        }
        
        if (result.size() == 0) { // no any cal result, so it a pure number expression
            result.add(Integer.parseInt(expression));
        }

        memo.put(expression, result);
        return result;
    }
    private int calculate(int x, int y, char operator) {
        if (operator == '-') {
            return x - y;
        }
        if (operator == '+') {
            return x + y;
        }
        if (operator == '*') {
            return x * y;
        }
        return 0;
    }
}

/*
if we meet "+", "-", "*"
get dfs, left part, right part
for loop cal


2
"-"
1-1 ->   1
         -
         1

2-1    ->    2
"-"          -
1            1

*/
```

T: O(n^3), 我們要記錄n^2個數級的DP,每個DP我們都經歷了分解點。所以時間複雜度大概是N^3

S: O(n)

class Solution {
    public List<Integer> diffWaysToCompute(String expression) {
        Map<String, List<Integer>> memo = new HashMap<>();
        return dfs(expression, memo);
    }
    private List<Integer> dfs(String expression, Map<String, List<Integer>> memo) {
        List<Integer> result = new ArrayList<>(); // every time get new value
        if (memo.containsKey(expression)) {
            return memo.get(expression);
        }
        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            if (c == '+' || c == '-' || c == '*') {
                List<Integer> left = dfs(expression.substring(0, i), memo); 
                List<Integer> right = dfs(expression.substring(i+1), memo); 

                for (int l : left) {
                    for (int r : right) {
                        if (c == '+') {
                            result.add(l + r);
                        } else if (c == '-') {
                            result.add(l - r);
                        } else if (c == '*') {
                            result.add(l * r);
                        }
                    }
                }
            }
        }
        if (result.isEmpty()) {
            result.add(Integer.valueOf(expression));
        }
        memo.put(expression, result);
        return result;
    }
}

/*
divide and conquer

"2*3-4*5"

2 3 4 5

(2) (3 4 5)

(2 3) (4 5)
...

List<Integer> left
List<Integer> right

for (int l : left) {
    for (int r : right) {
        l op r -> save to result
    }
}


*/

T: O(有多少分割方式) -> O(catalan number) = O(n^2), 因為是像是組合數切割分治
S: O(catalan number): n^2
```java
class Solution {
    Map<String, List<Integer>> memo = new HashMap<>();
    public List<Integer> diffWaysToCompute(String expression) {
        if (memo.containsKey(expression)) {
            return memo.get(expression);
        }
        List<Integer> result = new ArrayList<>(); // 每層 result 都會 re-new..., 最後傳回當層的幾個 result

        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            if (c == '-' || c == '*' || c == '+') {
                List<Integer> left = diffWaysToCompute(expression.substring(0, i));
                List<Integer> right = diffWaysToCompute(expression.substring(i+1));
                for (int l : left) {
                    for (int r : right) {
                        if (c == '-') {
                            result.add(l - r);                            

                        } else if (c == '*') {
                            result.add(l * r);
                        } else if (c == '+') {
                            result.add(l + r);
                        }
                    }
                }
            }
        }
        if (result.isEmpty()) {
            result.add(Integer.parseInt(expression));
        }
        memo.put(expression, result);
        return result;
    }
}

/*
所以關鍵是怎麼分支到剩兩個可以做運算 num1 operator num2, 左右分治可以做到
終止條件 base case 就是 沒operator 可以算, 是個數字

T: O(有多少分割方式) -> O(catalan number), 因為是像是組合數切割分治

"2*3-4*5"
->

1. "(2) *(3-4*5)"
       -> (3)-(4*5)
       -> (3-4)*(5)

2."(2 *3)(-4*5)"

3. "(2 *3-4)*(5)"
-> (2) *(3-4)
-> (2*3)-(4)


ex: 
"2-1-1"

   no opertaor, so add number to list[2]
  / 
"(2)-(1-1)"
       \
        return list[0]

        ->   list[2] - list[0] -> ans: 2

"(2-1)-(1)"
  /
  1

  -> list[1] - list[1] -> ans: 0

at last we can add memo to 

like 
1 + 1 + 1 + 1 + 1
那么按照算法逻辑,按照运算符进行分割,一定存在下面两种分割情况:

(1 + 1) + (1 + 1 + 1)
(1 + 1 + 1) + (1 + 1)

so 有重複
用 string 當 memo
*/
```

Last updated