试题 基础练习 完美的代价
问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
思路:
因为考虑到最少的情况,所以是贪心算法的思想。
模拟交换的过程
Impossible的情况:1 字符串的长度是奇数,但是出现一次的字符数目大于1。
2 字符串的长度是偶数,但是出现一次的字符数大于0
代码
import java.util.Scanner;
public class Main {
static Scanner scanner = new Scanner(System.in);
// 字符串交换函数
static void swap(char[] arr, int s, int e) {
char temp = arr[s];
arr[s] = arr[e];
arr[e] = temp;
}
public static void main(String[] args) {
int n = scanner.nextInt(); // 字符串长度
String string = scanner.next(); // 读取字符串
char[] arr = string.toCharArray(); // 将字符串转换为字符数组
int len = arr.length;
int swap_count = 0; // 记录交换次数
int once_char = 0; // 记录出现一次的字符数
// 遍历交换
for (int i = 0; i < n - 1; i++) { // 遍历1到n-1的字符
for (int j = n - 1; j >= i; j--) { // 从n-1开始往前找,是贪心算法的体现
if (i == j) { // i==j 表示没找到
if (once_char == 1 || len % 2 == 0) {
System.out.println("Impossible"); // 为Impossible的情况
return;
}
once_char++;
swap_count += (len / 2) - i;// 如果为奇数且只有一个出现一次的字符,那么就的模拟把他换到中间,需要移动(len/2—)-i次
} else if (arr[i] == arr[j]) { // 找到了那个与之匹配的字符
for (int k = j; k < n-1; k++) {
swap(arr, k, k + 1); // 模拟交换
swap_count++; // 交换次数加加
}
n--; // 固定了最有的字符,所以下次就不能再用了,因此可交换的字符长度范围要减少1
break; // 当前的字符确定了,进行下一轮的字符判断
}
}
}
System.out.println(swap_count);
}
}
参考学习
https://blog.csdn.net/selaotou11/article/details/104594393 题目解析
https://www.bilibili.com/video/BV1e7411T7FV?p=124 贪心算法