2022-12-10:给你一个由小写字母组成的字符串 s ,和一个整数 k
如果满足下述条件,则可以将字符串 t 视作是 理想字符串 :
t 是字符串 s 的一个子序列。
t 中每两个 相邻 字母在字母表中位次的绝对差值小于或等于 k 。
返回 最长 理想字符串的长度。
字符串的子序列同样是一个字符串,并且子序列还满足:
可以经由其他字符串删除某些字符(也可以不删除)但不改变剩余字符的顺序得到。
注意:字母表顺序不会循环
例如,‘a’ 和 ‘z’ 在字母表中位次的绝对差值是 25,而不是 1 。

答案2022-12-10:

二维动态规划的解。
N为字符串长度,E为字符集大小,K为差值要求。
时间复杂度O(NE)。
空间复杂度O(N
E)。

一维动态规划从左往右递推版。
N为字符串长度,E为字符集大小,K为差值要求。
时间复杂度O(N*K)。
空间复杂度O(E)。

从左往右递推 + 线段树优化。
N为字符串长度,E为字符集大小,K为差值要求。
时间复杂度O(N * logE)。
空间复杂度O(E)。

代码用rust编写。代码如下:

use std::iter::repeat;
fn main() {
let s = "acfgbd";
let k = 2;
let ans = longest_ideal_string1(s, k);
println!("ans = {}", ans);
let ans = longest_ideal_string2(s, k);
println!("ans = {}", ans);
let ans = longest_ideal_string3(s, k);
println!("ans = {}", ans);
} // 二维动态规划的解
// N为字符串长度,E为字符集大小,K为差值要求
// 时间复杂度O(N*E)
// 空间复杂度O(N*E)
fn longest_ideal_string1(s: &str, k: i32) -> i32 {
let ss: Vec<char> = s.chars().collect();
let n = s.len() as i32;
let mut arr: Vec<i32> = repeat(0).take(n as usize).collect();
for i in 0..n {
arr[i as usize] = ss[i as usize] as i32 - 'a' as i32;
}
let mut dp: Vec<[i32; 27]> = repeat([-1; 27]).take(n as usize).collect();
return f(&mut arr, 0, 26, k, &mut dp);
}
fn get_max<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T {
if a > b {
a
} else {
b
}
} fn get_min<T: Clone + Copy + std::cmp::PartialOrd>(a: T, b: T) -> T {
if a < b {
a
} else {
b
}
} // 数组s中所有的值都在0~25对应a~z
// 当前在s[i...]选择数字, 并且前一个数字是p
// 如果p<26,说明选择的前一个数字是p
// 如果p==26,说明之前没有选过任何数字
// 返回在前一个数字是p的情况下,在s[i...]上选择数字,最长理想子序列能是多长
// dp仅仅是缓存结构,暴力递归改动态规划常规技巧
fn f(s: &mut Vec<i32>, i: i32, p: i32, k: i32, dp: &mut Vec<[i32; 27]>) -> i32 {
if i == s.len() as i32 {
return 0;
}
if dp[i as usize][p as usize] != -1 {
return dp[i as usize][p as usize];
}
let p1 = f(s, i + 1, p, k, dp);
let mut p2 = 0;
if (p == 26 || i32::abs(s[i as usize] - p) <= k) {
p2 = 1 + f(s, i + 1, s[i as usize], k, dp);
}
let ans = get_max(p1, p2);
dp[i as usize][p as usize] = ans;
return ans;
} // 一维动态规划从左往右递推版
// N为字符串长度,E为字符集大小,K为差值要求
// 时间复杂度O(N*K)
// 空间复杂度O(E)
fn longest_ideal_string2(s: &str, k: i32) -> i32 {
let mut dp: [i32; 26] = [0; 26];
let mut c = 0;
let mut l = 0;
let mut r = 0;
let mut pre = 0;
let mut ans = 0;
let ss: Vec<char> = s.chars().collect();
for i in 0..ss.len() {
c = ss[i as usize] as i32 - 'a' as i32;
l = get_max(c - k, 0);
r = get_min(c + k, 25);
pre = 0;
for j in l..=r {
pre = get_max(pre, dp[j as usize]);
}
dp[c as usize] = 1 + pre;
ans = get_max(ans, dp[c as usize]);
}
return ans;
} // 从左往右递推 + 线段树优化
// N为字符串长度,E为字符集大小,K为差值要求
// 时间复杂度O(N * logE)
// 空间复杂度O(E)
fn longest_ideal_string3(s: &str, k: i32) -> i32 {
let ss: Vec<char> = s.chars().collect();
// 0 0 0
// 1(a) 2(b) ... 26(z)
let mut st = SegmentTree::new(26);
let mut c = 0;
let mut pre = 0;
let mut ans = 0;
for i in 0..ss.len() {
// i s.charAt(i)
// a 1
// b 2
// z 26
c = ss[i as usize] as i32 - 'a' as i32 + 1;
// 2 k = 3
// 1 2 3 4 5 6 7
// l = Math.max(c - k, 1)
// r = Math.min(c + k, 26)
pre = st.max(get_max(c - k, 1), get_min(c + k, 26));
ans = get_max(ans, 1 + pre);
st.update(c, 1 + pre);
}
return ans;
} struct SegmentTree {
n: i32,
max: Vec<i32>,
} impl SegmentTree {
fn new(maxSize: i32) -> Self {
let max: Vec<i32> = repeat(0).take(((maxSize + 1) << 2) as usize).collect();
SegmentTree {
n: maxSize + 1,
max,
}
}
fn update(&mut self, index: i32, c: i32) {
self.update0(index, index, c, 1, self.n, 1);
} fn max(&mut self, left: i32, right: i32) -> i32 {
return self.max0(left, right, 1, self.n, 1);
} fn pushUp(&mut self, rt: i32) {
self.max[rt as usize] = get_max(
self.max[(rt << 1) as usize],
self.max[(rt << 1 | 1) as usize],
);
} fn update0(&mut self, L: i32, R: i32, C: i32, l: i32, r: i32, rt: i32) {
if L <= l && r <= R {
self.max[rt as usize] = C;
return;
}
let mid = (l + r) >> 1;
if (L <= mid) {
self.update0(L, R, C, l, mid, rt << 1);
}
if (R > mid) {
self.update0(L, R, C, mid + 1, r, rt << 1 | 1);
}
self.pushUp(rt);
} fn max0(&mut self, L: i32, R: i32, l: i32, r: i32, rt: i32) -> i32 {
if L <= l && r <= R {
return self.max[rt as usize];
}
let mut mid = (l + r) >> 1;
let mut ans = 0;
if (L <= mid) {
ans = get_max(ans, self.max0(L, R, l, mid, rt << 1));
}
if R > mid {
ans = get_max(ans, self.max0(L, R, mid + 1, r, rt << 1 | 1));
}
return ans;
}
}

执行结果如下:


左神java代码

2022-12-10:给你一个由小写字母组成的字符串 s ,和一个整数 k 如果满足下述条件,则可以将字符串 t 视作是 理想字符串 : t 是字符串 s 的一个子序列。 t 中每两个 相邻 字母在字的更多相关文章

  1. [百度]数组A中任意两个相邻元素大小相差1,在其中查找某个数

    一.问题来源及描述 今天看了July的微博,发现了七月问题,有这个题,挺有意思的. 数组A中任意两个相邻元素大小相差1,现给定这样的数组A和目标整数t,找出t在数组A中的位置.如数组:[1,2,3,4 ...

  2. (笔试题)数组A中任意两个相邻元素大小相差1,在其中查找某个数。

    题目: 数组A中任意两个相邻元素大小相差1,现给定这样的数组A和目标整数t,找出t在数组A中的位置.如数组:[1,2,3,4,3,4,5,6,5],找到4在数组中的位置. 思路: 很明显,在数组中寻找 ...

  3. LeetCode 24. Swap Nodes in Pairs(交换链表中每两个相邻节点)

    题意:交换链表中每两个相邻节点,不能修改节点的val值. 分析:递归.如果以第三个结点为头结点的链表已经两两交换完毕(这一步递归实现---swapPairs(head -> next -> ...

  4. JZOJ 2022.02.10【提高组】模拟总结

    \(\text{简要题解}\) \(\text{GDOI2012}\) 的题 不得不说当年的题做起来真的很不爽 整体看起来就是数据结构+博弈论+宽搜+背包dp优化 考场上 \(T1\) 十分钟解决过了 ...

  5. 22.编写一个类A,该类创建的对象可以调用方法showA输出小写的英文字母表。然后再编写一个A类的子类B,子类B创建的对象不仅可以调用方法showA输出小写的英文字母表,而且可以调用子类新增的方法showB输出大写的英文字母表。最后编写主类C,在主类的main方法 中测试类A与类B。

    22.编写一个类A,该类创建的对象可以调用方法showA输出小写的英文字母表.然后再编写一个A类的子类B,子类B创建的对象不仅可以调用方法showA输出小写的英文字母表,而且可以调用子类新增的方法sh ...

  6. JS 从一个字符串中截取两个字符串之间的字符串

    /************************************************* 函数说明:从一个字符串中截取 两个字符串之间的字符串 参数说明:src_str 原串, start ...

  7. 黑马基础阶段测试题:创建一个存储字符串的集合list,向list中添加以下字符串:”C++”、”Java”、” Python”、”大数据与云计算”。遍历集合,将长度小于5的字符串从集合中删除,删除成功后,打印集合中的所有元素

    package com.swift; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; ...

  8. 给定一个字符串str,将str中连续两个字符为a的字符替换为b(一个或连续超过多个字符a则不替换)

    需求:给定一个字符串str,将str中连续两个字符为a的字符替换为b(一个或连续超过多个字符a则不替换) 如: a 不替换 b 不替换  ab 不替换 ba 不替换 aba 不替换  aab 替换为 ...

  9. C语言:根据形参c中指定的英文字母,按顺序打印出若干后继相邻字母,-主函数中放入一个带头节点的链表结构中,h指向链表的头节点。fun函数找出学生的最高分-使用插入排序法对字符串中的字符进行升序排序。-从文件中找到指定学号的学生数据,读入次学生数据,

    //根据形参c中指定的英文字母,按顺序打印出若干后继相邻字母,输出字母的大小与形参c一致,数量由形参d指定.例如:输入c为Y,d为4,则输出ZABC. #include <stdio.h> ...

  10. 2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组)

    2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组) https://www.luogu.com.cn/problem/P2516 题意: 给定字符串 \(S\) ...

随机推荐

  1. python之pyqt5-第一个pyqt5程序-图像压缩工具-小记

    (如想转载,请联系博主或贴上本博地址) 此为学习pyqt5的第一个程序,图像压缩工具. 因为比较简单,下面直接贴上代码. 效果图如下: # -*- coding: utf-8 -*- import s ...

  2. scrcpy投屏软件

    Android很好用得scrcpy 投屏软件: 下载传送门:https://github.com/Genymobile/scrcpy/releases 1.下载解压包后,解压至自己得电脑目录,并复制目 ...

  3. NameNode启动问题:Failed to load an FSImage file!

    NameNode启动问题:Failed to load an FSImage file! 2022-01-23 13:35:53,807 FATAL org.apache.hadoop.hdfs.se ...

  4. 【LeetCode2180】[Go/C++/C#/Ruby/Swift/Kotlin/Rust/PHP/TS/Racket/Dart/Java/Elixir/Scala/Erlang] 统计各位数字之和为偶数的整数个数

    目录 题解地址 代码 golang c++ C# ruby swift kotlin rust php typescript racket dart java elixir scala erlang ...

  5. smart rtmpd 服务器配置文件说明及优化方法介绍

    ---------------------------------------------------------------------------------------------------- ...

  6. python基础篇:Python基础知识,帮助初学者快速入门

    Python是一种高级编程语言,它易于学习和使用,因此成为了许多人的首选编程语言.本文将介绍Python的基础知识,以帮助初学者快速入门. 安装Python 在开始学习Python之前,您需要安装Py ...

  7. 浅谈Vue 2.x当中组件之间传值方式

    一.父子之间传值 1. 父传子 :props <!DOCTYPE html> <html lang="en"> <head> <meta ...

  8. AllenBradley罗克韦尔CIP通信协议介绍 C# AllenBradley(CIP)读写操作PLC数据 C#罗克韦尔(CIP)PLC通信 全开源下载

    罗克韦尔CIP通信协议(Control and Information Protocol)是一种面向对象的通信协议,它是用于工业自动化领域的数据通信协议.CIP协议可以在不同厂商.不同类型的自动化设备 ...

  9. ​KubeSphere离线无网络环境部署

    KubeSphere离线无网络环境部署 KubeSphere 是 GitHub 上的一个开源项目,是成千上万名社区用户的聚集地.很多用户都在使用 KubeSphere 运行工作负载.对于在 Linux ...

  10. 【AIGC未来的发展方向】面向人工智能的第一步,一文告诉你人工智能是什么以及未来的方向分析

    人工智能的概念 当人们提到"人工智能(AI)"时,很多人会想到机器人和未来世界的科幻场景,但AI的应用远远不止于此.现在,AI已经广泛应用于各种行业和生活领域,为我们带来了无限可能 ...