标题:求助一道字符串处理题目
取消只看楼主
RKNO
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2018-9-7
结帖率:80%
已结贴  问题点数:20 回复次数:5 
求助一道字符串处理题目
题目如下:
给定一个长度为n的,只含0和1的字符串。可对该字符串进行如下操作:
把这个这个串截出一部分连续的前缀(长度>=0),一部分连续的后缀(长度>=0),然后将它们水平翻转后,分别连回原串的“尾部”,“首部”。

操作前:     ( a[0] ... a[i] ) a[i+1] ... a[j-1] ( a[j] ... a[n-1] )
操作后:     ( a[n-1] ... a[j] ) a[i+1] ... a[j-1] ( a[i] ... a[0] )
注意: ( 0 <= i < j < n )

然后问:此串的子序列中最长的01010101...或10101010...串的长度是多少?(如果上述操作没有得到更好的答案,可不进行)

输入格式:
一个正整数n(2<=n<=1000000),下一行是1个长度为n只含0和1的字符串。
输出格式:
求得的最长的 01...或10...串的长度。

输入样例:
4
1010
6
100110

输出样例:
4
6

样例解释:
第1个样例不需要进行操作,最长的01或10串就是4
第2个样例(10)01(10) , 把括号中的串翻转后交换得到 (01)01(01)。
tips:分清楚子串和子序列的区别。
搜索更多相关主题的帖子: 字符串 处理 长度 操作 最长 
2018-11-24 20:03
RKNO
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2018-9-7
得分:0 
这题我想了好久,感觉最难的是上限100万的测试数据。。这使很多处理都不好做。。
我发现了把前缀和后缀翻转交换这个操作,和直接把中间部分翻转一下得到的结果是一样的。不知道这个能否简化一部分操作。。
比如(10)01(10),把括号中的翻转交换,和直接翻转括号外的"01"对结果来说是等价的。
2018-11-24 20:08
RKNO
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2018-9-7
得分:0 
回复 3楼 复旦
谢谢你的思路。但你的代码这复杂度肯定要超时的呀,对于每一个i和j都处理一次。
2018-11-25 10:41
RKNO
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2018-9-7
得分:0 
嗯,哪里不明白,我自认为表达很明白了。
还有你说的,求最长的01010...或者101010的长度可以数0和1的个数是什么意思,这个我不是很理解?
2018-11-25 23:32
RKNO
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2018-9-7
得分:0 
哦哦,懂了。谢谢。
2018-11-26 18:03
RKNO
Rank: 1
等 级:新手上路
帖 子:20
专家分:0
注 册:2018-9-7
得分:0 
结贴!!终于磨出来了!!这题放了好久,想不出怎么处理那个超长的字符串。但其实转换思路。并不需要模拟题目所述的操作,我们只需要知道结果就好了。
换个思路来分析:
题目要求的答案是字符串中(经过处理的或未经过处理的)最长的交替01子序列,注意是子序列,不是连续子序列,也不是子串。
也就意味着字符串中只有若干连续的0或者连续的1不起作用。
比方说:010(00)10(11)1,这个01串分别有两个0和两个1连在一起不起作用。这个时候我们尝试用题目的操作把它们拆开,试图让他们起作用。
也就是每个括号中间分开。翻转交换后得到:1(1 0)10(1 0)010 (为了方便理解我没把括号去掉),这样就多了两个字符起作用,maxlen+2。
而实际上,一次翻转交换操作最多可以使maxlen+2而已,可以理解成一次操作最多能使起作用的字符数+2。(忘了说,maxlen代表原串中最长01子序列的长度)
这样,我们只需要扫一遍原串,记录maxlen,同时记录是否有连续的0或1,就可以得出答案
上面的例子是连续的0和1都存在的情况。还有两种情况,一种是只存在连续的0,一种是只存在连续的1,分情况处理就好了。

以下附上通过代码:(不够精简请包涵)
程序代码:
#include <cstdio>
int main(void)
{
    int n;
    while (~scanf("%d\n", &n))//长度为n
    {
        char ch_last, ch_first = getchar();//字符串首位和末位,下面的判断需要
        int cnt = 1, a = ch_first-'0';
        int flag0 = 0, flag1 = 0;//记录字符串中是否有连续的0或1
        for (int i=1; i<n; ++i)
        {
            ch_last = getchar();//逐个字符输入,输入结束时ch_last保存着最后一个字符
            a ^= 1;
            if (ch_last==a+'0')
                cnt++;
            else
            {
                if (!flag0||!flag1)
                {
                    if (a==0) flag1 = 1;
                    else flag0 = 1;
                }
                a ^= 1;
            }
        }
        if (flag0&&flag1)//连续的0和连续的1
            cnt += 2;
        else if (flag0)//只有连续的0
        {
            if (ch_first-'0'||ch_last-'0')
                cnt++;
        }
        else if (flag1)//只有连续的1
        {
             if (!(ch_first-'0')||!(ch_last-'0'))
                cnt++;
        }
        printf("%d\n", cnt);
    }
    return 0;
}

2018-11-27 13:38



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-491520-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 1.193423 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved