PepperLa‘s Stringfang(详细解析+实现方法+代码)

PepperLa loves strings.His desire for strings is infinite, but his storage is limited.

There is a method to compress strings. A substring whose characters are all the same and are all lower case letters could be compressed into one character plus one hexadecimal number which represents character’s counting. (numbers over ten are represented in upper case letters) Here a substring is a string could be obtained by deleting several characters from the begin and end.

For example,the string is “aaacccccccccc”. compression operations could replace “aaa” with “a3”, and repalce “cccccccccc” with “cA”. So the compressed string becomes “a3cA”. And if you choose 17 ‘a’, you could compress it to “a11”, but you can’t compress “11” to “12”.

The method allows lossy compression which means you can miss at most 1 character before you compressing the string. It should be noted that after deleting one character the string is actually not successive.(See sample testcase for details)

You can do any times or even zero times of compression operations, find the shortest compressed string, if there are multiple answers, output the one with minimal lexicographic order.

Input
There are multiple test cases in this problem.

For every test case, the input contains one line, the given string.

The input guarantees that strings contains only lower case letters

For each test case, 1<string.length≤106, ∑length≤5×106
Output
For each test case, output a single line contains the answer string.

Example
Input
aaacccccccccc
aaabaaa
Output
a2cA
a3a3
Note
In first string, if you choose to miss one ‘a’, the string becomes “aacccccccccc” and compressed string is “a2cA”.

In second string, if you choose to miss one ‘b’, the string becomes something like “aaa aaa” the answer is not “a6” but “a3a3”.

题意:删除一个字符,使压缩后的字符串后的长度最短,如果有多组答案则输出字典序最小的一个
压缩字符串后要用16进制表示。
思路:因为要使字符串尽可能的短,我们来列举一下删除一个字符能使字符变短的三种情况
1.连续相同的字符数目为一,例如a删除一个a后,由a变无,长度减一;
2.连续相同的字符数目为二,例如aa删除一个a后,由a2变a,长度减一;
3.连续相同的字符数目为16的次方,如连续相同a数目为16,由a10变为aF,长度减一。
找到这三种情况还要判断一下删除后能否使字典序变小:
只有第一种情况下,满足此字符后面没字符或者此字符比下一个字符字典序大的情况,删除此字符能使字典序变小,其余的缩短字符的各种情况,都会使字典序变大,你们可以自己举例判断一下。

怎么才能满足条件:
1 如果我们找到第一个可以使长度减小,并能使字符串的字典序变小的地方,就删掉这个地方的字符。
2.如果我们找不到满足第一种的地方,我们要找最后一个可以使字符减小,但使字典序变大的地方,这样才能满足它字典序尽可能短
3.如果上述两种都没有的话,我们就删除第一个地方的一个字符,就能使字典序最小

实现方法:
第一种和第三种都很好写,只说一下可以使长度减小但使字典序变大的情况:
我们不确定是否要删除这种地方的字符。我们遇见一个种字符,就先将它存入记录答案的数组,并用一个变量b更新标记它在数组中的位置。如果我们遇不见第一种字符,我们就使b标记的位置的字符数减一,代表删除此处的一个字符。

实现代码

#include <bits/stdc++.h>
using namespace std;
struct node 
{
    char x;                                         //记录字符
    int y;                                          //记录字符个数
} t;
void p(int x)                                       //16进制输出
{
    if (x <= 1) return;
    printf("%X", x);
}
node ans[5000004];                                  //存入答案的数组
map<int, int> q;                               
int main() 
{
    char s[5000005], a;
    int i, n, j, k, c, b;
    for (i = 16; i < 5000006; i *= 16)              //利用map标记16的次方
    {
        q[i] = 1;
    }
    while (~scanf("%s", s)) 
    {
        int flag = 1;                               //flag=1代表还没有找到第一种和第二种
        c = 0;                                      //遇见第一种使flag=0,不再进行判断寻找
        n = strlen(s);                              //还没遇见第一种,遇见第二种时flag=2;
        a = s[0];
        j = 1;
        for (i = 1; i < n; i++)    
        {
            if (s[i] == a) 
            {
                j++;
            } 
            else 
            {
                t.x = a;
                t.y = j;
                if (j == 1 && flag) 
                {
                    if (a > s[i])                   //第一种情况,字符只有一个,删完不用存入数组
                        flag = 0;         
                    else                            //第二种情况
                    {
                        b = c;
                        ans[c++] = t;
                        flag = 2;
                    }
                } 
                else if ((q[j] || j == 2) && flag) //第二种情况
                {
                    b = c;
                    ans[c++] = t;
                    flag = 2;
                } 
                else
                    ans[c++] = t;
                j = 1;
                a = s[i];
            }
        }
        t.x = a;
        t.y = j;
        if (j == 1 && flag)                         //第一种情况
        {
            flag = 0;
        } 
        else if ((q[j] || j == 2) && flag)          //第二种情况
        {
            b = c;
            ans[c++] = t;
            flag = 2;
        } 
        else
            ans[c++] = t;
        if (flag == 1)                              //第三种情况
        ans[0].y--;
        for (i = 0; i < c; i++)                     //答案输出
        {
            if (flag == 2 && i == b) 
            {
                if (ans[i].y > 1) 
                {
                    printf("%c", ans[i].x);
                    p(ans[i].y - 1);
                }
            } 
            else 
            {
                printf("%c", ans[i].x);
                p(ans[i].y);
            }
        }
        printf("\n");
    }
}

不知道有没有更好的解题方法,希望各位大佬多指点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值