算法--排序问题

 

题目来自Leetcode 题解 - 排序​​​​​​​


 Kth Element

215. Kth Largest Element in an Array (Medium)

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

题目描述:找到倒数第 k 个的元素。

排序 :时间复杂度 O(NlogN),空间复杂度 O(1)

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

 :时间复杂度 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();
}

快速选择 :时间复杂度 O(N),空间复杂度 O(1)

public int findKthLargest(int[] nums, int k) {
    k = nums.length - k;
    int l = 0, h = nums.length - 1;
    while (l < h) {
        int j = partition(nums, l, h);
        if (j == k) {
            break;
        } else if (j < k) {
            l = j + 1;
        } else {
            h = j - 1;
        }
    }
    return nums[k];
}
//分区
private int partition(int[] a, int l, int h) {
    int i = l, j = h + 1;
    while (true) {
        while (a[++i] < a[l] && i < h) ;
        while (a[--j] > a[l] && j > l) ;
        if (i >= j) {
            break;
        }
        swap(a, i, j);
    }
    swap(a, l, j);
    return j;
}
//交换
private void swap(int[] a, int i, int j) {
    int t = a[i];
    a[i] = a[j];
    a[j] = t;
}

出现频率最多的 k 个元素

347. Top K Frequent Elements (Medium)

Given [1,1,1,2,2,3] and k = 2, return [1,2].

设置若干个桶,每个桶存储出现频率相同的数。桶的下标表示数出现的频率,即第 i 个桶中存储的数出现的频率为 i。

把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。

class Solution {
    public List<Integer> topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> frequencyForNum = new HashMap<>();
        for (int num : nums) {
            //往map里put,由对应的key就获取值+1,没有就用默认的0作为value
            frequencyForNum.put(num, frequencyForNum.getOrDefault(num, 0) + 1);
        }
        //桶数组
        List<Integer>[] buckets = new ArrayList[nums.length + 1];
        for (int key : frequencyForNum.keySet()) {
            int frequency = frequencyForNum.get(key);
            //如果当前桶未初始化,则将桶初始化
            if (buckets[frequency] == null) {
                buckets[frequency] = new ArrayList<>();
            }
            //将桶中加入元素
            buckets[frequency].add(key);
        }
        List<Integer> topK = new ArrayList<>();
        for (int i = buckets.length - 1; i >= 0 && topK.size() < k; i--) {
            //桶里为空,说明没有出现频率为i的数
            if (buckets[i] == null) {
                continue;
            }
            //第i个桶里的元素放入topk后不会出现溢出时
            if (buckets[i].size() <= (k - topK.size())) {
                topK.addAll(buckets[i]);
            //第i个桶里的元素放入topk后会出现溢出时,将桶截掉一部分,留下的元素正好补完topk
            } else {
                topK.addAll(buckets[i].subList(0, k - topK.size()));
            }
        }
        return topK;
    }
}

按照字符出现次数对字符串排序

451. Sort Characters By Frequency (Medium)

Input:
"tree"

Output:
"eert"

Explanation:
'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
public String frequencySort(String s) {
    Map<Character, Integer> frequencyForNum = new HashMap<>();
    for (char c : s.toCharArray())
        frequencyForNum.put(c, frequencyForNum.getOrDefault(c, 0) + 1);

    List<Character>[] frequencyBucket = new ArrayList[s.length() + 1];
    for (char c : frequencyForNum.keySet()) {
        int f = frequencyForNum.get(c);
        if (frequencyBucket[f] == null) {
            frequencyBucket[f] = new ArrayList<>();
        }
        frequencyBucket[f].add(c);
    }
    StringBuilder str = new StringBuilder();
    for (int i = frequencyBucket.length - 1; i >= 0; i--) {
        if (frequencyBucket[i] == null) {
            continue;
        }
        for (char c : frequencyBucket[i]) {
            for (int j = 0; j < i; j++) {
                str.append(c);
            }
        }
    }
    return str.toString();
}

按颜色进行排序

75. Sort Colors (Medium)

给定一个包含红色、白色和蓝色,一共 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

注意:
不能使用代码库中的排序函数来解决这道题。

示例:

输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]

进阶:

  • 一个直观的解决方案是使用计数排序的两趟扫描算法。
    首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

可以使用双指针法来做。

class Solution {
    public void sortColors(int[] nums) {
        //当前计算的位置,i
        int i = 0;
        //左指针标记当前左边交换的0的位置
        int left = 0;
        //右指针标记当前左边交换的2的位置
        int right = nums.length - 1;
        //当i走到右指针的位置,表示全部的数都被计算到,退出循环
        while (i <= right) {
            //nums[i]等于2,而且不再right右边时,做一次交换,right--,直到当前i不为2
            while (nums[i] == 2 && i < right) {
                swap(nums, i, right--);
            }
            //nums[i]等于0,而且不再left左边时,做一次交换,left++,直到当前i不为0
            while (nums[i] == 0 && i > left) {
                swap(nums, i, left++);
            }
            i++;
        }  
    }
    private void swap(int[] nums, int i, int j) {
        int t = nums[i];
        nums[i] = nums[j];
        nums[j] = t;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值