找出最长的神奇数列

110 阅读5分钟

问题分析

在这个问题中,给定一个由0和1组成的序列,我们的目标是找出最长的“神奇数列”。所谓“神奇数列”,是指由连续交替的0和1组成的子串,并且该子串长度至少为3。问题要求我们在给定的输入序列中,找到最长的交替子串,并返回该子串。如果有多个符合条件的子串,应该返回最先出现的那个。

关键点

  1. 交替特性:一个“神奇数列”是由0和1交替出现的子串。例如,010101101010 都是交替子串。
  2. 长度要求:为了被认为是“神奇数列”,该子串必须包含至少3个字符。
  3. 输出要求:如果多个神奇数列的长度相同,我们需要输出最先出现的那个。

解题思路

为了找到最长的神奇数列,我们可以使用一次遍历来检查所有可能的交替子串。具体步骤如下:

  1. 初始化变量:我们首先初始化一些变量,包括记录当前交替子串的起始位置和结束位置的leftright,以及记录最长交替子串的maxleftmaxright
  2. 遍历序列:我们遍历整个输入序列,从第二个字符开始。如果当前字符与上一个字符相同,则表示当前交替子串已经结束,此时我们需要检查该子串的长度。如果该子串长度大于之前的最长子串,就更新最长子串的起始和结束位置。然后,重新开始新的子串。
  3. 检查最后一段子串:循环结束后,我们还需要检查最后一个交替子串的长度,并更新最长子串的记录。
  4. 返回结果:根据记录的最长子串的位置,截取该子串并返回。

代码分析

以下是解决该问题的代码实现:

public class Main {

    public static String solution(String inp) {
        int left = 0, right = 0;
        char head = inp.charAt(0);
        int length = 0;
        int maxleft = 0, maxright = 0;

        // 遍历整个输入序列
        for (int i = 1; i < inp.length(); i++) {
            // 如果当前字符和之前的字符相同,表示交替子串结束
            if (inp.charAt(i) == head) {
                // 检查子串长度是否满足条件,并更新最大子串
                if (right - left >= 2) {
                    if (right - left > length) {
                        length = right - left;
                        maxleft = left;
                        maxright = right;
                    }
                }
                // 更新left和right指针,重新开始新的子串
                left = i;
                right = i;
            } else {
                // 否则,继续扩展当前子串
                right = i;
                head = inp.charAt(i);
            }
        }

        // 检查最后一个交替子串
        if (right - left >= 2 && right - left > length) {
            maxleft = left;
            maxright = right;
        }

        // 如果找到了符合条件的神奇数列,返回该子串
        if(maxright - maxleft >= 2) {
            return inp.substring(maxleft, maxright + 1);
        } else {
            return "";
        }
    }

    public static void main(String[] args) {
        // 测试
        System.out.println(solution("0101011101").equals("010101"));
    }
}

代码讲解

  1. 变量初始化leftright 用来标记当前交替子串的起始和结束位置,head 用来记录当前交替子串的第一个字符,maxleftmaxright 用来存储最长交替子串的起始和结束位置,length 用来记录当前最长子串的长度。
  2. 遍历输入字符串:我们从第二个字符开始,逐个检查输入字符串的每个字符。对于每个字符,如果它与前一个字符相同,说明交替序列结束,我们需要计算当前交替子串的长度,若长度大于当前记录的最长子串,则更新最长子串的起始和结束位置。
  3. 最后检查:由于遍历结束时,最后一段交替子串没有被检查,因此在循环外再次检查最后一个交替子串。
  4. 返回结果:最终,我们通过maxleftmaxright来截取并返回最长的交替子串。

时间复杂度

该算法只需一次遍历输入字符串,因此时间复杂度为 O(n),其中n是输入字符串的长度。由于我们仅使用了常数额外空间来存储一些指针和长度信息,因此空间复杂度为 O(1)

示例分析

  1. 输入:"0101011101"

    输出:"010101"

    解析:在这个例子中,最长的神奇数列是 "010101",长度为6。

  2. 输入:"1110101010000"

    输出:"10101010"

    解析:此输入中,最长的神奇数列是 "10101010",长度为8。

  3. 输入:"1010101010101010"

    输出:"1010101010101010"

    解析:该输入本身就是一个完全交替的序列,因此最长的神奇数列即为整个字符串,长度为16。

总结

该问题的核心思想是通过一次遍历来寻找交替子串,并通过记录交替子串的起始和结束位置来确保找出最长的神奇数列。在实现过程中,采用了双指针法,通过维护leftright指针来跟踪当前交替子串的范围,确保能够在O(n)的时间复杂度内解决问题。这种方法不仅高效,而且直观,适合解决类似的字符串匹配问题。