即使没有月亮,心中也是一片皎洁!|

昼阳Helios

园龄:1年6个月粉丝:0关注:0

代码随想录算法训练营第四天

代码随想录算法训练营第四天 | LeetCode 24(两两交换链表中的节点) LeetCode 19(删除链表的倒数第N个节点) LeetCode 160(链表相交) LeetCode 142(环形链表II)

24:两两交换链表中的节点

LeetCode 24(两两交换链表中的节点)
思路:

这道题其实很简单
画图模拟出是如何交换链表的就好了
要注意的是 这里的交换是 0和1交换 2和三交换以此类推

方法一

class Solution {
    public ListNode swapPairs(ListNode head) {
        if(null == head || null == head.next){
            return head;
        }
        //设置虚拟头节点
        ListNode newNode = new ListNode(-1,head);
        //当前节点
        ListNode cur = newNode;
        //第一节点
        ListNode first;
        ListNode second;
        //临时节点 保存从一,二节点后的第三节点
        ListNode temp;
        //开始遍历链表 一次查看两个节点
        while(null != cur.next && null != cur.next.next){
            //先赋值
            first = cur.next;
            second = cur.next.next;
            temp = cur.next.next.next;
            //节点交换 当前节点情况 cur first second temp
            cur.next = second;
            second.next = first;
            first.next = temp;
            //cur指针移动 当前节点情况 cur second first temp
            //因为temp是下一组要交换的节点组中的第一个节点
            //那么cur应该指向 temp的前驱节点first
            cur = first;
        }
        return newNode.next;
    }
}

19:删除链表的倒数第N个节点

LeetCode 19(删除链表的倒数第N个节点)
思路:

双指针法
使得两个指针距离为n-1 那么当前指针遍历到链表末尾的时候 后指针就是倒数第n个节点啦

方法一

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        //定义虚拟头节点
        ListNode newNode = new ListNode(-1,head);
        ListNode prev = head;
        ListNode cur = newNode;
        //位移前驱指针
        //使得prev和cur相距 n-1 因为倒数的是从1开始计数
        n = n - 1;
        while(n-- > 0){
            prev = prev.next;
        }
        //使prev遍历到链表结尾 cur也要跟着移动
        while(null != prev.next){
            prev = prev.next;
            cur = cur.next;
        }
        //删除节点
        cur.next = cur.next.next;
        return newNode.next;
    }
}

160:链表相交

LeetCode 160(链表相交)
思路:

假定a,b成环 当 a,b为null时跳至另一链表起点继续遍历一次
若 a:[4,1,8,4,5] b:[5,0,1,8,4,5]
4 1 (8 4 5) null 5 0 1 (8 4 5) null
a b

方法一

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB)
    {
        if(headA == null || headB == null){
            return null;
        }
        //假定A B成环 但实际上不是一个环
        ListNode a = headA;
        ListNode b = headB;
        //不会造成死循环 因为若链表不相交 到最后 a,b就会均为null 
        while(a != b){
            a = a == null ? headB : a.next;
            b = b == null ? headA : b.next;
        }
        return a;
    }
}

142:环形链表II

LeetCode 142(环形链表II)
思路:

快慢指针
fast 一次位移两步
slow 一次位移一步
如果有环 则fast和slow必定会相遇
那么如何找到环的入口呢?
假设从头结点到环形入口节点 的节点数为x。 环形入口节点到 fast指针与slow指针相遇节点 节点数为y。 从相遇节点 再到环形入口节点节点数为 z
那么相遇时:
slow指针走过的节点数为: x + y,
fast指针走过的节点数:x + y + n (y + z),n为fast指针在环内走了n圈才遇到slow指针, (y+z)为 一圈内节点的个数A。
因为fast指针是一步走两个节点,slow指针一步走一个节点, 所以 fast指针走过的节点数 = slow指针走过的节点数 * 2:
(x + y) * 2 = x + y + n (y + z)
两边消掉一个(x+y): x + y = n (y + z)
因为要找环形的入口,那么要求的是x,因为x表示 头结点到 环形入口节点的的距离。
所以要求x ,将x单独放在左面:x = n (y + z) - y ,
再从n(y+z)中提出一个 (y+z)来,整理公式之后为如下公式:x = (n - 1) (y + z) + z 注意这里n一定是大于等于1的,因为 fast指针至少要多走一圈才能相遇slow指针
当 n为1的时候,公式就化解为 x = z,
这就意味着,从头结点出发一个指针,从相遇节点 也出发一个指针,这两个指针每次只走一个节点, 那么当这两个指针相遇的时候就是 环形入口的节点。

方法一

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        //结尾有环的话 那么fast.next就不可能遇到null值
        while (fast != null && fast.next != null) {
            //慢指针一次走一步
            slow = slow.next;
            //快指针一次走两步
            fast = fast.next.next;
            //有环
            if (slow == fast) {
                ListNode a = fast;
                ListNode b = head;
                // a,b两个指针,从头结点和相遇结点,各走一步,直到相遇,相遇点即为环入口
                while (a != b) {
                    a = a.next;
                    b = b.next;
                }
                return a;
            }
        }
        return null;
    }
}

本文作者:昼阳Helios

本文链接:https://www.cnblogs.com/Q316/p/17692327.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   昼阳Helios  阅读(6)  评论(0编辑  收藏  举报
   
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起