蓝桥杯-基础训练-完美的代价

完美的代价

在这里插入图片描述

问题的分析及思路

思路一
  • 首先是如何判断其能不能成为回文串
  • 再进行回文处理
  • 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;
			}
		}
	}

}

其他的题,也都有整理,可以看我的博客 断然不然嘞?

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值