给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?
输出需要删除的字符个数。
import sys def min_palindrome(s): st = s[::-1] if len(s) <= 1: return 0 dynamic = [[0]*(len(s)+1) for i in range(len(s)+1)] for i in range(1, len(s)+1): for j in range(1, len(s)+1): if st[i-1] == s[j-1]: dynamic[i][j] = 1 + dynamic[i-1][j-1] else: dynamic[i][j] = max(dynamic[i-1][j],dynamic[i][j-1]) return len(s)-dynamic[-1][-1] for line in sys.stdin: print(min_palindrome(line.strip()))
""" 题目:给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?输出需要删除的字符个数。 突破口:碰到回文串,马上想到reverse。而对于回文串最长,可以考虑最长公共子序列。因此发现对原始串与reverse后的串寻找LCS,可以得到题解。 算法: 1. 构造reverse函数 2. 构造LCS函数 3. main函数求解,ret = 原字符串长度-lcs """ import sys def LCS(s1, s2): row = col = len(s1) dp = [[0 for _ in range(col+1)] for _ in range(row+1)] for i in range(1, row+1): for j in range(1, col+1): if s1[i-1] == s2[j-1]: dp[i][j] = dp[i-1][j-1] + 1 else: dp[i][j] = max(dp[i-1][j], dp[i][j-1]) return dp[row][col] if __name__ == '__main__': for line in sys.stdin: s = line.strip() ret = len(s) - LCS(s, s[::-1]) print(ret)
我用的python,一开妈用的递归,总是超时,后来反应过来要用动态规划,没来得及写完。
后来在错题里重做,总是有一个例子过不去,原来是输入的字符串里可能会有空格……,所以input()得到输入字符串之后要strip()一下。
def func(line): n = len(line) length = [[0 for i in range(n)] for j in range(n)] for i in range(n): length[i][i] = 1 for ll in range(1, n, 1): left = 0 while left + ll < n: right = left + ll if line[left] == line[right]: length[left][right] = 2 + length[left + 1][right - 1] else: length[left][right] = max(length[left + 1][right], length[left][right - 1]) left += 1 return length[0][n - 1] if __name__ == '__main__': while True: try: line = input().strip() n = len(line) print(n - func(line)) except: break
# Python 版本 动态规划求解最长公共子序列 import sys def LST(s1, s2): arr = [] for _ in range(len(s1)+1): arr.append([0]*(len(s2)+1)) for i in range(1, len(s1)+1): for j in range(1, len(s2)+1): arr[i][j] = arr[i-1][j-1]+1 if s1[i-1]==s2[j-1] else max(arr[i-1][j], arr[i][j-1]) return arr[len(s1)][len(s2)] if __name__=="__main__": while True: s = sys.stdin.readline().strip() if not s: break print(len(s)-LST(s, s[::-1]))
差一点就内存超限了额(#手动滑稽)
def lcp(_line):
"""
自己写的
:param _line:
:return:
"""
_len = len(_line)
if _line is None or _len == 0: # 处理特殊值
return 0
dp = [[0] * (_len + 1) for i in range(_len + 1)] # 动态规划
for i in range(_len): # 遍历求字符串与逆序的最大公共子序列
for j in range(_len):
if _line[i] == _line[_len - 1 - j]:
dp[i + 1][j + 1] = dp[i][j] + 1
else:
dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1])
return dp[_len][_len]
if __name__ == '__main__':
while True:
_line = sys.stdin.readline().strip()
if not _line:
break
_res = lcp(_line)
print(len(_line) - _res)
include<iostream> #include<string> using namespace std; const int MAX_LENGTH = 1002; int dynamic[MAX_LENGTH][MAX_LENGTH]; int min_palindrome(string s) { if(s.length() <= 1) return 0; for(int i=0; i<s.length(); ++i) { dynamic[i][i] = 0; } for(int l=2; l<=s.length(); ++l) { for(int s_ind=0; s_ind<=s.length()-l; ++s_ind) { if(s[s_ind] == s[s_ind+l-1]) dynamic[s_ind][s_ind+l-1] = s_ind+1<=s_ind+l-2 ? dynamic[s_ind+1][s_ind+l-2] : 0; else dynamic[s_ind][s_ind+l-1] = 1 + min(dynamic[s_ind+1][s_ind+l-1], dynamic[s_ind][s_ind+l-2]); } } return dynamic[0][s.length()-1]; } int main() { string s; while(cin >> s) { cout << min_palindrome(s) << endl; } }
import sys def min_palindrome(s): if len(s) <= 1: return 0 dynamic = [[0] * len(s)] * len(s) for l in xrange(2, len(s)+1): for s_ind in xrange(0, len(s)+1-l): if s[s_ind] == s[s_ind + l-1]: dynamic[s_ind][s_ind + l-1] = 0 if s_ind+1>s_ind + l-2 else dynamic[s_ind+1][s_ind + l-2] else: dynamic[s_ind][s_ind + l-1] = 1 + min(dynamic[s_ind+1][s_ind + l-1], dynamic[s_ind][s_ind + l-2]) return dynamic[0][len(s)-1] for line in sys.stdin: print min_palindrome(line.strip())
import sys try: while True: s = sys.stdin.readline().strip() if s == "": break strchar = list(s) length = len(strchar) dp = [[0]*length for i in range(length)] for j in range(length): #确定dp矩阵 次对角线的值。 dp[j - 1][j] = 0 if strchar[j-1]==strchar[j] else 1 for i in range(j-2, -1, -1):#i的取值范围为关键,递减从j-2到0 #print i,j,"===" #根据次对角线的值,计算次次对角线的值, #若是前后匹配s[i]==s[j],如abcda中的第一个a与最后一个a匹配, #那么只需要计算s[i+1]与s[j-1]之间的值了,如bcd字符串中需要进行比较的值 #否则,计算min(dp[i+1][j], dp[i][j-1])+1 #如,计算abcde,计算abcd与bcde,各自的dp值,在最小的方法上+1. if strchar[i] == strchar[j]: dp[i][j] = dp[i+1][j-1] else: dp[i][j] = min(dp[i+1][j], dp[i][j-1])+1 # for p in dp: # print p print dp[0][-1] except: pass
s = "abcda" strchar = list(s) length = len(strchar) dp = [[0]*length for i in range(length)] for j in range(length): dp[j - 1][j] = 0 if strchar[j-1]==strchar[j] else 1 for i in range(j-2, -1, -1): print i,j,"===" if strchar[i] == strchar[j]: dp[i][j] = dp[i+1][j-1] else: dp[i][j] = min(dp[i+1][j], dp[i][j-1])+1 for p in dp: print p