2370-最长理想子序列

Raphael Liu Lv10

给你一个由小写字母组成的字符串 s ,和一个整数 k 。如果满足下述条件,则可以将字符串 t 视作是 理想字符串

  • t 是字符串 s 的一个子序列。
  • t 中每两个 相邻 字母在字母表中位次的绝对差值小于或等于 k

返回 最长 理想字符串的长度。

字符串的子序列同样是一个字符串,并且子序列还满足:可以经由其他字符串删除某些字符(也可以不删除)但不改变剩余字符的顺序得到。

注意: 字母表顺序不会循环。例如,'a''z' 在字母表中位次的绝对差值是 25 ,而不是 1

示例 1:

**输入:** s = "acfgbd", k = 2
**输出:** 4
**解释:** 最长理想字符串是 "acbd" 。该字符串长度为 4 ,所以返回 4 。
注意 "acfgbd" 不是理想字符串,因为 'c' 和 'f' 的字母表位次差值为 3 。

示例 2:

**输入:** s = "abcd", k = 3
**输出:** 4
**解释:** 最长理想字符串是 "abcd" ,该字符串长度为 4 ,所以返回 4 。

提示:

  • 1 <= s.length <= 105
  • 0 <= k <= 25
  • s 由小写英文字母组成

视频讲解 已出炉,欢迎点赞三连,在评论区分享你对这场周赛的看法~

看到子序列相邻就可以往 DP 上想(回顾一下经典题 300. 最长递增子序列 ,它也是子序列相邻)。

字符串题目套路:枚举字符。定义 f[i][c] 表示 s 的前 i 个字母中的以 c 结尾的理想字符串的最长长度。

根据题意:

  • 选 s[i] 作为理想字符串中的字符,需要从 f[i-1] 中的 [s[i]-k,s[i]+k] 范围内的字符转移过来,即

    f[i][s[i]] = 1 + \max_{c=\max(s[i]-k,0)}^{\min(s[i]+k,25)} f[i-1][c]

  • 其余情况,f[i][c] = f[i-1][c]。

答案为 \max(f[n-1])。

代码实现时第一维可以压缩掉。

复杂度分析

  • 时间复杂度:O(nk),其中 n 为 s 的长度。
  • 空间复杂度:O(|\Sigma|),其中 |\Sigma| 为字符集合的大小,本题中字符均为小写字母,所以 |\Sigma|=26。
[sol1-Python3]
1
2
3
4
5
6
7
class Solution:
def longestIdealString(self, s: str, k: int) -> int:
f = [0] * 26
for c in s:
c = ord(c) - ord('a')
f[c] = 1 + max(f[max(c - k, 0): c + k + 1])
return max(f)
[sol1-Java]
1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public int longestIdealString(String s, int k) {
var f = new int[26];
for (var i = 0; i < s.length(); i++) {
var c = s.charAt(i) - 'a';
for (var j = Math.max(c - k, 0); j <= Math.min(c + k, 25); j++)
f[c] = Math.max(f[c], f[j]);
f[c]++;
}
return Arrays.stream(f).max().getAsInt();
}
}
[sol1-C++]
1
2
3
4
5
6
7
8
9
10
11
class Solution {
public:
int longestIdealString(string &s, int k) {
int f[26] = {};
for (char c : s) {
c -= 'a';
f[c] = 1 + *max_element(f + max(c - k, 0), f + min(c + k + 1, 26));
}
return *max_element(f, f + 26);
}
};
[sol1-Go]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func longestIdealString(s string, k int) (ans int) {
f := [26]int{}
for _, c := range s {
c := int(c - 'a')
for _, v := range f[max(c-k, 0):min(c+k+1, 26)] {
f[c] = max(f[c], v)
}
f[c]++
}
for _, v := range f {
ans = max(ans, v)
}
return
}

func min(a, b int) int { if b < a { return b }; return a }
func max(a, b int) int { if b > a { return b }; return a }
 Comments