给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?输出需要删除的字符个数。
输入描述:
输入数据有多组,每组包含一个字符串s,且保证:1<=s.length<=1000.
输出描述:
对于每组数据,输出一个整数,代表最少需要删除的字符个数。
输入例子:
abcda
google
输出例子:
2
2
其实就是一个最长公用子序列(LCS)问题。
先看看LCS的算法吧
(关于装饰器memo,详情请看记忆体化的装饰器)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ''' 递归版 ''' def rec_lcs(a, b): ''' 思路:从字符串的末尾开始,逐个匹配,不符合的砍掉。 ''' @memo def L(i, j): if min(i, j) < 0: return 0 if a[i] == b[j]: return 1 + L(i - 1, j - 1) return max(L(i - 1, j), L(i, j - 1)) return L(len(a) - 1, len(b) - 1) print rec_lcs('spock', 'asoka')
|
运行过程如图所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ''' 迭代版 ''' def lcs(a, b): ''' cur[i-1]对应递归版本的L(i-1,j) pre[i],pre[i-1]对应递归版本的L(i,j-1)与L(i-1,j-1) ''' n, m = len(a), len(b) pre, cur = [0] * (n + 1), [0] * (n + 1) for j in range(1, m + 1): pre, cur = cur, pre for i in range(1, n + 1): if a[i - 1] == b[j - 1]: cur[i] = pre[i - 1] + 1 else: cur[i] = max(pre[i], cur[i - 1]) return cur[n]
|
运行过程如图所示
原题解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| def lcs(a, b): ''' cur[i-1]对应递归版本的L(i-1,j) pre[i],pre[i-1]对应递归版本的L(i,j-1)与L(i-1,j-1) ''' n, m = len(a), len(b) pre, cur = [0] * (n + 1), [0] * (n + 1) for j in range(1, m + 1): pre, cur = cur, pre for i in range(1, n + 1): if a[i - 1] == b[j - 1]: cur[i] = pre[i - 1] + 1 else: cur[i] = max(pre[i], cur[i - 1]) return cur[n] if __name__=='__main__': while True: try: a=raw_input() A = [i for i in a.strip()] print len(A)-lcs(A,list(reversed(A))) except: break
|
来自腾讯2017暑期实习生编程题