计算最长公共子序列(LCS)的两种算法

最长公共子序列 LCS:

动态规划法得出以下:
LCS(Xm,Yn) = LCS(Xm-1,Yn-1)+1 ## xm=yn
LCS(Xm,Yn) = MAX{LCS(Xm-1,Yn),LCS(Xm,Yn-1)} ## xm!=yn

代码有如下两种方式实现:
1. 递归算法
递归算法实现,重点在于把它看成一颗二叉树,进行的分解算法。然而递归算法计算重复度太高。

#!/usr/bin/env python
# -*- coding:utf-8 -*-


def LCS(str_x, coord_x, str_y, coord_y):
	"""
	# 递归算法实现,重点在于把它看成一颗二叉树,进行的分解算法。然而递归算法计算重复度太高。
	:param str_x:
	:param coord_x: 初始值应传入 len(str_x) - 1
	:param str_y:
	:param coord_y: 初始值应传入 len(str_y) - 1
	:return:
	"""
	if coord_x < 0 or coord_y < 0:
		return ""

	if str_x[coord_x] == str_y[coord_y]:
		return LCS(str_x, coord_x-1, str_y, coord_y-1) + str_x[coord_x]
	else:
		sub_node_left = LCS(str_x, coord_x-1, str_y, coord_y)
		sub_node_right = LCS(str_x, coord_x, str_y, coord_y-1)
		if len(sub_node_left) > len(sub_node_right):
			return sub_node_left
		else:
			return sub_node_right

if __name__ == "__main__":
	# strX = "BDCABA"
	# strY = "ABCBDAB"
	strX = "abcicba"
	strY = "abdkscab"
	print (LCS(strX, len(strX)-1, strY, len(strY)-1))

2. 二维数组备忘法 (与动态规划法是两回事)
在这里插入图片描述

#!/usr/bin/env python
# -*- coding:utf-8 -*-

#strX = "BDCABA"
#strY = "ABCBDAB"
strX = "abcicba"
strY = "abdkscab"

def produceLcsXY(s_x, s_y):
	"""
	# LCS 二维数组备忘记法
	:param s_x:
	:param s_y:
	:return:
	"""
	len_x = len(s_x)
	len_y = len(s_y)

	print("初始化 %s*%s 的二维数组" %(len_x,len_y))
	storeXY = [[0 for i in range(len_x+1)] for j in range(len_y+1)]
	#print(storeXY)

	for y in range(1, len_y+1):
		for x in range(1, len_x+1):
			if strX[x-1] == strY[y-1]:
				storeXY[y][x] = storeXY[y-1][x-1] + 1
			else:
				storeXY[y][x] = max(storeXY[y-1][x], storeXY[y][x-1])

	print("生成 字符串:%s 和 字符串 %s 的LCS备忘记法" % (s_x, s_y))
	return storeXY

def getLCS(storeXY, s_x, s_y):
	"""
	# LCS回溯法取值
	:param storeXY:
	:param s_x:
	:param s_y:
	:return:
	"""
	len_x = len(storeXY[0])
	len_y = len(storeXY)

	LCS_string = ""
	x, y = len_x - 1, len_y - 1
	while True:
		if storeXY[y][x] == 0:
			break
		if s_x[x-1] == s_y[y-1]:
			LCS_string =  s_x[x-1] + LCS_string
			x, y = x-1, y-1
		else:
			if storeXY[y][x-1] > storeXY[y-1][x]:
				x, y = x - 1, y
			else:  # storeXY[y - 1][x] >= storeXY[y][x - 1]:
				x, y = x, y - 1

	print("最长公共子序列为:%s" %LCS_string)
	return LCS_string

if __name__ == "__main__":
	storeXY = produceLcsXY(strX, strY)
	for item in storeXY:
		print (item)
	print(getLCS(storeXY, strX, strY))

实践:求两字符串的相似度
c : 最长公共子串序列
m:字符1长度
n:字符2长度
相似度 = 2 * c / (m + n)

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