leetcode刷题2019-5-9

五一几天出去玩了,没有时间来刷题,今天起又要坚持了。昨天帮朋友笔试,抽到了最小编辑距离算法,这是一个经典的DP算法,网上的讲解很多也很杂,我就用的理解写一下。

问题描述

A是一篇杂志的文字校验员,负责改正文章里面的错字错句,我们要实现一个程序来统计A一天的工作量。A的操作分为三类:更改一个字、删除一个字或者增加一个字,我们需要通过对比校验前后的文章统计A最小需要操作多少次。为简化,我们假设文章的每行只包含数字和字母,不含空格等特殊字符。

输入描述:
	每一行输入为正整数N,表示文章的总行数(0<N<=10000)
	后面N行,为校验前的文章
	再后面N行,为校验后的文章

示例1:

输入
    2
	abcdef
	123456
	bcdg
	234567
输出
	5
	
说明
	删除了a,用g替换了e,删除了f,删除了1,增加了7,共操作5次

解题思路:

  • 题目主要是进行多次最小编辑距离的计算,只要我们编写一个计算最小编辑距离的函数即可,多次调用,每次返回最短距离的结果,相加即可输出。问题是怎么计算两个字符串的编辑距离了,例如现在有两个字符串 s = a b c d e f s=abcdef s=abcdef t = b c d g t=bcdg t=bcdg,我们怎么知道他们的最小编辑距离是多少了?
  • 所以就要拿出我们的利器动态规划了,我们不用关心他的过程是怎么样的,我们只用关注最短距离结果。动态规划方法是把问题向前分解,想要解决一个问题,需要先解决这个问题的子问题,那么要解决子问题,又需要解决子问题的子问题。通过先解决最小的子问题,再不断的解决更上一层的问题,那么就可以解决最终的问题。
  • 动态规划最经常的套路是定义转状态和找到状态转移方程。
首先对问题进行定义:

dp[i[j] 代表着 s 中前 i 个字符转移到 t 中前 j 个字符的最小编辑距离

状态转移公式:

先做一个二维数组找找规律,我们先填好数组的边界条件,当 s = 0 s=0 s=0时此时源字符串为空,到达目标字符串 t t t的最小编辑距离为字符串本身的长度,进行的操作为不断添加一个字符。所以dp[0][j]的最小编辑距离为j;当 t = 0 t=0 t=0时此时目标字符串为空,源字符串转移到目标字符串的方式为删除,有多少个删除多少个,所以dp[i][0]的最小编辑距离为i。

bcdg
01234
a1
b2
c3
d4
e4
f4
  • 接下来我们尝试从dp[1][1]出发,此时的dp[1][1]的来源方向有三个,分别是dp[0[0],dp[0][1],dp[1][0],他们代表着不同的含义。此时题目中描述了有三种操作:
    • 删除一个字符
      • s中删除一个字符变成t,也就是dp[1][1]=d[0][1]+1
    • 增加一个字符
      • s中增加一个字符变成t,也就意味着t删除一个字符,也就是dp[1][1]=d[1][0]+1
    • 替换一个字符
      • s中删除一个字符变成t,也就是dp[1][1]=d[0][0]+1
  • 我们应该去想想这个问题,既然有三种操作的话,那应该也有不用操作的情况。当 s [ i ] = = t [ j ] s[i]==t[j] s[i]==t[j]的时候,意味着s中第i个字符和t中第j个字符相等,此时dp[i][j]=dp[i-1][j-1],例如 i = 2 , j = 1 i=2,j=1 i=2,j=1 s = a b , t = b s=ab,t=b s=ab,t=b时s和t的最后一个相等,dp[2][1]=dp[1][0]

引用图片
此时表格也就变成了这样

bcdg
01234
a1 1 \color{blue}{1} 1234
b21234
c32123
d43212
e54322
f6543 3 \color{red}{3} 3

代码如下:

def mearch(s,t):
    dp = [[0]*(len(t)+1) for _ in range(len(s)+1)]
    for i in range(len(s)+1):
        dp[i][0] = i
    for i in range(len(t)+1):
        dp[0][i] = i
    for i in range(1,len(s)+1):
        for j in range(1,len(t)+1):
            if s[i-1] == t[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = min(dp[i-1][j-1], dp[i][j-1],dp[i-1][j])+1
    return dp[len(s)][len(t)]

n = int(input())
res = 0
origin = list()
for i in range(n):
    origin.append(input())
after = list()
for i in range(n):
    after.append(input())
for i in range(n):
    res += mearch(origin[i], after[i])
print(res)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值