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

83 阅读3分钟

找出最长的神奇数列

学习计划:

在复习动态规划中子序列问题的过程中,我选择了一道类似的简单题目来练习。虽然是简单题,但其重要性不容小觑,能够巩固基础知识(毕竟 哥们只会简单题)。希望通过这道题的练习,深化对动态规划的理解,为以后解决更复杂的问题打下坚实的基础。

题目解析:

我们需要找出一个由数字 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了. 有问题可以一起讨论.

相似的题目类型:

674. 最长连续递增序列 - 力扣(LeetCode)

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 "";

    }