【力扣刷题 | 第二十天】

目录

前言:

406. 根据身高重建队列 - 力扣(LeetCode)

452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

总结:


前言:

今天刷贪心算法的题目

406. 根据身高重建队列 - 力扣(LeetCode)

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

扫描二维码关注公众号,回复: 15793649 查看本文章

很多小伙伴在看到这道题的时候就直接蒙圈了,并没有清楚题目的要求,在这里我详细讲解一下:本题的意思是:people数组中每一个元素都有(a,b),a表示当前人的身高,b表示有在排好的序列中几个人比他高或者一样高(从左向右),一开始给出的顺序是乱序,我们要做的就是对这些元素进行排序,确保排序结果满足每一个元素中的b条件(从左往右数有多少个人大于等于自己的身高)。

其实这道题和我们之前刷过的分发糖果问题还是有一定的相似度,例如我们都要考虑两个维度,分发糖果是既要考虑比左边的人多,又要考虑比右边的人多,而这个就是既要考虑人数符合要求,还要考虑到高度符合要求,而我们解决问题的宏观思想也是一样的:分步求解!

我们用案例来给大家讲解:

people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]

此时我们先对身高进行排序(从高到低):

 那么此时在每一个人前面的一定是身高大于或等于自己身高的人,此时再根据给定数组中的自己前面的人数进行插入就好了,因为此时前面的都是大于等于自己身高的,因此有几个人比自己高,就把自己插到第[i]个位置上就好了。而插入是不会影响其他的数字的,因为我们是从后往前插入,那么插入加进来的时候,自己的左边和右边一定都比自己大,也就是说插入的元素并不会影响后面元素的前面的大于等于自己身高的人数。

例如:[7,0][7,1][6,1]

因为此时身高为6的要求只能有一个人身高比自己高,那么就插到[7,0]后面,变为[7,0][6,1][7,1],而[6,1]的插入并不会影响[7,1]前面比自己大的元素个数。

按照这种思想,最终就可以得到结果:

解法: 

class Solution {
public:
   static bool compare(const vector<int>& a, const vector<int>& b)
    {
        if(a[0]==b[0])
        {
           return a[1]<b[1];
        }
        return a[0]>b[0];
    }

      vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
          sort(people.begin(),people.end(),compare);
        
        vector<vector<int>>que;
          for(int i=0;i<people.size();i++)
          {
              int poision = people[i][1];
              que.insert(que.begin() + poision, people[i]);
          }
          
            return que;
      }
};

452. 用最少数量的箭引爆气球 - 力扣(LeetCode)

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。

一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足  xstart ≤ x ≤ xend,则该气球会被 引爆 。可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。

给你一个数组 points ,返回引爆所有气球所必须射出的 最小 弓箭数 。

 这道题太过于抽象,我们用画图来解释一下:横线就相当于气球,我们的弓箭只能垂直于x轴发射,只要穿过横线,就认为是爆炸,求最少多少只弓箭能让气球全部爆炸。我们要想用较少的弓箭射爆最多的气球,也就是首先尽量让气球重叠,其次就是让弓箭射重叠区域多的位置,而让气球尽量重叠,就是对气球进行排序,把[10,16],[2,8],[1,6],[7,12]先进行一个排序,排序顺序无所谓,从大到小或从小到大都无所谓,画图可得:

 而要想要这些排序好的气球爆炸,最少的方法就是:

在这两个位置释放弓箭,便可以用最小的弓箭数量射爆全部的气球。

在代码的逻辑上就是:

         如果这个气球的左边界小于上一个气球的右边界,那么这两个气球就是可以一起射爆的。

class Solution {
public:
    int findMinArrowShots(const vector<vector<int>>& points) {
        if (points.empty()) return 0;

        int result = 1;
        int prevEnd = points[0][1];
        int i = 1;
        while (i < points.size()) {
            if (points[i][0] > prevEnd) {
                ++result;
                prevEnd = points[i][1];
                ++i;
            }
            else {
                prevEnd = min(prevEnd, points[i][1]);
                ++i;
            }
        }
        return result;
    }
};

总结:

贪心算法题到后面思路上很难有创新,主要都是代码实现上的困难。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

猜你喜欢

转载自blog.csdn.net/fckbb/article/details/131776945
今日推荐