《剑指offer》——链表中环的入口结点

60 篇文章 3 订阅

更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~

T:

题目描述
一个链表中包含环,请找出该链表的环的入口结点。

基本做法

不考虑其中潜在的规律,就按照一般的方法,创建一个list,把扫描过的节点都存储在list中,知道下一个节点在list中已经存在,那就说明该节点就是入口节点。

这种方式下的时间复杂度为 O ( n 2 ) O(n^2) O(n2)

我的code:

    /*
     public class ListNode {
        int val;
        ListNode next = null;
     
        ListNode(int val) {
            this.val = val;
        }
    }
    */
    import java.util.ArrayList;
    import java.util.List;
    /**
     * T: 链表中环的入口结点
     *
     * 题目描述
     * 一个链表中包含环,请找出该链表的环的入口结点。
     *
     * date: 2015.12.13  19:28
     * @author SSS
     *
     */
    public class Solution {
     
        /**
         * 将所有扫描过的节点都放在list列表中,
         * 看是否下一个节点已经在list列表中出现过
         * @param pHead
         * @return
         */
        public ListNode EntryNodeOfLoop(ListNode pHead){
            ListNode targetNode = new ListNode(3);
            if (pHead == null || pHead.next == null) {
                return null;
            }
             
            List<ListNode> nodesList = new ArrayList<ListNode>();
             
            nodesList.add(pHead);
            targetNode = pHead.next;
            while (!nodesList.contains(targetNode)) {
                nodesList.add(targetNode);
                targetNode = targetNode.next;
            }
             
            return targetNode;
        }
    }

规律求解

首先是设置两个指针 p 1 , p 2 p_1, p_2 p1,p2,一个指针 p 1 p_1 p1步长为1, p 2 p_2 p2步长为2,让两个指针都从头结点往后走,如果存在环的话,两者肯定会再次相遇,因为在两个指针都进入环的时候,一个步长为2,一个步长为1,那就是说两个指针之间的距离每走一步就缩小1个单位,所以两个指针肯定会再次相遇。

在相遇的时候,假设指针 p 1 p_1 p1走了 x x x步,那么 p 2 p_2 p2肯定走了 2 x 2x 2x步,因为每次 p 2 p2 p2都比 p 1 p_1 p1多走了一步。

同时,还会发现,这个 p 2 p_2 p2多走的 x x x步,肯定是多走在了换上,也就是说, x x x是环的长度 n n n的整数倍,即有如下公式:

2 x = x + k ∗ n k = 1 , 2 , 3 , … 2x = x + k*n \qquad k = 1,2,3,\dots 2x=x+knk=1,2,3,

p 2 p_2 p2至少围着环转了一圈。

这里写图片描述

也就说,让一个指针指向环上的相遇点,一个指针指向头结点,同时以步长为1往后走,其碰头的那个结点,就是入口结点。

我的code:

    /*
     public class ListNode {
        int val;
        ListNode next = null;
     
        ListNode(int val) {
            this.val = val;
        }
    }
    */
     
    /**
     * T: 链表中环的入口结点
     *
     * 题目描述
     * 一个链表中包含环,请找出该链表的环的入口结点。
     *
     * date: 2015.12.13  19:39
     * @author SSS
     *
     */
    public class Solution {
     
        /**
         * 两个指针,一个指针步长为1,一个步长为2;
         * 先计算两个指针相交的位置点;
         * 然后让一个指针指向头结点,步长都为1,往后走,其相遇点就是入口点
         * 该规律可通过公式推导得出
         * @param pHead
         * @return
         */
        public ListNode EntryNodeOfLoop(ListNode pHead){
            ListNode targetNode = new ListNode(3);
            if (pHead == null || pHead.next == null) {
                return null;
            }
             
            ListNode preNode = pHead.next;
            ListNode postNode = pHead.next.next;
            // 找到相遇点
            while (preNode != postNode) {
                preNode = preNode.next;
                postNode = postNode.next.next;
            }
            // 将其中一个指针指向头结点
            postNode = pHead;
            // 步长都为1,同时往后走,直到两者相遇
            // 相遇点就是入口
            while (preNode != postNode) {
                preNode = preNode.next;
                postNode = postNode.next;
            }
            targetNode = preNode;
             
            return targetNode;
        }
    }

更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值