蓝桥杯基础练习 完美的代价(Java)(初试贪心)

蓝桥杯 基础练习 完美的代价

资源限制
时间限制:1.0s 内存限制:512.0MB

问题描述
  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
  交换的定义是:交换两个相邻的字符
  例如mamad
  第一次交换 ad : mamda
  第二次交换 md : madma
  第三次交换 ma : madam (回文!完美!)
  
输入格式
  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
  第二行是一个字符串,长度为N.只包含小写字母
  
输出格式
  如果可能,输出最少的交换次数。
  否则输出Impossible
  
样例输入
5

mamad
样例输出
3

import java.util.Scanner;
public class Main{
    
    
	public static void main(String[] args){
    
    
		Scanner input=new Scanner(System.in);
		int n=input.nextInt();
		char[] arr=new char[n];
		arr=input.next().toCharArray();
		int i,j,k=1,m=0,cishu=0,x,y,z;//cishu用于累积移动次数
		//缓存(字符交换时,缓存字符)  中间(回文串中应该放在中间的数)
		char huancun,zhongjian='0';
		String shuchu="*";
		//字符串的字符数是偶数的情况
		if(n%2==0){
    
    
			outer:
			for(i=0;i<n;i++){
    
    
				k=1;
				//找出arr中有几个相同的arr[i],并用k记录个数
				for(j=0;j<n;j++){
    
    
					if(i==j) continue;
					if(arr[i]==arr[j]){
    
    
						k++;
					}
				}
				//如果出现奇数个,则不可能形成回文串
				//因为字符串字符总数是偶数个
				if(k%2==1){
    
    
					shuchu="Impossible";
					break outer;//此时不用再检测其他字符
				}
			}
		    //满足形成回文串的条件,用cishu记录最少交换次数
		    //从外围向中间整理回文串,即根据最左边的字符,从最右边
		    //开始寻找第一个与其相同的字符,然后移动字符并记录移动次数
			if(shuchu=="*"){
    
    
				cishu=0;
				for(i=0;i<(n/2);i++){
    
    
					outer:
					for(j=n-1-i;j>i;j--){
    
    
						if(arr[i]==arr[j]){
    
    
							cishu+=n-1-i-j;
							//交换字符,且交换n-1-i-j次
							for(k=j;k<n-1-i;k++){
    
    
								huancun=arr[k];
								arr[k]=arr[k+1];
								arr[k+1]=huancun;
							}
							break outer;
						}
					}
				}
			}
		}
		//字符串的字符个数是奇数个时
		else{
    
    
			//判断是否可以形成回文串
			outer:
			for(i=0;i<n;i++){
    
    
				k=1;
				for(j=0;j<n;j++){
    
    
					if(i==j) continue;
					if(arr[i]==arr[j]){
    
    
						k++;
					}
				}
				if(k%2==1){
    
    
					//用m记录出现了多少次奇数个的字符,当m>=2时,不能形成回文串
					m++;
					//if语句不能放在zhongjian的赋值后
					//否则第二个开始的奇数个的字符会重新赋值给zhongjian
					//那么arr[i]恒等于zhongjian,if语句永远得不到执行
					if(m>1&&arr[i]!=zhongjian){
    
    
						shuchu="Impossible";
						break outer;//此时无需再接着判断后续字符
					}
					zhongjian=arr[i];//记录需要放在中间的数的字符
				}
			}
			//满足交换后可成为回文串的条件
			if(shuchu=="*"){
    
    
				cishu=0;
				outer:
				for(i=0;i<=(n/2+1);i++){
    
    
					for(j=n-1-i;j>=i;j--){
    
    
						//j!=i意味着可以找到除arr[i]本身外与其相同的字符
						if(arr[i]==arr[j]&&j!=i){
    
    
							cishu+=n-1-i-j;
							huancun=arr[j];
							for(k=j;k<n-1-i;k++){
    
    
								arr[k]=arr[k+1];
							}
							arr[n-1-i]=huancun;
							break;
						}
						//j==i意味着arr[i](用v代表)是需要放在最中间的那个字符
						//原先我是将v放着不管,先对剩余的字符排好序
						//再将计算将v放入最中间需要移动几次
						//但是,这并不是最优解决方法
						//于是改用:当遇到v时,将v与剩余未排好序的字符看成一个整体
						//以最右边的字符为基准,从最左边开始寻找与之相同的字符并移动
						//在该方法下,v最后不用移动就处于最中间
						if(j==i){
    
    
							//循环条件不是x>i,而是取到临近字符串最中间那个位置即可
							for(x=n-1-i;x>(n-1)/2;x--){
    
    
								for(y=n-1-x;y<x;y++){
    
    
									if(arr[y]==arr[x]){
    
    
										cishu+=(y-(n-1-x));
										huancun=arr[y];
										for(z=y;z>(n-1-x);z--){
    
    
											arr[z]=arr[z-1];
										}
										arr[n-1-x]=huancun;
										break;
									}
								}
							}
							break outer;
						}	
					}
				}
			}
		}
		//输出
		if(shuchu=="Impossible") System.out.print(shuchu);
		else System.out.print(cishu);
	}
}

贪心算法:局部最优以达整体最优

附其中一个评测数据:
(不能只考虑某些类型的字符串,应让代码更为严谨)
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/CSDNWudanna/article/details/105418628