问题描述
小F是一个好学的中学生,今天他学习了数列的概念。他在纸上写下了一个由 0 和 1 组成的正整数序列,长度为 n。这个序列中的 1 和 0 交替出现,且至少由 3 个连续的 0 和 1 组成的部分数列称为「神奇数列」。例如,10101 是一个神奇数列,而 1011 不是。现在,小F想知道在这个序列中,最长的「神奇数列」是哪一个。你能帮他找到吗?
如果有多个神奇数列,那么输出最先出现的一个。
解题思路
1.明确神奇数列的特点:
数列中的每个字符都与相邻字符交替,即 0 和 1 交替出现;
子串的最短长度为 6(包括至少三个交替单位 01 或 10)。
2.遍历字符串:
从每个字符开始尝试寻找交替子串。
如果当前字符与上一个字符不同,则继续扩展交替子串;
如果当前字符与上一个字符相同,则中断交替子串的查找。
3.记录最长交替子串:
每次中断时,检查当前交替子串是否符合神奇数列的条件(长度 ≥ 6 且交替次数 ≥ 3)。
如果当前子串比已记录的最长子串更长,则更新记录。
注意边界条件4.
如果整个字符串都交替,则在遍历结束时检查当前交替子串是否为最长子串。
代码实现:
public class Main {
public static String solution(String inp) {
int maxLen = 0; // 当前找到的最长神奇数列的长度
int startIndex = -1; // 记录最长神奇数列的起始位置
int n = inp.length(); // 输入字符串的长度
// 遍历字符串中的每个字符,尝试以其为起点寻找神奇数列
for (int i = 0; i < n; i++) {
int currentLen = 1; // 当前神奇数列的长度
int runs = 1; // 当前神奇数列的交替次数
char prevChar = inp.charAt(i); // 当前字符
int j = i + 1;
// 检查从当前位置开始的子串是否交替
while (j < n) {
if (inp.charAt(j) != prevChar) {
// 如果当前字符与前一个字符不同,则继续扩展神奇数列
runs++;
currentLen++;
prevChar = inp.charAt(j);
j++;
} else {
// 如果当前字符与前一个字符相同,则中断神奇数列
break;
}
}
// 如果找到的交替次数 >= 3 且长度符合条件
if (runs >= 3) {
// 更新最长神奇数列的记录
if (currentLen > maxLen || (currentLen == maxLen && i < startIndex)) {
maxLen = currentLen;
startIndex = i;
}
}
}
// 根据找到的起始位置和长度返回最长神奇数列
if (startIndex != -1) {
return inp.substring(startIndex, startIndex + maxLen);
} else {
return ""; // 如果没有找到符合条件的神奇数列,返回空字符串
}
}
public static void main(String[] args) {
System.out.println(solution("0101011101").equals("010101")); // 输出: "010101"
System.out.println(solution("1110101010000").equals("10101010")); // 输出: "10101010"
System.out.println(solution("1010101010101010").equals("1010101010101010")); // 输出: "1010101010101010"
System.out.println(solution("0000110000110100000").equals("1010")); // 输出: "1010"
System.out.println(solution("1011").equals("")); // 输出: "" (没有符合条件的神奇数列)
}
}
个人思考与分析
1.算法的关键点:
核心在于如何动态判断子串的交替性以及长度是否符合要求;
使用 runs 变量统计交替次数,保证逻辑清晰。
2.适用场景:
该算法适用于所有「连续模式匹配」的问题,如寻找最长交替数列、连续递增数列等。
3.个人收获:
通过本题学习了如何动态维护子串属性(长度、交替次数等)。
体会了在多条件问题中优先级的处理方法(长度优先、位置优先)。