leetcode 699. 掉落的方块(java)

265 篇文章 2 订阅
235 篇文章 0 订阅

leetcode 699. 掉落的方块

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/falling-squares

题目描述

在二维平面上的 x 轴上,放置着一些方块。
给你一个二维整数数组 positions ,其中 positions[i] = [lefti, sideLengthi] 表示:第 i 个方块边长为 sideLengthi ,其左侧边与 x 轴上坐标点 lefti 对齐。

每个方块都从一个比目前所有的落地方块更高的高度掉落而下。方块沿 y 轴负方向下落,直到着陆到 另一个正方形的顶边 或者是 x 轴上 。一个方块仅仅是擦过另一个方块的左侧边或右侧边不算着陆。一旦着陆,它就会固定在原地,无法移动。
在每个方块掉落后,你必须记录目前所有已经落稳的 方块堆叠的最高高度 。
返回一个整数数组 ans ,其中 ans[i] 表示在第 i 块方块掉落后堆叠的最高高度。

示例1:
在这里插入图片描述
输入:positions = [[1,2],[2,3],[6,1]]
输出:[2,5,5]
解释:
第 1 个方块掉落后,最高的堆叠由方块 1 组成,堆叠的最高高度为 2 。
第 2 个方块掉落后,最高的堆叠由方块 1 和 2 组成,堆叠的最高高度为 5 。
第 3 个方块掉落后,最高的堆叠仍然由方块 1 和 2 组成,堆叠的最高高度为 5 。
因此,返回 [2, 5, 5] 作为答案。

示例 2:
输入:positions = [[100,100],[200,100]]
输出:[100,100]
解释:
第 1 个方块掉落后,最高的堆叠由方块 1 组成,堆叠的最高高度为 100 。
第 2 个方块掉落后,最高的堆叠可以由方块 1 组成也可以由方块 2 组成,堆叠的最高高度为 100 。
因此,返回 [100, 100] 作为答案。
注意,方块 2 擦过方块 1 的右侧边,但不会算作在方块 1 上着陆。

线段树解法

线段树就是为了解决范围内更新的问题,这个问题很容易想到用线段树,
不明白线段树的可以查看上期Segment Tree 线段树算法
我们用懒加载的方式.来优化线段树.

代码演示

class Solution {
         public static class SegmentTree {
        private int N;
        private int[] MAX;
        private int[] change;
        private boolean[] update;

        /**
         * @param size
         */
        public SegmentTree(int size) {
            N = size + 1;
            MAX = new int[N << 2];
            change = new int[N << 2];
            update = new boolean[N << 2];
        }

        /**
         * 更新最大值
         *
         * @param rt
         */
        public void pushUp(int rt) {
            MAX[rt] = Math.max(MAX[rt << 1], MAX[rt << 1 | 1]);
        }

        public void pushDown(int rt, int l, int r) {
            if (update[rt]) {
                update[rt << 1] = true;
                update[rt << 1 | 1] = true;
                change[rt << 1] = change[rt];
                change[rt << 1 | 1] = change[rt];
                MAX[rt << 1] = change[rt];
                MAX[rt << 1 | 1] = change[rt];
                update[rt] = false;
            }
        }

        //update L ~ R 范围上的数字
        //l ~ r 是 rt 所在位置能覆盖的位置
        public void update(int L, int R, int C, int l, int r, int rt) {
            //懒加载 完全覆盖就不向下分发
            if (L <= l && r <= R) {
                change[rt] = C;
                update[rt] = true;
                MAX[rt] = C;
                return;
            }

            int mid = (r + l) >> 1;
            //向下分发
            pushDown(rt, mid - l + 1, r - mid);
            if (L <= mid) {
                update(L, R, C, l, mid, rt << 1);
            }
            if (R > mid) {
                update(L, R, C, mid + 1, r, rt << 1 | 1);
            }
            pushUp(rt);
        }

        //查询
        public int query(int L, int R, int l, int r, int rt) {
            if (L <= l && r <= R) {
                return MAX[rt];
            }
            int mid = (r + l) >> 1;
            pushDown(rt, mid - l + 1, r - mid);
            int left = 0;
            int right = 0;
            if (L <= mid) {
                left = query(L, R, l, mid, rt << 1);
            }
            if (R > mid) {
                right = query(L, R, mid + 1, r, rt << 1 | 1);
            }
            return Math.max(left, right);
        }
    }
    public HashMap<Integer,Integer> indexMap(int[][]positions){
        TreeSet<Integer> set = new TreeSet<>();
        for (int[]pos : positions){
            set.add(pos[0]);
            set.add(pos[0] + pos[1] - 1);
        }
        HashMap<Integer, Integer> map = new HashMap<>();
        int count = 0;
        for (Integer c : set){
            map.put(c,++count);
        }
        return map;
    }

    public List<Integer> fallingSquares(int[][] positions) {
        HashMap<Integer, Integer> map = indexMap(positions);
        int N = map.size();
        SegmentTree segmentTree = new SegmentTree(N);
        int max = 0;
        ArrayList<Integer> ans = new ArrayList<>();
        for (int[]arr : positions){
            int L = map.get(arr[0]);
            int R = map.get(arr[0] + arr[1] - 1);
            int height = segmentTree.query(L,R,1,N,1) + arr[1];
            max = Math.max(height,max);
            ans.add(max);
            segmentTree.update(L,R,height,1,N,1);
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值