1/22 测试一(STL 模拟 贪心)E.(贪心 通过修改字母和调整顺序使字符串成为回文串)Make Palindrome

1/22 测试一(STL 模拟 贪心)

E.(贪心 通过修改字母和调整顺序使字符串成为回文串)Make Palindrome

A string is called palindrome if it reads the same from left to right and from right to left. For example “kazak”, “oo”, “r” and “mikhailrubinchikkihcniburliahkim” are palindroms, but strings “abb” and “ij” are not.
You are given string s consisting of lowercase Latin letters. At once you can choose any position in the string and change letter in that position to any other lowercase letter. So after each changing the length of the string doesn’t change. At first you can change some letters in s. Then you can permute the order of letters as you want. Permutation doesn’t count as changes.
You should obtain palindrome with the minimal number of changes. If there are several ways to do that you should get the lexicographically (alphabetically) smallest palindrome. So firstly you should minimize the number of changes and then minimize the palindrome lexicographically.
Input
The only line contains string s (1 ≤ |s| ≤ 2·105) consisting of only lowercase Latin letters.
Output
Print the lexicographically smallest palindrome that can be obtained with the minimal number of changes.
Example
Input
aabc
Output
abba
Input
aabcd
Output
abcba

题意:
一个字符串,你可以通过改变其中字母的种类和顺序来使该字符串成为回文串,其中改变字母的种类记为改变次数,调整顺序不记录在内,输出回文串。若存在多种调整的方式,则输出字典序最小的情况。

思路:
用num数组记录每个字母出现的次数, 从字母a开始遍历,若字母数量为偶数,则将他放在首尾各一个,若字母数量为奇数,说明需要将他修改为别的字母,或将别的字母修改成他,这里我们为了使字典序最小,那么应该将大字母改成小字母,由于这里是从a开始遍历的,那么只需要从z开始从前遍历,找到数目为奇数的字母,将其修改为当前字母即可。 需要特殊考虑的是,若字符串为奇数个,那么将有一个单字符放在中间,这个需要额外考虑。
PS:易错点!!!
从后往前遍历的时候,一定要注意判断条件,不能让他遍历超过当前元素。
有一种情况比较特殊,例如aabcc,将aa排序后,排b的时候,从后遍历,无法找到奇数量的字母,而且这个时候放置还没有到达中心,那么这个时候其实是应该将这个奇数个数的字母放在中间位置的,即acbca,若不这样处理,那么就变成了abcba,这样就改变了两次字母了。

#include <iostream>
#include <string>
#include <string.h>
#include <stdio.h>
#define MAXN 200005

using namespace std;

int main()
{
    int num[30] = {0};
    char s[MAXN], ans[MAXN];
    scanf("%s", s);
    int len = strlen(s);
    for(int i = 0; i < len; i++)
    {
        num[s[i] - 'a']++;
    }
    int l = 0;
    for(int i = 0; i < 26; i++)
    {
        if(num[i])
        {
            int k = num[i] / 2;
            while(k--)
            {
                ans[l] = 'a' + i;
                ans[len - 1 - l] = 'a' + i;
                l++;
                num[i] -= 2;
            }
            if(num[i] == 1)
            {
                if((len % 2) && (l == len / 2))
                {
                    ans[l] = 'a' + i;
                    num[i]--;
                }
                else
                {
                    int j = 25;
                    while(num[j] % 2 == 0 && j > i)
                        j--;
                    if(j > i)
                    {
                        num[j]--;
                        ans[l] = 'a' + i;
                        ans[len - l - 1] = 'a' + i;
                        num[i]--;
                        l++;
                    }
                    else
                    {
                        ans[len/2] = 'a' + i;
                        num[i]--;
                    }
                }
            }
        }
    }
    ans[len] = '\0';
    printf("%s\n", ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值