(双序列型动态规划)lintcode困难623 · K步编辑

题目

描述
给出一个只含有小写字母的字符串的集合以及一个目标串,输出所有可以经过不多于 k 次操作得到目标字符串的字符串。

你可以对字符串进行一下的3种操作:

加入1个字母

删除1个字母

替换1个字母

样例

样例 1:
给出字符串 ["abc","abd","abcd","adc"],目标字符串为 "ac" ,k = 1
返回 ["abc","adc"]
输入:
[“abc”, “abd”, “abcd”, “adc”]
“ac”
1
输出:
[“abc”,“adc”]
解释:
“abc” 去掉 “b”
“adc” 去掉 “d”

样例 2:
输入:
[“acc”,“abcd”,“ade”,“abbcd”]
“abc”
2
输出:
[“acc”,“abcd”,“ade”,“abbcd”]
解释:
“acc” 把 “c” 变成 “b”
“abcd” 去掉 “d”
“ade” 把 “d” 变成 "b"把 “e” 变成 “c”
“abbcd” 去掉 “b” 和 “d”

分析

碰到这种题,想到跟之前的一道双序列的动态规划几乎一样,只不过这道题给定了n个字符串,我先用了跟上次一样的方法,只不过多了一个循环,判断每个字符串和目标字符串,动态规划的题还是老样子,先分析最后一步,然后分析转移方程

最后一步

可以进行的操作有替换,删除,增加
替换时将最后一个字符替换成目标字符,就看目标的前n-1项和当前字符串的前n-1项然后再加一即可
删除时,就看目标的前n项和当前字符串的前n-1项即可
增加时,就看目标字符串的前n-1项和当前字符串的前n-1项即可
当最后两个字符串相同时,只需要直到两个字符串的前n-1项
总共有这四种情况,再其中选出需要最少的步骤然后跟k比较,如果小于等于k,那这个字符串就加入答案中

转移方程

状态f[i][j] i表示当前字符串的长度,j表示目标字符串的长度,f[i][j]=min(f[i-1][j]+1删除,f[i][j-1]+1增加,f[i-1][j-1]+1替换,f[i-1][j-1]|最后一个字符相同)

代码部分

1.初始化

状态初始化一个字符串为空的情况,这时的值等于另一个字符串的长度,例如abc和一个空串,至少需要三步

		int strlen=str.size();
		int targetlen=target.size();
		
		vector<vector<int> > f(strlen+1,vector<int>(targetlen+1));
		
		f[0][0]=0;				//初始化  
		for(int i=1;i<=targetlen;i++)	//一个为空一个不为空 
			f[0][i]=i;
		for(int i=1;i<=strlen;i++)
			f[i][0]=i;
2.动规核心

前三种情况先比较选出一个最小值,然后判断最后一个字符是否相等,再去比较最后一种情况

		for(int i=1;i<=strlen;i++)		//动规核心 
		{
    
    
			for(int j=1;j<=targetlen;j++)
			{
    
    
				f[i][j]=min(f[i-1][j],f[i][j-1])+1;	//增删
				f[i][j]=min(f[i][j],f[i-1][j-1]+1);	//替换		 
				
				if(str[i-1]==target[j-1])		//相同时 
					f[i][j]=min(f[i][j],f[i-1][j-1]); 
			}
		} 
		
		return f[strlen][targetlen];
3.循环调用计算每个字符串是否符合要求

将符合要求的字符串储存在答案中

    	int wordlen=words.size();
    	vector<string> ans;
    	
    	for(int i=0;i<wordlen;i++)
    	{
    
    
    		if(mincnt(words[i],target)<=k)
    			ans.push_back(words[i]);
		}
		
		return ans;

完整代码

class Solution {
    
    
public:
	int mincnt(string str,string target)
	{
    
    
		int strlen=str.size();
		int targetlen=target.size();
		
		vector<vector<int> > f(strlen+1,vector<int>(targetlen+1));
		
		f[0][0]=0;				//初始化  
		for(int i=1;i<=targetlen;i++)	//一个为空一个不为空 
			f[0][i]=i;
		for(int i=1;i<=strlen;i++)
			f[i][0]=i;
			
		for(int i=1;i<=strlen;i++)		//动规核心 
		{
    
    
			for(int j=1;j<=targetlen;j++)
			{
    
    
				f[i][j]=min(f[i-1][j],f[i][j-1])+1;	//增删
				f[i][j]=min(f[i][j],f[i-1][j-1]+1);	//替换		 
				
				if(str[i-1]==target[j-1])		//相同时 
					f[i][j]=min(f[i][j],f[i-1][j-1]); 
			}
		} 
		
		return f[strlen][targetlen]; 
		 
	}
	
    vector<string> kDistance(vector<string> &words, string &target, int k) {
    
    
    	int wordlen=words.size();
    	vector<string> ans;
    	
    	for(int i=0;i<wordlen;i++)
    	{
    
    
    		if(mincnt(words[i],target)<=k)
    			ans.push_back(words[i]);
		}
		
		return ans;
    }
};

总结

当前方法在测试样例中只过了百分之80,下一篇分析重复情况,以及ac代码

猜你喜欢

转载自blog.csdn.net/weixin_46035615/article/details/123870395