链表(二):判断链表是否有环、链表中环的入口节点、链表中倒数最后k个节点、删除链表的倒数第n个节点、两个链表的第一个公共节点、链表相加(二)、单链表的排序、判断一个链表是否为回文结构、链表的奇偶重排

一、判断链表中是否有环

1.1 题目

在这里插入图片描述

1.2 题解

思路:快慢指针,快指针一次走两步,慢指针一次走一步,如果链表中有环,两个指针一定会在环中相遇

代码:

    public boolean hasCycle(ListNode head) {
        if(head==null) return true;
        ListNode slow=head;
        ListNode fast=head;
        while(fast!=null &&  fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            if(slow==fast){
                return true;
            }
        }
        return false;
    }

二、链表中环的入口节点

2.1 题目

在这里插入图片描述

2.2 题解

思路
在这里插入图片描述
结论:一个指针从链表头开始走,另一个指针从相遇点开始走,二者将在入口点相遇

代码:

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        if(pHead==null) return null;
        ListNode fast=pHead;
        ListNode slow=pHead;
        while(fast!=null && fast.next!=null){
            slow=slow.next;
            fast=fast.next.next;
            if(slow==fast){
                break;
            }
        }
        if(fast==null || fast.next==null) return null;
        while(pHead!=slow){
            pHead=pHead.next;
            slow=slow.next;
        }
       return pHead;
    }

三、链表中倒数最后k个节点

3.1 题目

在这里插入图片描述

3.2 题解

思路:快慢指针,让快指针走k步,再让两个指针一起走,当快指针走到尾时,慢指针走到倒数第k个节点
代码:

  public ListNode FindKthToTail (ListNode pHead, int k) {
         
     
        ListNode slow=pHead;
        ListNode fast=pHead;
        while(k>0 ){
            if(fast!=null){
            fast=fast.next;
            }else {
                slow=null;
            }
            k--;
        }
        while(fast!=null){
            slow=slow.next;
            fast=fast.next;
        }
        return slow;
    }

四、删除链表的倒数第n个节点

4.1 题目

在这里插入图片描述

4.2 题解

思路:快慢指针, 找到要删除节点的前一个节点,然后将要删除的节点删除即可
具体步骤

step1:定义傀儡节点dummy,dummy.next=head;
step2:slow和fast起出都指向傀儡节点
step3:fast指针从dummy开始,向后走n+1步
step4:slow和fast一起向后走,当fast为null时,slow指向的是要删除节点的前一个位置
step5:删除倒数第n个节点

代码:

  public ListNode removeNthFromEnd (ListNode head, int n) {
        ListNode dummy=new ListNode(-1);
        dummy.next=head;
        ListNode slow=dummy;
        ListNode fast=dummy;
        for(int i=0;i<=n;i++){
            if(fast!=null){
                fast=fast.next;
            }else {
                slow=null;
            }
        }
        while(fast!=null){
            slow=slow.next;
            fast=fast.next;
        }
        slow.next=slow.next.next;
        return dummy.next;

    }

五、两个链表的第一个公共结点

5.1 题目

在这里插入图片描述

5.2 题解

思路:双指针法,cur1从pHead1开始,cur2从pHead2开始,cur1和cur2每次都走一步,当cur1走到null的时候,就从cur2开始,当cur2走到null的时候,就从cur1开始,这样的遍历过程,能够保证cur1和cur2同时到达第一个公共节点,因为cur1和cur2遍历过的节点数是相等的,即使题中给的两个链表没有公共节点,cur1和cur2也会同时指向空节点

代码

 public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        
        ListNode cur1=pHead1;
        ListNode cur2=pHead2;
        while(true){
             if(cur1==cur2){
                 break;
             }  
             if(cur1==null){
                 cur1=pHead2;
             }else {
                 cur1=cur1.next;
             }  
             if(cur2==null){
                 cur2=pHead1;
             }else {
                 cur2=cur2.next;
             }
                    
        }
        return cur1;
    }

六、链表相加(二)

6.1 题目

在这里插入图片描述

6.2 题解

思路:先将两个链表反转,然后使用两个指针遍历两个链表,将两个链表的对应位相加,相加得到的值用来构造新节点,同时用tmp保存进位,加到下一位上

代码:

  public ListNode reverse(ListNode head){
         if(head==null) return null;
         if(head.next==null) return head;
         ListNode pre=null;
         ListNode cur=head;
         while(cur!=null){
             ListNode curNext=cur.next;
             cur.next=pre;
             pre=cur;
             cur=curNext;
         }
         return pre;
     }
    public ListNode addInList (ListNode head1, ListNode head2) {
        if(head1==null) return head2;
        if(head2==null) return head1;
        ListNode pHead1=reverse(head1);
        ListNode pHead2=reverse(head2);
        ListNode dummy=new ListNode(-1);
        ListNode cur=dummy;
        int val=0;
        int tmp=0;
        while(pHead1!=null || pHead2!=null){
            val=tmp;
             if(pHead1!=null){
                 val+=pHead1.val;
                 pHead1=pHead1.next;
             }
             if(pHead2!=null){
                 val+=pHead2.val;
                 pHead2=pHead2.next;
             }
             tmp=val/10;
             cur.next=new ListNode(val%10);
             cur=cur.next;
        }
        if(tmp>0){
            cur.next=new ListNode(tmp);
        }
        return reverse(dummy.next);

    }

七、单链表的排序

7.1 题目

在这里插入图片描述

7.2 题解

思路:归并排序

具体步骤:
step1:当链表为空或只有一个节点时,直接返回当前节点
step2:使用快慢指针的方式,找到当前链表的中间节点mid和中间节点的前一个节点midPre,从midPre位置与原链表断开
step3:原问题转化成了先对head到midPre 和 mid到fast(尾节点) 进行排序,然后再将者两段合并的子问题,使用递归解决

代码:

      ListNode merge(ListNode pHead1, ListNode pHead2) {
        if(pHead1==null) return pHead2;
        if(pHead2==null) return pHead1;
        ListNode dummy=new ListNode(-1);
        ListNode cur=dummy;
        while(pHead1!=null && pHead2!=null){
            if(pHead1.val<pHead2.val){
                cur.next=pHead1;
                pHead1=pHead1.next;
            }else {
                cur.next=pHead2;
                pHead2=pHead2.next;
            }
            cur=cur.next;
        }
        if(pHead1!=null){
            cur.next=pHead1;
        }
        if(pHead2!=null){
            cur.next=pHead2;
        }
        return dummy.next;
    }
     
    public ListNode sortInList (ListNode head) {
         if(head==null || head.next==null) return head;
         ListNode midPre=null;
         ListNode mid=head;
         ListNode fast=head;
         while(fast!=null && fast.next!=null){
             midPre=mid;
             mid=mid.next;
             fast=fast.next.next;
         }
         midPre.next=null;
         return merge(sortInList(head), sortInList(mid));
    }

八、判断一个链表是否为回文结构

8.1 题目

在这里插入图片描述

8.2 题解

思路:先找到链表的中间节点,然后将后半部分进行反转后与前半部分比较,遇到不相等的节点直接返回false

代码:

    public ListNode reverse(ListNode head){
        ListNode pre=null;
        ListNode cur=head;
        while(cur!=null){
            ListNode curNext=cur.next;
            cur.next=pre;
            pre=cur;
            cur=curNext;
        }
        return pre;
    }
    public boolean isPail (ListNode head) {
        ListNode slow=head;
        ListNode fast=head;
        while(fast!=null && fast.next!=null){
            slow=slow.next;
            fast=fast.next.next;
        }
        ListNode head1=reverse(slow);
        while(head!=null && head1!=null){
            if(head.val!=head1.val){
                return false;
            }
            head=head.next;
            head1=head1.next;
        }
        return true;
    }

九、链表的奇偶重拍

9.1 题目

在这里插入图片描述

9.2 题解

思路:准备四个指针,oddHead指向奇数链表的头,odd用来遍历奇数链表,even执行偶数链表的头,evenHead指向偶数链表的头,遍历结束时,odd指向的是奇数链表的最后一个节点,因此让odd.next=evenHead,这样就将整个偶数链表连接在了整个奇数链表的后面

在这里插入图片描述
代码:

 public ListNode oddEvenList (ListNode head) {
         if(head==null) return null;
         ListNode odd=head;
         ListNode oddHead=head; //奇数头
         ListNode evenHead=head.next; //偶数头
         ListNode  even=head.next;
         while(odd!=null && odd.next!=null && even!=null && even.next!=null){
             ListNode oddNext=odd.next.next;
             ListNode evenNext=even.next.next;
             odd.next=oddNext;
             even.next=evenNext;
             odd=oddNext;
             even=evenNext;
         }
         odd.next=evenHead;
         return oddHead;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值