完美的代价
给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。交换的定义是:交换两个相邻的字符。
思路:
1. 判断是否能够通过交换形成回文字符串。
(1)如果字符串的长度length
为奇数,那么有且仅有一个字符的频次为奇数。即出现频次是偶数的字符有 length-1
。
(2)如果字符串的长度为偶数,那么所有字符的长度都应该为偶数。即出现频次是偶数的字符有 length
。
可以通过map记录字符串中每个字符出现的次数
练习: 计算一个字符串中每个字符出现次数
分析:
1.创建Map集合,key是字符串中的字符,value是字符的个数
2.遍历字符串,获取每一个字符
3.使用获取到的字符,去Map集合判断key是否存在
key存在:
通过字符(key),获取value(字符个数)
value++
put(key,value)把新的value存储到Map集合中
key不存在:
put(key,1)
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
if (map.containsKey(s.charAt(i)))
map.put(s.charAt(i), map.get(s.charAt(i)) + 1);
else
map.put(s.charAt(i), 1);
}
通过遍历map中的值,判断频次是偶数的字符个数。
int count = 0;
//遍历map中值的办法。
for (Integer value : map.values()) {
if (value % 2 == 0)
count++;
}
if (s.length() % 2 == 0 && count == map.size())
return true;
if (s.length() % 2 == 1 && count == (map.size() - 1))
return true;
return false;
用 i
指向第一个字母。j
指向最后一个字母,进行比较。
(1)如果相同,则将i
向右移,将j
向左移。直到 i
移到
n
/
2
−
1
n/2-1
n/2−1的位置
(2)如果不同则在红色框框里寻找等和i
相同的字符
- 如果找到,则将
j
上的字符与该字符进行交换。(这里的交换不是直接将两个字符进行交换,而是通过不停与相邻元素进行交换) - 如果找不到,并且字符长度是奇数,说明
i
上的字符应该放在中间位置,但是如果我们现在将它放到中间位置,后面对字符的交换也会影响它的位置,所以我们将i
位置上的字符和后面一个字符交换。放到后面再处理,等到我们将不是中间的字符全部对称完毕,该字符自然也就在中间位置。
import java.util.HashMap;
import java.util.Scanner;
public class MapTest {
public static void main(String[] args) {
Scanner scn = new Scanner(System.in);
int n = scn.nextInt();
String s = scn.next();
if (check(s) == false)
System.out.println("Impossible");
else {
char[] c = s.toCharArray();
int count = 0;
for (int i = 0; i <= n / 2 - 1; i++) {
if (c[i] != c[n - 1 - i]) {
boolean find = false;
for (int k = n - 2 - i; k > i; k--) {
if (c[k] == c[i]) {
swap(c, k, n - 1 - i);
count += n - 1 - i - k;
find = true;
break;
}
}
if (find == false && n % 2 == 1) {
swap(c, i, i + 1);
count += 1;
i = i - 1;
}
}
}
System.out.println(count);
}
}
private static void swap(char[] c, int k, int i) {
while (k <= i - 1) {
adjswap(c, k, k + 1);
k++;
}
}
private static void adjswap(char[] c, int k, int i) {
char temp = c[k];
c[k] = c[i];
c[i] = temp;
}
public static boolean check(String s) {
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0; i < s.length(); i++) {
if (map.containsKey(s.charAt(i)))
map.put(s.charAt(i), map.get(s.charAt(i)) + 1);
else
map.put(s.charAt(i), 1);
}
int count = 0;
for (Integer value : map.values()) {
if (value % 2 == 0)
count++;
}
if (s.length() % 2 == 0 && count == map.size())
return true;
if (s.length() % 2 == 1 && count == (map.size() - 1))
return true;
return false;
}
}