【LeetCode】链表排序

链表题的几大法宝:

  • 双指针
  • dummyHead
  • 断链
  • 挂链

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

示例 1:

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这道题和链表的插入排序有点像,就是限制了时间复杂度和空间复杂度,但这每一个优化都是一种难点;

链表的插入排序解法:
 public ListNode sortList(ListNode head) {
           ListNode newHead = new ListNode(Integer.MIN_VALUE);
        newHead.next = head;
        ListNode cur = head;
        ListNode pre = newHead;
        while(cur!=null){
            //cur.val<pre.val 发现后边的数据 < 前边的数据时候 例如 12341,重新开始扫描
            if(cur.val<pre.val){
                //差在这里,没有更新头部,要注意呀
                ListNode newIndex = newHead.next;
                ListNode newPre   = newHead;
                while(newIndex!=pre&&newIndex.val<cur.val) {
                    newIndex = newIndex.next;
                    newPre = newPre.next;
                }
                //找到位置进行节点交换位置
                pre.next = cur.next;
                cur.next = newIndex;
                newPre.next = cur;
                cur = pre.next;
            }else{
                //cur.val>=pre.val 前边数据小于等于后边数据,说明已经排好序了,继续往前走
                cur = cur.next;
                pre = pre.next;
            }
        }
        return newHead.next;

    }

这个解法的思路:

  • 判断是否有序
  • 如果无序则在已排好序的链表中找到该插入的位置
  • 维护各节点
    4-2-3-1 这里维护的方式是将2的next域指向4,;
排序链表解法

归并排序 的解法可以用到这里;
分组;归并

先根据step分组(1,2,4,……)
然后每两组之间进行归并;

分组函数:

public ListNode cut(ListNode head,int step){
    while(--step!=0 && head!=null){
        head=head.next;
     }
     //如果链表不够step长就返回null
     if(head!=null){
         ListNode result=head.next;
         head.next=null;
         return result;
      }else{
         return null;
      }
    }

归并函数

public ListNode merge(ListNode l1,ListNode l2){
     ListNode work=new ListNode(0);
     ListNode head=work;
     while(l1!=null && l2!=null){
         if(l1.val<l2.val){
              work.next=l1;
              l1=l1.next;
          }else{
              work.next=l2;
              l2=l2.next;
           }
           work=work.next;
       }
       if(l1!=null){
           work.next=l1;
       }
       if(l2!=null){
           work.next=l2;
       }
       return head.next;
 }

主函数:

public ListNode sortList(ListNode head){
    ListNode dummyHead = new ListNode(Integer.MAX_VALUE);
    dummyHead.next=head;
    
    //计算长度
    int length=0;
    ListNode work=head;
    while(work!=null){
       work=work.length;
       length++;
    }
    ListNode tail=dummyHead;
    for(int step=1;step<length;step<<=1){
       work=dummyHead.next;
       tail=dummyHead;
       while(work!=null){
          ListNode left=work;
          ListNode right=cut(left,step);
          work=cut(right,step);
        
      //记录当前链表的最后一个位置,用于拼接下一趟循环产生的结果
         tail.next=merge(left,right);
         while(tail.next!=null){
             tail=tail.next;
          }
        }
      }
      return dummyHead.next;
  }

总的来说就是做链表的题一定要好好画图,来模拟中间维护节点的过程

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值