完美的代价(贪心算法)

问题描述  回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。

交换的定义是:交换两个相邻的字符
例如mamad
第一次交换 ad : mamda
第二次交换 md : madma
第三次交换 ma : madam (回文!完美!)
输入格式  
第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
第二行是一个字符串,长度为N.只包含小写字母输出格式  如果可能,输出最少的交换次数。否则输出Impossible
样例输入
5
mamad
样例输出
3
整体代码:

#include<stdio.h>
int main()
{
 char a[8000];
 char c;
 int i, j, n,t1=0;
 int t = 0,k,sum=0;
 int count[26] = { 0 };
 scanf_s("%d", &n);
 getchar();//缓冲接收到的\n
 gets_s(a);
 //确定各个字符的数量
  for (i = 0; i < n; i++)
  count[a[i] - 'a']++;

 for (i = 0; i < 26; i++)
 {
  if (count[i] % 2 != 0)
   t++;
 }
 j = n - 1;
 //如果奇数个字母且有超过一个字母是奇数个则不可能
 if (t > 1 && n % 2 != 0)
 {
  printf("Impossible");
  return 0;
 }
 //如果偶数个字母且有字母数量为奇数也不可能
 else if (t > 0 && n % 2 == 0)
 {
  printf("Impossible");
  return 0;
 }
 else
 {
 // 贪心算法 重点
 //从左到右遍历
  for (i = 0; i < (n - 1)/2; i++)
  {
  //从右向做遍历
   for (k = j; k > i; k--)
   {
    if (a[k] == a[i])
     break;
   }
   //如果该字母为奇数个则跳过该字母等全部完成后再加上
      if (k == i)
   {
    t1 = (n - 1) / 2 - k;
   }
   //找到对应字母和对应位置并记录交换次数
   else
   {
    for (; k != j; k++)
    {
     c = a[k];
     a[k] = a[k + 1];
     a[k + 1] = c;
     sum++;
     //puts(a);
    }
    j--;
   }
  }
 }
 printf("%d", sum+t1);
 return 0;
}

之中最难理解为

  1. 贪心算法
for (i = 0; i < (n - 1)/2; i++)
  {
   for (k = j; k > i; k--)
   {
    if (a[k] == a[i])
     break;
   }
   if (k == i)
   {
    t1 = (n - 1) / 2 - k;
   }
   else
   {
    for (; k != j; k++)
    {
     c = a[k];
     a[k] = a[k + 1];
     a[k + 1] = c;
     sum++;
     //puts(a);
    }
    j--;
   }
   
   
  }
  1. 字母为中心字符是的计算
    跳过这个字符的交换跳到下一个字符但对应位置仍是上一个在这里插入图片描述
    比如说是第三个为中心字符而第三个位置对应位置为第七个位置那么跳过这个字符进行下一个字符的对应
    即第四个位置与第七个位置对应如图

    在这里插入图片描述
    之后再将第三个位置到第五个位置交换
    在这里插入图片描述
    在这里插入图片描述
//字母为中心字符时
if (k == i)
   {
    t1 = (n - 1) / 2 - k;
   }

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值