python-动态规划算法-最大公共字符串和最大公共子序列区别?

python-动态规划算法-最大公共字符串和最大公共子序列区别?

一、动态规划的问题解决思路和区别

'''
动态规划:
    动态规划,是一种以空间换时间的技术,算法的根本目是解决冗余(重复计算)。
    1 每种动态规划解决方案都涉及网格;
    2 单元格中的值通常是你要优化的值;
    3 每个单元格都是一个子问题,因此你应该考虑如何将问题分成子问题,这有助于你找出网格的坐标轴;

最长公共子串和最长公共子序列,区别?
    最长公共子串要求在原字符串中是连续的,而子序列只需要保持相对顺序一致,并不要求连续。

'''

二、执行结果

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
获取最长公共子串
    1    x    x    1    2    3    4    5    6    x    x    1
2    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
1    0    0    0    0    0    0    0    0    0    0    0    0
2    0    0    0    0    0    0    0    0    0    0    0    0
3    0    0    0    0    0    0    0    0    0    0    0    0
4    0    0    0    0    0    0    0    0    0    0    0    0
5    0    0    0    0    0    0    0    0    0    0    0    0
6    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
1    0    0    0    0    0    0    0    0    0    0    0    0
1    0    0    0    0    0    0    0    0    0    0    0    0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
获取最长公共子串
    1    x    x    1    2    3    4    5    6    x    x    1
2    0    0    0    0    1    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
1    1    0    0    1    0    0    0    0    0    0    0    1
2    0    0    0    0    2    0    0    0    0    0    0    0
3    0    0    0    0    0    3    0    0    0    0    0    0
4    0    0    0    0    0    0    4    0    0    0    0    0
5    0    0    0    0    0    0    0    5    0    0    0    0
6    0    0    0    0    0    0    0    0    6    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
1    1    0    0    1    0    0    0    0    0    0    0    1
1    1    0    0    1    0    0    0    0    0    0    0    1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
s1(13) = 2yy123456yy11
s2(12) = 1xx123456xx1
最长公共子串:123456    索引:3    长度:6

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
最长公共子序列
    1    x    x    1    2    3    4    5    6    x    x    1
2    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
1    0    0    0    0    0    0    0    0    0    0    0    0
2    0    0    0    0    0    0    0    0    0    0    0    0
3    0    0    0    0    0    0    0    0    0    0    0    0
4    0    0    0    0    0    0    0    0    0    0    0    0
5    0    0    0    0    0    0    0    0    0    0    0    0
6    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
y    0    0    0    0    0    0    0    0    0    0    0    0
1    0    0    0    0    0    0    0    0    0    0    0    0
1    0    0    0    0    0    0    0    0    0    0    0    0
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
最长公共子序列
    1    x    x    1    2    3    4    5    6    x    x    1
2    0    0    0    0    1    1    1    1    1    1    1    1
y    0    0    0    0    1    1    1    1    1    1    1    1
y    0    0    0    0    1    1    1    1    1    1    1    1
1    1    1    1    1    1    1    1    1    1    1    1    2
2    1    1    1    1    2    2    2    2    2    2    2    2
3    1    1    1    1    2    3    3    3    3    3    3    3
4    1    1    1    1    2    3    4    4    4    4    4    4
5    1    1    1    1    2    3    4    5    5    5    5    5
6    1    1    1    1    2    3    4    5    6    6    6    6
y    1    1    1    1    2    3    4    5    6    6    6    6
y    1    1    1    1    2    3    4    5    6    6    6    6
1    1    1    1    2    2    3    4    5    6    6    6    7
1    1    1    1    2    2    3    4    5    6    6    6    7
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
s1(13) = 2yy123456yy11
s2(12) = 1xx123456xx1
最长公共序列:2134561    长度:7    times:156

三、代码

#!/usr/bin/env python3
# coding=utf-8

'''
动态规划:
    动态规划,是一种以空间换时间的技术,算法的根本目是解决冗余(重复计算)。
    1 每种动态规划解决方案都涉及网格;
    2 单元格中的值通常是你要优化的值;
    3 每个单元格都是一个子问题,因此你应该考虑如何将问题分成子问题,这有助于你找出网格的坐标轴;

最长公共子串和最长公共子序列,区别?
    最长公共子串要求在原字符串中是连续的,而子序列只需要保持相对顺序一致,并不要求连续。

'''

times = 0
def printDp(dp, s1, s2,msg=''):
    print('~'*60)
    print(msg)
    rows = tuple(s1)
    cols = tuple(s2)
    txt = '\t'.join(cols)
    print('\t%s'%txt)
    for i in range(len(rows)):
        arr = []
        arr.append(str(rows[i]))
        for j in range(len(cols)):
            arr.append(str(dp[i][j]))
        print('\t'.join(arr))
    print('~'*60)

def getDp(rowLen,colLen):
    arr =  [[0 for i in range(colLen)] for i in range(rowLen)]
    return arr

def commonSubstring(s1,s2):
    '''
    动态规划,获取最长公共子串:
        即获取二维数组中,连续且最长的对角线,对应坐标所上的字符;
        动态规划思考的问题:
            1 动态规划都涉及网格,name网格的 x、y 轴,分别是什么?-- x、y 分别为 s1、s2 中的字符;
            2 单元格中的值存什么?-- 存索引位置相邻的公共字符串长度值;
            3 知道公共字符串起始索引和公共字符串长度,就可以在s1或s2中将公共字符串截取出来;
        逻辑描述:
            1 构建一个长为 len(s1) 宽为 len(s2) 的矩阵,每个坐标点默认值为0;
            2 比较 x,y 轴对应的字母是否相同;
            3 相同则:当前坐标值 = 左上角坐标值+1;
    '''
    rowLen = len(s1)
    colLen = len(s2)
    rows = tuple(s1)
    cols = tuple(s2)
    dp = getDp(rowLen,colLen) # 构建图
    msg = '获取最长公共子串'
    printDp(dp,s1,s2,msg)
    maxLen = 0 # 最长公共字符串长度
    maxIndex = 0 # 最大长度子串终止索引
    for i in range(rowLen):
        for j in range(colLen):
            r = rows[i]
            c = cols[j]
            # 比较字符是否相同
            if r == c:
                v = 0
                # 左上角单元格值
                x = i - 1
                y = j - 1
                if x >= 0 and y >= 0:
                    v = dp[x][y]
                v += 1
                if maxLen < v:
                    maxLen = v
                    maxIndex = j # i、j 随便一个即可,因为两个值相同
                dp[i][j] = v
    printDp(dp,s1,s2,msg)
    strIndex = maxIndex - maxLen + 1
    commonStr = s1[strIndex:maxIndex+1] # 截取时注意开闭区间问题

    print('s1(%s) = %s'%(len(s1),s1))
    print('s2(%s) = %s'%(len(s2),s2))
    print('最长公共子串:%s\t索引:%s\t长度:%s'%(commonStr,strIndex,maxLen))
    return commonStr


def commonSubsequence(s1,s2):
    '''
    动态规划,获取最长公共子序列(注:子序列不要求字符串连续):
        同样是获取二维数组中对角线最长的坐标,但不要求连续,所对应的字符;
        动态规划思考的问题:
            1 动态规划都涉及网格,name网格的 x、y 轴,分别是什么?-- x、y 分别为 s1、s2 中的字符;
            2 单元格中的值存什么?-- 公共序列长度;
        逻辑描述:
            1 构建一个长为 len(s1) 宽为 len(s2) 的矩阵,每个坐标点默认值为0;
            2 比较 x,y 轴对应的字母是否相同;
            3 相同则:当前坐标值 = max(左侧值,上方值)+1;
    '''
    times = 0
    rowLen = len(s1)
    colLen = len(s2)
    rows = tuple(s1)
    cols = tuple(s2)
    dp = getDp(rowLen,colLen) # 构建图
    msg = '最长公共子序列'
    printDp(dp,s1,s2,msg)
    maxLen = 0 # 最长公共字符串长度
    arr = [] # 记录相同字符
    for i in range(rowLen):
        for j in range(colLen):
            times += 1
            r = rows[i]
            c = cols[j]
            if r == c:
                # 相同时,当前值 = 相同左上值 + 1
                v = 0
                # 左上角单元格值
                x = i - 1
                y = j - 1
                if x >= 0 and y >= 0:
                    v = dp[x][y]
                v += 1
                if maxLen < v:
                    maxLen = v
                    arr.append(rows[i]) #记录公共子序列
                dp[i][j] = v
            else:
                # 不同时,当前值 = max(左侧值,上方值) 取最大
                # 上侧值
                tv = 0
                tx = i
                ty = j-1
                if tx >= 0 and ty >= 0:
                    tv = dp[tx][ty]
                # 左侧值
                lv = 0
                lx = i - 1
                ly = j
                if lx >= 0 and ly >= 0:
                    lv = dp[lx][ly]
                v = max(tv,lv)
                dp[i][j] = v

    printDp(dp,s1,s2,msg)
    commonStr = ''.join(arr)
    print('s1(%s) = %s'%(len(s1),s1))
    print('s2(%s) = %s'%(len(s2),s2))
    print('最长公共序列:%s\t长度:%s\ttimes:%s'%(commonStr,maxLen,times))
    pass

def main():
    s1 = '2yy123456yy11'
    s2 = '1xx123456xx1'
    commonSubstring(s1,s2)
    print('\n\n')
    commonSubsequence(s1,s2)

if __name__ == '__main__':
    main()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值