leetcode 链表专题

 (1)力扣21 合并两个有序链表

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution 
{
    public ListNode mergeTwoLists(ListNode head1, ListNode head2)
    { 
       //创建一个新链表,将两个要合并的链表都插入到这个新的链表里面
       ListNode dummy=new ListNode(0);
       ListNode cur=dummy;
       while(head1!=null&&head2!=null)
       {
           //谁小谁插入
           if(head1.val<=head2.val)
           {
               cur.next=head1;
               head1=head1.next;
               cur=cur.next;
               cur.next=null;
           }
           else
           {
               cur.next=head2;
               head2=head2.next;
               cur=cur.next;
               cur.next=null;
           }
       }  
       //跳出这个循环之后,有可能某一个链表还不为空
       if(head1!=null)   cur.next=head1;
       if(head2!=null)   cur.next=head2;
       return dummy.next;
    }
}

(2)力扣86 分隔链表

把原链表分成两个小链表,一个链表中的元素大小都小于 x,另一个链表中的元素都大于等于 x,然后再将这两个链表连接起来

class Solution
{
    public ListNode partition(ListNode head, int x)
    {
        

        //链表1,用来装比x小的元素
        ListNode dummy1=new ListNode(-1);
        ListNode p1=dummy1;

        //链表2,用来装大于等于x的元素
        ListNode dummy2=new ListNode(-1);
        ListNode p2=dummy2;
        
        ListNode p=head;
        while(p!=null)
        {
            //大的加到链表2里面去
            if(p.val>=x)
            {
                p2.next=p;
                p2=p2.next;
                p=p.next;
                p2.next=null;
            }
            else
            {
                p1.next=p;
                p1=p1.next;
                p=p.next;
                p1.next=null;
            }
        }
        p1.next=dummy2.next;
        dummy2.next=null;
        return dummy1.next;
    }
}

 (3)力扣23 合并k个升序链表

利用最小堆找出k个链表第一个节点中,值最小的节点

每个链表把各自的第一个节点送进最小堆里面,最小的节点才能添加进新链表里面

//传入的是k个链表的头节点组成的数组:[head1,head2,head3.head4,head5......]

class Solution 
{
    public ListNode mergeKLists(ListNode[] lists)
    {
        if(lists.length==0)   return null;

        PriorityQueue<ListNode> pq=new PriorityQueue<ListNode>((a,b)->(a.val-b.val) );

        //将装满头节点的lists数组里面的头节点全部入最小堆
        for(ListNode head:lists)
        {
           if(head!=null)//加这个条件就是为了处理边界条件[[],[],[]],头结点全部都是空结点的情况
           {
              pq.add(head);
           }
        }

        ListNode dummy=new ListNode(-1);
        ListNode current=dummy;

        while(pq.size()!=0)
        {   
            //将堆顶的结点出堆
            ListNode temp=pq.poll();
 
           //如果这个结点后面还有结点,那么出堆的同时还要把它的next结点加入到堆里面
            if(temp.next!=null)
            {
                pq.add(temp.next);
            }
            
            尾插法形成新链表 
            current.next=temp;
            current=current.next;
            current.next=null;
        }
        return  dummy.next;
    }
}

(4)力扣19 删除链表的倒数第k个结点

遍历两次肯定是可以得到结果的,如果想只遍历一次就得到结果:双指针

总结:两个指针保持距离为k-1,一前一后,这样前面的指针跑到最后一个位置,后面的指针指向的就是倒数第k个结点

两个指针起始时,同时指向dummy结点,然后其中一个指针向后走k步,另一个指针向前走1步,这样两个指针之间就相差k-1步(也就是慢指针前进k-1步就能到达快指针的位置),两个指针一前一后,然后两个指针一起向后走,当后面的结点跑到最后一个位置的时候,前面的指针指向的就是倒数第k个节点

class Solution
{
    public ListNode removeNthFromEnd(ListNode head, int k) 
    {
        ListNode dummy = new ListNode(-1);
        dummy.next = head;

        ListNode slow = dummy;
        ListNode fast = dummy;
        
        //fast指针先前进k步
        for(int i=0;i<k;i++)
        {
          fast=fast.next;
        }
        //slow指针前进1步
       slow=slow.next;    

       //prev指针指向slow指针指向节点的上一个结点,便于删除
       ListNode prev = dummy;

        while (fast.next != null) 
        {
            fast = fast.next;            
            prev = slow;
            slow = slow.next;
        }
        
        //删除slow指针指向的结点
        prev.next = slow.next;

        // 释放 待删除节点slow 的next指针, 这句删掉也能AC
        slow.next = null;
        return dummy.next;
    }
}

(5)876. 链表的中间结点 - 力扣(LeetCode)

起始时两个指针 slow 和 fast 都指向链表头结点 head,然后slow指针一次走一步,fast指针一次走两步,这样,当 fast 走到链表末尾时,slow 就指向了链表中点

值得注意的是要按链表结点个数为奇数或者偶数进行排序

       

class Solution 
{
    public ListNode middleNode(ListNode head)
    {
       ListNode fast=head,slow=head;
       
       while(fast.next!=null&&fast.next.next!=null)
       {
           fast=fast.next.next;
           slow=slow.next;       
       }
 
       //结点个数为偶数个的时候
       if(fast.next!=null&&fast.next.next==null)
       {
           slow=slow.next;
           fast=fast.next;
       }
       //结点个数为奇数个的时候  什么都不做

       return  slow;
    }
}

 另一种写法:

并不是初始时,fast和slow都是位于head

而是fast=head.next,slow=head

class Solution 
{
    public ListNode middleNode(ListNode head)
    {
        ListNode fast = head.next,slow = head;

        while (fast != null && fast.next != null) 
        {
            slow = slow.next;
            fast = fast.next.next;
        }
        if(fast!=null)   
        {
            slow=slow.next;//偶数个
        }
        return slow;
       
    }
}

中间结点有关的题目:

力扣2095 删除链表的中间结点

class Solution 
{
    public ListNode deleteMiddle(ListNode head) 
    {
        ListNode middle=findMedian(head);//findMedian函数的功能是找出;链表的中间结点,返回这个中间结点
        ListNode dummy=new ListNode(-1);
        dummy.next=head;
        ListNode p=dummy;
        while(p.next!=middle)
        {
            p=p.next;
        }
        p.next=p.next.next;
        return dummy.next;
    }

    public ListNode findMedian(ListNode head)
    {
        
        ListNode slow=head;
        ListNode fast=head;
        while(fast.next!=null)
        {
            fast=fast.next;

            //通过[1,2,3,4,5,6]这个测试用例可以发现存在下面这种情况:
            //有可能只前进一步fast就到达了最后一个结点了,此时不能再前进了,再前进就会报越界异常了
            if(fast.next==null)
            {
               slow=slow.next;
               break;
            }
            else
            {
                fast=fast.next;
                slow=slow.next;
            } 
        }
        return slow;
    }
}

(6)力扣237  删除链表中的结点

注意这道题目中没有告诉你这个链表的头结点,传入的node就是我们要删除的结点

我们创建两个指针,一个指针p指向传入的结点,另一个指针q指向传入结点的下一个结点,

然后不断执行:

p.val=q.val
p=q;
q=q.next;

 循环终止的条件是:q.next=null,因为这样q就指向了最后一个节点,此时p.val=q.val,然后p.next=null即可

最后跳出循环的时候:

class Solution 
{
    public void deleteNode(ListNode node) 
    {
        ListNode p=node;
        ListNode q=node.next;
        while(q.next!=null)
        {
            p.val=q.val;
            p=q;
            q=q.next;
        }
        p.val=q.val;
        p.next=null; 
    }
}

(7)力扣141 环形链表,判断链表是否有环

方法一:


public class Solution
 {
    public boolean hasCycle(ListNode head) 
    {
        if(head==null)   return false;
        HashSet set=new HashSet();
        while(head!=null)
        {
            if(set.contains(head)) return true;
            else{
                 set.add(head);
                 head=head.next;
            }
        }
        return false;
    }
}

方法二:

每当慢指针 slow 前进一步,快指针 fast 就前进两步。

如果 fast 最终遇到空指针,说明链表中没有环;如果 fast 最终和 slow 相遇,那肯定是 fast 超过了 slow 一圈,说明链表中含有环

public class Solution
 {
    public boolean hasCycle(ListNode head) 
    {
       ListNode slow=head,fast=head;

       //一直往前移,直到fast=null
       while(fast!=null)
       {
           //slow移动一步,fast移动两步
           slow=slow.next;
           fast=fast.next;

           //进入这个循环,fast是不为null的,但是fast=fast.next后不能保证fast不为null
           //如果只走一步就为null了,直接返回false
           //第一步不为null才能走第二步
           if(fast==null)
           {
              return   false;
           }
           else
           {
               fast=fast.next;
           }


           if(slow==fast)   return true;
       }
       return false;
    }
}

(8)力扣链表中环的入口

上一个问题的进阶版:如果链表有环,返回这个环的起点

方法一:

public class Solution 
{
    public ListNode detectCycle(ListNode head) 
    {
        if(head==null)   return null;
        HashSet set=new HashSet();
        while(head!=null)
        {
            if(set.contains(head)) return head;
            else
            {
                 set.add(head);
                 head=head.next;
            }
        }
        return null;
    }
}

方法二:

当快慢指针相遇时,让其中任一个指针指向头节点(不是dummy结点,而是第一个有效的结点),然后让它俩以相同速度前进,再次相遇时所在的节点位置就是环开始的位置

public class Solution 
{
    public ListNode detectCycle(ListNode head) 
    {
       ListNode slow=head,fast=head;
       while(fast!=null)
       {
           slow=slow.next;
           fast=fast.next;
           if(fast!=null)
           {
               fast=fast.next;
           }
           else
           {
               return  null;
           }

           //有环了,slow等于head,然后slow,fast速度一致往前走,再次相遇的位置就是环的入口
           if(slow==fast)
           {
               slow=head;
               while(slow!=fast)
               {
                   slow=slow.next;
                   fast=fast.next;
               }
               return slow;
           }
       }
       return null;
    }
}

(9)160. 相交链表 - 力扣(LeetCode)两个链表是否相交

需要返回两个链表相交的起始结点

方法一:


public class Solution 
{
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) 
    {
        HashSet set=new HashSet();
        while(headA!=null)
        {
           set.add(headA);
           headA=headA.next;
        }
        while(headB!=null)
        {
            if(set.contains(headB))    return headB;
            headB=headB.next; 
        }
        return null;      
    }
}

方法二:

用两个指针 p1 和 p2 分别在两条链表上前进

p1 遍历完链表 A 之后开始遍历链表 B,让 p2 遍历完链表 B 之后开始遍历链表 A

 最终p1走过的距离是m+k+n,而p2走过的距离是n+k+m

 这道题存在的一个坑在于:

 这种情况,两个链表没有相交的部分时,容易陷入死循环,超时

解决方法:定义一个计数器count,p1指针遍历完A链表再跳到B链表,count++

                                                      p2指针遍历完B链表再跳到A链表,count++

这样count=2了,如果没有相交部分,那count还要++,所以如果count>2了,那就说明这两个链表没有相交的部分,返回null

public class Solution 
{
    public ListNode getIntersectionNode(ListNode headA, ListNode headB)
    {
        ListNode p1=headA,p2=headB;
        int count=0;

        if(p1==null||p2==null)  return null;
        //确保两个链表都不是空链表

        while(p1!=p2)
        {
            if(count>2)  return null;//count超过2,那这两个链表就没有相交部分
            
            //p1指针下一个到底指向哪一个结点,是直接p1.next,还是headB
            if(p1.next==null)
            {
                p1=headB;
                count++;
            }
            else
            {
                p1=p1.next;
            }

            if(p2.next==null)
            {
                p2=headA;
                count++;
            }
            else
            {
                p2=p2.next;
            }    
        }
        return p1;      
    }
}

(10)力扣707 设计链表

①解释题目:就是实现五个功能:获取链表中第index个结点的值,在表头添加元素,在表尾添加元素,在第index个结点之前添加结点,删除第index个结点

②这里定义了一个size,初始等于0,用来记录链表的长度,每次向链表中添加一个结点就size++,删除一个结点就size--

③由于index从0开始计数,所以size=最大的index+1

 ④跳出循环的时候current指向哪个结点

初始的时候current=dummy

while(int i=0;i<index;i++)
{
 current=current.next;
}

 有了这张表就很清晰(从第0轮开始)每i轮最终current会到达第i个结点

 所以可以判断:跳出这个循环,current=index-1,因为i=index的时候进不去循环

class MyLinkedList
{
      //dummy结点
      ListNode dummy;
      
      //用size来记录链表的长度,执行添加结点操作时size++
      int size;
     
    // 构造方法.初始化size和summy两个参数
    public MyLinkedList() 
    {
        size=0;
        dummy=new ListNode(0);  
    }
    
    //获取第index个结点的数值
    public int get(int index) 
    {
       if(index<0||index>=size)  return -1;

       ListNode current=dummy;
       for(int i=0;i<=index;i++)
       {
         current=current.next;
       }
       return current.val;
    }
    
    //链头添加一个结点
    public void addAtHead(int val) 
    {
        ListNode new_node=new ListNode(val);
        new_node.next=dummy.next;
        dummy.next=new_node;
        size++;
    }
    
    //链尾添加一个结点
    public void addAtTail(int val) 
    {
        ListNode new_node=new ListNode(val);
        ListNode current=dummy;
        for(int i=0;i<size;i++)
        {
            current=current.next;
        }
        current.next=new_node;
        size++;
    }

    //在第 index 个节点之前添加节点
    public void addAtIndex(int index, int val) 
    {
        //如果index小于0,在头部插入节点(直接调用前面写好的addAtHead函数)
        if(index<0)   addAtHead(val);
        //如果 index 等于链表的长度,在链表末尾添加元素,可以直接调用前面写好的addAtTail函数
        if(index==size)  addAtTail(val);
        //如果 index 大于链表长度,则不会插入节点
        if(index>size)  return;

        ListNode new_node=new ListNode(val);
        ListNode current=dummy;
        for(int i=0;i<index;i++)
        {
            current=current.next;
        }
        //跳出循环,此时current指向的是第index-1个结点
        new_node.next=current.next;
        current.next=new_node;
        size++;
    }
    
    public void deleteAtIndex(int index) 
    {
        if(index<0||index>=size)  return;

        ListNode current=dummy;
        for(int i=0;i<index;i++)
        {
            current=current.next;
        }
        //跳出循环,此时current指向的是第index-1个结点
        current.next=current.next.next;
        size--;
    }
}

 (11)剑指 Offer 24. 反转链表 - 力扣(LeetCode)反转链表

力扣206也是一样的题目

其实就是头插法创建一个新链表

总共三个指针,dummy和head这两个指针是肯定是不用说的,无非是多了一个指向head指针下一个结点的temp指针

核心就是下面这两行代码:

head.next=dummy.next;

dummy.next=head;

class Solution
 {
    public ListNode reverseList(ListNode head) 
    {
        if(head==null)  return null;
        ListNode dummy=new ListNode(-1);
        while(head!=null)
        { 
            //temp用来标记这一轮要插入结点的下一个结点(也就是下一轮要插入的结点,要不然下一轮找不到位置)
            ListNode temp=head.next;
           
            //这两行就是头插法插入结点到dummy结点的后面
            head.next=dummy.next;
            dummy.next=head;

            head=temp;
        }
        return dummy.next;
    }
}

(12) 92. 反转链表 II - 力扣(LeetCode)

 反转链表的某个区间

核心代码:

temp.next=q.next;

q.next=temp

class Solution 
{
    public ListNode reverseBetween(ListNode head, int m, int n) 
    {
        ListNode dummy = new ListNode(0);
        dummy.next = head;

        // 初始化指针,一前一后,p在前,q在后,先p后q
        ListNode q = dummy;
        ListNode p = dummy.next;

        // p移到第一个要反转的结点位置,q移动到第一个要反转的结点的前一个结点
        for(int i= 0; i < m - 1; i++) 
        {
            p = p.next;
            q = q.next;   
        }

        // 头插法插入节点
        for (int i = 0; i < n - m; i++) 
        {
            //存下来p指针后面的结点,将它用头插法插入到q指针后面去
            ListNode temp = p.next;
            
            //从链表中删除刚刚的temp结点
            p.next = p.next.next;
            
            //下面两行代码就是头插法,插入temp结点到g指针指向结点的
            temp.next = q.next;
            q.next = temp;
        }

        return dummy.next;
    }
}

(13)24. 两两交换链表中的节点 - 力扣(LeetCode)

class Solution 
{
    public ListNode swapPairs(ListNode head) 
    {
        ListNode dummy=new ListNode(0);
        dummy.next=head;

        ListNode current=dummy;
         
         //交换的是current的后面两个节点
        while(current.next!=null&&current.next.next!=null)
        {
            ListNode p=current.next;
            ListNode q=current.next.next;
            ListNode  temp=current.next.next.next;

            current.next=q;
            q.next=p;
            p.next=temp;
            current=p;
        }
        return dummy.next; 
    }
}

(14)力扣 1669 合并两个链表

class Solution 
{
    public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) 
    {
        ListNode dummy=new ListNode(0);
        dummy.next=list1;

        ListNode temp1=dummy;
        ListNode temp2=dummy;

        //temp1指针指到第a-1个结点
        for(int i=0;i<a;i++)
        {
            temp1=temp1.next;
        }
        
        //temp2指针指到第b+1个结点
        for(int j=0;j<b+2;j++)
        {
            temp2=temp2.next;
        }

        temp1.next=list2;

        ListNode temp3=list2;

        while(temp3.next!=null)
        {
            temp3=temp3.next;  
        }
        temp3.next=temp2;

        return dummy.next;
        
    }
}

(15)力扣234回文链表

将链表的值加入到数组里面,转化为判断是否为回文数组的问题

class Solution 
{
    public boolean isPalindrome(ListNode head) 
    { 
        ArrayList  a=new  ArrayList();
        if(head==null)    return true;
        while(head!=null)
        {
          a.add(head.val);
          head=head.next;
        }
        int i=0,j=a.size()-1;
        while(i<j)
        {
            if(a.get(i)!=a.get(j))
            {
                 return false;
            }    
            i++;
            j--;     
        }
        return true;
    }
}

 如果要求用O(1)的空间复杂度,思路:先找到链表中点,然后将链表的前半段进行反转,最后比较反转后的前半段和后半段是否所有元素相等

(16)力扣328 奇偶链表

第一个结点的索引是1,第二个结点的索引是2......

将索引为奇数的结点全部放到前面来,索引为偶数的结点都放到后面去

思路:整两个链表,一个链表是用来存储索引为奇数的结点,另一个链表用来存储索引为偶数的结点

class Solution
{
    public ListNode oddEvenList(ListNode head)
    {
        ListNode jishu_dummy=new ListNode(-1);//奇数链表的虚拟头节点
        ListNode jishu_tail=jishu_dummy;//奇数链表的尾结点

        ListNode oushu_dummy=new ListNode(-1);//偶数链表的虚拟头节点
        ListNode oushu_tail=oushu_dummy;//偶数链表的尾结点

        int num=1;

        //遍历原链表
        while(head!=null)
        {
            //偶数的话,就将这个结点添加到偶数链表里面去
            if(num%2==0)
            {
                oushu_tail.next=head;
                oushu_tail=oushu_tail.next;
                head=head.next;
                oushu_tail.next=null;
                num++;
            }
            else
            {
                jishu_tail.next=head;
                jishu_tail=jishu_tail.next;
                head=head.next;
                jishu_tail.next=null;
                num++;
            }
        }
        jishu_tail.next=oushu_dummy.next;
        
        return jishu_dummy.next;

    }
}

(17)力扣61  旋转链表

尾结点指向头节点,构造首尾相连的链表

在原链表中找到新链表的头节点p,并且找出这个头节点的前一个结点q

q.next=null

return p;即可

class Solution 
{
    public ListNode rotateRight(ListNode head, int k) 
    {
        if(head==null)  return null;
        ListNode dummy=new ListNode(-1);
        dummy.next=head;

        //求出链表的长度
        int length=1;
        while(head.next!=null)
        {
            head=head.next;
            length++;
        }
        //构建环形链表
        head.next=dummy.next;
        
        k=k%length;
        int result=length-k;

        ListNode temp=dummy;
        //temp指针跑到新链表的尾结点的位置,也就是新链表的头节点在旧链表中的前一个位置
        for(int i=0;i<result;i++)
        {
            temp=temp.next;
        }

        //新链表的头节点
        ListNode new_head=temp.next;
         
        temp.next=null;
        dummy.next=null;

        return new_head;
    }
}

 18. 力扣382 链表随机结点

Random test=new Random();

int num=random.nextInt(n);
//获得一个[0.n)的一个随机数
class Solution
{
    ArrayList<Integer> arraylist=new ArrayList();
    Random random=new Random();

    //构造函数,负责将链表中的所有值添加进arraylist里面
    public Solution(ListNode head) 
    {
        while(head!=null)
        {
            arraylist.add(head.val);
            head=head.next;
        }
    }
    public int getRandom() 
    {
        int num=random.nextInt(arraylist.size());
        return arraylist.get(num);
    }
}

接下来是两道链表相加的题目

每一位相加,比如a,b相加,sum=a+b+flag

(1)进位flag=sum%10

(2)这一位变成:sum=sum/10

然后进位flag送到下一轮去

19 力扣2 两数之和

 题目意思如下:

 要注意下面这种情况:最高位还要向前进1

核心代码:

sum=num1+num2+flag

currentNode.val=sum%10

flag=sum/10

class Solution 
{
    public ListNode addTwoNumbers(ListNode l1, ListNode l2)
    {
        //构造一个头结点 
        ListNode dummy=new ListNode(-1);
 
        //再整一个当前节点,初始时,当前节点等于dummy节点
        ListNode current=dummy;
 
        //进位标志
        int flag=0;
 
        //只要还有一个链表有数字,就要继续相加
        while(l1!=null||l2!=null)
        {
            int num1=0,num2=0,sum=0;
            if(l1!=null)
            {
               num1=l1.val;
            }
    
            if(l2!=null)
            {
                num2=l2.val;
            }
        
            sum=num1+num2+flag;
           
            //进位为flag/10
            flag=sum/10;
            //新节点的值为sum%10
            ListNode new_node=new ListNode(sum%10);
            current.next=new_node;
           
 
           //接下来就是将三个指针往后移l1.next,l2.next,current.next
            if(l1!=null)
            {
                l1=l1.next;
            }
            if(l2!=null)
            {
                l2=l2.next;
            }
            current=current.next;
        }
        //跳出循环,此时l1,l2都为空了,此时判断一下是否还有进位
        //如果有进位,就还要再new一个新节点
        if(flag==1)
        {
            ListNode new_node=new ListNode(1);
            current.next=new_node;
        }
        return dummy.next;
    }
}

19.力扣445  两数相加||

两数相加|和两数相加||之间的区别: 

即两数相加|第一个链表节点是低位

而两数相加||第一个链表节点是高位

方法一:写一个反转链表的函数,将两个链表分别反转,然后就是两个链表相加,最后的结果再进行一次反转

 方法二: 将两个链表的元素进栈,然后栈顶元素依次相加,采用头插法创建新链表

class Solution 
{
    public ListNode addTwoNumbers(ListNode l1, ListNode l2)
    { 
        Stack<Integer> stack1 = new Stack<>();
        Stack<Integer> stack2 = new Stack<>();
        
        while (l1 != null)
        {
            stack1.push(l1.val);
            l1 = l1.next;
        }
     
        while (l2 != null) 
        {
            stack2.push(l2.val);
            l2 = l2.next;
        }
        
        int  flag = 0;

        ListNode head = null;
        
        while (!stack1.isEmpty() || !stack2.isEmpty() || carry > 0) 
        {
            int sum = carry;
            sum += stack1.isEmpty()? 0: stack1.pop();
            sum += stack2.isEmpty()? 0: stack2.pop();
            ListNode node = new ListNode(sum % 10);
            node.next = head;
            head = node;
            carry = sum / 10;
        }
        return head;
    }
}

20.链表的归并排序:力扣148   排序链表

和数组的归并排序也是一样的,

(1) 找中点

(2)左右子链表(左右子数组)分别排好序

(3)将两个有序链表进行合并(两个链表合并)

class Solution
{
    public ListNode sortList(ListNode head) 
    {
      if(head==null||head.next==null)   return  head; 
      
       //step1:找中间结点
        ListNode fast = head.next, slow = head;
        while (fast != null && fast.next != null) 
        {
            slow = slow.next;
            fast = fast.next.next;
        }
       
       ListNode temp=slow.next;//中点的下一个结点
  
       slow.next=null;//将链表一分为二

       ListNode left= sortList(head);//将前半段链表进行排序

       ListNode right=sortList(temp);//将后半段链表进行排序

       //接下来合并两个有序链表
       ListNode result=merge(left,right);

       return  result;
    }

    public  ListNode  merge(ListNode left,ListNode right)
    {
       ListNode dummy=new  ListNode(0);

       ListNode current=dummy;

       while(left!=null&&right!=null)
       {
           if(left.val<=right.val)
           {
              current.next=left;
              left=left.next;
              current=current.next;
              current.next=null;
           }
           else
           {
              current.next=right;
              right=right.next;
              current=current.next;
              current.next=null;

           }
       }

       //跳出循环,一定有一个链表还没有比较完
       if(left!=null)//这个if-else结构可以用三元表达式来代替:current.next=left!=null?left:right;
       {
           current.next=left;
       }
       else
       {
           current.next=right;
       }
       return  dummy.next;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>