基础练习 完美的代价

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

3



贪心算法


思路:

先判断出现字母的个数为奇数的数量_count,若_count>1,就是impossible;如果_count为零,就是所有的都能配对成功,左边开始固定一个字母,就从右边对称位置开始往左边搜,第一个遇到一样的字母的就向右移到对应的位置。一直如此重复就解出来了;

单是_count=1时,寻找时会遇到找不到的情况,应为这个字母就是放在最中间,这个时候就要从右边开始固定,开始从左边开始位置向右边找,这样的话中间的那一个最后自己就到最中间去了;


接下来设定一种理想情况,就是不会被破坏的情况,就是最后回文中靠近两边的字母一定是更早到达对应的位置,因为如果是中间的元素更早到达平衡位置,你再调外侧的元素内侧一定会被打乱,所以假设一种理想情况,即不会被打乱的情况,那么假设此时移动的次数为理想距离;如果移动配对两侧的元素,他就是理想距离,但是配对两侧的元素的时候由于移动会使一些字母偏离理想距离,又会使一些字母更靠近理想距离,为什么呢,应为这样的操作会使字母往中间靠拢,有元素大于理想距离,就一定有元素小于理想距离,所以移动的总次数一定不会超过理想距离,所以这样的策略一定是对的。

/**
 * 
 */
package 基础练习;

import java.awt.Checkbox;
import java.util.Scanner;

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

	/**
	 * @param args
	 */
	private static int change = 0; // 改变的次数
	private static int old = 0; // 记录出现奇数次字符
	private static char charold = 0;// 记录奇数字符

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		int N = Integer.parseInt(sc.nextLine());
		String s = sc.nextLine();
		char str[] = s.toCharArray();
		Boolean flag = check(str); // 是否可以组成回文

		if (!flag) {
			System.out.println("Impossible");
		} else {
			for (int i = 0; i < N / 2; i++) {
				if (str[i] != charold) {// 从右开始找对称
					int j = 0;
					for (j = N - 1 - i; j > i; j--) {
						if (str[i] == str[j])// 找到
							break;
					}
					change += N - 1 - i - j; // 移动次数
					for (int j2 = j; j2 < N - 1; j2++) {
						str[j2] = str[j2 + 1];
					}
					str[N - 1 - i] = str[i];// 对称点

				}
				// 从左边开始
				else {
					int j = 0;
					for (j = i; j < N - 1 - i; j++) {
						if (str[j] == str[N - 1 - i])
							break;// 找到

					}
					change += j - i;// 移动次数
					for (int j2 = j; j2 < i; j2--) {
						str[j2] = str[j2 - 1];
					}
					str[i] = str[N - 1 - i]; // 对称点
				}
			}
			System.out.println(change);

		}
	}

	private static boolean check(char[] str) {
		int arr[] = new int[26];
		for (int i = 0; i < str.length; i++) {
			arr[str[i] - 'a']++;
		}
		for (int i = 0; i < 26; i++) {
			if (arr[i] % 2 == 1) {
				old++;
				charold = (char) (i + 'a');
			}

		}
		if (old > 1)
			return false;
		return true;

	}

}

提交到蓝桥杯系统只得了60分。 有四个没有ac不知道什么原因。还在研究中。。。。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章