LeetCode 解碼方法(DFS,遞歸,動態規劃)

題目:

一條包含字母 A-Z 的消息通過以下方式進行了編碼:

'A' -> 1
'B' -> 2
...
'Z' -> 26
給定一個只包含數字的非空字符串,請計算解碼方法的總數。

示例 1:

輸入: "12"
輸出: 2
解釋: 它可以解碼爲 "AB"(1 2)或者 "L"(12)。
示例 2:

輸入: "226"
輸出: 3
解釋: 它可以解碼爲 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

解法分析:

第一種方法:看到題目的第一感覺是DFS可以做,每次可以搜索一個或者兩個字符,一直搜到最後一個字符結束,這樣就找到了一種組合。

具體代碼如下:

void dfs(char *s, int length, int pos, int *cnt)
{
    if (pos == length) {
        (*cnt)++;
        return;
    }

    /* 如果是0,說明走不通直接返回 */
    if (s[pos] == '0') {
        return;
    }

    /* 取一個字母情況 */
    dfs(s, length, pos + 1, cnt);

    if ((pos < length - 1)) {
        int num = (s[pos] - '0') * 10 + (s[pos + 1] - '0');
        if (num <= 26) {
            dfs(s, length, pos + 2, cnt);
        }
    }
}

int numDecodings(char * s)
{
    int length = strlen(s);
    if (length == 0) return 0;
    int cnt = 0;
    dfs(s, length, 0, &cnt);
    return cnt;
}

DFS的方法的性能隨着規模的擴大成指數級惡化,但是在Leetcode還是可以勉強AC的

通過 1372 ms 6.8 MB C

第二種方法:遞歸的方式,我們可以考慮每個問題的求解都可以看成在原來的長度-1的字符串後面再添加一個字符的問題的求解,在一個字符串的後面再添加一個字符,要考慮到這個添加的字符以及添加的字符和前面一個字符的組合關係。

具體代碼:

int getNum(char *s, int length) {
    printf("length %d \n", length);
    if (length == 1) {
        if (s[length - 1] == '0') {
            return 0;
        }

        return 1;
    }

    if (length == 0) {
        return 1;
    }

    int cnt = 0;
    if (s[length - 1] != '0') {
        cnt += getNum(s, length - 1);
    }

    int num = (s[length - 1] - '0') + (s[length - 2] - '0') * 10;
    if (num <= 26 && num > 0 && s[length - 2] != '0') {
        cnt += getNum(s, length - 2);
    }

    if (num == 0) {
        return 0;
    }

    return cnt;
}

int numDecodings(char * s)
{
    int length = strlen(s);
    if (length == 0) return 0;
    return getNum(s, length);
}

由於存在大量的重複計算,因此遞歸的做法在Leetcode中是超時的;

第三種方法:動態規劃的方法,大家都知道在運用遞歸求解問題的時候基本都可以轉化爲動態規劃的做法,動態規劃的核心是迭代的關係,在計算中要記錄已經計算過的結果,這樣使用迭代解題,避免大量的重複計算。

具體代碼:

int numDecodings(char * s)
{
    int length = strlen(s);
    int *result = (int *)malloc(sizeof(int) * length);
    memset(result, 0, sizeof(int) * length);

    if (s[0] == '0') {
        return 0;
    }

    result[0] = 1;
    for (int i = 1; i < length; i++) {
        if (s[i] == '0' && s[i - 1] == '0') {
            return 0;
        }

        if (s[i] != '0') {
            result[i] += result[i - 1];
        }

        if (s[i - 1] != '0') {
            int num = (s[i - 1] - '0') * 10 + (s[i] - '0');
            if (num <= 26) {
                if (i > 1) {
                    result[i] += result[i - 2];
                } else {
                    result[i] += 1;
                }
            } 
        }
    }

    int cnt = result[length - 1];
    free(result);
    return cnt;
}

最終效果還行:

通過 4 ms 6.9 MB C

動態規劃的性能是DFS的幾百倍!

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