【在校整理-06 最常公共子序列与子串+2048小游戏+KNN简单实例】(注:仅供参考学习使用)
一、课题内容和要求
本篇中 ,主要是本人程序设计实验周的课程试验,包括最常公共子序列与子串、2048小游戏和K-NN算法简单示例共三个不同部分的实验内容。
1、问题描述
1.1最长公共子序列与子串
问题描述:
(1)公共子序列
给定两个字符串,求解这两个字符串的最长公共子序列。
一个特定序列的子序列就是将给定序列中零个或多个元素去掉后得到的结果(不改变元素间相对次序)。一个序列,如果是两个或多个已知序列的子序列,且是所有子序列中最长的,则为最长公共子序列。
算法设计:给定两个字符串,求解这两个字符串的最长公共子序列。数据输入:输入两个字符串;输出:最长公共子序列。
样例:
输入:“aabcd”
“12abcabcd”
输出:“abcd”
(2)公共子串
在计算机科学中,最长公共子串问题是寻找两个或多个已知字符串最长的子串。此问题与最长公共子序列问题的区别在于子序列不必是连续的,而子串却必须是。
有两个字符串,这两个字符串可能会存在公共的部分,如字符串"abcdef" 和字符串"defg",这两个字符串之间有共同的字符串,“d”,“e”,“f”,“de”,“ef”,“def” 等。最长的公共子串就是"def"
1.2 2048小游戏
2.1问题描述与介绍:
给定一个2048的局面,和下一步的指令,计算出变化后的局面,游戏规则如下:(1)游戏是一个4 x 4的格子。
(2)玩家通过上,下,左,右控制数字方格滑动
(3)每滑动一次,所有数字方块都会往滑动的方向靠拢,相同数字的方块在靠拢相撞时会相加:单个数字方块滑动过程中遇到非0的不同数值其他方块,则停止滑动。
(4)不断的叠加最终拼出2048这个数字就算成功。
(5)每次滑动后,会在某个空白格子中随机出现2或者4,如果不存在空白格子,则游戏结束,算作失败。
输入:
样例的前4行是整数行,每行4个整数,如果整数为0表示空白格子,其他为数字。每个样例的第5行,是指令,指令为"LEFT",“DOWN”",“RIGHT”",“UP”,依次表示滑动的方向。
样例输入:
2 2 0 0 2 0 2 0
2 0 2 0 2 2 2 2
2 0 0 2 0 2 0 2
0 0 2 2 4 2 2 0
LEFT LEFT
样例输出:
4 0 0 0 4 0 0 0
4 0 0 0 4 4 0 0
4 0 0 0 4 0 0 0
4 4 0 0 4 4 0 0
1.3 K-NN算法实例
3.1问题描述与介绍:
kNN: k-nearest neighbor classification
K最近邻(k-Nearest Neighbor,KNN)分类算法,是一个理论上比较成熟的方法,也是最简单的机器学习算法之一。该方法的思路是:如果一个样本在特征空间中的k个最相似( 即 特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别。
二、源程序代码
最长公共子序列与子串代码:
// 代码很烂,轻喷。注:仅供参考学习使用。
# coding:utf-8
"""
一、
2.最长公共子序列(动态规划)问题描述:
给定两个字符串,求解这两个字符串的最长公共子序列。
一个特定序列的子序列就是将给定序列中零个或多个元素去掉后得到的结果(不改变元素间相对次序)。
一个序列,如果是两个或多个已知序列的子序列,且是所有子序列中最长的,则为最长公共子序列。
算法设计:给定两个字符串,求解这两个字符串的最长公共子序列。数据输入:输入两个字符串
结果输出:最长公共子序列例:
输入:’aabcd‘ ‘12abcabcd’
输出:‘abcd’
"""
import copy
# 求最常公共子序列
def lcs(str1, str2):
len_str1 = len(str1)
len_str2 = len(str2)
# 用字典来解决需要新开列表来存储或指向子序列的问题
init_unit = {
"最长公共子序列长度LSC_len": 0,
"最长公共子序列LSC": []
} # 字典中建立子序列的长度和子序列两个key
# 列表推导式生成多个列表,用于记录后续数据使用
dp = [[init_unit] * (len_str2 + 1) for i in range(len_str1 + 1)]
# m+1行, n+1列
for i in range(0, len_str1 + 1):
for j in range(0, len_str2 + 1):
if i == 0 or j == 0:
dp[i][j] = init_unit # 存在字符串为空的情况直接置零
elif str1[i - 1] == str2[j - 1]:
tmp_str = copy.copy((dp[i - 1][j - 1])["最长公共子序列LSC"])
tmp_str.append(str1[i - 1])
unit = {
"最长公共子序列长度LSC_len": (dp[i - 1][j - 1])["最长公共子序列长度LSC_len"] + 1,
"最长公共子序列LSC": tmp_str}
dp[i][j] = unit
elif str1[i - 1] != str2[j - 1]:
if (dp[i - 1][j])["最长公共子序列长度LSC_len"] > (dp[i][j - 1])["最长公共子序列长度LSC_len"]: # 存储最长的信息
dp[i][j] = dp[i - 1][j]
else:
dp[i][j] = dp[i][j - 1]
else:
pass
pass # 跳出内层循环
pass # 结束循环
for k, v in dp[len_str1][len_str2].items():
if type(v) == list:
v = ''.join(v)
print(k, ':', v) # 循环打印字典中的结果
# 求解最长公共子串
def lsc_of_str(str1, str2):
# 利用二维数组实现两个字符串的遍历后保存连续位相同与否的状态
len_str1, len_str2 = len(str1), len(str2) # 存储字符串长度
# 列表推导式嵌套生成类似数组。多一位确保不会溢出
record = [[0 for i in range(len_str2 + 1)] for j in range(len_str1 + 1)]
len_of_lsc = 0 # 记录最长匹配长度
step = 0 # 匹配的起始位
for i in range(len_str1):
for j in range(len_str2):
if str1[i] == str2[j]:
record[i + 1][j + 1] = record[i][j] + 1 # 相同则累加并标记长度
if record[i + 1][j + 1] > len_of_lsc:
len_of_lsc = record[i + 1][j + 1] # 获取最大匹配长度
step = i + 1 # 记录最大匹配长度的终止位置
if not record:
print('最长公共子串LSC_string为:无' + '\n' + '最长公共子串长度LSC_string_len :', len_of_lsc)
else:
print('最长公共子串长度LSC_str_len :', len_of_lsc, '\n' + '最长公共子串LSC_string :', str1[step - len_of_lsc:step])
# 运行函数
def run():
str1, str2 = input('请输入第一个字符串:'), input('请输入第二个字符串:') # 输入字符串
# str1 = 'aabcd'
# str2 = '12abcabcd'
lcs(str1, str2) # 测试最长公共子序列
lsc_of_str(str1, str2) # 测试最长公共子串
if __name__ == '__main__':
run()
2048小游戏实现代码:
// 代码很烂,轻喷。注:仅供参考学习使用。
# coding ='utf-8'
"""
1.为了测试方便,先把胜利标准记为16(可改)。
2.指令"LEFT","DOWN","RIGHT"","UP"依次记为'a','s','d','w'。
"""
import os, sys
import random
import itertools
def trim(seqs, direction=0): # 去零补零取相反
return ([0, 0, 0,