leetcode
leetcode 2051 ~ 2100
最长理想子序列

最长理想子序列

难度:

标签:

题目描述

代码结果

运行时间: 289 ms, 内存: 16.4 MB


// Problem description:
// Given a string s and an integer k, find the length of the longest ideal subsequence in s.
// A subsequence is ideal if the absolute difference between the positions of every two adjacent characters in the subsequence is less than or equal to k.

import java.util.stream.IntStream;

public class LongestIdealSubsequenceStream {
    public int longestIdealString(String s, int k) {
        int[] dp = new int[26];

        s.chars().forEach(c -> {
            int pos = c - 'a';
            int maxLength = IntStream.rangeClosed(Math.max(0, pos - k), Math.min(25, pos + k))
                                   .map(i -> dp[i])
                                   .max()
                                   .orElse(0);
            dp[pos] = maxLength + 1;
        });

        return IntStream.of(dp).max().orElse(0);
    }
}

解释

方法:

该题解采用动态规划的方式来求解最长理想子序列的长度。dp数组的每个元素dp[ord(c)]表示以字符c结尾的最长理想子序列的长度。遍历给定字符串s中的每个字符c,计算以该字符结尾的最长理想子序列长度,方法是查看在字符c的ASCII码基础上前后k范围内的所有字符所记录的最长子序列长度,找到最大值后加1即为以字符c结尾的最长理想子序列的长度。最后,返回dp数组中的最大值即可。

时间复杂度:

O(n*k)

空间复杂度:

O(1)

代码细节讲解

🦆
在动态规划解法中,dp数组为何选择长度为128,这是否与ASCII码的范围有关?
是的,dp数组选择长度为128是因为ASCII码标准定义了128个字符(从0到127),包括控制字符和可打印字符。通过将dp数组的大小设置为128,可以直接使用字符的ASCII值作为索引,方便对每个可能的字符进行操作和记录。这样的设计简化了代码实现,同时确保了对所有ASCII字符的覆盖,从而不受限于特定类型的字符,如只有小写字母或只有数字等。
🦆
在计算dp[ord_c]时,为什么是取前后k个ASCII范围内的dp值的最大值加1?这样做的主要逻辑是什么?
在该问题中,理想子序列允许序列中的字符在ASCII码表中相差至多k。因此,对于每个字符c,我们查找在其ASCII值前后k的范围内(即ord(c)-k到ord(c)+k)的所有字符对应的最长子序列长度,取这些长度的最大值再加1,即可得到以字符c结尾的最长理想子序列的长度。这样做的主要逻辑是利用已知的子问题(较短的理想子序列的长度)来解决更大的问题(以当前字符结束的理想子序列的长度),这是动态规划方法的核心思想。
🦆
该算法在处理字符时是否考虑了所有可能的字符(包括非小写字母)?如果是,这样做是否有潜在的问题或优点?
是的,该算法通过使用大小为128的dp数组,覆盖了所有ASCII字符,包括控制字符、数字、大写字母、小写字母等。这种做法的优点在于算法的通用性和适用性更广,不受具体字符类型的限制。然而,这也可能带来潜在的问题,比如包括非可打印字符可能会对实际应用造成困扰,因为在某些情况下,这些字符可能不被期望出现在理想子序列中。
🦆
在实际代码实现中,为什么选择了range 'ord_c - k: ord_c + k + 1',这里的边界处理(比如当ord_c - k < 0或ord_c + k > 127时)是如何确保不会出现错误的?
在Python中,列表切片操作可以自动处理边界问题。即如果索引超出了列表的开始或结束,Python会返回从开始到结束的有效切片。例如,如果ord_c-k小于0,切片会从索引0开始;如果ord_c+k超过127,切片会在索引127结束。这种特性使得代码能够在不进行额外边界检查的情况下正常运行,简化了代码的实现。

相关问题