完美的代价
问题的分析及思路
思路一
- 首先是如何判断其能不能成为回文串
- 再进行回文处理
- pass,因为先去判断是否为回文数,就需要遍历字符串两层,太浪费了,一定更好的方法
思路二
- 这个思路是我自己在纸上手写的时候发现的
- 首先当我判断为回文串的时候,是从将第一个字符与最后一个字符相比,即这样的对应关系,
- 当两侧的字符一致时,再去判断第二位与倒数第二位,以此类推
- 如果均相同,则为回文串
- 故又根据贪心的思想,我们每一步都拿到最优,即只存在单向的移动,即我们可以这样去想,
- 假定字符串的左半边已经确定,只需要将右半边排好,一一对应就好,
- 故可以即从第一个字符开始判断,得到和它一样的字符,的坐标,
- 移至最后一位,即可
- 为了避免已经处理过的两侧字符,对下一步进行干扰,直接删除已经满足回文的两侧字符
- 故永远是第一位与最后一位的判断
- 而对于是否可以构成回文串的判断,这里有两点
- 当初始字符串长度为偶数时,即不可能存在唯一字符
- 当初始字符串长度为奇数时,即只能存在一个唯一字符
- 根据此判断标准,可得以处理
- 现在就要谈一下终止条件了
- 因为每满足了最外围两侧的回文,我们就删除其,
- 故最终,得到的字符串长度是为1 或者 0 的,此时即可结束
- 这里只是简要的思路重现记叙,具体实现看代码
遇到的一些问题
- 首先就是对于其,用那种数据结构/集合去承载
- 第一次写的时候用的是StringBuider,因为具体什么原因,我忘记了,最终没有选用其
- 最终使用ArrayList,链表对于删除,操作执行效率还是高一些
- 计算出来的次数,比题解多
- 这个也是郁闷了我很多的问题,
- 即,当拿到唯一字符的时候,不要移动其,位置。
- 当回文串排列完毕后,再将唯一字符移至中间,这样才是最少的次数
- 不能每次拿到唯一字符,就将其放置中间。。。。。说多了都是泪
可优化点
- 这里我删除首位已回文字符的操作,实则是可以通过控制,每次的查找对应字符的范围,去替代了,这样代码也就会简洁很多
- 一些已经没用的语句,我没有删除,但已经标明了,
- 不删除,是方便之后回顾,见谅
import java.util.ArrayList;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int i = scanner.nextInt();
ArrayList<Character> string = new ArrayList<Character>(i);
char[] charArray = scanner.next().toCharArray();
for (int j = 0; j < i; j++) {
string.add(charArray[j]);
}
int result = 0; // 最终结果
Character onlyCharacter = '0'; // 用于保存那个唯一的字符 当字符串长度为奇数时 也可以删除了 没用了
int onlyNum = 0; // 唯一字符的个数 用于判别是否可以作为回文数的标准
int deleteNum = 0; // 已经删除了两边 相同的字符的次数 用于之后将唯一字符移至字符串中间时 作为计算基数
while (true) {
// 最终字符串为长度为0,或者为1时, 判断结束(其实这里已经不可能为1了,因为在下面,我将唯一字符从字符串中剔除了,)
if (string.size()==0||string.size()==1) {
System.out.println(result);
return;
}
// 如果字符串首位两个字符相同时,删除这两个字符,直到其不同
if (string.get(0).equals(string.get(string.size()-1))) {
string.remove(0);
string.remove(string.size()-1);
// 获取删除次数
deleteNum++;
continue;
}
// 字符串的首字符
Character head = string.get(0);
// 和首字符相同的字符,且是最后一个。 得到其坐标
int lastIndex = string.lastIndexOf(head);
// 如果其坐标等于0,则表示此字符是唯一的
if (lastIndex==0) {
// 如果初始字符串长度为偶数的话,要成为回文数,则不可能存在为唯一字符
if (i%2==0) {
System.out.println("Impossible");
return;
}else {
// 当初始字符串长度为奇数时,要成为回文串,则只能有一个唯一字符(这里第二个判断条件,已经无用了,原因同上,
// 因为已经删除了唯一字符,保留其,是为了日后回顾时,想起当时的思路历程)
if (onlyNum==0||(onlyNum!=0&&head.equals(onlyCharacter))) {
//当收到第一个唯一字符时,不再接受唯一字符
onlyNum++;
//删除唯一字符
string.remove(0);
//当,所有回文排列好后,再将唯一字符移至字符串中间所需要的次数
result += i/2 - deleteNum;
}else {
// 如果已经有了唯一字符,在发现唯一字符,则不能成为回文串
System.out.println("Impossible");
return;
}
}
}else {
// 得到和首字符相同的 字符 且是最后一个 的坐标
// 将其交换至末尾
int end = string.size()-1;
Character lastCharacter = string.get(lastIndex);
// 删除 字符
string.remove(lastIndex);
// 添加到末尾
string.add(lastCharacter);
// 得到交换次数
int swopTime = end-lastIndex;
result+=swopTime;
}
}
}
}
其他的题,也都有整理,可以看我的博客 断然不然嘞?