算法-排序


title: 算法 - 排序
date: 2022-5-5
tags:

  • 算法
  • LeetCode
  • 排序
    categories:
  • 算法
  • 排序

排序

一、归并排序

1.1 链表的归并排序

147. 对链表进行插入排序

方法一(自顶向下):

  1. 通过快慢指针寻找中间节点(需要注意 fast 指针的初始化为 head 的 next )
  2. head 和 slow 指针分别指向两个链表,递归这两个链表
  3. 合并这两个链表
class Solution {
    public ListNode sortList(ListNode head) {
        if (head == null || head.next == null){
            return head;
        }
        // 需要注意的是:这里fast指针的初始指向head指针的next
        ListNode fast = head.next, slow = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        // tmp 指向第二段链表的头部
        ListNode tmp = slow.next;
        // 断开链表
        slow.next = null;
        ListNode left = sortList(head);
        ListNode right = sortList(tmp);

        // h 用来合并链表
        ListNode h = new ListNode(0);
        // res 记录头节点
        ListNode res = h;
        while (left != null && right != null) {
            if (left.val < right.val) {
                h.next = left;
                left = left.next;
            } else {
                h.next = right;
                right = right.next;
            }
            h = h.next;
        }
        h.next = left != null ? left : right;
        return res.next;
    }
}

二、快速排序

快速排序的模板

步骤:

  1. 结束条件:左指针 >= 右指针
  2. 取 pivot :取 left 或者 取 (left, right] 区间的随机数
  3. 将区间内的 大于 pivot 的数放到 pivot 的右边,小于 pivot 的数放到 pivot的左边(这里需要注意的是:一定是先以动 right 指针,再以动 left 指针,因为最开始 pivot 会保存 left 指针位置的数,所以 当 right 指针找到一个 pivot 小的数,并将 left 指针位置的数置为 right 指针所指向的数时,由于 pivot 已经提前保存了该数,所以,不用怕覆盖掉,后续的循环中,left 和 right 会交替保存对方的数)
    • 先移动 right 指针:找到一个比 pivot 小的数的 right 停止 while,将 left 索引的位置的数置为 right 指针所指的数
    • 后移动 left 指针:找到一个比 pivot 大的数的 left 停止 while,将 right 指针所指向的的位置的数置为 left 位置所指向的数;
  4. 循环结束后,left 会等于 right,该位置就是 pivot 的最终位置,将该处索引的值置为 pivot 即可
  5. 递归 left 到 i - 1 和 i + 1 到 right
// 普通的快速排序
public static void quickSort(int[] nums, int left, int right) {
    if (left >= right) {
        return;
    }
    int i = left, j = right;
    int pivot = nums[left];
    while (i < j) {
        while (nums[j] >= pivot && i < j) {
            j--;
        }
        nums[i] = nums[j];
        while (nums[i] <= pivot && i < j) {
            i++;
        }
        nums[j] = nums[i];
    }
    nums[i] = pivot;
    quickSort(nums, left, i - 1);
    quickSort(nums, i + 1, right);
}

// 随机 pivot 的快速排序
public static void quickSortRandomPivot(int[] nums, int left, int right) {
    if (left >= right) {
        return;
    }
    int i = left, j = right;
    int randomIndex = left + 1 + (int) (Math.random() * (right - left));
    swap(nums, left, randomIndex);
    int pivot = nums[left];

    while (i < j) {
        while (nums[j] >= pivot && i < j) {
            j--;
        }
        nums[i] = nums[j];
        while (nums[i] <= pivot && i < j) {
            i++;
        }
        nums[j] = nums[i];
    }

    nums[i] = pivot;
    quickSortRandomPivot(nums, left, i - 1);
    quickSortRandomPivot(nums, i + 1, right);
}

public static void swap(int[] nums, int i, int j) {
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}

2.1 数组中的第K个最大元素

思路:由于再经过一次快排后 pivot 的位置就是他的最终位置,[left, pivot索引) 和 (pivot索引 , right] 区间的数也再其最终位置的区间,所以只要再次递归目标值所在的区间的数就可以了。

public class Solution {
    int target;

    public int findKthLargest(int[] nums, int k) {
        this.target = nums.length - k;
        quickSortRandomPivot(nums, 0, nums.length - 1);
        return nums[nums.length - k];
    }

    public void quickSortRandomPivot(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        int i = left, j = right;
        int randomIndex = left + 1 + (int) (Math.random() * (right - left));
        swap(nums, left, randomIndex);
        int pivot = nums[left];

        while (i < j) {
            while (nums[j] >= pivot && i < j) {
                j--;
            }
            nums[i] = nums[j];
            while (nums[i] <= pivot && i < j) {
                i++;
            }
            nums[j] = nums[i];
        }
        nums[i] = pivot;

        if (i < target) {
            quickSortRandomPivot(nums, i + 1, right);
        } else if (i > target) {
            quickSortRandomPivot(nums, left, i - 1);
        }
    }
    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值