LeetCode282. 給表示式新增運算子
阿新 • • 發佈:2020-08-28
對於每個位置的兩個數之間,都有四種選擇:加、減、乘、不填符號(這樣兩個數就連在一起構成一個更大的數)。
我們可以構造一個代數結構,使得不管下一個位置的數是什麼,這個數後面填什麼符號,我們都能記錄前面已經計算過的字串的值。
這個代數結構是a + b × c。 a 是我們前面記錄過的字串表示式的值,b是我們當前搜尋到的數,c是b下一個位置的數。
這樣,如果c後面的符號是+,則整個表示式的值可以用(a+b×c) + 1 × _ 來維護,a + b × c就是a變數的下一個值,也就是我們當前已經
搜尋到的字串表示式的值,_是剩下的字串的值。a更新為 a+b×c, b更新為1;
同理,如果c後面的符號是-,則整個表示式的值可以用(a+b×c) + (-1) × _來維護。 a更新為a+b×c, b更新為-1;
如果c後面的符號是×,則整個表示式的值可以用a+(b×c)×_來維護。a還是a,b更新為b×c。
如果c後面不填符號,我們直接更新c為一個更大的數: c = c × 10 + num[i] - '0';表示兩個數連起來成為一個數。
我們可以在字串num的最後一位加上一個'+',這樣有一個好處,當我們搜尋到倒數第二個位置(加上‘+’之前的最後一個位置)時,我們只要看
a的值是否是target就行了,如果a的值是target,則我們可以存下來當前的方案path(path是一個string型別的變數)。 這是因為如果最後一位是
'+',則當前的a被更新為a + b * c(上面分析過了),如果遍歷完了原num字串,這時的a就是最終的答案。
程式碼如下:
typedef long long LL; // 中間結果可能爆int,需要long long來存 class Solution { public: vector<string> res; string path; // path存放當前方案 void dfs(string& num, int u, int len, LL a, LL b, LL target) { // u是當前搜尋到了字串num的位置,len是當前方案path的長度 if(u == num.size()) { // 如果搜尋到了num的最後一個位置('+') if(a == target) { // 這時a存放的就是當前方案下字串num的值 res.push_back(path.substr(0, len - 1)); // len - 1是因為最後一位是'+' } } else { LL c = 0; // c是我們當前要搜尋的數 for(int i = u; i < num.size(); ++i) { c = c * 10 + num[i] - '0'; path[len++] = num[i]; // 先把這個數加到方案path裡 path[len] = '+'; // 搜尋'+'的方案 dfs(num, i + 1, len + 1, a + b * c, 1, target); // a更新為a + b * c, b更新為1 if(i + 1 < num.size()) { // 如果沒到倒數第二位,說明還有插入'-'和'*'的方案 path[len] = '-'; dfs(num, i + 1, len + 1, a + b * c, -1, target); // a, b的更新之前已經分析過了 path[len] = '*'; dfs(num, i + 1, len + 1, a, b * c, target); } if(num[u] == '0') { // 不能有前導0 break; } } } } vector<string> addOperators(string num, int target) { path.resize(100); // 因為搜尋的複雜度是指數級的,所以path長度不可能太長 dfs(num, 0, 0, 0, 1, target); // 最開始a是0,b是1,表示 0 + 1 * (整個num表示式可能的取值) return res; } };