7.以最小插入次数构造回文串

以最小插入次数构造回文串(难度:中等)

比如说如一个s="abcea",算法返回2,插入两个字符="abecba"或者"aebcbea"。如果输入"aba" 那么返回0,本身就是回文串,无需操作

思路分析

	回文串一般都是字符串从中间向两端扩散,构造回文串也是类似的

dp数组定义

	上节课说了:字符串问题一般都是 二维dp
	dp[i][j]:对于字符串s[i...j]最少进行dp[i][j]次操作才能成文 回文串
	i----j ,定义的是区间

base case

	如果想求是整个s的最小插入次数,根据这个定义,也就是求dp[0][n-1]的大小
	同时 base case 也很容易想到,i==j时候,dp[i][j]==0,因为i==j时,s[i...j]就是一个字符,本身就是回文串,所以不需要进行任何操作

状态转移方程

	状态转移方程就是 从小规模的问题 推出 最终大问题的解的答案,从 base case 推导
	
	如果想要计算 dp[i][j]的值,而且假设已经计算出来了子问题dp[i+1][j-1](i,j因为是区间,在逐渐缩小)的值,能不能想办法推出 dp[i][j]?

一种情况 S[i]==s[j]

	if(s[i]==s[j]){  
		//因为已经是回文串了,缩小成子问题
		//i++ ;j--
		dp[i][j]=dp[i+1][j-1];  
	}

另一种情况 S[i]!=s[j]

	if(s[i]!=s[j]){  
		dp[i][j]=dp[i+1][j-1]+2;
	}

正常序列 x b a a b y
发现 x != y
将y插入到x的右边,x插入到y的右边,(实际没修改,只是记录步数)
两步操作,所以+2,然后继续处理 子问题 i+1和j-1的区间[i+1,j-1]

不对,比如下面的两种情况

		只需要插入一个就可以变成回文串

步骤1、做选择,先将s[i..j-1]或者s[i+1..j-1]变成回文串。

怎么做选择呢?
		谁变成回文串,插入的字符少,就选择谁.
		比如上面图2,s[i+1..j]变成回文串的代价小,因为本身就是回文串,根本不需要插入;同理,对于图3,将s[i..j-1]变成回文串的代码小
		然而,如果s[i+1..j]和s[i..j-1]都不是回文串,都至少需要插入一个字符才能变成回文串,所以选择那个都一样

怎么知道s[i+1..j]和s[i..j-1]哪个代价小呢?
回头看看dp数组的定义,不就是变成回文串的 代价吗????所以 取min 就好啦

步骤2、根据步骤一的选择,将s[i..j]变成回文串

		如果在步骤1 中 选择把s[i+1..j]变成回文串,那么在s[i+1..j]右侧插入一个 s[i]一定可以将 s[i..j]变成回文的;
		同理;选择把s[i..j-1]变成回文串,那么在s[i..j-1]左侧插入一个 s[j]一定可以将 s[i..j]变成回文的,

一种情况 S[i]!=s[j]

	if(s[i]!=s[j]){  
		//步骤一选择代价小的
		//步骤二必然要进行一次插入
		dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1;
	}

综合起来状态转移方程

	if(s[i]==s[j]){  
		//因为已经是回文串了,缩小成子问题 //i++ ;j--
		dp[i][j]=dp[i+1][j-1];  
	}
	if(s[i]!=s[j]){  
		//步骤一选择代价小的
		//步骤二必然要进行一次插入
		dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1;
	}

完整代码如下

	//从下至上
	//从左至右
	略
	自己写
posted @ 2021-07-05 23:16  宋佳强  阅读(160)  评论(0编辑  收藏  举报