• 完美的代价


    Description

    回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。

    小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。

    交换的定义是:交换两个相邻的字符

    例如: mamad

    第一次交换 ad : mamda;

    第二次交换 md : madma;

    第三次交换 ma : madam (回文!完美!)

    Input

    第一行是一个整数N,表示接下来的字符串的长度(N ≤ 8000)。

    第二行是一个字符串,长度为N.只包含小写字母。

    Output

    如果可能,输出最少的交换次数。

    否则输出Impossible。

    Sample Input

    5
    mamad
    

    Sample Output

    3

     

    #include<stdio.h>
    int main(){
        int n;//代表要输入的字符长度
        int flag=0;//用来标记是否出现了不能匹配的单个字符
        int count=0;// 用来表示最少的交换次数
        int j;//用来盛放n-1的值,仅是为了方便
        char a[8005];//用来盛放字符串
        char t;//用于字符的交换
        scanf("%d",&n);//输入n
        scanf("%s",a);//输入字符串
        j=n-1;
        for(int i=0;i<j;i++){//从下标为i的字符开始,到下标为【j-1】的字符结束,依次固定字符
            for(int k=j;k>=i;k--){//然后从下标为j的字符开始,到下标为i的结束(也就是从后往前)依次与固定的字符作比较
                 if(i==k){//当固定的字符在字符串中没有找到能与它匹配的字符时
                    if(n%2==0||flag){//判断字符串的长度是不是偶数,或者flag的值是否为1
                        printf("Impossible");//如果满足这两个条件中的任意一个,那么这个字符不可能是回文串,输出Impossible结束即可
                        return 0;
                    }
                    flag=1;//如果字符串长度为奇数并且flag的值为0,就将flag赋值为1 ,代表出现了不能匹配的单个字符
                    count+=n/2-i;//count的值加上n/2-i ,n/2-i代表这个单个字符移到字符串中间位置的步数
                }
                else if(a[i]==a[k]){// 如果两个字符相同,即固定的字符在后面找到了与它能匹配的字符
                    for(int b=k;b<j;b++){//将a[k]这个字符移到a[j]的位置
                        t=a[b];//交换过程
                        a[b]=a[b+1];
                        a[b+1]=t;
                        count++;//每交换一次,count自增1
                    }
                    j--;//当固定的字符找到能与它匹配的字符时,j自减1 ,这一步很关键
                    break;// 当固定的字符找到能与它匹配的字符时,跳出第二层循环,第一层循环继续固定下一个字符
                }
            }
        }
        printf("%d",count);//输出count的值
        return 0;
    }

    有几个问题详细解释一下:

     

    一:  如果在回文串里有两个字符相同,我们就暂且称呼这两个字符相互匹配

     

    二:  回文串的特点:如果回文串的长度为偶数,那么回文串里任何一个字符都能找到与之匹配的字符,如果回文串的长度为奇数,那么回文串里只能有一个字符是不能匹配的,大家仔细想一想这个特点。

     

    三:关于代码中第 25 行为何要判断长度是否为偶数:当出现不能匹配的字符时,才会判断这个条件。因为回文串长度为偶数时,任何一个字符都是可匹配的,所以,当字符串中出现不可匹配的字符并且字符长度为偶数时,该字符串一定不是回文串。只有奇数长度的回文串才会出现不可匹配的字符,并且只能有一个不能匹配的字符。

     

    四:关于代码中第 25 行为何要判断 flag 是否为 1:当出现不能匹配的字符时,才会判断这个条件。flag  为  1  代表字符串中已经出现了一个不可匹配的字符,当出现不能匹配的字符并且 flag 为 1 时,代表这个字符串里有两个不可匹配的字符,这与回文串的特点不符,所以该字符串一定不是回文串。

     五:j--与  i++几乎是同时发生的,我们可以这样理解,当字符串中的第一个字符与最后一个匹配好了的话,我们就暂时将他们舍弃,先不管他们,只看他们中间的字符就行,

     

     

     

     

    用几个例子来理解一下过程:

     

    样例一:mamad

     

    1

     首先在这里,代码中的 n 为 5,j 为 4,i 为 0,然后固定下标为 i 的字符,此时 i 为 0,即字符 m,然后从下标为 j 的字符开始,也就是从字符 d 开始,依次向前与 m 作比较,

    字符 d 与字符 m 不相同,继续向前走,

    走到字符 a字符 a 与字符 m 仍然不相同,继续向前走,

    走到字符 m字符 m 与字符 m 相同,

    这时,将第二个 m 移到下标为 j 的字符的地方,也就是字符 d 那里,首先 m 与 a 交换位置,count 自增 1,字符串变为 maamd,然后 m 与 d 交换位置,count 自增1,字符串变为 maadm,交

    换步骤完成这时,j 会自减 1,j 变为 3,同时 break 跳出第二层循环,第一层循环的 i 自增 1,i 变为1

     

    这时继续固定字符,固定下标为 i 的字符,此时 i 为 1,也就是字符 a,然后从下标为 j的字符开始,此时 j 为 3,也就是从字符 d 开始,依次向前与 a 作比较

     

    字符 d 与字符 a 不相同,继续向前走,走到字符 a

     

    字符 a 与字符 a 相同,这时,将第二个 a 移到下标为 j 的地方,也就是字符 d 那里,字符 a与字符 d 交换位置,count 自增 1,字符串变为 madam,交换步骤完成

     

    这时,j 会自减 1,j 变成 2,同时 break 跳出第二层循环,第一层循环的 i 自增 1,i 变为2

     

    这时,继续执行第一层循环,发现 i=j=2,不符合循环条件,跳出循环,输出 count 的值,

     

    count 共自增三次,所以输出 3.

     

    样例二:accc

     

    首先在这里,代码中的 n 为 4,j 为 3,i 为 0,然后固定下标为 i 的字符,此时 i 为 0,即字符 a,然后从下标为 j 的字符开始,也就是从字符 c 开始,依次向前与 a 作比较,

     

    字符 c 与字符 a 不相同,继续向前走,走到字符 c

     

    字符 c 与字符 a 不相同,继续向前走,走到字符 c

     

    字符 c 与字符 a 不相同,继续向前走,走到字符 a

     

    这时,代码中 i 的值与 k 的值相同,字符 a 在字符串中找不到能与它匹配的字符,这时,判断字符长度是否为偶数或者  flag  是否为  1,这时发现字符长度为偶数,那么该字符串一定不是回文串。

     

    样例三:abc

     

    1 

    首先在这里,代码中的 n 为 3,j 为 2,i 为 0,然后固定下标为 i 的字符,此时 i 为 0,即字符 a,然后从下标为 j 的字符开始,也就是从字符 c 开始,依次向前与 a 作比较

    字符 c 与字符 a 不相同,继续向前走,走到字符 b

     

    字符 b 与字符 a 不相同,继续向前走,走到字符 a

     

    这时,发现字符 a 在字符串中找不到能与它匹配的字符,这时,判断字符长度是否为偶数或者 flag 是否为 1,这时发现字符长度为奇数,并且 flag 为初始值 0,这时将 flag 赋值为1,count+=   n/2-i,n/2-i 这里的值为 1,代表将字符 a 移到字符串中间所需要的步骤,注意一下,这时并不用真的将字符 a 移到字符串中间,只需加上所需步骤即可

     

    2

     这时,i 自增 1,变为 1,j 仍为 2,然后继续固定下标为 i 的字符,即固定字符 b,从下标为 j 的字符开始,也就是从字符 c 开始,依次向前与 b 作比较

    字符 c 与字符 b 不相同,继续向前走,走到字符 b

     

    这时,i 的值与 k 的值相同,判断字符长度是否为偶数或者 flag 是否为 1,发现字符长度为奇数,flag 为 1,代表此时已经发现了两个不可匹配的字符,那么该字符串不可能为回文串。

    
    
  • 相关阅读:
    第四章学习小结
    第三章学习小结
    第二章学习小结
    DS第五章学习小结
    DS第四章学习小结
    DS第三章小结
    第五章小结
    第四章小结
    第三章小结
    第二章小结
  • 原文地址:https://www.cnblogs.com/fate-/p/12229800.html
Copyright © 2020-2023  润新知