基礎練習 完美的代價

問題描述
  迴文串,是一種特殊的字符串,它從左往右讀和從右往左讀是一樣的。小龍龍認爲迴文串纔是完美的。現在給你一個串,它不一定是迴文的,請你計算最少的交換次數使得該串變成一個完美的迴文串。
  交換的定義是:交換兩個相鄰的字符
  例如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不知道什麼原因。還在研究中。。。。


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