问题描述
小C拿到了一个长度为n的二进制串。他发现通过一些操作可以得到一个很有趣的效果。每次操作是将这个字符串按顺序分为两部分,分别将两部分各自翻转后再按原顺序拼接。小C想知道,通过进行任意次数的操作后,能够得到的最长的连续交替01子串的长度是多少。
示例
当前的二进制串是 01001,可以先将其分为 010 和 01 两部分,分别翻转得到 010 和 10,按原顺序拼接后得到 01010,此时最长的连续交替子串是 01010,长度为 5。
测试样例
示例 1:
输入:
s = "10010"
输出:5
示例 2:
输入:
s = "011010"
输出:4
示例 3:
输入:
s = "1010101"
输出:7
示例 4:
输入:
s = "11001100"
输出:2
示例 5:
输入:
s = "111"
输出:1
问题分析
我们来分析一下这个问题,我们需要找到通过任意次数的操作后,能够得到的最长的连续交替01子串的长度。每次操作是将字符串分为两部分,分别翻转后再拼接。
关键点
翻转操作:每次操作是将字符串分为两部分,分别翻转后再拼接。
解题思路
- 暴力法:我们可以尝试所有可能的分割点,对每个分割点进行翻转操作,然后计算拼接后的字符串中最长的交替子串长度。这种方法的时间复杂度较高,但可以作为初步思路。
- 优化思路:观察翻转操作的特性,实际上我们只需要考虑字符串的某些特定分割点,而不是所有分割点。例如,我们可以考虑字符串的对称性,或者某些特定的模式(如 "0101" 或 "1010")。
数据结构选择
- 字符串:用于存储和操作二进制串。
- 在C++中,我们可以很方便的使用string类型的成员函数
substr()函数实现对原串的分隔,再使用reverse()函数对函数进行翻转,最后再将其拼接即可。
算法步骤
- 遍历所有可能的分割点:对于每个分割点,将字符串分为两部分,分别翻转后再拼接。
- 计算拼接后的字符串中最长的交替子串长度:遍历拼接后的字符串,记录当前交替子串的长度,并更新最大长度。
- 返回最大长度。
优化
其实对于被分割的两个字符串,其内部的01交替子串长度并没有发生变化,我们仅仅需要考虑两者连接处产生的01交题串变化即可。
代码
int solution(const std::string& s) {
int ans = 1, n = s.size();
for(int i=0;i<s.size();i++) {
string a = s.substr(0,i), b = s.substr(i,n-i);
reverse(a.begin(),a.end());
reverse(b.begin(), b.end());
a = a + b;
int cnt = 1;
for(int j=1;j<n;j++) {
if(a[j] == a[j-1]) cnt=1;
else cnt ++;
ans = max(ans, cnt);
}
}
return ans;
}
时间复杂度
最终我们的代码使用了一个二重循环,达到了 的时间复杂度,对于通过本题来说已经足够了。