You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

117 lines
2.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2023_01_2_week;
import java.util.ArrayList;
// 给你一个只包含小写英文字母的字符串 s 。
// 每一次 操作 ,你可以选择 s 中两个 相邻 的字符,并将它们交换。
// 请你返回将 s 变成回文串的 最少操作次数 。
// 注意 ,输入数据会确保 s 一定能变成一个回文串。
// 测试链接 : https://leetcode.cn/problems/minimum-number-of-moves-to-make-palindrome/
public class Code04_MinimumNumberOfMovesToMakePalindrome {
public static int minMovesToMakePalindrome(String s) {
int n = s.length();
ArrayList<ArrayList<Integer>> indies = new ArrayList<>();
// a -> 0 -> 含有a的所有位置{...}
// b -> 1 -> 含有b的所有位置{...}
for (int i = 0; i < 26; i++) {
indies.add(new ArrayList<>());
}
// AABAA...
// 12345
// A -> 0 : {1 2 4 5}
// B -> 1 : {3... }
for (int i = 0, j = 1; i < n; i++, j++) {
int c = s.charAt(i) - 'a';
indies.get(c).add(j);
}
// 原始下标 -> 该去往的下标 存在arr中
int[] arr = new int[n + 1];
// 建立好indexTree初始时下标1~n上认为全是1
IndexTree it = new IndexTree(n);
for (int i = 0, l = 1; i < n; i++, l++) {
// i -> 拿字符 从下标0开始
// l -> 从下标1开始
// arr[l] != 0
// 当前的l曾经作为姘头之一的右侧之前填过了
if (arr[l] == 0) {
int c = s.charAt(i) - 'a';
// l......r
int r = indies.get(c).remove(indies.get(c).size() - 1);
if (l == r) {
arr[l] = (1 + n) / 2;
it.add(l, -1);
} else {
// l != r
// l -> 左边的序号! 0...l累加和
int kth = it.sum(l);
arr[l] = kth;
arr[r] = n - kth + 1;
it.add(r, -1);
}
}
}
return number(arr, new int[n + 1], 1, n);
}
public static class IndexTree {
public int[] tree;
public int n;
public IndexTree(int size) {
tree = new int[size + 1];
n = size;
for (int i = 1; i <= n; i++) {
add(i, 1);
}
}
public int sum(int i) {
int ans = 0;
while (i > 0) {
ans += tree[i];
i -= i & -i;
}
return ans;
}
public void add(int i, int v) {
while (i < tree.length) {
tree[i] += v;
i += i & -i;
}
}
}
public static int number(int[] arr, 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);
}
public static int merge(int[] arr, 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) {
ans += arr[p1] > arr[p2] ? (p2 - m) : 0;
help[i--] = arr[p1] > arr[p2] ? arr[p1--] : 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;
}
}