前言:在网上看到一道360的秋招真题,题目如下:
仔细读题后发现这是一道求解最长公共子序列的问题,最好使用动态规划算法。
小B坐火车,从起点到终点的车站序列已知,期间他睡了两觉,到终点的时候还在睡,也就是说中间他醒了两次,这两次清醒的时间,有两个车站子序列,现在让我们分析这两段路是去的时候看到的,还是回来的时候看到的,来回都能看到,还是说压根不存在。
一共有四种结果:
forward
backward
invalid
both
首先将两个子串连接,判断连接后的子串是否正好是与总串的最长公共子序列
若是,则forward验证
然后反转总串,再判断连接后的子串是否正好是与总串的最长公共子序列
若是,则backward验证
若都不是则不存在这样的车站序列
1、最长公共子序列的结构(问题的最优子结构性质)
2、子问题的递归结构(建立递归关系)
由最优子结构性质可知,要找出X和Y的最长公共子序列可按以下方式递归地进行:
(1)当xm=yn时,找出Xm-1和Yn-1的最长公共子序列。
(2)当xm≠yn时,必须解两个子问题,找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。这两个公共子序列中较长者即为X和Y的一个最长公共子序列。
数据结构1:用C[i][j]记录序列和的最长公共子序列的长度
数据结构2:用B[i][j]记录当前序列和的来源
(1)若C[i][j]由C[i-1][j-1]得到,B[i][j] = 1
(2)若C[i][j]由C[i-1][j]得到,B[i][j] = 2
(3)若C[i][j]由C[i][j-1]得到,B[i][j] = 3
我的代码:
# encoding :utf-8 def lcs(k, l, slist, B): if k == 0 or l == 0: return if B[k][l] == 1: res.append(slist[k]) lcs(k - 1, l - 1, slist, B) elif B[k][l] == 2: lcs(k, l - 1, slist, B) else: lcs(k - 1, l, slist, B) def lcs2(k, l, sslist, B): if k == 0 or l == 0: return if B[k][l] == 1: res.append(sslist[k]) lcs2(k - 1, l - 1, sslist, B) elif B[k][l] == 2: lcs2(k, l - 1, sslist, B) else: lcs2(k - 1, l, sslist, B) while 1: fo = 0 ba = 0 s = raw_input() a = raw_input() b = raw_input() ss = s[::-1] slist = list(s) slist.insert(0, '0') ablist = list(a + b) ablist.insert(0, '0') sslist = list(ss) sslist.insert(0, '0') C = [([0] * len(ablist)) for i in range(len(slist))] B = [([0] * len(ablist)) for i in range(len(slist))] CC = [([0] * len(ablist)) for i in range(len(sslist))] BB = [([0] * len(ablist)) for i in range(len(sslist))] # print C # print slist # print ablist res = [] for i in range(1, len(slist)): for j in range(1, len(ablist)): if slist[i] == ablist[j]: C[i][j] = C[i - 1][j - 1] + 1 B[i][j] = 1 elif C[i - 1][j] > C[i][j - 1]: C[i][j] = C[i - 1][j] B[i][j] = 3 else: C[i][j] = C[i][j - 1] B[i][j] = 2 lcs(len(slist) - 1, len(ablist) - 1, slist, B) print ablist print res if res[::-1] == ablist[1:]: fo = 1 res = [] for i in range(1, len(sslist)): for j in range(1, len(ablist)): if sslist[i] == ablist[j]: CC[i][j] = CC[i - 1][j - 1] + 1 BB[i][j] = 1 elif CC[i - 1][j] > CC[i][j - 1]: CC[i][j] = CC[i - 1][j] BB[i][j] = 3 else: CC[i][j] = CC[i][j - 1] BB[i][j] = 2 lcs2(len(sslist) - 1, len(ablist) - 1, sslist, BB) print res if res[::-1] == ablist[1:]: ba = 1 if fo == 1 and ba == 0: print "forward" elif fo == 0 and ba == 1: print "backward" elif fo == 1 and ba == 1: print "both" else: print "invalid"别人的代码:
while 1: a = raw_input() b = raw_input() c = raw_input() e = len(b) if (b in a) & (c in a): bl = a.find(b) if bl + e <= len(a) - 1: if a.find(c, bl + e) > 0: res = 1 else: res = 0 else: res = 0 else: res = 0 d = a[::-1] if (b in d) & (c in d): bl = d.find(b) if bl + e <= len(a) - 1: if d.find(c, bl + e) > 0: res += 2 else: res += 0 else: res += 0 else: res += 0 if res == 0: print'invalid' if res == 1: print'forward' if res == 2: print'backward' if res == 3: print'both'看了人家的代码才体会到什么是差距,人家的代码简洁而又漂亮。这里再恶补一下find函数是怎么用的,发现没有,有了find函数,根本就不需要写求解最长公共子序列的函数了…
函数原型:s.find(str, pos_start, pos_end)