zoukankan      html  css  js  c++  java
  • T4 字符串的修改 题解

    有 A=a1a2a3„am,B=b1b2b3„bn 两个字符串(均为小写字母)现在要通过以下操作将 A
    或 A 的一个后缀修改为 B:
    1. 删除 删除掉 A 中的某一个字符。
    2. 添加 将某一个字符添加到 A 中任意位置。
    3. 替换 将 A 中某一字符替换为另一个。
    求出最小操作次数
    第一行为字符串 A。第二行为字符串 B(长度均不超过 1000)。
    题目描述很有让人爆搜的想法啊,看到数据,嗯,绝望了。
    以这种大小明显不是爆搜可以解决的吧,看起来很像dp的样子呢,试试吧(重点我也没想到别的算法)
    之前我看一个大佬的博客,大佬表示只要想通怎么去做就可以了,他每一步是怎么实现的不重要,仔细去想反而会更加迷糊。
    (我上午试图仔细想想,试图把一些奇怪的问题都想出来,但我发现越来越乱,其实只要知道他让我们干什么,我们该怎么干就好了,具体会发生什么我们不需要知道。)
    本来我是在写后缀的,dp[i][j]=a的后i个数要多少步才能变成b的前j个数。
    但是这个代码有点太恶心人了,我脑子有点乱,感觉这不是什么好主意……
    我就改了一下主意:dp[i][j]=a的前i个数要多少步才能变成b的前j个数。
    大家想想啊,虽然这个是前缀,但如果前缀没什么用是不是可以忽略掉,竟然这样的话,代码清晰,思路也清晰就不是事了。
    emm,写完了,但出了一点小问题。
    大家都知道字符串第一个字符的下表是0,竟然是0的话,那么就不能出现什么dp[x-1]之类的东西,会崩掉的。
    这不是很大的事情,但我处理的有些繁琐,导致自己出的一个数据一直过不去,还不知道为啥。
    然后就来了一波操作,让输入的字符串下标整体向后移动了一下。
    减少了奇怪的操作,问题解决了。
    虽然我不知道为什么会有问题,但我知道是哪里出了问题,替代掉它就可以了。
    一些奇怪的问题解决了,接下来是正经的dp了。
    通过前面的说法,dp[i][j]表示a的前i个字符改变成b的前j个字符的次数。
    我们可以得到一个简单好想的状态转化方程,就像新手礼包一样。dp[i][j]=min(dp[i-1][j-1]+bj,min(dp[i-1][j]+1,dp[i][j-1]));
    emm,有点长,同学们可能看不懂,简单解释一下,我们把他分开,变成3部分
    第一部分:dp[i-1][j-1]+bj
    bj的意思是新加进来的两个字符是否相等,相等就抵消了嘛,不想等还要处理……
    这一步还包含替换操作。
    相等的话bj就是0,不相等就是1咯。
    第二部分:dp[i-1][j]+1
    第三部分:dp[i][j-1]+1
    这2部分对应j-1和i-1的情况,我们会发现这两个有个共同点,就是现在的j比刚才的i多1个,所以我们只要在之前的里面再加上一个就可以解决了。
    3个操作都想出来了,该放个代码了
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    #include<cstring>
    using namespace std;
    long long dp[1005][1005],ac,bc,bj;
    char a[1005],b[1005];
    int main()
    {
    	freopen("str.in","r",stdin);
    	freopen("str.out","w",stdout);
    	cin>>a+1>>b+1;
    	ac=strlen(a+1);
    	bc=strlen(b+1);
    	for(int i=1;i<=ac;i++)//dp不初始化,考完两行泪啊。
    	{
    		dp[i][0]=0;
    	}
    	for(int i=1;i<=bc;i++)
    	{
    		dp[0][i]=i;
    	}
    	for(int i=1;i<=ac;i++)//简单和谐的代码
    	{
    		for(int j=1;j<=bc;j++)
    		{
    			if(a[i]==b[j])
    			{
    				bj=0;
    			}else
    			{
    				bj=1;
    			}
    			dp[i][j]=min(dp[i-1][j-1]+bj,min(dp[i][j-1]+1,dp[i-1][j]+1));
    		}
    	}
    	cout<<dp[ac][bc]<<endl;
    	return 0; 	
    }
    

    思路写了这么多,代码只有40行(如果我不是这个码风可能还短),dp这种东西想起来有点难,写起来还是挺好写的。

    附加:奉劝你们不要深究,明白为什么这么写就好,硬要想中间发生了什么会让脑子很乱(可能只有我这样),实在想不明白可以私下问我。看不看的见就随缘吧。

  • 相关阅读:
    Mono的简单例子
    Struts2基础学习(四)—类型转换器和数据校验
    Struts2基础学习(三)—Result和数据封装
    Struts2基础学习(二)—Action
    Struts2基础学习(一)—初识Struts2
    jQuery基础学习(三)—jQuery中的DOM操作
    jQuery基础学习(二)—jQuery选择器
    jQuery基础学习(一)—jQuery初识
    JavaScript基础学习(九)—DOM
    JavaScript基础学习(八)—事件
  • 原文地址:https://www.cnblogs.com/lichangjian/p/12872776.html
Copyright © 2011-2022 走看看