九章算法 - 三、劃分型動態規劃 512. 513. 108. 437.

512. Decode Ways

有一個消息包含A-Z通過以下規則編碼

'A' -> 1
'B' -> 2
...
'Z' -> 26

現在給你一個加密過後的消息,問有幾種解碼的方式

提示:首先合法輸入f[0] = 1.遍歷s從1到n-1。如果當前字符不等於0那麼f[i]+=f[i-1],如果當前字符的前一個字符不爲0,並且兩者加起來是小於26的,那麼結果還要加上法f[i-2](此時爲結尾兩個數字結合的情況)。

答案:

class Solution {
public:
    /**
     * @param s: a string,  encoded message
     * @return: an integer, the number of ways decoding
     */
    int numDecodings(string &s) {
        if (s == "" || s[0] == '0') 
            return 0;
        
        int n = s.size();
        vector<int> f(n, 0);
        f[0] = 1;
        for (int i = 1; i < n; i++) {
            if (s[i] != '0')
                f[i] += f[i-1];
            if (s[i-1] != '0' && stoi(s.substr(i-1, 2)) <= 26) 
                f[i] += i == 1 ? 1 : f[i-2];
            if (!f[i])
                return 0;
        }
        
        return f[n-1];
    }
};

513. Perfect Squares

給一個正整數 n, 請問最少多少個完全平方數(比如1, 4, 9...)的和等於n。

提示:因爲1^1 = 1所以每個正整數都有解。

           動態規劃, 設 f[i] 表示加和爲 i 的最少完全平方數的個數.

          狀態轉移方程: f[i] = min{i, f[i - j * j] + 1} (j*j <= i)

           邊界: f[i*i] = 1。

答案:時間複雜度O(N^3/2)

class Solution {
public:
    /**
     * @param n: a positive integer
     * @return: An integer
     */
    int numSquares(int n) {
        // write your code here
        vector<int> f(n + 1, 0x7fffffff);
        f[0] = 0;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j*j <= i; j++ ){
                f[i] = min(f[i], f[i - j*j] + 1);
            }
        }
        return f[n];
    }
};

108. Palindrome Partitioning II

給定字符串 s, 需要將它分割成一些子串, 使得每個子串都是迴文串.

最少需要分割幾次?

提示:首先將回文串分爲兩種,奇數與偶數,設置數組變量isPlin[i][j]表示i到j是否爲迴文串。

dp[i] = min{dp[j] + 1} (j < i 並且 s[j + 1], s[j + 2], ... , s[i] 是迴文串)

答案:

class Solution {
public:
    /**
     * @param s: A string
     * @return: An integer
     */
    int minCut(string &s) {
        // write your code here

        int n = s.size();
        if (n == 0) {
            return 0;
        }
        
        //Calculate isPalin
        vector<vector<bool>> isPalin(n, vector<bool>(n, false));
        int i, j, p;
        
        for (p = 0; p < n; ++p) {
            i = j = p;
            while (i >= 0 && j < n && s[i] == s[j]) {
                isPalin[i][j] = true;
                --i;
                ++j;
            }
        }
        
        for (p = 0; p < n-1; ++p) {
            i = p;
            j = p + 1;
            while (i >= 0 && j < n && s[i] == s[j]) {
                isPalin[i][j] = true;
                --i;
                ++j;
            }
        }

        //Caculate minCut
        vector<int> f(n+1);
        //vector<int> pi(n+1);
                
        f[0] = 0;
        for (i=1; i<=n; ++i) {
            f[i] = INT_MAX;
            for (j = 0; j < i; ++j) {
                if (isPalin[j][i-1] && f[j] != INT_MAX && f[j] + 1 < f[i]) {
                    f[i] = f[j] + 1;
                    //pi[i] = j;
                }
            }
        }
        
        // print solution
        /*i = n;
        while (i != 0) {
            // pi[i]~i-1
            for (j = pi[i]; j < i; ++j) {
                cout<<s[j];
            }
            
            cout<<""<<endl;
            i = pi[i];
        }*/
        
        return f[n] - 1;
    }
};

437. Copy Books

給定 n 本書, 第 i 本書的頁數爲 pages[i]. 現在有 k 個人來複印這些書籍, 而每個人只能複印編號連續的一段的書, 比如一個人可以複印 pages[0], pages[1], pages[2], 但是不可以只複印 pages[0], pages[2], pages[3] 而不復印 pages[1].

所有人複印的速度是一樣的, 複印一頁需要花費一分鐘, 並且所有人同時開始複印. 怎樣分配這 k 個人的任務, 使得這 n 本書能夠被儘快複印完?

返回完成複印任務最少需要的分鐘數.

提示:f[k][i]爲k個抄寫員最少需要多少時間抄完前i本書。用二分法時間複雜度更低。如果k>n,相當於k=n。

          

答案:時間複雜度O(N^2K) 空間O(N)

class Solution {
public:
    /**
     * @param pages: an array of integers
     * @param k: An integer
     * @return: an integer
     */
    int copyBooks(vector<int> &pages, int k) {
        // write your code here
                // write your code here
        int n = pages.size();
        if (n == 0) {
            return 0;
        }
        
        if(k > n){
            k = n;
        }

        int i, j, m, sum;

        vector<vector<int>> f(2, vector<int>(n+1));
        for (i = 0; i <= n; ++i) {
            f[0][i] = INT_MAX;
        }

        f[0][0] = 0;
        for (i = 1; i <= k; ++i) {
            for (j = 0; j <= n; ++j) {
                f[i&1][j] = INT_MAX;
                sum = 0;
                for (m = j; m >= 0; --m) {
                    if (f[!(i&1)][m] < INT_MAX) {
                        f[i&1][j] = min(f[i&1][j], max(sum, f[!(i&1)][m]));
                    }

                    if (m > 0) {
                        sum += pages[m - 1];
                    }
                }
            }
        }

        return f[k&1][n];
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章