LeetCode 排序

基础部分

912. 排序数组

中等

给你一个整数数组 nums,请你将该数组升序排列。

示例 1:

输入:nums = [5,2,3,1]
输出:[1,2,3,5]

示例 2:

输入:nums = [5,1,1,2,0,0]
输出:[0,0,1,1,2,5]

提示:

  1. 1 <= nums.length <= 50000
  2. -50000 <= nums[i] <= 50000
class Solution {
    public int[] sortArray(int[] nums) {
        quickSort(nums,0,nums.length-1);
        return nums;
    }

    private void quickSort(int[] nums, int l, int r) {
        if (l >= r) return;
        int mid = pattern(nums,l,r);
        if (mid != l){
            int tmp = nums[mid];
            nums[mid] = nums[l];
            nums[l] = tmp;
        }
        quickSort(nums,l,mid-1);
        quickSort(nums,mid+1,r);
    }

    private int pattern(int[] nums, int l, int r) {
        int first = nums[l];
        int i = l;
        int j = r + 1;
        while (i < j){
            do { //先判断后加,会多加一个,所以 do..while
                i++;
            }while (nums[i] < first && i < r);
            do {
                j--;
            }while (nums[j] > first && j > l);
            if (i >= j) break; //弄多了就换回来了,所以检查一下
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
        return j;
    }
}

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

中等

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4

说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

//减治的快排
class Solution {
    public int findKthLargest(int[] nums, int k){
        quickSort(nums,k-1,0,nums.length-1);
        return nums[k-1];
    }

    private void quickSort(int[] nums, int index, int l, int r) {
        if (l >= r) return;
        int mid = pattern(nums,l,r);
        if (mid != l){
            int tmp = nums[mid];
            nums[mid] = nums[l];
            nums[l] = tmp;
        }
        if (mid > index) quickSort(nums,index,l,mid-1);
        else quickSort(nums,index,mid+1,r);
    }

    private int pattern(int[] nums, int l, int r) {
        int first = nums[l];
        int i = l;
        int j = r + 1;
        while (i < j){
            do {
                i++;
            }while (nums[i] > first && i < r);
            do {
                j--;
            }while (nums[j] < first && j > l);
            if (i >= j) break;
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
        return j;
    }
}
//堆排序:建立k大小的小根堆,堆顶即为所求
class Solution {
    public int findKthLargest(int[] nums, int k){ //O(n*logk)
        //PriorityQueue 优先级队列,底层是二叉堆
        //(n1,n2)->n1-n2 小根堆
        PriorityQueue<Integer> heap = new PriorityQueue<>((n1,n2)->n1-n2);
        for (int num : nums) {
            heap.add(num); //O(logk)
            if (heap.size() > k) heap.poll(); //O(logk)
        }
        return heap.poll();
    }
}

347. 前 K 个高频元素

中等

给定一个非空的整数数组,返回其中出现频率前 *k* 高的元素。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

提示:

  • 你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
  • 你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
  • 你可以按任意顺序返回答案。
// 设置若干个桶,每个桶存储出现频率相同的数。桶的下标表示数出现的频率,即第 i 个桶中存储的数出现的频率为 i。
// 把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。
class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer,Integer> map = new HashMap<>();
        for (int num : nums)
            map.put(num,map.getOrDefault(num,0)+1); //数字频数哈希表
        List<Integer>[] buckets = new LinkedList[nums.length+1];
        for (Integer num : map.keySet()){
            int freq = map.get(num);
            if (buckets[freq] == null) //没初始化=>没有内存=>没法add
                buckets[freq] = new LinkedList<>();
            buckets[freq].add(num); //放到对应频数的桶里
        }
        int[] res = new int[k];
        int index = 0;
        for (int i = buckets.length-1; i > 0 && index < k; i--) {
            if (buckets[i] == null) continue;
            for (Integer num : buckets[i])
                res[index++] = num;
        }
        return res;
    }
}

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

中等

给定一个字符串,请将字符串里的字符按照出现的频率降序排列。

示例 1:

输入:
"tree"

输出:
"eert"

解释:
'e'出现两次,'r'和't'都只出现一次。
因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。

示例 2:

输入:
"cccaaa"

输出:
"cccaaa"

解释:
'c'和'a'都出现三次。此外,"aaaccc"也是有效的答案。
注意"cacaca"是不正确的,因为相同的字母必须放在一起。

示例 3:

输入:
"Aabb"

输出:
"bbAa"

解释:
此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。
注意'A'和'a'被认为是两种不同的字符。
class Solution {
    public String frequencySort(String s) {
        char[] chars = s.toCharArray();
        Map<Character,Integer> map = new HashMap<>();
        for (char aChar : chars)
            map.put(aChar,map.getOrDefault(aChar,0)+1);
        List<Character>[] buckets = new LinkedList[chars.length+1];
        for (Character c : map.keySet()) {
            int freq = map.get(c);
            if (buckets[freq] == null) buckets[freq] = new LinkedList<>();
            buckets[freq].add(c);
        }
        StringBuilder res = new StringBuilder();
        for (int i = buckets.length - 1; i > 0; i--) {
            if (buckets[i] == null) continue;
            for (Character c : buckets[i]) {
                for (int j = 0; j < i; j++) res.append(c);
                if (res.length() == chars.length) break;
            }
        }
        return res.toString();
    }
}

75. 颜色分类

中等

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

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

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

示例:

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

进阶:

  • 一个直观的解决方案是使用计数排序的两趟扫描算法。
    首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
  • 你能想出一个仅使用常数空间的一趟扫描算法吗?
// 0跟head换,head++;2跟tail换,tail--
// 换就完事了,判断一样费时间
// 注意:跟tail换时指针不往前走,因为不知道换个啥回来
class Solution {
    public void sortColors(int[] nums) {
        int head = 0, curr = 0;
        int tail = nums.length - 1;
        int tmp;
        while (curr <= tail) {
            if (nums[curr] == 0) {
                tmp = nums[head];
                nums[head++] = nums[curr];
                nums[curr++] = tmp;
            }
            else if (nums[curr] == 2) {
                tmp = nums[curr];
                nums[curr] = nums[tail];
                nums[tail--] = tmp;
            }
            else curr++;
        }
    }
}

频率排序

853. 车队

中等

N 辆车沿着一条车道驶向位于 target 英里之外的共同目的地。

每辆车 i 以恒定的速度 speed[i] (英里/小时),从初始位置 position[i] (英里) 沿车道驶向目的地。

一辆车永远不会超过前面的另一辆车,但它可以追上去,并与前车以相同的速度紧接着行驶。

此时,我们会忽略这两辆车之间的距离,也就是说,它们被假定处于相同的位置。

车队 是一些由行驶在相同位置、具有相同速度的车组成的非空集合。注意,一辆车也可以是一个车队。

即便一辆车在目的地才赶上了一个车队,它们仍然会被视作是同一个车队。

会有多少车队到达目的地?

示例:

输入:target = 12, position = [10,8,0,5,3], speed = [2,4,1,1,3]
输出:3
解释:
从 10 和 8 开始的车会组成一个车队,它们在 12 处相遇。
从 0 处开始的车无法追上其它车,所以它自己就是一个车队。
从 5 和 3 开始的车会组成一个车队,它们在 6 处相遇。
请注意,在到达目的地之前没有其它车会遇到这些车队,所以答案是 3。

提示:

  1. 0 <= N <= 10 ^ 4
  2. 0 < target <= 10 ^ 6
  3. 0 < speed[i] <= 10 ^ 6
  4. 0 <= position[i] < target
  5. 所有车的初始位置各不相同。
class Car{ //用类来整合比别的数据结构舒服
    int position;
    double time;

    public Car(int position, double time) {
        this.position = position;
        this.time = time;
    }
}
class Solution {
    public int carFleet(int target, int[] position, int[] speed) {
        int len = position.length;
        Car[] cars = new Car[len];
        for (int i = 0; i < len; i++)
            cars[i] = new Car(position[i],(double)(target-position[i])/speed[i]);
        Arrays.sort(cars,(x,y)->(y.position-x.position)); //按位置的降序
        int res = 0;
        for (int i = 0; i < len; i++) {
            res++;
            double head = cars[i].time;
            while (i < len && cars[i].time <= head) i++; //在我后边的,用时小于等于我的,才能追上我,和我同步到达
            i--; //for自带自增,会多加一次,所以减回来
        }
        return res;
    }
}

179. 最大数

中等

给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。

示例 1:

输入: [10,2]
输出: 210

示例 2:

输入: [3,30,34,5,9]
输出: 9534330

说明: 输出结果可能非常大,所以你需要返回一个字符串而不是整数。

class Solution {
    public String largestNumber(int[] nums) {
        //这样写会报错,基本数据类型都不能这么些,所以后边先把int[]转成了String[]
        //Arrays.sort(nums,(x,y) -> (String.valueOf(y)+String.valueOf(x)).compareTo(String.valueOf(x)+String.valueOf(y));
        String[] strs = new String[nums.length];
        for(int i = 0; i < nums.length; i++)
            strs[i] = String.valueOf(nums[i]);
        Arrays.sort(strs, (x, y) -> (y + x).compareTo(x + y));
        StringBuilder res = new StringBuilder();
        for(String s : strs)
            res.append(s);
        return res.toString();
    }
}

148. 排序链表

中等

O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

示例 1:

输入: 4->2->1->3
输出: 1->2->3->4

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5
class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) 
            return head; //递归到头只有head了,这时候开始merge
        ListNode slow = head, fast = head.next;
        while (fast != null && fast.next != null){ //二分链表
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode head2 = slow.next;
        slow.next = null;
        return merge(sortList(head),sortList(head2)); //递归合并
    }

    private ListNode merge(ListNode a,ListNode b) { //合并有序链表
        ListNode node = new ListNode(0);
        ListNode p = node;
        while (a != null && b != null){
            if (a.val < b.val){
                p.next = a;
                a = a.next;
            }else {
                p.next = b;
                b = b.next;
            }
            p = p.next;
        }
        p.next = a != null ? a : b;
        return node.next;
    }
}

56. 合并区间

中等

给出一个区间的集合,请合并所有重叠的区间。

示例 1:

输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:

输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
class Solution {
    public int[][] merge(int[][] intervals) {
        if (intervals.length < 2) return intervals;
        Arrays.sort(intervals,(a,b)->(a[0]-b[0]));
        List<int[]> list = new LinkedList<>();
        list.add(intervals[0]);
        for (int i = 1; i < intervals.length; i++) {
            int tail = list.get(list.size()-1)[1];
            if (intervals[i][0] > tail){
                list.add(intervals[i]);
            }else if (intervals[i][1] > tail){
                list.get(list.size()-1)[1] = intervals[i][1];
            }
        }
        int len = list.size();
        int[][] res = new int[len][2];
        for (int i = 0; i < len; i++) {
            res[i] = list.get(i);
        }
        return res;
    }
}
posted @ 2020-07-24 11:21  鹏懿如斯  阅读(517)  评论(0编辑  收藏  举报