2022-07-21:给定一个字符串str,和一个正数k, 你可以随意的划分str成多个子串, 目的是找到在某一种划分方案中,有尽可能多的回文子串,长度>=k,并且没有重合。 返回有几个回文子串。 来
Posted 福大大架构师每日一题
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2022-07-21:给定一个字符串str,和一个正数k, 你可以随意的划分str成多个子串, 目的是找到在某一种划分方案中,有尽可能多的回文子串,长度>=k,并且没有重合。 返回有几个回文子串。 来相关的知识,希望对你有一定的参考价值。
2022-07-21:给定一个字符串str,和一个正数k,
你可以随意的划分str成多个子串,
目的是找到在某一种划分方案中,有尽可能多的回文子串,长度>=k,并且没有重合。
返回有几个回文子串。
来自optiver。
答案2022-07-21:
马拉车算法+贪心。
代码用rust编写。代码如下:
use rand::Rng;
fn main()
let n: i32 = 20;
let r = 3;
let test_time: i32 = 50000;
println!("测试开始");
for i in 0..test_time
let str = random_string(n, r);
let k = rand::thread_rng().gen_range(0, str.len() as i32) + 1;
let ans1 = max1(&str, k);
let ans2 = max2(&str, k);
if ans1 != ans2
println!("i = ", i);
println!("str = ", str);
println!("k = ", k);
println!("ans1 = ", ans1);
println!("ans2 = ", ans2);
println!("出错了!");
break;
println!("测试结束");
// 暴力尝试
// 为了测试
// 可以改成动态规划,但不是最优解
fn max1(s: &str, k: i32) -> i32
if s.len() == 0
return 0;
let mut str = s.as_bytes().to_vec();
return process1(&mut str, 0, k);
fn process1(str: &mut Vec<u8>, index: i32, k: i32) -> i32
if str.len() as i32 - index < k
return 0;
let mut ans = process1(str, index + 1, k);
for i in index + k - 1..str.len() as i32
if is_palindrome(str, index, i)
ans = get_max(ans, 1 + process1(str, i + 1, k));
return ans;
fn is_palindrome(str: &mut Vec<u8>, mut ll: i32, mut rr: i32) -> bool
while ll < rr
if str[ll as usize] != str[rr as usize]
return false;
ll += 1;
rr -= 1;
return true;
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
// 最优解
// 时间复杂度O(N)
fn max2(s: &str, k: i32) -> i32
if s.len() == 0
return 0;
let mut str = manacher_string(s);
let mut p = vec![];
for _ in 0..str.len() as i32
p.push(0);
let mut ans = 0;
let mut next = 0;
// k == 5 回文串长度要 >= 5
// next == 0
// 0.... 8 第一块!
// next -> 9
// 9.....17 第二块!
// next -> 18
// 18....23 第三块
// next一直到最后!
next = manacher_find(&mut str, &mut p, next, k);
while next != -1
next = if str[next as usize] == ('#' as u8)
next
else
next + 1
;
ans += 1;
next = manacher_find(&mut str, &mut p, next, k);
return ans;
fn manacher_string(s: &str) -> Vec<u8>
let str = s.as_bytes().to_vec();
let mut ans: Vec<u8> = vec![];
for _ in 0..str.len() as i32 * 2 + 1
ans.push(0);
let mut index: i32 = 0;
for i in 0..ans.len() as i32
if (i & 1) == 0
ans[i as usize] = '#' as u8;
else
ans[i as usize] = str[index as usize];
index += 1;
return ans;
// s[l...]字符串只在这个范围上,且s[l]一定是'#'
// 从下标l开始,之前都不算,一旦有某个中心回文半径>k,马上返回右边界
fn manacher_find(s: &mut Vec<u8>, p: &mut Vec<i32>, l: i32, k: i32) -> i32
let mut c = l - 1;
let mut r = l - 1;
let n = s.len() as i32;
for i in l..s.len() as i32
p[i as usize] = if r > i
get_min(p[(2 * c - i) as usize], r - i)
else
1
;
while i + p[i as usize] < n
&& i - p[i as usize] > l - 1
&& s[(i + p[i as usize]) as usize] == s[(i - p[i as usize]) as usize]
p[i as usize] += 1;
if p[i as usize] > k
return i + k;
if i + p[i as usize] > r
r = i + p[i as usize];
c = i;
return -1;
// 为了测试
fn random_string(n: i32, r: i32) -> String
let mut ans: String = String::from("");
let ans_len = rand::thread_rng().gen_range(1, n);
for _ in 0..ans_len
ans.push((rand::thread_rng().gen_range(0, r) + 'a' as i32) as u8 as char);
return ans;
执行结果如下:
以上是关于2022-07-21:给定一个字符串str,和一个正数k, 你可以随意的划分str成多个子串, 目的是找到在某一种划分方案中,有尽可能多的回文子串,长度>=k,并且没有重合。 返回有几个回文子串。 来的主要内容,如果未能解决你的问题,请参考以下文章
2021-12-27:给定一个字符串str,和一个正数k, str子序列的字符种数必须是k种,返回有多少子序列满足这个条件。 已知str中都是小写字母, 原始是取mod, 本节在尝试上,最难的, 搞出
2021-08-30:给定两个字符串str1和str2,在str1中寻找一个最短子串,能包含str2的所有字符,字符顺序无所谓,str1的这个最短子串也可以包含多余的字符。返回这个最短包含子串。(代码
2021-12-02:给定一个字符串str,和一个正数k。 返回长度为k的所有子序列中,字典序最大的子序列。 来自腾讯。
2022-04-07:给定一个只由‘a‘和‘b‘组成的字符串str, str中“ab“和“ba“子串都可以消除, 消除之后剩下字符会重新靠在一起,继续出现可以消除的子串... 你的任务是决定一种消除的
2023-01-06:给定一个只由小写字母组成的字符串str,长度为N, 给定一个只由01组成的数组arr,长度为N, arr[i] == 0表示str中i位置的字符不许修改, arr[i] ==