【字符串 L】A015_完美的代价(贪心细节)

一、题目描述

回⽂串,是⼀种特殊的字符串,它从左往右读和从右往左读是⼀样的。⼩⻰⻰认为回⽂串才是完美
的。现在给你⼀个串,它不⼀定是回⽂的,请你计算最少的交换次数使得该串变成⼀个完美的回⽂
串。
交换的定义是:交换两个相邻的字符
例如mamad
第⼀次交换 ad : mamda
第⼆次交换 md : madma
第三次交换 ma : madam (回⽂!完美!)

输⼊格式
	第⼀⾏是⼀个整数N,表示接下来的字符串的⻓度(N <= 8000)
	第⼆⾏是⼀个字符串,⻓度为N.只包含⼩写字⺟

输出格式
	如果可能,输出最少的交换次数。
	否则输出Impossible
	
样例输⼊
5
mamad

样例输出
3

二、题解

方法一:贪心

思路

  • 先判断字符串是否能够组成回文串,统计每个字符出现的次数。
    • 如果出现次数为奇数的字符的个数 >= 2 是不能组成回文串的。比如,“abcd”.
  • 查找是否存在不同位置的相同字母。
    • 从哪开始反向找?应该从当前位置的镜像位置的开始反向查找,即 N-cur-1。
    • 从后往前递归地查找与当前位置 cur 字符相同的另一个字符的最后出现的位置 findLast()。
      • 如果找到,将其与 cur 的镜像位置交换。
      • 找不到怎么办?cur 位置的字符将是出现次数为奇数字符。然后将 cur 与 cur+1 位置字符进行交换,然后再查一次。
        • 比如在 dmamma 中查找 d,找不到则将 d 与 m 交换,mdamma;cur 位置还是不变。

* 核心逻辑:从外往里地将与当前位置 cur 相同的字符移动到 N-cur-1 位置(即镜像位置),这样可保证移动的次数最小。

public class Main {
	char[] s;
	int N;
	int res;
	public static void main() {
		Scanner sc = new Scanner(System.in);
		//1. 统计出现次数为奇数次的字符个数
		N = sc.nextInt();
		s = sc.next().toCharArray();
		int[] map = new int[26];
		for (char c : s)  map[c - 'a']++;
		
		int cnt = 0;
		for (int n : map) {
			if (n % 2 == 1) 
				cnt++;
		}
		if (cnt >= 2) {
			System.out.println("Impossible");
			return;
		}
		
		//主干
		for (int l = 0; l < N/2; l++) {
		  int lastI = find(i);
			swap(lastI, r);x
		}
		return;
	}
	
	//交换
	private static void swap (int l, int r) {
		if (l == r || s[l] == s[r])
			return;
		
		int temp = s[l+1];
		s[l+1] = s[r];
		s[r] = temp;
		
		res++;
		swap(l+1, r);
	}
	
	//找到与当前字符相同的最后的出现位置
	private int find(int cur) {
		for (int i = N-cur-1; i > cur; i--) {
			if (s[i] = s[cur])
				return i;
		}
		swap(cur, cur+1);	//如果找不到
		return find(cur);
	}
}

复杂度分析

  • 时间复杂度: O ( ) O()
  • 空间复杂度: O ( ) O()
发布了495 篇原创文章 · 获赞 105 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_43539599/article/details/104887996