欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-21 23:40:03
...

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

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

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


解题主要思路

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

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

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

然后再将两个指针同时向中间移动一步,比较下一个值
对称字符串问题(详细解答!)
但是在实际算法中,我们想要实现这个过程却非常简单,只需要左边指针移动,右边指针不移动就能实现这个效果。每继续这么一个操作,我们就记录一下,添加了一个字符串。这时,我们已经添加了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]的时候再取最大的值(和前面讲到的取①②最小的是一个道理)。然后再继续比较,直到最后得出答案。