思路:
遍历一次, 从前到后记录,由于目标是删除一个,然后删除前导0或者前导1, 所以如果我们遇到前导是两个或者两个以上, 我门直接删除即可,否则的话,就去遍历后面的寻找个数大于一个的数字,然后删除其中一个,如果找不到, 则直接删除即可,具体看代码注解:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+6;
int t;
char s[maxn];//输入的字符串
int a[maxn]; //转换成int类型的存储到a数组内 ,方便处理
int sum[maxn];// 记录的连续的个数,例如1100111 则sum数组记录2 2 3, 连续的个数;
int bol[maxn];// 用来记录大于等于2两个连续的数字在sum内的下标,如果没有这个就会超时。
int main()
{
cin >> t;
while(t --)
{
int n;
cin >> n;
scanf(" %s",s+1);
for(int i = 1; i <= n; i ++)//这里就是转换为int类型存储到a数组
{
a[i] = s[i]-'0';
}
a[n+1] = -1; //这里是为了方便下面的for循环来提出最后一个连续的个数,可以自己去掉输出一下sum数组,就知道了
int z = 1; // sum数组的计数器
int ji = 0; //连续数字的计数器
int jiji = 1; //大于等于两个相同字符的数组bol的下标
for(int i = 2; i <= n+1; i ++)
{
if(a[i] == a[i-1]) //如果与前一个字符相同,则加一
{
ji ++;
}
else
{
sum[z] = ji+1; //如果与前一个不同,则记录下前面相同的个数
if(sum[z] >= 2) //如果个数大于等于两个则将下标放入数组bol
{
bol[jiji] = z;
jiji ++;
}
ji = 0; //归零
z ++;
}
}
// for(int i = 1; i < z; i ++) //这里可以输出试试 可以查看sum数组
// {
// cout << sum[i] << " ";
//
// }
// cout << endl;
int ans = 0;
int left = 1; //当作下标来表示bol数组
for(int i = 1; i < z; i ++)
{
if(sum[i] > 1)//如果前导的大于等于二 则直接输出即可
{
ans ++;
}
else
{
while(bol[left] < i && left < jiji)//如果bol记录的数字已经被输出了 ,则后移下标left
{
left ++;
}
if(left < jiji)//如果bol数组还存在数字大于等于2
{
sum[bol[left]] --; //则将sum数组个数减一
if(sum[bol[left]] == 1)//如果等于一 则bol数组向下一个走
{
left ++;
}
ans ++;
}
else
{
i ++;ans ++;//如果全都是一个字符,则一下跳两个不同的字符
}
}
}
cout << ans << endl;
}
return 0;
}
师会长,没讲明白的问我啊。