您的位置:首页 > 编程语言 > Java开发

基础练习 完美的代价

2017-02-12 10:37 267 查看
问题描述
  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。

  交换的定义是:交换两个相邻的字符

  例如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不知道什么原因。还在研究中。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 蓝桥杯 贪心