蓝桥杯 basic19试题 基础练习 完美的代价

记录我的刷题历程

蓝桥杯 basic19试题 基础练习 完美的代价

资源限制

时间限制:1.0s 内存限制:512.0MB

问题描述

回文串,是一种特殊的字符串,它从左往右读和从右往左读是一样的。小龙龙认为回文串才是完美的。现在给你一个串,它不一定是回文的,请你计算最少的交换次数使得该串变成一个完美的回文串。
  交换的定义是:交换两个相邻的字符
  例如mamad
  第一次交换 ad : mamda
  第二次交换 md : madma
  第三次交换 ma : madam (回文!完美!)
输入格式
  第一行是一个整数N,表示接下来的字符串的长度(N <= 8000)
  第二行是一个字符串,长度为N.只包含小写字母
输出格式
  如果可能,输出最少的交换次数。
  否则输出Impossible

样例输入

5
mamad

样例输出

3

思路与大致想法

刚开始的思路是设置两个指针往中间走,两个指针分别寻找与自己最近的那个相同的字母,若是两个指针同时找到了位置距离差距相同的字母,则默认按照从左到右的顺序,将找到的字母相邻置换,直到与当前指针字母构成回文,逐项返回,直到两个指针相遇或者相邻,使循环结束。

遇到的问题

思路不够周全最后导致有很多的遗漏问题,例如回文串的奇数或者偶数数量可能对变换产生的影响,impossible的输出条件,以及是否是离自己最近的变换可以得到最少的变换次数等等。最终得分30

错误代码

import java.util.Scanner;

public class Main {

    public static boolean IsHuiWen(String s){
        int i=0;
        int j=s.length()-1;
        while(i<j){
            if(s.charAt(i)!=s.charAt(j)){
                return false;
            }
            i++;
            j--;
        }
        return true;
    }
    public static int feedback1(StringBuilder s1,int i,int j){
        int q=0;
        for (int p=i+1;p<j;p++){
            if(s1.charAt(p)==s1.charAt(i)){
                q=p;
                break;
            }
        }
        return q-i;
    }
    public static int feedback2(StringBuilder s1,int i,int j){
        int q=j;
        for (int p=j-1;p>i;p--){
            if(s1.charAt(p)==s1.charAt(j)){
                q=p;
                break;
            }
        }
        return j-q;
    }

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int n=scanner.nextInt();
        String s=scanner.next();
        int count=0;
        StringBuilder s1=new StringBuilder(s);
        if(IsHuiWen(s)){
            System.out.println(0);
            return;
        }
        if(n%2==0){
            int i=0;
            int j=s.length()-1;
            while (i<j){
                if(s1.charAt(i)!=s1.charAt(j)){
                    int x=feedback1(s1,i,j);
                    int y=feedback2(s1,i,j);
                    if(x>0&&y>0) {
                        if (x <= y) {
                            for (int m = x; m < j; m++) {
                                char temp = s1.charAt(m);
                                s1.setCharAt(m, s1.charAt(m + 1));
                                s1.setCharAt(m + 1, temp);
                                count++;
                            }
                        }
                        else {
                            for (int m = j-y; m >i; m--) {
                                char temp = s1.charAt(m);
                                s1.setCharAt(m, s1.charAt(m - 1));
                                s1.setCharAt(m - 1, temp);
                                count++;
                            }
                        }
                    }
                    else if(x>0){
                        for (int m = x; m < j; m++) {
                            char temp = s1.charAt(m);
                            s1.setCharAt(m, s1.charAt(m + 1));
                            s1.setCharAt(m + 1, temp);
                            count++;
                        }
                    }
                    else if (y>0){
                        for (int m = j-y; m >i; m--) {
                            char temp = s1.charAt(m);
                            s1.setCharAt(m, s1.charAt(m - 1));
                            s1.setCharAt(m - 1, temp);
                            count++;
                        }
                    }
                    else {
                        System.out.println("Impossible");
                        return;
                    }

                }
                if(IsHuiWen(s1.toString())){
                    System.out.println(count);
                    break;
                }
                i++;
                j--;

            }

        }
        else {
            int i=0;
            int j=s.length()-1;
            while (i<j){
                if(s1.charAt(i)!=s1.charAt(j)){
                    int x=feedback1(s1,i,j);
                    int y=feedback2(s1,i,j);
                    if(x>0&&y>0) {
                        if (x <= y) {
                            for (int m = i+x; m < j; m++) {
                                char temp = s1.charAt(m);
                                s1.setCharAt(m, s1.charAt(m + 1));
                                s1.setCharAt(m + 1, temp);
                                count++;
                            }
                        }
                        else {
                            for (int m = y-i; m > i; m--) {
                                char temp = s1.charAt(m);
                                s1.setCharAt(m, s1.charAt(m - 1));
                                s1.setCharAt(m - 1, temp);
                                count++;
                            }
                        }
                    }
                    else if(x>0){
                        for (int m =i+x; m < j; m++) {
                            char temp = s1.charAt(m);
                            s1.setCharAt(m, s1.charAt(m + 1));
                            s1.setCharAt(m + 1, temp);
                            count++;
                        }
                    }
                    else if (y>0){
                        for (int m = j-y; m >i; m--) {
                            char temp = s1.charAt(m);
                            s1.setCharAt(m, s1.charAt(m - 1));
                            s1.setCharAt(m - 1, temp);
                            count++;
                        }
                    }
                    else {
                        System.out.println("Impossible");
                        return;
                    }

                }
                if(IsHuiWen(s1.toString())){
                    System.out.println(count);
                    break;
                }
                i++;
                j--;
                if(j==n/2){
                    if(s1.charAt(i)==s1.charAt(j)){
                        System.out.println(count);
                        break;
                    }
                    System.out.println("Impossible");
                    break;
                }

            }

        }

    }
}

结果

由结果可见思路不是很周全

借鉴完别人经验之后的思路

1.先判断impossible的情况
奇数字符串时
abcbe 出现3个奇数次的字符
abcde 出现5个奇数次的字符
则n个字符串如果不是回文,则出现了大于1个的字符出现奇数次的情况
双数字符串时
aaba 出现2个奇数次的字符
acbd 出现4个奇数次的字符
则n个字符如果不是回文,则如果出现1个奇数次字符就不是
2.不是impossible的情况
双数
i到n/2位置时停止循环
设置两个指针往中间走,两个指针分别寻找与自己最近的那个相同的字母,若是两个指针同时找到了位置距离差距相同的字母,则默认按照从左到右的顺序,将找到的字母相邻置换,直到与当前指针字母构成回文,逐项返回,直到两个指针相遇或者相邻,使循环结束。
单数
i,j两个指针相遇时停止循环
先记录出现奇数次的那个字符与中间的距离,然后将它放在一边,
开始双数的排序,最后与双数结果相加输出

正确代码部分

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int n=scanner.nextInt();
        String s=scanner.next();
        StringBuilder s1=new StringBuilder(s);
        int end=s.length()-1;//最后一个字符
        int count=0;//计数
        int isApp=0;//出现奇数字符的个数
        for (int i=0;i<end;i++){
            for (int j=end;j>=i;j--){
                if(i==j){//没相同字符
                    if(n%2==0||isApp==1){
                        System.out.println("Impossible");
                        return;
                    }
                    isApp=1;
                    count=count+Math.abs(n/2-i);

                }
                else if(s1.charAt(i)==s1.charAt(j)){
                    for (int k=j;k<end;k++){
                        char temp=s1.charAt(k);
                        s1.setCharAt(k,s1.charAt(k+1));
                        s1.setCharAt(k+1,temp);
                        count++;
                    }
                    end--;
                    break;
                }
            }
        }
        System.out.println(count);

    }
}

成功截图

在这里插入图片描述

思考

我们可以发现用了三层for循环,时间复杂度最高为n^3,感觉最占用时间的是逐项的替换,就思考能否通过只记录交换次数,不进行逐项替换节省时间

优化代码

import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        String s = scanner.next();
        int result = 0;//计数
        int rightNum = 0;//当前位置
        boolean[] flag = new boolean[n];
        boolean hasOne = false;
        for (int i = 0; i < n; i++) {
            if (flag[i]) continue;
            int temp = 0;
            for (int j = n - 1; j >= i; j--) {
                if (flag[j]) continue;
                if (i == j) {
                    if ((n % 2 ) == 0 || hasOne) {
                        System.out.println("Impossible");
                        return;
                    }
                        result += Math.abs(rightNum - (n/2));//加上最后一个奇数插入所需的交换次数
                        hasOne = true;
                    } else if (s.charAt(i) == s.charAt(j)) {
                        rightNum++;//遇到相同字符,就把当前位置指向下一个
                        result += temp;
                        flag[j] = true;//说明j位置已被配对过
                        break;
                    } else {
                        temp++;//两个交换的数的距离
                    }
                }



            }
        System.out.println(result);
        }
    }

结论

成功把时间复杂度降到了n^2

借鉴来源

https://www.cnblogs.com/cao-lei/p/7163223.html
第一次写博客,思路也许不太清晰,仅作为个人记录学习使用,如果各位大佬们有意见和建议也可以在评论区加以指导。一起进步一起学习

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值