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的几百倍!

猜你喜欢

转载自blog.csdn.net/daida2008/article/details/103518788