代码随想录算法训练营第四天 | 24. 两两交换链表中的节点,19.删除链表的倒数第N个节点 ,面试题 02.07. 链表相交,142.环形链表II

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

题目链接:24. 两两交换链表中的节点

解题思路

思路一(虚拟头节点)

解题思路如下图:
在这里插入图片描述
代码实现:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode pre;
        pre = head;
        ListNode humNode = new ListNode(-1);
        humNode.next = pre;
        ListNode cru = humNode;
        if(pre == null){
            return head;
        }
        while(pre != null && pre.next != null){
            ListNode temp = pre.next;
            ListNode temp1 = temp.next;
            cru.next = temp;
            temp.next = pre;
            pre.next = temp1;
            cru = pre;
            pre = temp1;
        }
        return humNode.next;
    }
}

注意:
1.链表中最为重要的解题要点,我们不能直接用链表指针进行修改,我应该创建一个指针去代替链表指针去修改链表。
2.在进行指针移动的时候,需要注意cru,pre会移动到哪个节点上。
3.对于特殊的基数节点我们可以将while写为(pre != null && pre.next != null)
4.在虚拟头节点算法中输出链表时,应该排除虚拟头节点(humNode.next)。

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

题目链接:19.删除链表的倒数第N个节点

解题思路

思路一(暴力解法)

可以将这道题转换为删除第几个节点,但是面临一个问题:因为链表无法得到其长度,我们需要先遍历一边链表,得出链表长度。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        int sz = 0;
        ListNode pre = head;
        while(pre != null){
            pre = pre.next;
            sz++;
        }
        if(sz - n == 0 || sz == 1){
            return head.next;
        }
        ListNode cur = head;
        for(int i = 0; i < sz - n - 1; i++){
            cur = cur.next;
        }
        cur.next = cur.next.next;
        return head;        
    }
}

思路二(双指针)

我们将使用两指针(fast,slow),我们可以模拟倒数n,首先先让fast和slow距离n,当slow指针移动到最后一个节点,fastz指针则为倒数n的前一个节点。
在这里插入图片描述
注意:
1.图中slow.next指向fast只是这道题的巧合,实际是slow.next = slow.next.next。
2.使用虚拟节点是防止,链表中只有一个值时,fast.next报错(fast为null)。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode Humhead = new ListNode(-1);
        Humhead.next = head;
        ListNode fast = Humhead;
        ListNode slow = Humhead;
        for(int i = 0; i < n; i++){
            fast = fast.next;
        }
        while(fast.next != null){
            slow = slow.next;
            fast = fast.next;
        }
        slow.next = slow.next.next;
        return Humhead.next;      
    }
}

LeetCode 面试题 02.07. 链表相交

题目链接:面试题 02.07. 链表相交

解题思路

思路一

分析题目可得:
1. 链表是不会在分叉的,因为链表节点只会存一个指针
我先将两个链表进行遍历,求出长度为后面头结点对其做准备
在这里插入图片描述
我们将两个链表的头节点对其,再遍历如果指针相等就输出节点,如果不相等,两个头节点往后移一位
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode cur = headA;
        ListNode pre = headB;
        int ALen = 0;
        int BLen = 0;
        //求headA的长度
        while(cur != null){
            cur = cur.next;
            ALen++;
        }
        //求headB的长度
        while(pre != null){
            pre = pre.next;
            BLen++;
        }
        cur = headA;
        pre = headB;
        //如果cur长度小于pre长度,我们将长度大变成cur,为了节省代码,可以不用单独写cur长度小于pre长度的实现函数
        if(BLen > ALen){
            int temp = ALen;
            ALen = BLen;
            BLen = temp;
            ListNode tempNode = cur;
            cur = pre;
            pre = tempNode;
        }

        int len = ALen - BLen;
        while(len > 0){
            cur = cur.next;
            len--;
        }
        //找出相交的节点
        while(cur != null){
            if(cur == pre){
                return cur;
            }
            cur = cur.next;
            pre = pre.next;
        }
        return null;
    }
}

LeetCode 142.环形链表II

题目链接:142.环形链表II

解题思路

思路一(快慢双指针)

在这里插入图片描述
我们假设fast的速度时slow的两倍,相遇时2(x+y) = x+y+n(z+y),化简可得x=(n-1)(z+y)+z,从这个公式可得,如果以相同的速度,一个从head开始,另一个从交点开始,同时开始移动,最后相交的的节点一定时环形入口节点。

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow){
                ListNode index1 = fast;
                ListNode index2 = head;
                while(index1 != index2){
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;
    }
}

疑虑点:为什么慢指针与快指针相遇,慢指针还没走完一圈环?
在这里插入图片描述
在这里插入图片描述

快指针比慢指针速度快,慢指针在跑第一圈的时候,假设快指针没有相遇,并且快指针就在慢指针前面很短的距离(忽略不计),慢指针已经跑玩一圈(一圈常为x)的时候才追上,快指针的需要跑了 2x,才能重新追上,但是一圈只有x,如何在不经过慢指针的情况下,跑两圈,显然假设就不成立

总结

1.涉及到修改链表时,需要使用虚拟头节点(另外:如果头节点修改时不会面临空指针报错可以不用使用虚拟头节点(206.反转链表))。
2.链表是不会在分叉的,因为链表节点只会存一个指针
3.第四题等同于一道数学题(涉及追及问题(不懂的话可以观看:链表遍历学清楚! | LeetCode:19.删除链表倒数第N个节点))

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值