热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[LeetCode]FallingSquares下落的方块

Onaninfinitenumberline(x-axis),wedropgivensquaresintheordertheyaregiven.Thei-th

 

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(vectorint, int>>& positions) {
        int n = positions.size(), cur = 0;
        vector<int> heights(n), res;
        for (int i = 0; i i) {
            int len = positions[i].second, left = positions[i].first, right = left + len;
            heights[i] += len;
            for (int j = i + 1; j j) {
                int l = positions[j].first, r = l + positions[j].second;
                if (l  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(vectorint, int>>& positions) {
        vector<int> res;
        mapint, int>, int> m;
        int curMax = 0;
        for (auto &pos : positions) {
            vectorint>> t;
            int len = pos.second, start = pos.first, end = start + len, h = 0;
            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 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[0], a[1]}] = a[2];
            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 题目讲解汇总(持续更新中...)


推荐阅读
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文详细介绍了PHP中与URL处理相关的三个函数:http_build_query、parse_str和查询字符串的解析。通过示例和语法说明,讲解了这些函数的使用方法和作用,帮助读者更好地理解和应用。 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了在Vue项目中如何结合Element UI解决连续上传多张图片及图片编辑的问题。作者强调了在编码前要明确需求和所需要的结果,并详细描述了自己的代码实现过程。 ... [详细]
  • 热血合击脚本辅助工具及随机数生成器源码分享
    本文分享了一个热血合击脚本辅助工具及随机数生成器源码。游戏脚本能够实现类似真实玩家的操作,但信息量有限且操作不可控。热血合击脚本辅助工具可以帮助玩家自动刷图、换图拉怪等操作,并提供了雷电云手机的扩展服务。此外,还介绍了使用mt_rand函数作为随机数生成器的代码示例。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
author-avatar
我确实是一只猪_143_267
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有