1. 程式人生 > 實用技巧 >LeetCode282. 給表示式新增運算子

LeetCode282. 給表示式新增運算子

對於每個位置的兩個數之間,都有四種選擇:加、減、乘、不填符號(這樣兩個數就連在一起構成一個更大的數)。

我們可以構造一個代數結構,使得不管下一個位置的數是什麼,這個數後面填什麼符號,我們都能記錄前面已經計算過的字串的值。

這個代數結構是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;
    }
};