资源限制
内存限制:512.0MB C/C++时间限制:1.0s Java时间限制:3.0s Python时间限制:5.0s
问题描述
回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母
输出格式
如果可能,输出最少的交换次数。
否则输出Impossible
样例输入
5
mamad
样例输出
3
思路:1.贪心算法 2.从左到右枚举每个字符,移动对应字符。个数为单的字符放中间。
贪心算法(Greedy Algorithm)是一种在求解问题时,每一步都选择当前最优解,以期望最终得到全局最优解的算法思想。贪心算法的基本思想可以总结为“每一步都做出一个局部最优的选择,最终就能得到全局最优解”。
贪心算法通常包含以下关键步骤:
找到可选的子问题: 首先,将原问题拆分成一系列可选的子问题或决策。
找到局部最优解: 对每个子问题,找到一个局部最优解。这个局部最优解应该是一个贪心选择,即在当前状态下选择最优的方式。
合并子问题的解: 将各个子问题的局部最优解合并起来,得到原问题的解。
检查解的有效性: 最后,检查得到的解是否满足问题的约束和要求。如果满足,就认为得到了问题的解。
原文链接:https://blog.csdn.net/AlgorithmHero/article/details/132460794
代码:
法一
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n, flag = 0, ans = 0;
int p,i,k,j;
char *str;
scanf("%d", &n);
str = (char*)malloc(n * sizeof(char)+1);
scanf("%s", str);
j = n - 1;
int sign = 0;
for( i = 0; i < j; i++)
{
for( k = j; k >= 0; k--)
{
if(k == i)
{
flag++;
if(n % 2 == 0 || flag > 1)
{
printf("Impossible\n");
return 0;
}
ans += n/2 - i;
break;
}
else if(str[k] == str[i])
{
for( p = k; p < j; p++)
{
str[p] = str[p + 1];
ans++;
}
str[j] = str[i];
j--;
break;
}
}
}
printf("%d\n", ans);
return 0;
}
详细记录
评测点序号 | 评测结果 | 得分 | CPU使用 | 内存使用 | 下载评测数据 |
---|---|---|---|---|---|
1 | 正确 | 10.00 | 0ms | 2.667MB | 输入 输出 |
2 | 正确 | 10.00 | 0ms | 2.476MB | 输入 输出 |
3 | 正确 | 10.00 | 0ms | 2.464MB | 输入 输出 |
4 | 正确 | 10.00 | 0ms | 2.468MB | 输入 输出 |
5 | 正确 | 10.00 | 0ms | 2.464MB | 输入 输出 |
6 | 正确 | 10.00 | 0ms | 2.480MB | 输入 输出 |
7 | 正确 | 10.00 | 0ms | 2.476MB | 输入 输出 |
8 | 正确 | 10.00 | 0ms | 2.468MB | 输入 输出 |
9 | 正确 | 10.00 | 0ms | 2.476MB | 输入 输出 |
10 | 正确 | 10.00 | 0ms | 2.488MB | 输入 输出 |
法二:
- 统计每个字母的个数判断是否能构成回文,奇数字母超过1直接输出impossible,否则准备计算交换次数
- 从第一个字母到中间位置开始交换。
交换有两种情况:中间位置字母、非中间位置字母。奇数字母移到中间,非中间字母移到对称位置,分别加上对应的移动次数。
#include<stdio.h>
int change(char str[], char x, int len){
int i, j, k, count = 0;
for(i = 0; i < len/2 ; i++){
if(str[i] == x){
for(j = i; j < len-i-1; j++){
if(str[j] == str[len - i - 1])
break;
}
count += j - i;
for(k = j; k > i; k--)
str[k] = str[k-1];
str[i] = str[len - 1 - i];
}
else{
for(j=len-1-i; j>=i; j--){
if(str[i] == str[j])
break;
}
count += len - 1 - i - j;
for(k = j; k < len - 1 - i; k++)
str[k]=str[k+1];
str[len - i - 1]=str[i];
}
}
return count;
}
int main(){
char str[8000]={0}, x;
int len, b[26]={0}, i, j, k = 0;
scanf("%d", &len);
getchar();
for(i = 0; i < len; i++){
scanf("%c", &str[i]);
}
for(i = 0; i < len; i++){
j = str[i]-'a';
b[j]++;
}
for(j = 0; j < 26; j++){
if(b[j] % 2 != 0){
k++;
x = j + 'a';
}
}
if( k>=2 ){
printf("Impossible\n");
}
else
printf("%d\n", change(str, x, len));
return 0;
}
详细记录 |
|
---|
法三:
90%正确
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i,j,l,n,k,sum=0,flat=1,c=-1;
char *a;
scanf("%d",&n);
a=(char *)malloc(n*sizeof(char));
scanf("%s",a);
j=n-1;
//利用贪心的思想,将每个遍历的字符找到后面与他相同的然后交换到正确的位置时所需的交换次数
for(i=0;i<j;i++){
for(k=j;k>=i;k--){
if(k==i){
if(n%2==0||c!=-1){
flat=0;
break;
}
c=1;
sum=sum+n/2-i;
break;
}
if(a[k]==a[i]){
for(l=k;l<j;l++){
a[l]=a[l+1];
}
a[j]=a[i];
sum=sum+j-k;
j--;
break;
}
}
if(flat==0){
break;
}
}
if(flat==0)
printf("Impossible");
else if(sum==0)
printf("0");
else
printf("%d\n",sum);
return 0;
}
详细记录
评测点序号 | 评测结果 | 得分 | CPU使用 | 内存使用 | 下载评测数据 |
---|---|---|---|---|---|
1 | 运行错误 | 0.00 | 0ms | 2.718MB | 输入 输出 |
2 | 正确 | 10.00 | 0ms | 2.511MB | 输入 输出 |
3 | 正确 | 10.00 | 0ms | 2.503MB | 输入 输出 |
4 | 正确 | 10.00 | 0ms | 2.503MB | 输入 输出 |
5 | 正确 | 10.00 | 0ms | 2.503MB | 输入 输出 |
6 | 正确 | 10.00 | 0ms | 2.503MB | 输入 输出 |
7 | 正确 | 10.00 | 0ms | 2.511MB | 输入 输出 |
8 | 正确 | 10.00 | 0ms | 2.503MB | 输入 输出 |
9 | 正确 | 10.00 | 0ms | 2.511MB | 输入 输出 |
10 | 正确 | 10.00 | 0ms | 2.511MB | 输入 输出 |