Leetcode - 周赛427

发布于:2024-12-18 ⋅ 阅读:(44) ⋅ 点赞:(0)

目录

一,3379. 转换数组

二,3380. 用点构造面积最大的矩形 I

三,3381. 长度可被 K 整除的子数组的最大元素和

四,3382. 用点构造面积最大的矩形 II


一,3379. 转换数组

本题就是一个模拟题,难点在于如何计算循环数组移动之后的下标,可以模拟循环,遇到-1转成n-1,遇到 n 转成 0,或者直接使用模运算。

代码如下:

class Solution {
    public int[] constructTransformedArray(int[] nums) {
        int n = nums.length;
        int[] ans = new int[n];
        for(int i=0; i<n; i++){
            int j = (nums[i]%n + i + n) % n;
            ans[i] = nums[j];
        }
        return ans;
    }
}

二,3380. 用点构造面积最大的矩形 I

本题数据范围小,直接暴力枚举,代码如下:

class Solution {
    //(x,y) (a,b) (x,b) (a,y)
    public record Data(int x, int y){

    }
    public boolean check(int i, int j, int[][] p){
        int cnt = 0;
        for(int[] t : p){
            int x = t[0], y = t[1];
            if(x >= Math.min(p[i][0], p[j][0]) && x <= Math.max(p[i][0], p[j][0]) && y >= Math.min(p[i][1], p[j][1]) && y <= Math.max(p[i][1], p[j][1]))
                    cnt += 1;
        }
        return cnt == 4;
    }
    public int maxRectangleArea(int[][] p) {
        int n = p.length;
        Set<Data> set = new HashSet<>();
        for(int i=0; i<n; i++){
            set.add(new Data(p[i][0], p[i][1]));
        }
        int ans = -1;
        for(int i=0; i<n; i++){
            for(int j=i+1; j<n; j++){
                Data d1 = new Data(p[i][0], p[j][1]);
                Data d2 = new Data(p[j][0], p[i][1]);
                if(p[i][0] != p[j][0] && p[i][1] != p[j][1] && set.contains(d1) && set.contains(d2) && check(i, j, p)){
                    ans = Math.max(ans, Math.abs(p[i][0]-p[j][0]) * Math.abs(p[i][1]-p[j][1]));
                }
            }
        }
        return ans;
    }
}

三,3381. 长度可被 K 整除的子数组的最大元素和

本题看到子数组的最大和,第一时间想到的是滑动窗口,但是题目还要求子数组的长度可以被 k 整除,所以如果使用滑动窗口就需要枚举窗口的大小即 k 及其倍数,但是这样做时间复杂度为O(n^2/k),必然会超时。

再看题目求子数组的和,子数组和可以用前缀和(suf)来求,假设子数组的区间为 [L,R] 且 R - L + 1 是 k 的倍数,枚举子数组的右端点R,要求 suf[R] - suf[L-1] 的最大值 (L-1 = [R - ?*k,...,R - 2*k,R - k]),就是求 suf[L-1] (L-1 = [R - ?*k,...,R - 2*k,R - k]) 的最小值。因为是从小到大枚举nums数组,所以可以一边枚举,一边计算 min(suf[L-1])。画个图理解一下:

代码如下:

class Solution {
    public long maxSubarraySum(int[] nums, int k) {
        long ans = Long.MIN_VALUE;
        int n = nums.length;
        long[] suf = new long[n+1];
        long[] pre = new long[k];
        Arrays.fill(pre, Long.MAX_VALUE/2);
        for(int i=0; i<n; i++){
            suf[i+1] = suf[i] + nums[i];
        }
        for(int i=0; i<=n; i++){
            ans = Math.max(ans, suf[i] - pre[i%k]);
            pre[i%k] = Math.min(pre[i%k], suf[i]);
        }
        return ans;
    }
}

四,3382. 用点构造面积最大的矩形 II

 

class Solution {
    //树状数组
    static class Fenwick{
        int[] f;
        public Fenwick(int n){
            f = new int[n];
        }
        void add(int i){
            while(i < f.length){
                f[i] += 1;
                i += i & -i;
            }
        }
        int pre(int i){
            int res = 0;
            while(i > 0){
                res += f[i];
                i -= i & -i;
            }
            return res;
        }
        int query(int l, int r){
            return pre(r) - pre(l-1);
        }
    }
    //左下角右上角(x1,y1) (x2,y2) 面积area
    private record Query(int x1, int x2, int y1, int y2, long area){
    }
    //qid:记录是那个区域的查询,一个区域有两个查询[0,x1-1] - [0, x2] : [y1, y2] 
    //sign:记录是当前区域内查询的加减操作
    //[y1,y2]:是[0,x] - [y1,y2]的区域查询
    private record Data(int qid, int sign, int y1, int y2){
    }
    public long maxRectangleArea(int[] xCoord, int[] yCoord) {
        Map<Integer, List<Integer>> xMap = new HashMap<>();//(x,[y1,y2,y3...])
        Map<Integer, List<Integer>> yMap = new HashMap<>();//(y,[x1,x2,x3...])
        int n = xCoord.length;
        for(int i=0; i<n; i++) {
            xMap.computeIfAbsent(xCoord[i], k->new ArrayList<>()).add(yCoord[i]);
            yMap.computeIfAbsent(yCoord[i], k->new ArrayList<>()).add(xCoord[i]);
        }
        //(x,y1)的相邻下面一个点(x,y2)
        Map<Long, Integer> below = new HashMap<>();
        for(var e : xMap.entrySet()){
            int x = e.getKey();
            List<Integer> ys = e.getValue();
            ys.sort(null);
            for(int i=1; i<ys.size(); i++){
                below.put((long)x<<32|ys.get(i), ys.get(i-1));
            }
        }
        //(x1,y)的相邻左边一个点(x2,y)
        Map<Long, Integer> left = new HashMap<>();
        for(var e : yMap.entrySet()){
            int y = e.getKey();
            List<Integer> xs = e.getValue();
            xs.sort(null);
            for(int i=1; i<xs.size(); i++){
                left.put((long)xs.get(i)<<32|y, xs.get(i-1));
            }
        }

        //方便离散化
        List<Integer> xs = new ArrayList<>(xMap.keySet());
        List<Integer> ys = new ArrayList<>(yMap.keySet());
        xs.sort(null);
        ys.sort(null);

        //统计满足条件(即是矩形)的左下角(x1,y1)右上角(x2,y2)
        List<Query> queries = new ArrayList<>();
        for(var e : xMap.entrySet()){
            int x2 = e.getKey();
            List<Integer> listY = e.getValue();
            for(int i=1; i<listY.size(); i++){
                int y2 = listY.get(i);
                int x1 = left.getOrDefault((long)x2<<32|y2, -1);
                if(x1 < 0) continue;
                int y1 = listY.get(i-1);
                //判断(x2,y1)和(x1,y1)相邻
                if(left.getOrDefault((long)x2<<32|y1, -1) != x1)
                    continue;
                //判断(x1,y2)和(x1,y1)相邻
                if(below.getOrDefault((long)x1<<32|y2, -1) != y1)
                    continue;
                queries.add(new Query(
                    Collections.binarySearch(xs, x1),
                    Collections.binarySearch(xs, x2),
                    Collections.binarySearch(ys, y1),
                    Collections.binarySearch(ys, y2),
                    (long)(x2-x1)*(y2-y1)
                ));
            }
        }

        //添加二维查询 - 一块区域需要两个查询[0,x1-1] - [0, x2] : [y1, y2] 
        List<Data>[] qs = new ArrayList[xs.size()];
        Arrays.setAll(qs, i -> new ArrayList<>());
        for(int i=0; i<queries.size(); i++){
            Query q = queries.get(i);
            if(q.x1 > 0){//[0,x1-1] : [y1, y2] 
                qs[q.x1-1].add(new Data(i, -1, q.y1, q.y2));
            }
            //[0, x2] : [y1, y2] 
            qs[q.x2].add(new Data(i, 1, q.y1, q.y2));
        }

        int[] res = new int[queries.size()];
        Fenwick tree = new Fenwick(ys.size()+1);//[1,n]
        for(int i=0; i<xs.size(); i++){
            for(int y : xMap.get(xs.get(i))){
                tree.add(Collections.binarySearch(ys, y)+1);
            }
            for(Data q : qs[i]){
                res[q.qid] += q.sign * tree.query(q.y1+1, q.y2+1);
            }
        }
        long ans = -1;
        for(int i=0; i<res.length; i++){
            if(res[i] == 4)
                ans = Math.max(ans, queries.get(i).area);
        }
        return ans;
    }
}