8.27网易笔试题

我共通过两题,最后一题一直超时。
第一题,贴墙纸。
思路:把需要的所有墙纸贴好,然后取出中间的m*m的子矩阵就可以了
代码如下:
import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int T = in.nextInt(); while (T-- > 0) { int n = in.nextInt(); int m = in.nextInt(); char[][] a = new char[n][]; for (int i = 0; i < n; i++) a[i] = in.next().toCharArray(); getCenterMatrix(n, m, a); } } private static void getCenterMatrix(int n, int m, char[][] a) { int width = 1 + ((m - n - 1) / (2 * n) + 1) * 2; //System.out.println("width = " + width); char[][] c = new char[width*n][width*n]; for (int i = 0; i < c.length; i += n) { for (int j = 0; j < c.length; j += n) { for (int k = 0; k < n; k++) { for (int h = 0; h < n; h++) { c[i+k][j+h] = a[k][h]; } } } } int st = (width * n - m) / 2; for (int i = st; i < st+m; i++) { for (int j = st; j < st+m; j++) { System.out.print(c[i][j]); } System.out.println(); } System.out.println(); } }
第二题,求矩阵覆盖的面积。难点在于有多个矩阵覆盖了同一块区域,但是这块区域的面积只能被计算一次。如果暴力去做可能会超时,于是观察题目数据量,矩形的坐标范围在[0,1000]之间,同时矩阵的数量为[1, 500],所有可以考虑枚举Y轴,然后把包含这个Y轴的所有矩阵在这条Y轴上的面积都计算一遍!为了计算的快速,需要先按照x0坐标排序,问题就转化为了如下问题:
给你一堆线段, [1,3], [5, 7],...,请你算出线段所覆盖的最大长度!这样就能算出每一个Y坐标覆盖的面积,然后把0-1000的面积加起来就是总的面积了。
注意:边缘不能重复计算,比如矩阵[0,0,1,1]的面积为1,而不是4,也就是说y为0时不可以和y为1时同时计算。我在代码中没有考虑矩阵的下边缘。
if (i > y0 && i <= y1) // 不考虑下边缘AC代码如下:
import java.util.*; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); int T = in.nextInt(); int x0, y0, x1, y1; while (T-- > 0) { int n = in.nextInt(); ArrayList<int[]> recs = new ArrayList<>(); for (int i = 0; i < n; i++) { x0 = in.nextInt(); y0 = in.nextInt(); x1 = in.nextInt(); y1 = in.nextInt(); recs.add(new int[]{x0, y0, x1, y1}); } // 按照x0排序 recs.sort(Comparator.comparingInt(o -> o[0])); // 找出有效矩阵 boolean[] ok = new boolean[n]; for (int i = 0; i < n; i++) { if (!ok[i]) { for (int j = i + 1; j < n; j++) { if (crossed(recs.get(i), recs.get(j))) { ok[i] = ok[j] = true; } } } } //System.out.println(Arrays.toString(ok)); int area = 0; for (int i = 0; i <= 1000; i++) { int len = 0, st = -1, end = -1; for (int j = 0; j < n; j++) { if (!ok[j]) continue; int[] t = recs.get(j); x0 = t[0]; y0 = t[1]; x1 = t[2]; y1 = t[3]; //if (y1 == i) continue; if (i > y0 && i <= y1) { // 不考虑下边缘 if (x0 > end) { len += x1 - x0; end = x1; } else if (x1 > end) { len += x1 - end; end = x1; } } } area += len; } System.out.println(area); } } private static boolean crossed(int[] r1, int[] r2) { // x0 >= x1 if (r1[0] >= r2[2] || r2[0] >= r1[2]) return false; // y0 >= y1 if (r1[1] >= r2[3] || r2[1] >= r1[3]) return false; return true; } }
思路:枚举所有可能的边,但是超时。。。有AC大佬给个思路吗?