回文字符串 完美的代价

目录

问题描述

输入格式

输出格式

样例输入

样例输出

思路分析

Java题解

python题解

问题描述

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

输入格式

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

输出格式

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

样例输入

5
mamad

样例输出

3

思路分析

        这个题目文档是将字符串变成回文子串的最少交换次数,这是一个贪心问题,我们需要思考,怎么样才能保证他得到的交换次数是最小的,那么就是不能有浪费的交换次数。

        我们思考,在判断一个字符串是否是回文子串时,我们常用的方法就是,定义两个指针left,right,初始化指针指向子串的头和尾节点,判断指针指向的字符是否相同,然后就能判断该字串是否是回文子串。

        那么在这里我们肯定也是要找不符合的节点位置,那么在找到不符合的节点left和right后,我们还需要使用distance_left和distance_right方法来寻找从左边找和right相等的字符位置,以及从右边找和left相等的字符的位置,也就是和left节点相同的字符的位置和与right节点相同的字符的位置,然后要求是交换次数最少的,那么就用需要最小交换次数的字符,这样在变换之后两边的字符是符合最终要求的,只有中间的是存在不符合要求的,但永远会比两边的距离要小,这样交换次数也会越来越小,得到的结果也将会是最小的结果。

        那么在思考,在进行这一步变换的最终结果中,实际上是可以看成将符合条件的字符移到了需要变换的left或者right的位置,就可以使用动态数组快速的变换过来,那么在这个变化过程中交换的次数实践上就是初始点的位置到目标点的距离,在进行累加即可得到最终的结果

Java题解

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        input.nextLine();
        String s = input.nextLine();
        ArrayList<Character> lst = new ArrayList<>();
        for (char c:s.toCharArray()){
            lst.add(c);
        }
        int left = 0,right = n-1;
        int counts = 0;
        boolean flag2 = true;
        while (left < right){
            if (lst.get(left) != lst.get(right)){
                int l =  distance_left(left,lst,right),r = distance_right(left,lst,right);
                if (l == 10000 && r == -100) {
                    System.out.println("Impossible");
                    flag2 = false;
                    break;
                };
                if (l - left <= right - r){
                    char a = lst.remove(l);
                    lst.add(left,a);
                    counts += l-left;
                }
                else {
                    boolean flag = false;
                    if (right != n-1)  flag= true;
                    char a = lst.remove(r);
                    if (flag)lst.add(right,a);
                    else lst.add(a);
                    counts += right - r;
                }
            }
            left += 1;
            right -= 1;
        }
        if (flag2) System.out.println(counts);
    }

    private static int distance_left(int left, ArrayList<Character> lst, int right) {
        for (int i = left+1;i < right;i ++){
            if (lst.get(i) == lst.get(right)) return i;
        }
        return 10000;
    }
    private static int distance_right(int left, ArrayList<Character> lst, int right) {
        for (int i = right-1;i > left;i --){
            if (lst.get(i) == lst.get(left)) return i;
        }
        return -100;
    }

}

python题解

def distance_left(left,lst,right):
    for i in range(left+1,right):
        if lst[i] == lst[right]:return i
    return 10000

def distance_right(left,lst,right):
    for i in reversed(range(left+1,right)):
        if lst[i] == lst[left]:return i
    return -100

n = int(input())
lst = list(input())
counts,left,right = 0,0,n-1
flag2 = True
while left < right:
    if lst[left] != lst[right]:
        l = distance_left(left,lst,right)
        r = distance_right(left,lst,right)
        if l == 10000 and r == -100:
            print("Impossible")
            flag2 = False
            break

        if l-left <= right - r:
            a = lst.pop(l)
            lst.insert(left,a)
            counts += l-left
        else:
            flag = False
            if right != n-1:
                flag = True
            a = lst.pop(r)
            if flag:lst.insert(right,a)
            else:lst.append(a)
            counts += right - r
    left += 1
    right -= 1
if flag2:print(counts)

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

黑色卷心菜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值