0
点赞
收藏
分享

微信扫一扫

【算法】构造回文串(完美的代价)


题目

基础练习 完美的代价

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

问题描述

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

输入格式

第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
  第二行是一个字符串,长度为N.只包含小写字母

输出格式

如果可能,输出最少的交换次数。
  否则输出Impossible

样例输入

5
mamad

样例输出

3


思路

构造回文串,O(n^2)方法

不能构成回文的情况:( 代码体现在 if (n % 2 == 0 || single) 这一行 )
1.字符串是偶数,并且有一个奇数的字符
2.字符串中有俩个或以上的奇数的字符

能构成回文的情况:
1.字符串是奇数时,从第一个字符开始循环,从最后一个字符开始往前寻找

如果找到一样的字符,则将找到的字符移到最后一个,并且将其标记为已处理(或者说是,需处理的区间减少,代码是end–)

如果未找到,则说明此字符是奇数字符,奇数字符直接统计移动到中间需要多少步就行,因为该字符实际上应该是最后才
移动,若先移动,则在部分情况下会导致步数增加(如assmm字符串)

接下来从第二个字符开始循环,从未处理的最后一个字符开始往前寻找,以此类推
(因为俩边的字符已经处理过,无需再处理)

2.字符串的偶数时,即不纯在奇数字符的情况,
直接从第一个字符开始循环,从最后一个字符开始往前寻找
如果找到一样的字符,则将找到的字符移到最后一个,并且将其标记为已处理
然后继续循环即可


代码

#include<iostream>

using namespace std;

int main()
{
	int n, cnt = 0;//cnt指步数
	bool single = false;//记录是否存在奇数字符
	string s;
	cin >> n >> s;
	int end = n - 1;//end指未排序的最后一个字符,初始值就是第n-1个字符
	
	for (int i = 0; i <= n/2; i++)
	{
		for (int j = end; j >= i; j--)
		{
			//打印详细步骤,调试用
			//for (int m = 0; m < n; m++)
			//	cout << s[m];
			//cout << "  i :" << i << "j :" << j << endl;

			if (j == i)
			{
				//当j==i时,说明已经发现一个单独的字符,如果数列为偶数列,或者之前也存在一个单字符,那么就不能构成回文串
				if (n % 2 == 0 || single)
				{
					cout << "Impossible";
					return 0;
				}
				single = true;//标记已经发现单个字符
				cnt += n / 2 - j;//累计将他移动到中心需要的步数
				break;
			}
			else if (s[j] == s[i])//发现与当前字符相等的字符
			{
				//将较后的字符移到未处理的最后一位,即end的位置
				for (int k = j; k < end; k++)
				{
					swap(s[k], s[k + 1]);
					cnt++;
				}
				end--;//第end的位置,已处理完毕,不能再处理,end--
				break;
			}
		}
	}
	
	cout << cnt;
	return 0;
}
举报

相关推荐

0 条评论