排序

78 阅读2分钟

215. 数组中的第K个最大元素

快速选择

  1. Arrays.sort() 调库快排
    时间复杂度 O(nlogn),空间复杂度 O(1)

  2. randPartition() 返回 pivot 的下标 p,代表 pivot 为 第 p 小的值。通过 pk 比较来反复调用(分治)。
    注:等号加在哪需要仔细考虑
    时间复杂度 O(n),空间复杂度 O(1)

注:

  • randPartition() 把数组分成了两部分。如果是快速排序,会在这里递归地对两部分进行快速排序。而在快速选择中,由于知道要找的第 N - k 小的元素在哪部分中,我们不需要对两部分都做处理,这样就将平均时间复杂度下降到 O(n)
  • Random rand = new Random();
    int p = rand.nextInt(r - l + 1) + l;
    // 随机数生成
    

  • 创建一个大顶堆,将所有数组中的元素加入堆中,并保持堆的大小小于等于 k。这样,堆中就保留了前 k 个最大的元素。这样,堆顶的元素就是正确答案。
    PriorityQueue 实现原理为二叉小顶堆(可自定义Comparator)。poll() 为弹出小顶堆堆顶元素。
    时间复杂度 O(nlogk),空间复杂度 O(k)

      public int findKthLargest(int[] nums, int k) {
          PriorityQueue<Integer> pq = new PriorityQueue<>(); // 小顶堆
          for (int val : nums) {
              pq.add(val);
              if (pq.size() > k)  // 维护堆的大小为 K
                  pq.poll();
          }
          return pq.peek();
      } 
    

💣347. 前 K 个高频元素

自己没想出来

哈希表 + 桶排序(或建堆等排序算法)

将每个元素的出现频率存到哈希表。设置若干个桶,每个桶存储出现频率相同的数。桶的下标表示数出现的频率,即第 i 个桶中存储的数出现的频率为 i
从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。

桶用 List<Integer>[] 表示。

  • ⭐注意 List 数组的初始化。
List<Integer>[] tempList = new ArrayList[nums.length];
for (...) {
    tempList[i] = new ArrayList<>();
}
  • ⭐对于 List<List<Integer>> 类型,可以这样作插入(18题)
// result 为 List<List<Integer>> 类型, nums[i] 为 Integer
// Arrays.asList:数组转换为 List
// 8 个基本类型无法作为 asList 的参数,因此要用包装类型,如 Integer
result.add(new ArrayList<>(Arrays.asList(nums[i], nums[j], nums[l], nums[r])));

451. 根据字符出现频率排序

与上一题解法相同

哈希表 + 堆排序

桶排序时间复杂度优于堆排序。

  • 字符串的处理对运行速度有较大影响。
    String 通过 + 运算符的拼接速度很慢(题目超时)。 StringBuilderappend()insert() 更快。

💣75. 颜色分类(荷兰国旗🇳🇱问题)

⭐三路快速排序 或 桶排序

// 三路快排思想,大于 1 的放右边,小于 1 的放左边,等于 1 的不动
while (one < two) {
    if (nums[one] == 0) {
        swap(nums, ++zero, one++);
    }
    else if (nums[one] == 2) {
        swap(nums, --two, one);
    }
    else {
        ++one;
    }
}