今日算法题

题目一:完美的代价

问题描述:

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

输入、输出格式:

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

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

解决思路:

  • 我们先画一个简图:

(1)将end处的字符与begin处的字符进行比较,如果相等:将end处的字符移动到字符串末端,计算出移动的次数,begin向后移动一个字符end向前移动一个字符并重复(1)的操作。

(2)如果不相等:将end向前移动一个字符,重复(1)的操作直到遇到begin。

  • 我们需要注意,如果没有找到与字符串第一个字符相等的字符,那说明该字符很有可能是中间字符,此时我们直接计算将该字符移到数组中间的次数即可,并且将begin向前移动一个字符重复(1)的操作即可。

解决代码:


import java.util.Scanner;

public class Main {
    private static int times = 0;
    private static boolean isMiddle = false;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        String s = sc.next();

        char[] chs = s.toCharArray();

        if(perfect(chs,0, N-1)) {
            System.out.println(times);
        }
        else {
            System.out.println("Impossible");
        }

    }

    private static boolean perfect(char[] chs, int begin, int end) {
        if(begin >= end) {
            return true;
        }

        for(int i = end; i > begin; i--) {
            if(chs[i] == chs[begin]) {
                move(chs, i, end);
                times += (end - i);
                return perfect(chs, begin+1, end-1);
            }
        }

        if(!isMiddle) {
            isMiddle = true;
            times += (chs.length / 2 - begin);
            return perfect(chs, begin+1, end);
        }

        return false;
    }

    /**
     * 将数组中的指定字符移动到指定位置
     * @param chs:字符数组
     * @param target:指定字符的位置
     * @param des:目标的位置
     */
    private static void move(char[] chs, int target, int des) {
        char c = chs[target];

        for(int i = target; i < des; i++) {
            chs[i] = chs[i+1];
        }

        chs[des] = c;
    }

}

题目二:矩形面积交

问题描述:

平面上有两个矩形,它们的边平行于直角坐标系的X轴或Y轴。对于每个矩形,我们给出它的一对相对顶点的坐标,请你编程算出两个矩形的交的面积。(时间限制:1.0s,内存限制:512.0MB)

输入、输出格式:

输入仅包含两行,每行描述一个矩形。
在每行中,给出矩形的一对相对顶点的坐标,每个点的坐标都用两个绝对值不超过10^7的实数表示。

输出仅包含一个实数,为交的面积,保留到小数后两位。

解决思路:

  • 由于后面计算相交矩形的面积时需要知道矩形的长和宽,而长和宽是根据横纵坐标算出的,所以我们将横、纵坐标分别存储在两个数组中。

  • 判断两个矩形不相交的思路:通过画图,两个矩形不相交的相对位置有4种情况(上、下、左、右),并且所给矩形的对角线也有两种情况(递增和递减)。

  • 计算相交矩形长和宽的思路:我们可以先画一个简图:

得出上图中红色字体的公式是有前提的,即:arr1[3] > arr1[1] > arr1[2] > arr1[0]和arr2[3] > arr2[1] > arr2[2] > arr2[0],所以我们在计算之前可以先对横纵坐标数组分别进行排序,再计算即可。

解决代码:


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

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        double[] arr1 = new double[4];   // 存储横坐标
        double[] arr2 = new double[4];   // 存储纵坐标
        for (int i = 0; i < 4; i++) {
            arr1[i] = sc.nextDouble();
            arr2[i] = sc.nextDouble();
        }

        // 两个矩形不相交有四种相对位置,取最大最小值是由于矩形有两条对角线
        if ((Math.max(arr1[0], arr1[1]) <= Math.min(arr1[2], arr1[3])) || (Math.max(arr1[2], arr1[3]) <= Math.min(arr1[0], arr1[1])) ||
                (Math.max(arr2[0], arr2[1]) <= Math.min(arr2[2], arr2[3]) || (Math.max(arr2[2], arr2[3]) <= Math.min(arr2[0], arr2[1])))) {
            System.out.println("0.00");
        }
        else {
            Arrays.sort(arr1);
            Arrays.sort(arr2);
            double i = arr1[2] - arr1[1];
            double j = arr2[2] - arr2[1];
            System.out.println(String.format("%.2f", i*j));
        }

    }
}

posted @ 2020-03-18 17:24  samsaraaa  阅读(143)  评论(0编辑  收藏  举报