KMP的next数组, 参考:https://blog.csdn.net/weixin_42102584/article/details/88360361
题目意思:
给出两个0-1字符串s和t,问如何重排s可以使得产生的新字符串中包括最多的连续子串t,输出重排结果。
本题要点:
1、对字符串 t 计算 next 数组, next[lent] 就是字符串t的最长的前后缀, 假如 next[lent] == idx,
坐标范围 [1, idx] 这部分字符串假设是 x
坐标范围 [idx + 1, lent] 这部分字符串假设是 y,
xyyyyyy, 显然此种构造方式是最省字母的让 tt 多次出现的构造方式
2、用len0, len1 来统计字符串s中, ‘0’ 和 '1’出现的次数:
输出 调整后的 字符串 ans 时候,输出1, --len1, 输出0, --len0。
尽量每 lent 个字符,凑够 一个字符串 t。具体输出看代码。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int MaxN = 500010;
char s[MaxN], t[MaxN], ans[MaxN];
int Next[MaxN];
int lens, lent, len0, len1, len;
void calc_next()
{
Next[1] = 0;
for(int i = 2, j = 0; i <= lent; ++i)
{
while(j > 0 && t[i] != t[j + 1])
j = Next[j];
if(t[i] == t[j + 1])
++j;
Next[i] = j;
}
}
void solve()
{
len0 = 0, len1 = 0;
for(int i = 1; i <= lens; ++i)
{
if(s[i] == '0')
++len0;
else
++len1;
}
calc_next();
len = lent - Next[lent]; //字符串 t的最长前后缀长度
for(int i = 1, j = 1; i <= lens; ++i, ++j)
{
if(t[j] == '1' && len1)
{
ans[i] = '1';
--len1;
}else if(t[j] == '0' && len0){
ans[i] = '0';
--len0;
}else{
if(len1)
{
ans[i] = '1';
--len1;
}else{
ans[i] = '0';
--len0;
}
}
if(j == lent)
j = Next[j];
}
printf("%s\n", ans + 1);
}
int main()
{
scanf("%s%s", s + 1, t + 1);
lens = strlen(s + 1), lent = strlen(t + 1);
if(lens < lent)
{
printf("%s\n", s + 1);
return 0;
}
solve();
return 0;
}
/*
101101
110
*/
/*
110110
*/