BJTU1874 01数列
题目:
有一个仅由0和1组成的数列,每次可以选择一对相邻的0和1消除。
求经过多次操作后,这个数列最短为多少?
输入数据:
一行一个长度为𝑛 (1≤𝑛≤105),仅包含 0 和 1的数列。
输出数据:
一行一个数字,表示经过多次操作后最短的数列长度。
样例:
输入1010011,输出1。
解释:
这道题大家一般先想到的都是贪心解决,每一次便利对相邻的两个元素进行判断,再对字符串进行删减。
所以我们先介绍这一种方法。
判断的条件当然就是相邻元素是否一个为0一个为1,此处我选择判断二者的和来判断(有多种方法),然后利用string类型的erase( )函数对字符串进行删改。
但是在这其中要注意字符串的下表也要随着其内容的删减而改变,例如删减了两个元素后,要遍历下一元素,则需要将 i-1 ,如果没有删减,才是 i++ ,这是比较关键的一点。
另外还有一点,尽量减少参数的传递,就算必须要用也尽量用引用解决,一开始就是吃了这个的亏吧可能,一直在函数里写的循环,然后在主函数调用,就一直TLE😭。最后写在了main函数中就AC了。
该种方法代码如下:
#include<cstdio>
#include<algorithm>
#include<string>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<vector>
using namespace std;
string s;
int main()
{
cin>>s;
int i = 0;
while(i < s.size()-1 )
{
if ( s[i] + s[i + 1] == 0x61)
{
s.erase(i, 2);
if(i > 0)
{
i -= 1;
}
if(s.size() < 2)
{
break;
}
}
else
{
i++;
}
}
cout<<s.size()<<endl;
return 0;
}
另外还有一种比较巧妙的解法,仔细思考一下,当这一串字符中有1且有0时,总会有一个1和一个0挨在一起,因此不必考虑字符01的位置关系,简单地通过数量关系就可以解决这个问题。
消去的元素个数,始终都是0,1中个数较小的数量的二倍。即:
min(num0,num1) * 2
因此最后的元素个数,用整体的size减去它即可,代码如下:
#include<cstdio>
#include<algorithm>
#include<string>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<vector>
using namespace std;
string s;
int main()
{
int num1 = 0;
int num0 = 0;
cin>>s;
for(int i = 0;i < s.length();i++)
{
if(s[i] == '0')
{
num0++;
}
else
{
num1++;
}
}
cout<<s.length() - min(num0,num1)*2<<endl;
return 0;
}