找出最长的神奇数列
学习计划:
在复习动态规划中子序列问题的过程中,我选择了一道类似的简单题目来练习。虽然是简单题,但其重要性不容小觑,能够巩固基础知识(毕竟 哥们只会简单题)。希望通过这道题的练习,深化对动态规划的理解,为以后解决更复杂的问题打下坚实的基础。
题目解析:
我们需要找出一个由数字 0 和 1 组成的序列中,最长的「神奇数列」。神奇数列的定义是:0 和 1 交替出现,且至少由 3 个连续的 0 和 1 组成的部分序列。例如,10101 是一个神奇数列,而 1011 不是。需要注意的是,如果有多个神奇数列,要求输出最先出现的那个。
首先经典动规五部曲
(1)确定 dp数组含义
(2)确定递推公式
(3)dp数组初始化
(4)确定遍历顺序
(5)打印 dp数组
1、定义 dp数组
首先,我们需要定义一个 dp 数组,dp[i] 表示以位置 i 开始的最长神奇数列的长度。也就是说,i 表示遍历到的字符串位置,从该位置开始所能得到的最长交替子序列的长度。
2、递推公式
递推公式需要根据问题的特点来确定。对于这个问题,如果当前位置的字符与下一个位置的字符不同(即 s[i] != s[i+1]),那么我们可以将当前的长度加一,即 dp[i] = dp[i+1] + 1。如果相同,则从当前位置重新开始计数,长度为 1。
注意我是倒序的,如果是正序应该是(s[i] != s[i-1])dp[i] = dp[i-1] + 1
3、初始化
由于每个字符本身可以看作长度为 1 的子序列,因此我们可以将 dp 数组全部初始化为 1。这表示在最坏的情况下,最长的神奇数列长度为 1。
4、遍历顺序
在这道题中,我们需要输出最先出现的最长神奇数列。如果我们正序遍历字符串,当遇到相同长度的神奇数列时,最后更新的那个起始位置才是最先出现的。然而,为了简化问题,我选择倒序遍历字符串。这样,当我们更新最大长度时,保留的起始位置就是最先出现的那个。 正序的话也许需要维护一个下标跟着循环,我脑子没那么灵光怕错,就用 map 记录对应 max 和下标了.
5、其他条件
题目说至少由 3 个连续的 0 和 1 组成的部分数列称为「神奇数列」,那保证 max >= 3 时才输出结果就行了。
用 c++写的代码,让豆包AI改成Java了.
有问题可以一起讨论.
相似的题目类型:
Java 代码:
public class Main {
public static String solution(String s) {
int[] dp = new int[s.length() + 2];
Arrays.fill(dp, 1);
int max = 0;
Map<Integer, Integer> mmap = new HashMap<>();
for (int i = s.length() - 1; i > 0; i--) {
if (s.charAt(i) != s.charAt(i - 1)) {
dp[i] = dp[i + 1] + 1;
}
if (dp[i] >= max) {
max = dp[i];
mmap.put(max, i);
}
}
if (max >= 3) {
int startIdx = mmap.get(max) - 1;
int length = max;
return s.substring(startIdx, startIdx + length);
}
return "";
}