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. Ubuntu NVIDIA显卡驱动+CUDA安装(多版本共存)

    NVIDIA显卡驱动 1.禁止集成的nouveau驱动 solution 1 (recommand) # 直接移除这个驱动(备份出来) mv /lib/modules/3.0.0-12-generic ...

  2. redis的数据操作和python操作redis+关系非关系数据库差异

    关系型数据库(RMDBS) 数据库中表与表的数据之间存在某种关联的内在关系,因为这种关系,所以我们称这种数据库为关系型数据库. 典型:Mysql/MariaDB.postgreSQL.Oracle.S ...

  3. echart 解决setOption线残留

    前言: Antd + echarts 我想要实现的是点击表的某一行自动生成对应的折线图,我在点击第一行生成5条线,我在点击第二行的时候,本该生成2条线,结果还是5条线: 最开始我以为设置的 serie ...

  4. Android studio手机界面的显示

    终于显示出来啦! 前几天因为SDK的地址错误一直不显示,现在终于显示出来啦! 关于报错原因的话,我也不太清楚是咋解决的,就改了改Android studio软件里面下载SDK的地址,就出来啦!(只要报 ...

  5. 《操作系统导论》读书笔记1——CPU虚拟化,进程

    系列文章目录和关于我 一丶CPU的虚拟化 一个桃子,我们称之为物理(physical)桃子.但有很多想吃这个桃子的 人,我们希望向每个想吃的人提供一个属于他的桃子,这样才能皆大欢喜.我们把给每个 人的 ...

  6. python3各数据类型的常用方法

    python3数据类型包括: 数字.字符串str.列表list.元组tuple.字典dict.集合set.布尔bool 1.字符串(str)-可变-用"".''定义 (1)uppe ...

  7. 手动实现一个call bind

    一.call的实现(apply类似) //完成版 Function.prototype.setCall = function (obj){ var object = obj || window let ...

  8. Java中的命名规范

    Java中的命名规范 一. 常规约定 类一般采用大驼峰命名,方法和局部变量使用小驼峰命名,而大写下划线命名通常是常量和枚举中使用. 类型 约束 例 项目名 全部小写,多个单词用中划线分隔'-' spr ...

  9. 逍遥自在学C语言 | 关系运算符

    前言 一.人物简介 第一位闪亮登场,有请今后会一直教我们C语言的老师 -- 自在. 第二位上场的是和我们一起学习的小白程序猿 -- 逍遥. 二.构成和表示方式 关系运算符的作用是判断符号两边大小的关系 ...

  10. [Java/Arthas]Arthas The telnet port 3658 is used by process 13988 instead of target process 11208, y[转载]

    1 问题描述 Arthas 跟踪 一个已经在tomcat部署的工程quality,第一次使用过的是135091号进程,后来出现问题,换进程连接,报错如上图所示,提示端口占用.原因是上次连接了一个进程, ...