题意: 现有一个长度为n的01字符串,你可以跳跃选择任意字符组成字符串(需保证相对顺序不变),如果相邻字符互不相同则可以把他们01番置,求最少操作次数使原字符串相邻字符互不相同。
知识点: 动态规划,字符串,思维。
思路: 因为相邻字符串互不相同,则最终结果一定是010101...或者101010...的形式,所以我们可以拿这两个字符串和原字符串比较把需要变换的字符拿出来,得到两个新的字符串命名为c1和c2,接着我们在对c1和c2处理之后看看哪个需要的操作次数小就可以了。
我们得到需要变换的字符串后,想要把他们全部01反置,你就可以从当前位置一直往后找不同字符
比如需要反置的字符串为11010010
则首先获得第一个字符1接着我们找0,找到0在找1,重复这个步骤可以得到第一个子串为101010
接着我们再找第二个,现在这个需要反置的字符串还剩下10,直接作为第二个子串
接着我们提取出来的子串都是相邻字符互不相同的存在,也就是可以直接反置,所以我们反置的最小次数就变成了子串的个数。
接着我们就可以借用动态规划的思想,设置两个变量x0和x1来记录结尾为0的子串个数和结尾为1的子串个数。
那么假设现在x0=1,x1=1,如果接着往后搜索又碰见了1,那么我们就可以把它并在结尾为0的子串身上,这样x0-1,x1+1。而如果没有结尾为0的子串则新开一个结尾为1的子串也就是x1+1。遇见0也是同样的道理。
参考代码:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define endl '\n'
using namespace std;
int main()
{
cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
string s,c1,c2;
cin >> s;
for(int i=0;i<n;i++){
if(s[i]!=('0'+(i&1)))
c1.push_back(s[i]);
else
c2.push_back(s[i]);
}
int x1=0,x2=0,minn;
for(int i=0;i<(int)c1.size();i++){
if(c1[i]=='0'){
if(x1==0)
x2++;
else
x1--,x2++;
}
else{
if(x2==0)
x1++;
else
x1++,x2--;
}
}
minn=x1+x2;
x1=x2=0;
for(int i=0;i<(int)c2.size();i++){
if(c2[i]=='0'){
if(x1==0)
x2++;
else
x1--,x2++;
}
else{
if(x2==0)
x1++;
else
x1++,x2--;
}
}
cout << min(minn,x1+x2) << endl;
}
return 0;
}

京公网安备 11010502036488号