• Leetcode406. 根据身高重建队列


    Leetcode406. 根据身高重建队列

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

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

    示例 1:

    输入:people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
    输出:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
    解释:
    编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
    编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
    编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 01 的人。
    编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
    编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0123 的人。
    编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
    因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    示例 2:

    输入:people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
    输出:[[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]
    
    • 1
    • 2

    题解:
    方案一:从低到高考虑
    思路与算法

    当每个人的身高都不相同时,如果我们将他们按照身高从小到大进行排序,那么就可以很方便地还原出原始的队列了。

    为了叙述方便,我们设人数为 nn,在进行排序后,它们的身高依次为 h 0 , h 1 , ⋯   , h n − 1 h_0, h_1, \cdots, h_{n-1} h0,h1,,hn1,且排在第 i i i 个人前面身高大于 h i h_i hi的人数为 k i k_i ki。如果我们按照排完序后的顺序,依次将每个人放入队列中,那么当我们放入第 i i i 个人时:

    • 0 , ⋯   , i − 1 0, \cdots, i-1 0,,i1 个人已经在队列中被安排了位置,并且他们无论站在哪里,对第 i i i 个人都没有任何影响,因为他们都比第 i i i个人矮;
    • 而第 i + 1 , ⋯   , n − 1 i+1, \cdots, n-1 i+1,,n1 个人还没有被放入队列中,但他们只要站在第 i i i 个人的前面,就会对第 i i i个人产生影响,因为他们都比第 i i i个人高。

    如果我们在初始时建立一个包含 n n n 个位置的空队列,而我们每次将一个人放入队列中时,会将一个「空」位置变成「满」位置,那么当我们放入第 i i i 个人时,我们需要给他安排一个「空」位置,并且这个「空」位置前面恰好还有 k i k_i ki个「空」位置,用来安排给后面身高更高的人。也就是说,第 i i i 个人的位置,就是队列中从左往右数第 k i + 1 k_i+1 ki+1个「空」位置。
    那么如果有身高相同的人,上述 k i k_i ki定义中的大于就与题目描述中要求的大于等于不等价了,此时应该怎么修改上面的方法呢?我们可以这样想,如果第 i i i个人和第 j j j 个人的身高相同,即 h i = h j h_i = h_j hi=hj,那么我们可以把在队列中处于较后位置的那个人的身高减小一点点。换句话说,对于某一个身高值 h h h,我们将队列中第一个身高为 h h h 的人保持不变,第二个身高为 h h h 的人的身高减少 δ \delta δ,第三个身高为 hh 的人的身高减少 2 δ 2\delta 2δ,以此类推,其中 δ \delta δ 是一个很小的常数,它使得任何身高为 h h h 的人不会与其它(身高不为 h h h 的)人造成影响。

    如何找到第一个、第二个、第三个身高为 hh 的人呢?我们可以借助 k k k值,可以发现:当 h i = h j h_i=h_j hi=hj时,如果 k i > k j k_i > k_j ki>kj,那么说明 i i i 一定相对于 j j j 在队列中处于较后的位置(因为在第 j j j 个人之前比他高的所有人,一定都比第 i i i 个人要高),按照修改之后的结果, h i h_i hi略小于 h j h_j hj,第 i i i 个人在排序后应该先于第 j j j 个人被放入队列。因此,我们不必真的去对身高进行修改,而只需要按照 h i h_i hi为第一关键字升序, k i k_i ki为第二关键字降序进行排序即可。此时,具有相同身高的人会按照它们在队列中的位置逆序进行排列,也就间接实现了上面将身高减少 δ \delta δ 这一操作的效果。

    这样一来,我们只需要使用一开始提到的方法,将第 ii 个人放入队列中的第 k i + 1 k_i+1 ki+1个空位置,即可得到原始的队列。

    方案二:从高到低考虑

    同样地,我们也可以将每个人按照身高从大到小进行排序,处理身高相同的人使用的方法类似,即:按照 h i h_i hi为第一关键字降序, k i k_i ki为第二关键字升序进行排序。如果我们按照排完序后的顺序,依次将每个人放入队列中,那么当我们放入第 i i i 个人时:

    • 0 , ⋯   , i − 1 0, \cdots, i-1 0,,i1个人已经在队列中被安排了位置,他们只要站在第 i i i 个人的前面,就会对第 i i i
      个人产生影响,因为他们都比第 i i i 个人高;
    • 而第 i + 1 , ⋯   , n − 1 i+1, \cdots, n-1 i+1,,n1 个人还没有被放入队列中,并且他们无论站在哪里,对第 i i i
      个人都没有任何影响,因为他们都比第 i i i 个人矮。

    在这种情况下,我们无从得知应该给后面的人安排多少个「空」位置,因此就不能沿用方法一。但我们可以发现,后面的人既然不会对第 i i i个人造成影响,我们可以采用「插空」的方法,依次给每一个人在当前的队列中选择一个插入的位置。也就是说,当我们放入第 i i i 个人时,只需要将其插入队列中,使得他的前面恰好有 k i k_i ki个人即可。

    java代码:

    /**
         * 方案一
         * @param people
         * @return
         */
        public static int[][] reconstructQueue(int[][] people) {
    
            //按照第一个升序排列,第二个降序排列
            Arrays.sort(people, new Comparator<int[]>() {
                @Override
                public int compare(int[] p1, int[] p2) {
                    if (p1[0] != p2[0]) {
                        return p1[0] - p2[0];
                    } else {
                        return p2[1] - p1[0];
                    }
                }
            });
    
            int n = people.length;
            int[][] res = new int[n][];
            for (int[] p : people) {
                int pre = p[1] + 1;
                for (int i = 0; i < n; i++) {
                    if (res[i] == null) {
                        pre--;
                        if (pre == 0) {
                            res[i] = p;
                            break;
                        }
                    }
                }
            }
            return res;
        }
    
    
    public static int[][] reconstructQueue2(int[][] people) {
    
            //按照第一个降序排列,第二个升序排列
            Arrays.sort(people, new Comparator<int[]>() {
                @Override
                public int compare(int[] p1, int[] p2) {
                    if (p1[0] != p2[0]) {
                        return p2[0] - p1[0];
                    } else {
                        return p1[1] - p2[1];
                    }
                }
            });
    
            List<int[]> ans = new ArrayList<int[]>();
            for (int[] person : people) {
                ans.add(person[1], person);
            }
            return ans.toArray(new int[ans.size()][]);
        }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
  • 相关阅读:
    安捷伦E9300A射频传感器E9300B
    帆软FineReport决策报表之页面布局
    近端安全互联样例使用指导
    3分钟了解Android中稳定性测试
    【GlobalMapper精品教程】026:影像黑边白边出现的原因及解决办法汇总
    算能RISC-V通用云编译飞桨paddlepaddle@openKylin留档
    啊哈,终于知道了怎么获取网站的logo
    排序算法1:冒泡排序、快速排序、插入排序
    (微信小程序系列:一)携带参数跳转半屏微信小程序 先 A->B 后 B ->A
    uniCloud 如何创建数据表
  • 原文地址:https://blog.csdn.net/sunhaiting666/article/details/126499147