279. 最长连续交替的01子串问题 | 豆包MarsCode AI刷题

112 阅读3分钟

问题描述

小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子串的长度。每次操作是将字符串分为两部分,分别翻转后再拼接。

关键点

翻转操作:每次操作是将字符串分为两部分,分别翻转后再拼接。

解题思路

  1. 暴力法:我们可以尝试所有可能的分割点,对每个分割点进行翻转操作,然后计算拼接后的字符串中最长的交替子串长度。这种方法的时间复杂度较高,但可以作为初步思路。
  2. 优化思路:观察翻转操作的特性,实际上我们只需要考虑字符串的某些特定分割点,而不是所有分割点。例如,我们可以考虑字符串的对称性,或者某些特定的模式(如 "0101" 或 "1010")。

数据结构选择

  • 字符串:用于存储和操作二进制串。
  • 在C++中,我们可以很方便的使用string类型的成员函数substr()函数实现对原串的分隔,再使用reverse()函数对函数进行翻转,最后再将其拼接即可。

算法步骤

  1. 遍历所有可能的分割点:对于每个分割点,将字符串分为两部分,分别翻转后再拼接。
  2. 计算拼接后的字符串中最长的交替子串长度:遍历拼接后的字符串,记录当前交替子串的长度,并更新最大长度。
  3. 返回最大长度

优化

其实对于被分割的两个字符串,其内部的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;
}

时间复杂度

最终我们的代码使用了一个二重循环,达到了 O(n2)O(n^2) 的时间复杂度,对于通过本题来说已经足够了。