2023-05-27:给你一个只包含小写英文字母的字符串 s 。 每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换。 请你返回将 s 变成回文串的 最少操作次数 。 注意 ,输入数据
2023-05-27:给你一个只包含小写英文字母的字符串 s 。
每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换。
请你返回将 s 变成回文串的 最少操作次数 。
注意 ,输入数据会确保 s 一定能变成一个回文串。
输入:s = "letelt"。
输出:2。
答案2023-05-27:
大体过程如下:
1.定义结构体 IndexTree,其中包含一个整型切片 tree 和整型变量 n,用于实现树状数组。
2.定义函数 createIndexTree(size int) *IndexTree,用于创建一个大小为 size 的树状数组并初始化,返回该数组的指针。
3.定义函数 sum(it *IndexTree, i int) int,用于求以 i 为结尾的前缀和。
4.定义函数 add(it *IndexTree, i int, v int),用于将第 i 个位置上的值增加 v。
5.定义函数 merge(arr []int, help []int, l int, m int, r int) int,用于归并排序并统计逆序对数量。
6.定义函数 number(arr []int, help []int, l int, r int) int,用于递归地求解整个序列中的逆序对数量。
7.定义函数 minMovesToMakePalindrome(s string) int,用于求解将字符串 s 变成回文串的最少操作次数。首先遍历字符串,将每个字符第一次出现的下标加入到对应字符的索引列表中。然后定义一个整型切片 arr 用于记录每个字符与其对称位置之间的距离,以及一个 IndexTree 类型的变量 it 用于记录每个字符在左半部分的逆序对数量。遍历整个字符串,对于每个未处理的位置,找到它与其对称位置之间的距离,并计算出在左半部分有多少个字符与该字符构成了逆序对。最后调用 number 函数求解 arr 中的逆序对数量即可。
8.在 main 函数中定义字符串 s = "letelt",并调用 minMovesToMakePalindrome 函数输出结果。
时间复杂度为 $O(n\log n)$,空间复杂度为 $O(n)$。
其中,遍历整个字符串的时间复杂度为 $O(n)$,建立字符索引列表的时间复杂度为 $O(n)$,建立树状数组的时间复杂度为 $O(n\log n)$,递归求解逆序对数量的时间复杂度为 $O(n\log n)$,归并排序中合并两个有序子序列的时间复杂度为 $O(n)$。
而空间复杂度中,建立字符索引列表占用的空间为 $O(26n)$,建立树状数组占用的空间为 $O(n\log n)$,递归求解逆序对数量时传递的辅助数组占用的空间为 $O(n)$。
go语言完整代码如下:
package main
import "fmt"
func main() {
s := "letelt"
result := minMovesToMakePalindrome(s)
fmt.Println(result)
}
func minMovesToMakePalindrome(s string) int {
n := len(s)
indies := make([][]int, 26)
for i := 0; i < 26; i++ {
indies[i] = []int{}
}
for i := 0; i < n; i++ {
c := int(s[i]) - 'a'
indies[c] = append(indies[c], i+1)
}
arr := make([]int, n+1)
it := newIndexTree(n)
for i, l := 0, 1; i < n; i, l = i+1, l+1 {
if arr[l] == 0 {
c := int(s[i]) - 'a'
r := indies[c][len(indies[c])-1]
indies[c] = indies[c][:len(indies[c])-1]
if l == r {
arr[l] = (1 + n) / 2
it.add(l, -1)
} else {
kth := it.sum(l)
arr[l] = kth
arr[r] = n - kth + 1
it.add(r, -1)
}
}
}
return number(arr, make([]int, n+1), 1, n)
}
type indexTree struct {
tree []int
n int
}
func newIndexTree(size int) *indexTree {
tree := make([]int, size+1)
ans := &indexTree{tree: tree, n: size}
for i := 1; i <= size; i++ {
ans.add(i, 1)
}
return ans
}
func (it *indexTree) sum(i int) int {
ans := 0
for i > 0 {
ans += it.tree[i]
i -= i & -i
}
return ans
}
func (it *indexTree) add(i int, v int) {
for i < len(it.tree) {
it.tree[i] += v
i += i & -i
}
}
func number(arr []int, help []int, l int, r int) int {
if l >= r {
return 0
}
mid := l + ((r - l) >> 1)
return number(arr, help, l, mid) + number(arr, help, mid+1, r) + merge(arr, help, l, mid, r)
}
func merge(arr []int, help []int, l int, m int, r int) int {
i := r
p1 := m
p2 := r
ans := 0
for p1 >= l && p2 > m {
if arr[p1] > arr[p2] {
ans += p2 - m
help[i] = arr[p1]
i--
p1--
} else {
help[i] = arr[p2]
i--
p2--
}
}
for p1 >= l {
help[i] = arr[p1]
i--
p1--
}
for p2 > m {
help[i] = arr[p2]
i--
p2--
}
for i := l; i <= r; i++ {
arr[i] = help[i]
}
return ans
}

rust语言完整代码如下:
fn main() {
let s = String::from("letelt");
let result = min_moves_to_make_palindrome(s);
println!("{}", result);
}
fn min_moves_to_make_palindrome(s: String) -> i32 {
let n = s.len();
let mut indies: Vec<Vec<i32>> = vec![vec![]; 26];
for (i, c) in s.chars().enumerate() {
let index = (c as u8 - b'a') as usize;
indies[index].push((i + 1) as i32);
}
let mut arr: Vec<i32> = vec![0; n as usize + 1];
let mut it = IndexTree::new(n as i32);
let mut i = 0;
let mut l = 1;
while i < n {
if arr[l as usize] == 0 {
let c_index = (s.chars().nth(i as usize).unwrap() as u8 - b'a') as usize;
let a = indies[c_index].len() - 1;
let r = indies[c_index][a];
indies[c_index].remove(a);
if l == r {
arr[l as usize] = (1 + n as i32) / 2;
it.add(l, -1);
} else {
let kth = it.sum(l);
arr[l as usize] = kth;
arr[r as usize] = n as i32 - kth + 1;
it.add(r, -1);
}
}
i += 1;
l += 1;
}
number(&mut arr, &mut vec![0; n as usize + 1], 1, n as i32)
}
struct IndexTree {
tree: Vec<i32>,
n: i32,
}
impl IndexTree {
fn new(size: i32) -> Self {
let tree = vec![0; size as usize + 1];
let mut ans = Self { tree, n: size };
for i in 1..=size {
ans.add(i, 1);
}
return ans;
}
fn sum(&self, mut i: i32) -> i32 {
let mut ans = 0;
while i > 0 {
ans += self.tree[i as usize];
i -= i & -i;
}
ans
}
fn add(&mut self, mut i: i32, v: i32) {
while i < self.tree.len() as i32 {
self.tree[i as usize] += v;
i += i & -i;
}
}
}
fn number(arr: &mut Vec<i32>, help: &mut Vec<i32>, l: i32, r: i32) -> i32 {
if l >= r {
return 0;
}
let mid = l + ((r - l) >> 1);
return number(arr, help, l, mid) + number(arr, help, mid + 1, r) + merge(arr, help, l, mid, r);
}
fn merge(arr: &mut Vec<i32>, help: &mut Vec<i32>, l: i32, m: i32, r: i32) -> i32 {
let mut i = r;
let mut p1 = m;
let mut p2 = r;
let mut ans = 0;
while p1 >= l && p2 > m {
ans += if arr[p1 as usize] > arr[p2 as usize] {
p2 - m
} else {
0
};
if arr[p1 as usize] > arr[p2 as usize] {
help[i as usize] = arr[p1 as usize];
p1 -= 1;
} else {
help[i as usize] = arr[p2 as usize];
p2 -= 1;
};
i -= 1;
}
while p1 >= l {
help[i as usize] = arr[p1 as usize];
i -= 1;
p1 -= 1;
}
while p2 > m {
help[i as usize] = arr[p2 as usize];
i -= 1;
p2 -= 1;
}
for i in l..=r {
arr[i as usize] = help[i as usize];
}
ans
}

c++完整代码如下:
#include <iostream>
#include <vector>
using namespace std;
struct IndexTree {
vector<int> tree;
int n;
IndexTree(int size) {
tree.resize(size + 1);
n = size;
for (int i = 1; i <= n; i++) {
add(i, 1);
}
}
int sum(int i) {
int ans = 0;
while (i > 0) {
ans += tree[i];
i -= i & -i;
}
return ans;
}
void add(int i, int v) {
while (i < tree.size()) {
tree[i] += v;
i += i & -i;
}
}
};
int merge(vector<int>& arr, vector<int>& help, int l, int m, int r);
int number(vector<int>& arr, vector<int>& help, int l, int r) {
if (l >= r) {
return 0;
}
int mid = l + ((r - l) >> 1);
return number(arr, help, l, mid) + number(arr, help, mid + 1, r) + merge(arr, help, l, mid, r);
}
int merge(vector<int>& arr, vector<int>& help, int l, int m, int r) {
int i = r;
int p1 = m;
int p2 = r;
int ans = 0;
while (p1 >= l && p2 > m) {
if (arr[p1] > arr[p2]) {
ans += p2 - m;
help[i--] = arr[p1--];
}
else {
help[i--] = arr[p2--];
}
}
while (p1 >= l) {
help[i--] = arr[p1--];
}
while (p2 > m) {
help[i--] = arr[p2--];
}
for (i = l; i <= r; i++) {
arr[i] = help[i];
}
return ans;
}
int minMovesToMakePalindrome(char* s) {
int n = strlen(s);
vector<vector<int>> indies(26, vector<int>());
for (int i = 0, j = 1; i < n; i++, j++) {
int c = s[i] - 'a';
indies[c].push_back(j);
}
vector<int> arr(n + 1, 0);
IndexTree it(n);
for (int i = 0, l = 1; i < n; i++, l++) {
if (arr[l] == 0) {
int c = s[i] - 'a';
int r = indies[c].back();
indies[c].pop_back();
if (l == r) {
arr[l] = (1 + n) / 2;
it.add(l, -1);
}
else {
int kth = it.sum(l);
arr[l] = kth;
arr[r] = n - kth + 1;
it.add(r, -1);
}
}
}
vector<int> help(n + 1, 0);
int ans = number(arr, help, 1, n);
return ans;
}
int main() {
char s[] = "letelt";
int result = minMovesToMakePalindrome(s);
cout << result << endl;
return 0;
}

2023-05-27:给你一个只包含小写英文字母的字符串 s 。 每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换。 请你返回将 s 变成回文串的 最少操作次数 。 注意 ,输入数据的更多相关文章
- UVA-11584 Partitioning by Palindromes 动态规划 回文串的最少个数
题目链接:https://cn.vjudge.net/problem/UVA-11584 题意 给一个字符串序列,问回文串的最少个数. 例:aaadbccb 分为aaa, d, bccb三份 n< ...
- 3676: [Apio2014]回文串 求回文串长度与出现次数的最大值
「BZOJ3676」[Apio2014] 回文串 Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所 ...
- Longest Palindrome 最长回文串问题
1.题目 Given a string s, find the longest palindromic substring in s. You may assume that the maximum ...
- 力扣算法:125-验证回文串,131-分割回文串---js
LC 125-验证回文串 给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写. 说明:本题中,我们将空字符串定义为有效的回文串. 注:回文串是正着读和反着读都一样的字符串. ...
- BZOJ 3676: [Apio2014]回文串
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 2013 Solved: 863[Submit][Status ...
- NYOJ 1023 还是回文(DP,花最少费用形成回文串)
/* 题意:给出一串字符(全部是小写字母),添加或删除一个字符,都会产生一定的花费. 那么,将字符串变成回文串的最小花费是多少呢? 思路:如果一个字符串增加一个字符 x可以形成一个回文串,那么从这个字 ...
- BZOJ3676 [Apio2014]回文串
Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行 ...
- ACM题目————最长回文串
Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入有多组cas ...
- 【BZOJ】【3676】【APIO2014】回文串
回文自动机/Manacher+SA 这道题可以用Manacher找出本质不同的回文串(令max增大的所有回文串),然后再用SA跑出来有多少相同. 还有一种做法就是回文自动机(Orz Hzwer)的裸题 ...
- bzoj 3676: [Apio2014]回文串 回文自动机
3676: [Apio2014]回文串 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 844 Solved: 331[Submit][Status] ...
随机推荐
- Linux & 标准C语言学习 <DAY1>
Linux系统简单介绍: BCPL->New B->C->UNIX->Minix->Linux->gcc 美国贝尔实验室 1968 Linu ...
- 干货 | BitSail Connector 开发详解系列一:Source
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 BitSail 是字节跳动自研的数据集成产品,支持多种异构数据源间的数据同步,并提供离线.实时.全量.增量场景下全 ...
- RTC月度小报6月丨编程挑战赛圆满收官;声网上市1周年回顾...
本月亮点速览 产品与技术: 声网Agora 实时音视频服务正式上线 HTC VIVE Sync App,支持非 VR 用户 「灵动课堂」发布 1.1.2 版本 「互动直播」6 月共发布两个版,最新版本 ...
- Spring IOC——源码分析
Spring 容器的 refresh() 创建容器 1 //下面每一个方法都会单独提出来进行分析 2 @Override 3 public void refresh() throws BeansExc ...
- ASP.NET Core - 选项系统之选项使用
上一篇 ASP.NET Core - 选项系统之选项配置 中提到 IOptions.IOptionsMonitor 和 IOptionsSnapshot 三个接口,通过这三个接口都可以从依赖注入容器中 ...
- 宝塔上部署FastAPI的步骤和一些注意点
为了运维方便,选择直接用宝塔来管理python fastapi的项目,虽然直接部署可能性能更好更灵活,但是我选择了低层本,每个人的选择可能是不一样的,各有 考虑吧. 本文的大逻辑是先写一个hellow ...
- react中类组件、函数组件、state、单层遍历、多层遍历、先遍历后渲染、if-else、三目运算符
1.回顾 module.exports = { entry: {}, output: {}, plugins: [], module: {}, resolve: {}, devServe: {} } ...
- CTF-RE-学习记录-汇编
八进制运算 加法表 1+1=2 1+2=3 2+2=4 1+3=4 2+3=5 3+3=6 1+4=5 2+4=6 3+4=7 4+4=10 1+5=6 2+5=7 3+5=8 4+5=11 5+5= ...
- 基于开源的 ChatGPT Web UI 项目,快速构建属于自己的 ChatGPT 站点
作为一个技术博主,了不起比较喜欢各种折腾,之前给大家介绍过 ChatGPT 接入微信,钉钉和知识星球(如果没看过的可以翻翻前面的文章),最近再看开源项目的时候,发现了一个 ChatGPT Web UI ...
- 从0开始学杂项 第三期:隐写分析(2) PNG图片隐写
Misc 学习(三) - 隐写分析:PNG 图片隐写 在上一期,我主要讲了讲自己对于隐写分析.信息搜集和直接附加的一些浅薄理解,这一期我们继续对隐写分析的学习,开始讲隐写分析最喜欢考的一项--图片隐写 ...