完美的代价

题目:

* 题目:
* 回文串,是一种特殊的字符串,它从左往右和从右往左读是一样的。
* 现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变为完美的回文回文串。
* 例如:mamad
* 第一次交换:mamda
* 第二次交换:madma
* 第三次交换:madam

* 输入格式:
* 第一行输入整数n ,表示字符串的长度(n <=8000 )
* 第二行输入字符串,长度为n,只包含小写字母

* 输出格式:
* 如果可能,输出最少次数
* 否则,输出Impossible

* 样列输入
* 5
* mamad
* 样例输出
* 3

解题思路:
  • 输入
  • 处理数据
  • 输出
输入:
Scanner sc = new Scanner(System.in);
        int len = sc.nextInt();
        String str = sc.next();
处理数据:(多读题,解题的关键)
关键词提取:

回文串:

第一个与倒数第一一样

第二个与倒数第二一样

思考:

什么是回文串?

怎么判断它是回文串

结论:

(1)根据回文串的定义:我们需要俩个指针,一个从左往右,一个从右往左

(2)根据第一点,我们可以定义一个指针从左往右遍历,一个指针从右往左遍历找到相同的就将它丢到最后,长度--

如图当我们找到m后将m移动到最后,m不可能再次被移动【回文串特性:当前数据的第一个,与当前数据的最后一个一样】

(3)第一个与最后一个位置确定,那就可以缩短数组的长度

如果没有找到呢?

按照刚才的思路如果没有找到,我们不管它会出现什么样的情况?

我们把c假装看不见跳过对后面的数据排列,让它除掉c就是回文数,最后只需要移动c即可;


思路总结:

这题最重要是思路是将左右移动的数据:转换为只移动一个方向;我们每一次假设左边得到的数据是已经排好序的,从当前左边的数据中确定当前最后位置的数据;

在这个过程中,我们对数组的长度减少,减少交换的可能次数,保证数据只从一个方向移动,所以可以作为最少移动次数;

1、判断数据是否可以构成回文串

        //判断是否为可成为回文串
        //将数据类型转换为数组减少charAt的调用
        char[] arr = str.toCharArray();
        //1、判断长度是否符合
        if (len != arr.length) {
            System.out.println("Impossible1");
            return;
        }
        //2、判断是否可以构成回文串
        int[] num = new int[26];
        for (int i = 0; i < arr.length; i++) {
            int k = arr[i] - 97;
            num[k]++;
        }
        int ans = 0;
        for (int i : num) {
            if (i % 2 == 1) {
                ans++;
            }
        }
        if (ans > 1) {
            System.out.println("Impossible2");
            return;
        }

2、构建回文串,记录回文数据

     ans = 0;//记录移动次数
        int end = len - 1;
        for (int i = 0; i < (len+1) / 2; i++) {
            int j;
            for (j = end; j > i; j--) {
                if (arr[i] == arr[j]) {
                    while (j < end) {
                        char tmp = arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = tmp;
                        j++;
                        ans++;
                    }
《《  长度--  》》
                    end--;
                    break;
                }
            }
            if (i == j) {
                ans += (len-1) / 2 - i;
            }
        }
输出:ans记录次数
System.out.println(ans);

完整代码:《因为懒,所以没有使用方法》

package LanQiao.text;

import java.util.Scanner;

/**
 * 题目:
 * 回文串,是一种特殊的字符串,它从左往右和从右往左读是一样的。
 * 现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变为完美的回文回文串。
 * 例如:mamad
 * 第一次交换:mamda
 * 第二次交换:madma
 * 第三次交换:madam
 * <p>
 * 输入格式:
 * 第一行输入整数n ,表示字符串的长度(n <=8000 )
 * 第二行输入字符串,长度为n,只包含小写字母
 * <p>
 * 输出格式:
 * 如果可能,输出最少次数
 * 否则,输出Impossible
 * <p>
 * 样列输入
 * 5
 * mamad
 * 样例输出
 * 3
 */
public class 回文串 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int len = sc.nextInt();
        String str = sc.next();

        //判断是否为可成为回文串
        //将数据类型转换为数组减少charAt的调用
        char[] arr = str.toCharArray();
        //1、判断长度是否符合
        if (len != arr.length) {
            System.out.println("Impossible1");
            return;
        }
        //2、判断是否可以构成回文串
        int[] num = new int[26];
        for (int i = 0; i < arr.length; i++) {
            int k = arr[i] - 97;
            num[k]++;
        }
        int ans = 0;
        for (int i : num) {
            if (i % 2 == 1) {
                ans++;
            }
        }
        if (ans > 1) {
            System.out.println("Impossible2");
            return;
        }


        ans = 0;
        int end = len - 1;
        for (int i = 0; i < (len+1) / 2; i++) {
            int j;
            for (j = end; j > i; j--) {
                if (arr[i] == arr[j]) {
                    while (j < end) {
                        char tmp = arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = tmp;
                        j++;
                        ans++;
                    }
                    end--;
                    break;
                }
            }
            if (i == j) {
                ans += (len-1) / 2 - i;
            }
        }
        System.out.println(ans);
    }
}

各位小伙伴有没有画图工具推荐~,excle还是不顺手,非常感谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

续写少年!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值