計算最長公共子序列(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)

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