###### tags: `LeetCode` `DFS` `Medium` `String` `Devide and Conquer` # LeetCode #241 [Different Ways to Add Parentheses](https://leetcode.com/problems/different-ways-to-add-parentheses/) ### (Medium) 給定一個含有數字和運算符的字符串,為表達式添加括號,改變其運算優先級以求出不同的結果。你需要給出所有可能的組合的結果。有效的運算符號包含 +, - 以及 * 。 --- 首先先建立一個無序map容器<string, vector<int>>儲存運算式為x時所有的運算可能(依不同運算優先級別)。 遞迴函式的目標為回傳該字串的所有運算組合(數組), 核心概念為讀取到一個運算符時,以該運算符為界分割左右字串, 並以左右字串為參數遞迴呼叫函式。拿到左右字串遞迴函式回傳的數組後, 針對每一個數組元素進行組合運算, 並將結果存入答案數組中, 最後回傳。 在進行最小分割的遞迴函式時, 由於字串內容只有一個數字, 此時上面的左右子字串進行組合運算不會發生, 因此在for迴圈結束後ans數組為空, 此時直接將字串內容存入ans數組中並回傳, 因此該遞迴的上層函式會收到左右皆為一個數字的數組, 並進行運算在回傳, 並如此遞迴。 此外, 使用無序map儲存計算結果(特定字串為key, 該字串的所有運算結果為value), 並在遞迴函式開始時判斷該算式是否被計算過, 若map中存在該算式, 可直接回傳值(整數數組), 省去時間; 同理,在函式最後回傳答案數組時, 同樣須將該字串的運算式結果組合數組存入map中。 --- ``` namespace cal{ int plus(int a, int b){ return a+b; } int minus(int a, int b){ return a-b; } int multiply(int a, int b){ return a*b; } } class Solution { public: unordered_map<string, vector<int>> m; vector<int> diffWaysToCompute(string expression) { return ways(expression); } const vector<int>& ways(const string& input){ if(m.count(input))return m[input]; vector<int> ans; for(int i=0;i<input.size();i++){ char op = input[i]; if(op=='+'||op=='-'||op=='*'){ const string left = input.substr(0, i); const string right = input.substr(i+1); const vector<int>& l = ways(left); const vector<int>& r = ways(right); function<int(int, int)> f; switch(op){ case '+':f=cal::plus;break; case '-':f=cal::minus;break; case '*':f=cal::multiply;break; } for(int a:l) for(int b:r) ans.push_back(f(a,b)); } } if(ans.empty()) ans.push_back(stoi(input)); return m[input]=ans; } }; ```