动态规划,以空间换时间,自底向上求解

  计算两字符串的最长公共子序列(可以不连续)

/**
 找出 两个 字符串 的公共 子序列(动态规划)
 @param str1 字符串1
 @param str2 字符串2
 */
void maxPublicSubSequence(char *str1, char *str2) {
    assert(str1 != NULL && str2 != NULL);

    // 字符串 1 长度
    int str1Length = strlen(str1);
    // 字符串 2 长度
    int str2Length = strlen(str2);
    // 开辟 二维 存储 数组 (并初始化 值为:0)

    int **postionArray = (int **)malloc(sizeof(int *) * (str1Length + 1));

    for (int i = 0; i <= str1Length; i ++) {
        postionArray[i] = (int *)malloc(sizeof(int) * (str2Length + 1));
    }

    for (int i = 0; i <= str1Length; i++) {
        for (int j = 0; j <= str2Length; j++) {
            postionArray[i][j] = 0;
        }
    }


    // 循环 遍历
    for(int i = 1; i <= str1Length; i++) {
        for(int j = 1; j <= str2Length; j ++) {
            // 如果 两个字符 相同
            if (str1[i - 1] == str2[j - 1]) {
                 postionArray[i][j] = postionArray[i - 1][j - 1] + 1;

            }
            // 如果 两个 字符 不同
            else {
               postionArray[i][j] = (postionArray[i - 1][j] > postionArray[i][j - 1]) ? postionArray[i - 1][j] : postionArray[i][j - 1];
            }

        }
    }

    for (int i = 0; i < str1Length; i++) {
        for (int j = 0; j < str2Length; j++) {
            printf("%d ", postionArray[i][j]);
        }
        printf("\n");
    }



    int i, j ;
    for (i = str1Length, j = str2Length; i >= 1  && j >= 1;) {
        if (str1[i - 1] == str2[j - 1]) {
            printf("%c ", str1[i - 1]);
            i --;
            j --;
        }
        else {
            if (postionArray[i][j - 1] > postionArray[i - 1][j]) {
                j--;
            }
            else {
                i --;
            }
        }
    }

    // 释放开辟数组
    for (int i = 0; i < str1Length; i++) {
        free(postionArray[i]);
    }
    free(postionArray);
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        maxPublicSubSequenceTwo("ABCBDAB" , "BDCABA");
    }
    return 0;
}

  给定两个字符串,求出它们之间最长的相同子字符串的长度。

  穷举法:

#import <Foundation/Foundation.h>
/**
 找出 两个 字符串 的 最长 公共 子串 (穷举法)
 @param str1 字符串1
 @param str2 字符串2
 */
void maxPublicSubStringOne(char *str1, char *str2) {
    assert(str1 != NULL && str2 != NULL);

    // 起始 位置
    int startPosition = 0;
    // 公共 子串 长度
    int maxStringLength = 0;

    // 循环 遍历 所有 子字符串
    for (int i = 0; i < strlen(str1); i ++) {
        for (int j = 0; j < strlen(str2); j++) {
            // 如果 两个 字符 相等
            if(str1[i] == str2[j]) {
                // 继续 比较 后面的字符
                int k = 1;
                while (str1[i + k] == str2[j + k] && str1[i + k] != '\0' && str2[j + k] != '\0') {
                    k ++;
                }
                // 如果 k 大于 最长 字符串
                if (k > maxStringLength) {
                    // 公共 子串 长度
                    maxStringLength = k;
                    // 起始位置
                    startPosition = i;
                }
            }
        }
    }

    if(maxStringLength > 0) {
        for (int i = startPosition; i <= maxStringLength; i++) {
            printf("%c ", str1[i]);
        }
    }
}

  动态规划法

/**
 找出 两个 字符串 的公共 子串(动态规划)
 @param str1 字符串1
 @param str2 字符串2
 */
void maxPublicSubStringTwo(char *str1, char *str2) {
    assert(str1 != NULL && str2 != NULL);

    // 起始 位置
    int startPosition = 0;
    // 公共 子串 长度
    int maxStringLength = 0;
    // 字符串 1 长度
    int str1Length = strlen(str1);
    // 字符串 2 长度
    int str2Length = strlen(str2);
    // 开辟 二维 存储 数组 (并初始化 值为:0)

    int **postionArray = (int **)malloc(sizeof(int *) * str1Length);

    for (int i = 0; i < str1Length; i ++) {
        postionArray[i] = (int *)malloc(sizeof(int) * str2Length);
    }

    for (int i = 0; i < str1Length; i++) {
        for (int j = 0; j < str2Length; j++) {
            postionArray[i][j] = 0;
        }
    }


    // 循环 遍历
    for(int i = 0; i < str1Length; i++) {
        for(int j = 0; j < str2Length; j ++) {
            // 如果 两个字符 相同
            if (str1[i] == str2[j]) {
                // 判断 释放 是 边界 情况
                if (i == 0 || j == 0) {
                    // 边界 情况
                    postionArray[i][j] = 1;
                }
                // 非边界 情况
                else {
                    postionArray[i][j] = postionArray[i - 1][j - 1] + 1;
                }

                if (postionArray[i][j] > maxStringLength) {
                    maxStringLength = postionArray[i][j];
                    startPosition = i - postionArray[i][j] + 1;
                }
            }

        }
    }

    // 打印 字符串
    if(maxStringLength > 0) {
        for (int i = 0; i <= maxStringLength; i++) {
            printf("%c ", str1[startPosition + i]);
        }
    }
    // 释放开辟数组
    for (int i = 0; i < str1Length; i++) {
        free(postionArray[i]);
    }
    free(postionArray);
}

  

参考链接:

求2个字符串的最长公共子序列和最长公共子字符串

详解动态规划——邹博讲动态规划

01-25 20:47