剑指Offer(10)有环链表 翻转链表

剑指offer(10) 有环链表 反转链表

题目:

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

思路:

快慢指针,当前一个指针和后一个指针相遇时,有环,提前结束则无.

然后将慢指针指向头节点,两个指针一起走,每次都走一步,相遇时即为入口节点。

(以下证明学习自牛客却顾所来径的回答)

1、设置快慢指针,假如有环,他们最后一定相遇。

2、两个指针分别从链表头和相遇点继续出发,每次走一步,最后一定相遇与环入口。

证明结论1:设置快慢指针fast和low,fast每次走两步,low每次走一步。假如有环,两者一定会相遇(因为low一旦进环,可看作fast在后面追赶low的过程,每次两者都接近一步,最后一定能追上)。

证明结论2:

设:

链表头到环入口长度为–a

环入口到相遇点长度为–b

相遇点到环入口长度为–c

img

则:相遇时

快指针路程=a+(b+c)k+b ,k>=1 其中b+c为环的长度,k为绕环的圈数(k>=1,即最少一圈,不能是0圈,不然和慢指针走的一样长,矛盾)。

慢指针路程=a+b

快指针走的路程是慢指针的两倍,所以:

(a+b)*2=a+(b+c)k+b

化简可得:

a=(k-1)(b+c)+c 这个式子的意思是: 链表头到环入口的距离=相遇点到环入口的距离+(k-1)圈环长度。其中k>=1,所以k-1>=0圈。所以两个指针分别从链表头和相遇点出发,最后一定相遇于环入口。

链接:https://www.nowcoder.com/questionTerminal/253d2c59ec3e4bc68da16833f79a38e4?f=discussion来源:牛客网

代码:

public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        ListNode fast=pHead;
        ListNode low=pHead;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            low=low.next;
            if(fast==low)
                break;
            //找到相遇点
        }
        if(fast==null||fast.next==null)
            return null;
        low=pHead;
        //慢指针从头开始
        while(fast!=low){
            fast=fast.next;
            low=low.next;
        }
        return low;
        //如果相遇返回环入口
    }

题目:

输入一个链表,反转链表后,输出新链表的表头。

思路:

方法1

建立一个栈,每次push进去节点,知道为空,然后每次pop出来的节点的next指针指向下一个pop出来的节点,直到栈为空。时间空间均为O(n)

方法2

维护2个指针,遍历的时候,直接将指针的指向逆序。时间O(n),空间O(1)。

方法3

递归,先递归到最后一个节点,然后逆向处理每个节点,直到递归至反转前的第一个节点。

TIM图片20190926155731.png

假如1-2-3-4

反转后的是 4-3-2-1

修改了指向后,原链表指向还存在,需要删除,所以有head->next = NULL; 依照这样的思路一直递归到1,返回之前记录的节点

代码:

/**
     * 建立一个栈,每次push进去节点,知道为空,
     * 然后每次pop出来的节点的next指针指向下一个pop出来的节点,直到栈为空。时间空间均为O(n)
     */
    public ListNode ReverseList(ListNode head)
    {
        if (head == null)
        {
            return null;
        }
        if (head.next == null)
        {
            return head;
        }
        ListNode p = head;
        Stack<ListNode> stack = new Stack();
        while (p.next != null)
        {
            stack.push(p);
            p = p.next;
        }
        ListNode newHead = p;
        while (!stack.empty())
        {
            p.next = stack.pop();
            p = p.next;
        }
        p.next = null;
        //最后一个指向null
        return newHead;
    }

    /**
     * 维护2个指针,遍历的时候,
     * 直接将指针的指向逆序。时间O(n),空间O(1)。
     */
    public ListNode ReverseList1(ListNode head)
    {
        if (head == null)
        {
            return null;
        }
        if (head.next == null)
        {
            return head;
        }
        ListNode pre = null;
        ListNode next = null;
        while (head != null)
        {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

    /**
     * 递归方法
     * 处理当前节点前,处理当前节点的下一个节点
     * 递归到最后一个节点开始处理
     */
    public static ListNode ReverseList2(ListNode pHead)
    {
        //如果链表为空或者链表中只有一个元素
        if(pHead==null||pHead.next==null) return pHead;

        //先反转后面的链表,走到链表的末端结点
        ListNode pReverseNode=ReverseList2(pHead.next);

        //再将当前节点设置为后面节点的后续节点
        pHead.next.next=pHead;
        pHead.next=null;

        return pReverseNode;
    }
    public static void main(String[] args)
    {
        ListNode node1 = new ListNode(1);
        ListNode node2 = new ListNode(2);
        ListNode node3 = new ListNode(3);
        ListNode node4 = new ListNode(4);
        ListNode node5 = new ListNode(5);
        ListNode node6 = new ListNode(6);
        ListNode node7 = new ListNode(7);

        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;
        node5.next = node6;
        node6.next = node7;

        ListNode old = node1;
        while (old != null)
        {
            System.out.print(" " + old.val);
            old = old.next;
        }
        System.out.println();
//        deleteDuplication(node1);
        ListNode newNode = ReverseList2(node1);
        while (newNode != null)
        {
            System.out.print(" " + newNode.val);
            newNode = newNode.next;
        }
    }

ion(node1);
ListNode newNode = ReverseList2(node1);
while (newNode != null)
{
System.out.print(" " + newNode.val);
newNode = newNode.next;
}
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值