leetcode:406. 根据身高重建队列

题目

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

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

示例:

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

解答 & 代码

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

  1. 排序:对 peoplehi = people[i][0] 降序排列,按 ki=people[i][1] 升序排列。即排序后,升高高的人排在前面;如果身高相同,则 k 小的排在前面(k 是前面身高大于或等于它的人数)
  • 排序后数组变为 people = [[7, 0], [7, 1], [6, 1], [5, 0], [5, 2], [4, 4]]
  1. 遍历排序后的 people 数组,依次将每个元素插入结果数组 resultpeople[i] 插入的位置为 ki = people[i][1],即
  • [7, 0] 插入在 result0 个位置,插入后 result = [[7, 0]]
  • [7, 1] 插入在 result1 个位置,插入后 result = [[7, 0], [7, 1]]
  • [6, 1] 插入在 result1 个位置,插入后 result = [[7, 0], [6, 1], [7, 1]]
  • [5, 0] 插入在 result0 个位置,插入后 result = [[5, 0], [7, 0], [6, 1], [7, 1]]
  • [5, 2] 插入在 result2 个位置,插入后 result = [[5, 0], [7, 0], [5, 2], [6, 1], [7, 1]]
  • [4, 4] 插入在 result4 个位置,插入后 result = [[5, 0], [7, 0], [5, 2], [6, 1], [4, 4], [7, 1]]

    1. class Solution {
    2. private:
    3. // 快排分割函数
    4. int partition(vector<vector<int>>& arr, int left, int right)
    5. {
    6. int randomIdx = random() % (right - left + 1) + left;
    7. swap(arr[left], arr[randomIdx]);
    8. vector<int> pivot = arr[left];
    9. while(left < right)
    10. {
    11. while(left < right && (arr[right][0] < pivot[0] ||
    12. (arr[right][0] == pivot[0] && arr[right][1] >= pivot[1])))
    13. --right;
    14. arr[left] = arr[right];
    15. while(left < right && (arr[left][0] > pivot[0] ||
    16. (arr[left][0] == pivot[0] && arr[left][1] <= pivot[1])))
    17. ++left;
    18. arr[right] = arr[left];
    19. }
    20. arr[left] = pivot;
    21. return left;
    22. }
    23. // 快速排序
    24. void quickSort(vector<vector<int>>& arr, int left, int right)
    25. {
    26. if(left >= right)
    27. return;
    28. int pivot = partition(arr, left, right);
    29. quickSort(arr, left, pivot - 1);
    30. quickSort(arr, pivot + 1, right);
    31. }
    32. public:
    33. vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
    34. int len = people.size();
    35. // 1. 对 people 数组进行排序,排序规则:按 hi 降序,ki 升序
    36. // 即身高 h 高的排前面;若身高 h 相同,则 k 小的排前面(k 是前面身高大于或等于它的人数)
    37. quickSort(people, 0, len - 1);
    38. vector<vector<int>> result; // 结果数组
    39. // 2. 遍历排序后的 people 数组,依次将每个元素插入结果数组,插入规则:
    40. // 插入的位置为 ki = people[i][1]
    41. for(int i = 0; i < len; ++i)
    42. result.insert(result.begin() + people[i][1], people[i]);
    43. return result;
    44. }
    45. };

    复杂度分析:设数组长度为 N

  • 时间复杂度 [中等] 406. 根据身高重建队列 - 图1

    • 数组快速排序时间复杂度 O(NlogN)
    • 排序后,每次插入时间复杂度 O(N),N 次插入,总体时间复杂度 [中等] 406. 根据身高重建队列 - 图2
  • 空间复杂度 O(log N):
    • 快排的递归函数栈空间复杂度 O(logN)(快速排序就相当于二叉树的前序遍历,空间复杂度即递归深度取决于树的高度)
    • 结果数组的空间复杂度不计入

执行结果:

  1. 执行结果:通过
  2. 执行用时:144 ms, 在所有 C++ 提交中击败了 42.80% 的用户
  3. 内存消耗:12.3 MB, 在所有 C++ 提交中击败了 40.79% 的用户