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. 使用php将字典格式的字符串转为array

    例: 原字符串为 $a = '{"errcode":0,"errmsg":"ok","msgid":1472671765 ...

  2. java并发编程实践-线程安全性

    线程是CPU资源调度的基本单位,如果一个程序中只有一个线程,则最多只能在一个处理器上运行,如果电脑/服务器是双处理器系统,则单线程的程序只能使用一半的CPU资源,所以,多线程是提高处理器资源利用率的重 ...

  3. SpringBoot笔记--配置文件分类+yaml相关知识+读取配置文件内容

    配置文件 要是需要使用自己的配置替换默认配置时,需要使用后缀名为application.properties或者application.yml(application.yaml)进行配置 当然,几个文 ...

  4. Windows7系统显存只有4GB

    Windows7安装后,专用视屏内存只有4GB可用,是不是Windows7不支持4G以上显存的显卡呢?之前在网上有人说,虽然系统显示可用只有4G显存,但是游戏内实际可以超过4G.本人没有特地去试验过. ...

  5. 爬取JSON文件并且存储

    思路 1 先调用模块 2 定义一个函数 2.1 获取网址(点击评论 找到JSON的文件(分析评论preview)获取Request URL后面的地址) 2.2 添加用户的请求头 2.3 使用get方法 ...

  6. 红队实战靶场ATT&CK(二)

    一.环境配置 web靶机有一块NAT网卡,只需要修改这块NAT网卡的网关,IP改成与攻击机器同网段就可以了 到web靶机中C:/Oracle/Middleware/user_projects/doma ...

  7. 四个常见的Linux面试问题

    四个常见的Linux面试问题. 刚毕业要找工作了,只要是你找工作就会有面试这个环节,那么在面试环节中,有哪些注意事项值得我的关注呢?特别是专业技术岗位,这样的岗位询问一般都是在职的工程师,如何在面试环 ...

  8. WPF 界面布局、常用控件入门教程实例 WPF入门学习控件快速教程例子 WPF上位机、工控串口通信经典入门

    WPF(Windows Presentation Foundation)是一种用于创建 Windows 桌面应用程序的框架,它提供了丰富的控件库和灵活的界面布局,可以创建现代化的用户界面.下面是 WP ...

  9. 计网学习笔记七 IP protocol basic

    在这一节讲了IP协议的基本内容:包括IPv4提供的操作.数据报在IPv4下是怎么样的结构.数据报是怎样切片发送的.IPv4的编址方式有什么--IPv6在下一节讲网络层协议簇时细讲. IPv4协议的具体 ...

  10. 二进制安装Kubernetes(k8s) v1.26.0 IPv4/IPv6双栈

    二进制安装Kubernetes(k8s) v1.26.0 IPv4/IPv6双栈 https://github.com/cby-chen/Kubernetes 开源不易,帮忙点个star,谢谢了 介绍 ...