掉落的方块
- leetcode 699. 掉落的方块
- 题目描述
- 线段树解法
- 代码演示
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;
}
}