手撕算法——归并排序及排序链表

归并排序

对于归并排序,大家怕是都不陌生,也可以非常熟练的写出归并排序的代码,因此本篇文章的重点并不是向大家介绍归并排序,而是讨论归并排序的拓展题型——力扣:148.排序链表。至于归并排序的原理可以参考:图解排序算法(四)之归并排序,下面也贴出代码实现

代码实现

/**
归并排序
 分而治之
 通过递归分,然后merge
 */
public class MergeSort {

    public  void sort(int[] a,int begin,int end,int[] tmp){
        int mid=(begin+end)/2;
        if(begin<end){//if begin<end 则分
            sort(a,begin,mid,tmp);
            sort(a,mid+1,end,tmp);
            merge(a,begin,mid,end,tmp);
        }
    }
    public void merge(int a[] ,int begin,int mid,int end,int[] tmp){
        int i=begin;
        int j=mid+1;
        int t=0;
        while(i<=mid&&j<=end){
            if(a[i]<=a[j]){
                tmp[t++]=a[i++];
            }else{
                tmp[t++]=a[j++];
            }
        }
        while(i<=mid){
            tmp[t++]=a[i++];
        }
        while(j<=end){
            tmp[t++]=a[j++];
        }
        /*
       // System.arraycopy(a,0,tmp,0,a.length);
        for(int index=begin;index<=end;index++){
            a[index]=tmp[index];
        }*/

        t=0;
        while(begin<=end){
            a[begin++]=tmp[t++];
        }
    }

    public static void main(String[] args) {
        MergeSort mergeSort=new MergeSort();
        int[] a= {8,4,5,7,1,3,6,2};
        int[] tmp=new int[a.length];
        mergeSort.sort(a,0,a.length-1,tmp);

        for(int e :tmp){
            System.out.println(e);
        }
    }
}

排序链表

题目描述:

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

示例 1:

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

示例 2:

输入: -1->5->3->4->0
输出: -1->0->3->4->5

归并排序的时间复杂度为O(nlogn),这个大家都知道,但是数组的归并排序,我们需要创建一个临时数组来保存中间结果,空间复杂度为n。所以这道题的主要思想就是如何利用链表的将归并排序的空间复杂度降为1。
结合归并排序的思想,我们主要需要考虑以下几个问题:

  1. 如何找到中间节点
  2. 如何进行拆分
  3. 如何进行合并
    结合之前做链表类题型,我们可以很轻松的想到答案,这里直接贴出关键代码:
    (1) 通过快慢指针找中点。
ListNode fast=head.next,slow=head;
        //快慢指针 fast先置为 head.next,当它走到末尾时 slow指向的正好是中间节点的下标
        //fast 如果也置为 head, slow最终指向的是中间节点的先一个的下标  这里需要明确一下
        while(fast!=null&&fast.next!=null){
            slow=slow.next;
            fast=fast.next.next;
        }

(2)拆分链表

		ListNode tmp=slow.next;
        slow.next=null;//拆分
        ListNode left=sortList(head);
        ListNode right=sortList(tmp);

(3)通过虚假头结点进行链表合并

		ListNode h=new ListNode(0);//构造虚假链表头
        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;

总结

总体来说这是一道非常不错的题目,链表相关的知识点和排序都考察到了,非常值得学习!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值