回文字符串 完美的代价

发布时间:2024年01月06日

目录

问题描述

输入格式

输出格式

样例输入

样例输出

思路分析

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)

文章来源:https://blog.csdn.net/m0_71859701/article/details/135329784
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。