On an infinite number line (x-axis), we drop given squares in the order they are given.

The i-th square dropped (positions[i] = (left, side_length)) is a square with the left-most point being positions[i][0] and sidelength positions[i][1].

The square is dropped with the bottom edge parallel to the number line, and from a higher height than all currently landed squares. We wait for each square to stick before dropping the next.

The squares are infinitely sticky on their bottom edge, and will remain fixed to any positive length surface they touch (either the number line or another square). Squares dropped adjacent to each other will not stick together prematurely.

Return a list ans of heights. Each height ans[i] represents the current highest height of any square we have dropped, after dropping squares represented by positions[0], positions[1], ..., positions[i].

Example 1:

Input: [[1, 2], [2, 3], [6, 1]]
Output: [2, 5, 5]
Explanation:

After the first drop of positions[0] = [1, 2]: _aa _aa ------- The maximum height of any square is 2.

After the second drop of positions[1] = [2, 3]: __aaa __aaa __aaa _aa__ _aa__ -------------- The maximum height of any square is 5. The larger square stays on top of the smaller square despite where its center of gravity is, because squares are infinitely sticky on their bottom edge.

After the third drop of positions[1] = [6, 1]: __aaa __aaa __aaa _aa _aa___a -------------- The maximum height of any square is still 5. Thus, we return an answer of [2, 5, 5].

Example 2:

Input: [[100, 100], [200, 100]]
Output: [100, 100]
Explanation: Adjacent squares don't get stuck prematurely - only their bottom edge can stick to surfaces.

Note:

  • 1 <= positions.length <= 1000.
  • 1 <= positions[i][0] <= 10^8.
  • 1 <= positions[i][1] <= 10^6.

这道题不就是经典的俄罗斯方块么?!只不过是简化版的,我们只有方块下落,没有其他那些奇形怪状的东西,这样简化了难度,不过方块的大小不是固定的,有可能很大,但是不管方块再大,只要有一点点部分搭在其他方块上面,整个方块都会在上面,并不会掉下来,让我们求每落下一个方块后的最大高度。我们知道返回的是每落下一个方块后当前场景中的最大高度,那么返回的数组的长度就应该和落下方块的个数相同。所以我们可以建立一个heights数组,其中heights[i]表示第i块方块落下后所在的高度,那么第i块方块落下后场景的最大高度就是[0, i]区间内的最大值。那么我们在求出heights数组后,只要不停返回[0, i]区间内的最大值即可。继续来看,这道题的难点就是方块重叠的情况,我们先来想,如果各个方块不重叠,那么heights[i]的高度就是每个方块自身的高度。一旦重叠了,就得在已有的基础上再加上自身的高度。那么我们可以采用brute force的思想,对于每个一个下落的方块,我们都去看和后面将要落下的方块有没有重叠,有的话,和后面将要落下的方块的位置相比较,取二者中较大值为后面要落下的方块位置高度heights[j]。判读两个方块是否重叠的方法是如果方块2的左边界小于方块1的右边界,并且方块2点右边界大于方块1点左边界。就拿题目中的例子1来举例吧,第一个下落的方块的范围是[1, 3],长度为2,则heights[0]=2,然后我们看其和第二个方块[2, 5]是否重叠,发现是重叠的,则heights[1]更新为2,再看第三个方块[6, 7],不重叠,不更新。然后第二个方块落下,此时累加高度,则heights[1]=5,再看第三个方块,不重叠,不更新。然后第三个方块落下, heights[2]=1。此时我们heights数组更新好了,然后我们开始从头遍历,维护一个当前最大值curMax,每次将[0, i]中最大值加入结果res即可,参见代码如下:

解法一:

class Solution {
public:
vector<int> fallingSquares(vector<pair<int, int>>& positions) {
int n = positions.size(), cur = ;
vector<int> heights(n), res;
for (int i = ; i < n; ++i) {
int len = positions[i].second, left = positions[i].first, right = left + len;
heights[i] += len;
for (int j = i + ; j < n; ++j) {
int l = positions[j].first, r = l + positions[j].second;
if (l < right && r > left) {
heights[j] = max(heights[j], heights[i]);
}
}
}
for (int h : heights) {
cur = max(cur, h);
res.push_back(cur);
}
return res;
}
};

我们来看一种时间复杂度为O(nlogn)的解法,这种解法将每一个不同高度的区间都存到了一个HashMap中,然后每当有新的方块落下的时候,可以使用二分法来快速定位到可能发生重叠的区间的位置,如果有重叠的话,将原区间再根据高度拆成多个小区间,并且一直维护一个当前出现过的最高值,并加入结果res中。我们的HashMap的映射是建立pair和int之间的映射,由于HashMap是有自动排序的功能,默认的是使用pair中第一个元素,正好就是每个方块的起始位置。然后我们遍历每个下落的方块,建立一个临时的二维数组t,用来保存拆分后的小区间。然后我们取出当前方块的起始终止位置start和end,然后我们希望在HashMap中找第一个不大于当前方块起始位置的区间,在Java中我们可以使用floorKey()函数,但是在C++中,我们只有lower_bound()和upper_bound()可以用,分别表示找第一个不大于目标值,和第一个大于目标值的区间,那么我们为了找到第一个不大于当前起始位置的区间,可以先用upper_bound()来找到第一个大于起始位置的区间,然后向前移动一个,就是第一个不大于的了。注意向前移动操作有前提条件,就是upper_bound()返回的位置不能是首位置,否则无法前移,还有就是如果前一个区间的结束为止小于等于当前区间的起始位置,说明两个区间没有重叠,我们再移回来。

下面就要进行拆分区间的核心操作了,我们用一个while循环,循环条件是it存在,并且it指向区间的起始位置小于当前区间的结束位置。由于之前的操作确定了这两个区间一定会有重叠,那么重叠的方式就有一下四种(上方为当前区间,下方为it区间):

      ———
| |
———
————————
| |
————————

如上图所示,如果当前区间(上方)的起始位置大于it指向区间(下方)的起始位置,说明红色那段区间需要被拆分出来,我们将其拆分出来并存入数组t中。

  ———
| |
———
————————
| |
————————

如上图所示,如果当前区间(上方)的结束位置小于it指向区间(下方)的结束位置,说明洋红色那段区间需要被拆分出来,我们将其拆分出来并存入数组t中。

  ———
| |
———
————————
| |
————————

如上图所示,红色区间和洋红色区间都需要拆分出来,我们将其拆分出来并存入数组t中。

————————
| |
————————
———
| |
———

如上图所示,底层方块被完全覆盖了,没有区间需要被拆分出来。

我们用底层it指向的区间的高度来更新h,这里的h表示当前方块下落后的基础高度,然后我们将底层it指向的区间删除,因为我们已经将没有被覆盖的区间拆分出来并存入数组t中了。注意erase()函数返回的是被删除区间的下一个位置,这样使得我们的while函数能继续判断,直到it区间和当前区间不再重叠位置。退出while循环后,我们需要将当前下落方块的区间加入HashMap中,高度为基础高度h加上自身高度len。接下来就把数组t中拆分出来的小区间都加入到HashMap中,然后用当前用h+len来更新curMax,表示当前场景最大高度,加入结果res中,参见代码如下:

解法二:

class Solution {
public:
vector<int> fallingSquares(vector<pair<int, int>>& positions) {
vector<int> res;
map<pair<int, int>, int> m;
int curMax = ;
for (auto &pos : positions) {
vector<vector<int>> t;
int len = pos.second, start = pos.first, end = start + len, h = ;
auto it = m.upper_bound({start, start});
if (it != m.begin() && (--it)->first.second <= start) ++it;
while (it != m.end() && it->first.first < end) {
if (start > it->first.first) t.push_back({it->first.first, start, it->second});
if (end < it->first.second) t.push_back({end, it->first.second, it->second});
h = max(h, it->second);
it = m.erase(it);
}
m[{start, end}] = h + len;
for (auto &a : t) m[{a[], a[]}] = a[];
curMax = max(curMax, h + len);
res.push_back(curMax);
}
return res;
}
};

类似题目:

The Skyline Problem

参考资料:

https://leetcode.com/problems/falling-squares/solution/

https://leetcode.com/problems/falling-squares/discuss/108769/C++-O(nlogn)

LeetCode All in One 题目讲解汇总(持续更新中...)

[LeetCode] Falling Squares 下落的方块的更多相关文章

  1. Falling Squares

    2020-01-08 10:16:37 一.Falling squares 问题描述: 问题求解: 本题其实也是一条经典的区间问题,对于区间问题,往往可以使用map来进行区间的维护操作. class ...

  2. [Swift]LeetCode699. 掉落的方块 | Falling Squares

    On an infinite number line (x-axis), we drop given squares in the order they are given. The i-th squ ...

  3. 【leetcode】699. Falling Squares

    题目如下: On an infinite number line (x-axis), we drop given squares in the order they are given. The i- ...

  4. leetcode 699. Falling Squares 线段树的实现

    线段树实现.很多细节值得品味 都在注释里面了 class SegTree: def __init__(self,N,query_fn,update_fn): self.tree=[0]*(2*N+2) ...

  5. [LeetCode] Word Squares 单词平方

    Given a set of words (without duplicates), find all word squares you can build from them. A sequence ...

  6. Leetcode: Word Squares && Summary: Another Important Implementation of Trie(Retrieve all the words with a given Prefix)

    Given a set of words (without duplicates), find all word squares you can build from them. A sequence ...

  7. LeetCode Perfect Squares

    原题链接在这里:https://leetcode.com/problems/perfect-squares/ 题目: Given a positive integer n, find the leas ...

  8. #Leetcode# 977. Squares of a Sorted Array

    https://leetcode.com/problems/squares-of-a-sorted-array/ Given an array of integers A sorted in non- ...

  9. LeetCode699. Falling Squares

    On an infinite number line (x-axis), we drop given squares in the order they are given. The i-th squ ...

随机推荐

  1. Post Office

    Post Office poj-1160 题目大意:给你在数轴上的n个村庄,建立m个邮局,使得每一个村庄距离它最近的邮局的距离和最小,求距离最小和. 注释:n<=300,m<=min(n, ...

  2. 定位bug的姿势对吗?

    举个例子来说明 WEB页面上数据显示错误,本来应该显示38,  结果显示35,这个时候你怎么去定位这个问题出在哪里? 1.通过fiddler抓包工具(或者其他抓包工具), 分析接口返回的数据是35还是 ...

  3. 实现Windows数据绑定

    dataSet数据集   dataset驻留于内存临时存储数据简单的理解为一个临时数据库将数据源的数据保存在内存中独立于任何数据库创建dataset对象引入命名空间:system.Datadatase ...

  4. 使用cocopod管理第三方

    扭捏了两年多一直不愿意使用cocopod来管理第三方,一直感觉直接拖拽第三方就挺方便的,直到今天使用第三方库WebViewJavascriptBridge,拖拽一直有问题,不得已研究.使用了cocop ...

  5. [日常] 最近的一些破事w...

    更新博文一篇以示诈尸(大雾 (其实只是断了个网然后就彻底失踪了一波w...连题解都没法写了QAQ) $ \tiny{诈尸的实际情况是老姚提前走还把十一机房门锁了然而钥匙在联赛的时候就还了于是并不能进去 ...

  6. Beta No.1

    一.今日任务 重新熟悉整体项目 对整个项目在未来的beta冲刺中进程有一个合理的规划 由于我们送出的是一个负责前端的成员,引入的也是一个负责前端工作的女生,(女生做起美工比起男生更加得心应手吧)所以我 ...

  7. 2017-2018-1 Java演绎法 第八周 作业

    团队任务:UML设计 团队组长:袁逸灏 本次编辑:刘伟康 团队分工 第一次使用泳道图,感觉非常方便,从图中的箭头和各个活动框中可以清晰地看出分工流程: 不过既然是博客园,分工就不能只贴图,markdo ...

  8. alpha-咸鱼冲刺day2-紫仪

    总汇链接 一,合照 emmmmm.自然是没有的. 二,项目燃尽图 三,项目进展 今天并没有什么进展,弄了好久好像也只研究出怎么把JS的功能块插入进去.html的信息提交这些还不知道要怎么弄. 四,问题 ...

  9. 201621123057 《Java程序设计》第2周学习总结

    一.本周学习总结 基本数据类型 char实质属于整型.boolean类型取值只有true和false两种. 引用数据类型 包装类:自动装箱 与 自动拆箱 数组:一维数组遍历数组用foreach循环:多 ...

  10. python之路--day6---文件处理

    一.文件 1.文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件, 可以将自己的数据永久保存下来. 2.操作流程 #1. 打开文件,得到文件句柄并赋值给一个变量--f = o ...