资源限制
时间限制:1.0s 内存限制:512.0MB
问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
样例输入
5
mamad
样例输出
3
思路解析:
- 首先要判断是否满足回文,即没有“对象”的字符的个数要小于等于一
我在判断的时候使用了两种容器:set和multiset容器。
s.begin() // 返回指向第一个元素的迭代器 s.clear() // 清除所有元素 s.count() // 返回某个值元素的个数 s.empty() // 如果集合为空,返回true(真) s.end() // 返回指向最后一个元素之后的迭代器,不是最后一个元素 s.equal_range() // 返回集合中与给定值相等的上下限的两个迭代器 s.erase() // 删除集合中的元素 s.find() // 返回一个指向被查找到元素的迭代器 s.get_allocator() // 返回集合的分配器 s.insert() // 在集合中插入元素 s.lower_bound() // 返回指向大于(或等于)某值的第一个元素的迭代器 s.key_comp() // 返回一个用于元素间值比较的函数 s.max_size() // 返回集合能容纳的元素的最大限值 s.rbegin() // 返回指向集合中最后一个元素的反向迭代器 s.rend() // 返回指向集合中第一个元素的反向迭代器 s.size() // 集合中元素的数目 s.swap() // 交换两个集合变量 s.upper_bound() // 返回大于某个值元素的迭代器 s.value_comp() // 返回一个用于比较元素间的值的函数
转载于:
(https://blog.csdn.net/love20165104027/article/details/81510406)
- 还要满足交换次数最少(贪心,此处不做详解),即当遇到没有“对象”的字符时,不需要真正的去把它交换到中间,只需要计算出该过程中需要的交换次数即可,加到count上即可。
代码如下:
#include<iostream>
#include<string>
#include<set>
using namespace std;
string s;//全局变量,获取用户输入的字符串
bool judge(int n)
{
multiset<char>m1;//两种容器,set容器不能出现重复的,multiset容器可以出现重复值,
set<char>m2;//都是定义的char类型的,不能定义成string型的,要将s中的字母以单个字符的形式存入容器。
int flag = 0;//单个奇数字符的个数。
for (int i = 0; i < n; i++)//利用循环将s中的单个字符存入容器中。
{
m1.insert(s[i]);
m2.insert(s[i]);
}
multiset<char>::iterator p1 = m1.begin();
set<char>::iterator p2 = m2.begin();
for (p2; p2 != m2.end(); p2++)
{
if (m1.count(*p2) % 2 != 0)//count的作用是返回*p2这个字符的个数。
flag++;//若是奇数个flag++。
}
if (flag > 1)//当大于一个时肯定不能构成回文字符串!
return false;
else
return true;
}
void show(int x)
{
if (!judge(x))
cout << "Impossible" << endl;
if(judge(x))
{
int count = 0;//交换的次数。
int end = x-1;//字符串s的末尾。
int i, j;
for (i = 0; i < end; i++)//头开始
{
for (j = end; j > i; j--)//尾开始
{
if (s[i] == s[j])
{
for (int k = j; k <= end-1; k++)
{
swap(s[k], s[k + 1]);//将找到的对应的字符交换到尾巴。
count++;//次数对应增加。
}
end--;//交换完毕后,end--,就是尾巴向前一位
break;//此时跳出第二个循环,结果就是头和尾巴都向着中间移了一位。
}
}
if (i == j)//此时就是代表着那个没有“对象”的那个字符。
{
count = count + (x - 1) / 2 - i;//算出他移到中间位置的交换次数,但此时并不需要真正的进行交换,
}//显然此处就是单纯的是count增加了,并没有使用swap进行交换,目的就是为了满足最小次数。
}
cout<<count<<endl;
}
}
int main()
{
int n;
cin >> n;
cin >> s;
show(n);
}
评测数据(可自行验证):
- 58
fkgikmvqufokkuuiwqbfugwwwukigsvobbsygkokyuwgbmuqgkoqfjuiwj - 214