对称字符串问题(详细解答!)

对称字符串问题(详细解答!)

本题原题目来自于蓝桥杯的“密码脱落”问题,想见原题请自行搜索。

在此概括一下题目大意:给出一个字符串,求最多添加多少个字符,能让该字符串变为对称字符串。


解题主要思路

我们首先从该字符串的两端开始,依次比较。如果发现相等,皆大欢喜,两个箭头都往中间移动一位。
这里写图片描述
如果发现不等,这时候的问题就出现了。我们该从哪边补全字符串,才能使添加的字符串最少呢?解决这个问题的办法就是——都试一下,哪个最小就走哪边。
这里写图片描述
我们就拿上图的数字作为例子

① 在右边添加一个和左边指针一样的值

这里写图片描述

然后再将两个指针同时向中间移动一步,比较下一个值
这里写图片描述
但是在实际算法中,我们想要实现这个过程却非常简单,只需要左边指针移动,右边指针不移动就能实现这个效果。每继续这么一个操作,我们就记录一下,添加了一个字符串。这时,我们已经添加了1个字符了
这里写图片描述
然后再继续比较,就会发现已经是个对称字符串了。

② 在左边添加一个和右边指针一样的值

这里写图片描述
然后再将两个指针同时向中间移动一步,比较下一个值。
这里写图片描述
同理,我们实现算法时,只需要将右边指针移动,左边指针不移动就行了。
这里写图片描述
同理,每进行这么一个操作,我们记录一下,已经添加了1个字符了

当我们在继续比较的时候发现这两个字符还不相等。

于是我们再分两种情况,从左边添加字符,和从右边添加字符,发现都要添加一个字符才能满足对称,因此,这时我们已经添加了2个字符了。

③ 取①,②中值最小的

则发现最少需要添加一个字符,就能让它变为对称字符串

总结

大家可以发现这是一个递归的操作,逐次比较,发现相同就同时向中间移动一位,不同就分两种情况讨论,取最小的。

代码

相信大家根据以上的描述,应该已经会自己完成代码部分了。但是在这里,我们介绍一种用二维数组的方法来解决这个问题。

先砸出代码

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <windef.h>
#include <string.h>
#define Max 1000

int main()
{
    char arr1[Max];
    char arr2[Max];
    char arr[Max][Max];
    int i, len, j = 0;

    gets(arr1);
    len = strlen(arr1);

    for(i = len-1; i >= 0; i--, j++)
    {
       arr2[j] = arr1[i];
    }

    arr2[len] = '\0';
   for(i = 0; i <= len; i++)
    {
        arr[i][0] = 0;
    }
    for(j = 0; j <= len; j++)
    {
        arr[0][j] = 0;
    }
    for(i = 1; i <= len; i++)
    {
        for(j = 1; j <= len;j ++)
        {
            if(arr1[i-1] == arr2[j-1])
            {
                arr[i][j] = arr[i-1][j-1] + 1;
            }
            else
            {
                arr[i][j] = max(arr[i-1][j] , arr[i][j-1]);
            }
        }
    }
    printf("%d\n", len-arr[len][len]);

    return 0;
}

代码讲解

在代码中,我们定义了两个字符串,分别用来存储这个字符串和这个字符串倒过来的样子,和一个二维数组(本来应该定义为int类型的更好理解,但是int会溢出,char不会,char其实也可以用来存储数字)
随后我们观察一下这个二维数组存储值的规律:arr[ i ] [ j ]存储的值取决于这个字符串第i个值和倒数第j个值是不是相等,如若相等,这个值就等于arr[ i-1 ] [ j-1 ]的值+1,如果不等,就等于arr[ i-1 ][ j ]和arr[ i ][ j-1 ]中较大的那个。先不用理解,记住就好了。

我们先尝试一下输入ABCA字符串,这个二维数组的内容是什么。
哈哈
我们乍一眼看过去会很难发现这个二维数组的规律。我们先斜着观察,假如这个字符串的值是ABBA,那么最中间的那条斜着的值应该是1234,而不是1123。
为什么ABCA中是1123呢?
因为在比较第二个值和倒数第二个值的时候(也就是B和C),发现这两个值不相等了,就将此处的值保持不变(因为最后的结果是用len 减去这个值,所以这个值越小,需要添加的字符就越多)

这时候我们再观察arr[3][2]和arr[2][3],发现两个字符相等,于是就都+1。然后在arr[3][3]的时候再取最大的值(和前面讲到的取①②最小的是一个道理)。然后再继续比较,直到最后得出答案。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值