找出最长的神奇数列| 豆包MarsCode AI 刷题

216 阅读5分钟

寻找最长神奇数列问题的双指针解法分析

一、问题理解

本题要求在一个由 0 和 1 组成的字符串序列中,找出最长的“神奇数列”。所谓“神奇数列”是指序列中至少由 3 个连续的 0 和 1 交替出现组成的部分数列。如果有多个最长的神奇数列,则输出最先出现的那一个。这就是一个双指针的基础题,思路很清晰,不断遍历,记录最大长度,相邻两字符相等时神奇序列就停止。

我们可以先询问豆包给出一些步骤提示

image.png 然后我们可以写出自己的代码

二、solution函数

public static String solution(String inp) {
    int n = inp.length();
    // 用于记录最长神奇数列的长度,初始化为0
    int maxLength = 0;
    // 用于记录最长神奇数列在原字符串中的起始索引,初始化为0
    int startIndex = 0;

    // 外层循环,从字符串开头开始遍历,i为可能的神奇数列起始位置
    for (int i = 0; i < n; i++) {
        int j = i;
        // 内层循环,从当前起始位置i开始向后遍历
        while (j < n) {
            // 计算当前从i到j的子串长度
            int length = j - i + 1;
            // 如果已经到达字符串末尾或者当前字符和下一个字符相等(可能是神奇数列结束)
            if (j == n - 1 || inp.charAt(j) == inp.charAt(j + 1)) {
                // 检查子串长度是否大于等于3
                if (length >= 3) {
                    // 如果当前子串长度大于已记录的最长神奇数列长度
                    if (length > maxLength) {
                        maxLength = length;
                        startIndex = i;
                    }
                }
                // 将i更新为j,跳过已经检查过的部分
                i = j;
                break;
            }
            j++;
        }
    }
    // 返回最长神奇数列
    return inp.substring(startIndex, startIndex + maxLength);
}

三、算法流程分析

外层循环遍历

  1. 使用for循环,以i作为索引,从0开始遍历整个字符串,直到i < n。这里的i代表了每次尝试寻找神奇数列的起始点。在每次循环中,我们都将重新探索从当前i位置开始的子串是否包含更长的神奇数列。

内层循环探索

  1. 对于每个i,初始化j = i,然后开始while循环。只要j小于n,循环就会持续进行。在这个循环中,我们开始探索从ij这部分子串的特性。
  2. 在循环内部,首先计算当前从ij的子串长度length,计算公式为j - i + 1。这个长度值将用于后续判断是否满足神奇数列的条件。

神奇数列条件判断与更新

  1. 接着,通过if (j == n - 1 || inp.charAt(j) == inp.charAt(j + 1))来检查是否满足神奇数列可能的结束条件。这里有两种情况:一是当j已经到达字符串倒数第二个位置(j == n - 1),因为此时已经无法再检查下一个相邻字符对,所以也需要进行判断;另一种情况是当当前字符inp.charAt(j)和下一个字符inp.charAt(j + 1)相等时,这可能意味着神奇数列的结束(因为神奇数列是 0 和 1 交替出现的)。
  2. 当满足上述结束条件之一时,进一步检查子串长度length是否大于等于3。如果是,说明当前子串有可能是一个神奇数列。
  3. 然后,再检查length是否大于当前记录的最长神奇数列长度maxLength。如果大于,就更新maxLength为当前长度length,并将startIndex更新为当前的起始索引i。这样就找到了一个新的、可能更长的神奇数列。

索引调整与下一轮准备

  1. 当满足神奇数列结束条件后,将i的值更新为j,跳过已经检查过的子串部分,避免重复检查。然后break语句跳出内层while循环,准备进行下一次外层for循环。

结果返回

  1. 最后,当外层for循环结束后,根据找到的最长神奇数列的起始索引startIndex和长度maxLength,使用inp.substring(startIndex, startIndex + maxLength)从原字符串中提取并返回最长的神奇数列。这个子串就是我们最终要找的结果。

四、时间复杂度分析

  1. 外层循环 外层for循环遍历整个字符串,时间复杂度为 O(n)O(n),其中n是字符串的长度。
  2. 内层循环 内层while循环在最坏情况下也会遍历整个字符串(虽然在实际中会提前跳出),但平均来看,它的时间复杂度也是 O(n)O(n)。所以整个算法的时间复杂度是 O(n2)O(n^2)

五、改进思考

  1. 优化方向 可以考虑使用更高效的数据结构或算法来降低时间复杂度。例如在发现连续相同字符时,利用一些数学规律来更快地计算当前子串的长度,而不是每次都通过j - i + 1来计算。
  2. 空间复杂度考虑 当前代码的空间复杂度较低,主要是几个常数级别的变量。但如果采用额外的数据结构来优化,需要注意空间复杂度的平衡,避免因过度使用空间而导致性能下降。 总之,这段代码虽然能够正确地解决寻找最长神奇数列的问题,但在时间复杂度方面还有一定的优化空间,可以通过进一步的分析和改进来提高算法的效率。