博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LeetCode中经典的排序问题
阅读量:3948 次
发布时间:2019-05-24

本文共 4578 字,大约阅读时间需要 15 分钟。

最近看完算法4第二章排序后,对LeetCode中的排序题目作了以下总结:

堆排序:

题目描述:

找到未排序数组中的第k个最大元素。请注意,它是排序顺序中的第k个最大元素,而不是第k个不同元素。

Input: [3,2,1,5,6,4] and k = 2  Output: 5Input: [3,2,3,1,2,4,5,5,6]   and k = 4  Output: 4

解题方法:

1、对整个输入数组进行排序,然后通过它的索引(即O(1))操作访问该元素:

时间复杂度 O(NlogN),空间复杂度 O(1)。

public int findKthLargest(int[] nums, int k) {
final int N = nums.length; Arrays.sort(nums); return nums[N - k]; }

2、堆排序也可以用于求解 Kth Element 问题,堆顶元素就是 Kth Element。使用面向最小值的优先级队列来存储第K个最大值。该算法迭代整个输入并维持优先级队列的大小。优先队列可以用堆来实现:

时间复杂度 O(NlogK),空间复杂度 O(K)。

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

3、基于切分partion的快速选择算法;快速排序的 partition() 方法,会返回一个整数 j 使得 a[l…j-1] 小于等于 a[j],且 a[j+1…h] 大于等于 a[j],此时 a[j] 就是数组的第 j 大元素。可以利用这个特性找出数组的第 k 个元素。

时间复杂度 最佳情况:O(N) 最坏情况:O(N ^ 2),空间复杂度 O(1)

我们如何才能改进上述解决方案并使其保证O(N)?答案非常简单,刚开始时要对数组进行洗牌shuffle,使其随机化输入,这样即使提供最坏情况输入,算法也不会受到影响。因此,所需要做的就是改变输入。

public int findKthLargest(int[] nums, int k) {
shuffle(nums);//打乱数组 k = nums.length - k; int lo = 0; int hi = nums.length - 1; while (lo < hi) {
final int j = partition(nums, lo, hi); if(j < k) {
lo = j + 1; } else if (j > k) {
hi = j - 1; } else {
break; } } return nums[k]; } //切分 private int partition(int[] a, int lo, int hi) {
int i = lo; int j = hi + 1; while(true) {
while(i < hi && less(a[++i], a[lo])); while(j > lo && less(a[lo], a[--j])); if(i >= j) {
break; } exch(a, i, j); } exch(a, lo, j); return j; } //交换 private void exch(int[] a, int i, int j) {
final int tmp = a[i]; a[i] = a[j]; a[j] = tmp; } //比较是否小于 private boolean less(int v, int w) {
return v < w; } private void shuffle(int a[]) {
final Random random = new Random(); for(int ind = 1; ind < a.length; ind++) {
final int r = random.nextInt(ind + 1); exch(a, ind, r); } }

桶排序

找出出现频率最多的 k 个数

题目描述:

给定非空的整数数组,返回k个最常见的元素。

Input: nums = [1,1,1,2,2,3], k = 2Output: [1,2]Input: nums = [1], k = 1Output: [1]

解决方法:

设置若干个桶,每个桶存储出现频率相同的数,并且桶的下标代表桶中数出现的频率。

class Solution {
public List
topKFrequent(int[] nums, int k) {
Map
map = new HashMap<>(); for(int a : nums){
map.put(a,map.getOrDefault(a,0)+1); //判断a是否存在,如果没出现 } List
[] buckets = new ArrayList[nums.length + 1]; for(int i : map.keySet()){
int frequency = map.get(i); if(buckets[frequency]==null){
buckets[frequency] = new ArrayList<>(); } buckets[frequency].add(i); } List
topK = new ArrayList<>(); //从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数 for(int i = buckets.length - 1; i >= 0 && topK.size() < k;i--){
if(buckets[i]!=null){
topK.addAll(buckets[i]); } } return topK; } }

荷兰国旗问题:

题目描述:

给定一个具有红色,白色或蓝色的n个对象的数组,对它们进行就地 排序,使相同颜色的对象相邻,颜色顺序为红色,白色和蓝色。

这里,我们将使用整数0,1和2分别表示红色,白色和蓝色。

注意: 您不应该使用库的排序功能来解决此问题。

Input: [2,0,2,1,1,0]Output: [0,0,1,1,2,2]

解决方法:

使用三向切分快速排序,将数组分成三个区间:等于红色、等于白色、等于蓝色。

class Solution {
public void sortColors(int[] nums) {
int zero = 0; int two = nums.length - 1; int one = 0; while(one <= two){
if (nums[one] == 0){
swap(nums,zero++,one++); //从前面开始交换的已经比较过了 }else if (nums[one] == 2){
swap(nums,two--,one); //这里注意one不要++,从后面交换到前面的还无法比较 }else {
one++; } } } private static void swap(int [] nums,int a,int b){
int i = nums[a]; nums[a] = nums[b]; nums[b] = i; } }

转载地址:http://nerwi.baihongyu.com/

你可能感兴趣的文章
敏捷笔记
查看>>
SOA业务理解与应用
查看>>
Google File System(中文翻译)
查看>>
Google's BigTable 原理 (翻译)
查看>>
MapReduce:超大机群上的简单数据处理
查看>>
设计模式笔记(转载)
查看>>
加站点加入IE的可信站点做法
查看>>
软件研发中的《破窗理论》
查看>>
敏捷的三种误区和五种改进
查看>>
vs2010一些设置
查看>>
Python 3 之多线程研究
查看>>
简单明了《a标签的href》跳转页面情况,看完秒懂!!!
查看>>
Android系统目录结构
查看>>
Activity的生命周期及启动模式整理
查看>>
android的IPC机制思维导图
查看>>
Fragment中mAdded和mDetached标志位
查看>>
Android的View事件机制思维导图
查看>>
Spring中Bean的装配思维导图
查看>>
View的工作原理
查看>>
Window和WindowManager思维导图
查看>>