【代码随想录算法训练营Day04】24.两两交换链表中的节点; 19.删除链表的倒数第N个节点; 面试题 02.07. 链表相交; 142.环形链表II; 总结

Day 4 第二章 链表part02

  • 今日任务
    • 24.两两交换链表中的节点; 19.删除链表的倒数第N个节点; 面试题 02.07. 链表相交; 142.环形链表II; 总结

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

自己的思路(✅通过)

▶️双指针思想
pFn0NLt.png

public static ListNode swapPairs(ListNode head) {  
    ListNode dummyHead = new ListNode();  
    dummyHead.next = head;  
    ListNode cur, pre, temp;  
    if(head == null || head.next == null) return head;  
    cur = head.next;  
    pre = head;  
    temp = dummyHead;  
    while(cur != null){   
		temp.next = cur;  
        pre.next = cur.next;  
        cur.next = pre;  
        temp = pre;  
        if(pre.next == null || pre.next.next == null) return dummyHead.next;  
        pre = pre.next;  
        cur = pre.next; //注意pre已经移到后面了,所以只需要一次next    
    }  
    return dummyHead.next;  
}

❌ 错误点:java.lang.NullPointerException: Cannot read field "next" because "<parameter1>" is null,通过判断当headhead.next为空时提前返回head

没有考虑输入的链表(头结点就取名为head吧)只有一个结点的情况,这个时候,如果访问她的next域就会报这个错误,解决方法是:在程序一开始就先对这种极端进行判断(一般需要直接返回head,注意:不能直接返回null,虽然head有可能为空,但是题目要求返回ListNode类型的数据,(如果head为null,访问 head不会报错))

递归版本

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

自己的思路(✅通过)

▶️双指针思想
pFnD94U.png

public static ListNode removeNthFromEnd(ListNode head, int n) {  
    ListNode cur, pre;  
    ListNode dummyHead = new ListNode();  
    dummyHead.next = head;  
    cur = head;  
    pre = dummyHead;  
    //cur向后移,使pre是cur做尾节点时的倒数第n+1个方便进行删除操作  
    //倒数第n个,cur需移n-1次  
    while(cur.next != null && n>1){  
        cur = cur.next;  
        n--;  
    }  
    //cur和pre一起向后移直到cur移到该链表的尾节点  
    while(cur.next != null){  
        cur = cur.next;  
        pre = pre.next;  
    }  
    pre.next = pre.next.next;  
    return dummyHead.next;  //注意不是返回head,head可能被删了  
}

面试题 02.07. 链表相交

自己的思路(✅通过)

一开始把题目想错了,以为还有从头相交的情况,耽误了很多时间

▶️双指针思想:将A, B链表以尾部对齐,先把A链表的头节点移到与B的头节点平齐再遍历之后的节点看是否相交。

public static ListNode getIntersectionNode(ListNode headA, ListNode headB) {  
    ListNode curA = headA;  
    ListNode curB = headB; 
    //获取A,B链表的长度 
    int n1 = getSize(headA);  
    int n2 = getSize(headB);  
    int n;  
    //判断哪个链表更长,并移动长链表的节点
    if(n1 > n2){  
        int x = n1 - n2;  
        while(x > 0){  
            curA = curA.next;  
            x --;  
        }  
        n = n2;  
    }else{  
        int x = n2 - n1;  
        while(x > 0){  
            curB = curB.next;  
            x --;  
        }  
        n = n1;  
    }  
    //遍历后面的节点
    while(n > 0){  
        if(curA == curB){  
            return curA;  
        }  
        curA = curA.next;  
        curB = curB.next;  
        n --;  
    }  
    return null;  
}  
public static int getSize(ListNode head){  
    int size = 1;  
    ListNode temp = head;  
    while(temp.next != null){  
        temp = temp.next;  
        size ++;  
    }  
    return size;  
}

142.环形链表II

双指针思路(看视频)

自己实在是没思路,决定直接看视频。

▶️双指针思想:快慢指针

a. 判断是否有环
  • 大体思路: 定义一个快指针一个慢指针,如果有环快慢指针总会相遇,如果没环就不会相遇。
  • 快满指针速度: 慢指针一次走一个节点,快指针每次走两个节点
b. 寻找环入口

pFuKJd1.png

public static ListNode detectCycle(ListNode head) {  
    ListNode fast = head, slow = head, cur = head;  
    while(fast != null && fast.next != null && fast.next.next != null){  
        fast = fast.next.next;  
        slow = slow.next;  
        if(fast == slow){  
            while(slow != cur){  
                slow = slow.next;  
                cur = cur.next;  
            }  
            return slow;  
        }  
    }  
    return null;  
}

❌ 错误点:java.lang.NullPointerException: Cannot read field "next" because "<parameter1>" is null,要想判断fast.next.next != null前面必须提前判断fast != null && fast.next != null

链表总结

  • 链表一定要分清节点和指针的概念。 new ListNode()是真实存在的一个节点, head = new ListNode() 相当于 head指针指向了一个真实的节点, node = head, 相当于nodehead同时指向了这个真实的节点
  • 尽量不要去动虚拟头节点,因为虚拟头节点本来就是个工具节点,操作后面的节点本身就好
  • 20
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值