【java-数据结构10-链表经典例题3】

 几天不见,甚是想念,这几天小编也是浅浅的鸽了一下~本篇文章也是是单向链表例题的压轴文章(也就是导数第二篇~),话不多说,进入今天的正题叭~

1.输入两个链表,找出它们的第一个公共结点

  在看到这个题的第一反应,我们首先要想的是,两个链表相交,是什么类型的?两个节点相交,相交后面的节点怎么办,是“X”型还是“Y”型?其实是“Y”我们还是借助图片来理解

    

注意 :链表相交是地址,不是元素!

那么,如何找到这个交点呢

1.我们先定义两个cur,让两个cur分别等于两个链表的头节点

2.让两个cur每次分别走一步

3.此时两cur相遇的节点就是相交的节点

如图

   其实,仔细想想就不难发现以上理论是经不起推敲的,因为在交点之前,都刚好有两个节点,一人走一步的情况才能刚好找到交点(路程一样,速度一样)

  如果一个交点前是三个节点,一个交点前是两个节点,又该怎么办呢

如图

链表1长度为5(3+2)链表2为4(2+2),我们只需两个链表相减,得到差值1(5-4),先让长的先走差值步,在以同样的速度走,即可

注意:我们也不要忘了先确定那个链表长,或者一个链表为空,一个不为空的情况 

代码如下

 public static MySingleList.ListNode getIntersectionNode(MySingleList.ListNode headA,
                                                            MySingleList.ListNode headB) {
        //1、分别求2个链表的长度
        int lenA = 0;
        int lenB = 0;

        MySingleList.ListNode pL = headA;//假设pL 所指向的链表 是最长的链表
        MySingleList.ListNode pS = headB;//假设pS 所指向的链表 是最短的链表
        while(pL != null) {
            lenA++;
            pL = pL.next;
        }

        while(pS != null) {
            lenB++;
            pS = pS.next;
        }

        pL = headA;
        pS = headB;

        //分别求得了 2个链表的长度
        int len = lenA - lenB;
        //修正指向 和 len的差值
        if(len < 0) {
            pL = headB;
            pS = headA;
            len = lenB - lenA;
        }
        
        //让最长的链表 先走差值步
        while(len != 0) {
            pL = pL.next;
            len--;
        }

        //3、就是相遇的点
        while(pL != pS) {
            pL = pL.next;
            pS = pS.next;
        }
        return pL;
    }

调用测试

 private static void createIntersect(MySingleList.ListNode headA,
                                        MySingleList.ListNode headB) {
        headB.next.next = headA.next.next;
    }
    public static void main(String[] args) {
        MySingleList mySingleList = new MySingleList();

        mySingleList.addLast(12);
        mySingleList.addLast(23);
        mySingleList.addLast(34);
        mySingleList.addLast(45);
        mySingleList.addLast(56);
        mySingleList.display();
        MySingleList mySingleList1= new MySingleList();

        mySingleList1.addLast(8);
        mySingleList1.addLast(15);
        mySingleList1.addLast(30);
        mySingleList1.addLast(40);
        mySingleList1.addLast(78);
        mySingleList1.display();
        createIntersect(mySingleList.head,mySingleList1.head);
        MySingleList.ListNode ret = getIntersectionNode(mySingleList.head,mySingleList1.head);
        System.out.println(ret.val);

     
    }

运行截图

2.给定一个链表,判断链表中是否有环。

什么是有环呢,话不多说,上图

那么,我们可以理解为,两个人同时跑,一快一慢,快的先跑到环里之后,开始在环里转圈,此时,慢的也进环了,由于,快的已经在环里跑了,如果两个相遇即证明有环,如图(这里有点绕,大家注意理解)

快的速度是慢的两倍(只有这种情况是合理的,条件不合理否则容易跳过)

比如,一个走一步,一个走三步,这种情况就永远不会相遇

两个速度只能差一步

fast:2         slow:1

其实本质就是一个追击问题,每次追一步总能追上

注意:不要忘记为空的情况

代码如下

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

测试调用

这里我们先手动将链表变为有环链表,代码如下

这个过程很简单,只需让最后一个节点的next域等于前面的某一节点即可

public void createLoop() {
        
        ListNode cur = head;
        while (cur.next != null) {
            cur = cur.next;
        }
       

        cur.next = head.next;
    }

下面我们进行调用

public static void main(String[] args) {

        MySingleList mySingleList = new MySingleList();

        mySingleList.addLast(12);
        mySingleList.addLast(23);
        mySingleList.addLast(34);
        mySingleList.addLast(45);
        mySingleList.addLast(56);
        mySingleList.display();
        mySingleList.createLoop();
       mySingleList.hasCycle();
        System.out.println(mySingleList.hasCycle());
    }

运行截图

 

  

  由于今天的文章稍难,所以我们今天只介绍两道题,剩下的两道题我们下一篇文章再继续介绍,敬请期待叭~觉着小编将的好的可以点点关注~我们下期再见
 

  • 22
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值