重生之我在代码随想录刷算法第四天 | 24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题 02.07. 链表相交、142.环形链表II

参考文献链接:代码随想录

本人代码是Java版本的,如有别的版本需要请上代码随想录网站查看。

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

[力扣题目链接]

解题思路

这道题我感觉比较简单,跟昨天翻转的比较像,只要能弄明白节点的next究竟指向谁,也就是到底怎么交换即可。

虚拟头节点

为了头节点操作方便,我们还是加入虚拟头节点,具体如何交换请看注释以及下方我画的图

在这里插入图片描述

/**
 * 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 dummpy = new ListNode();
        dummpy.next = head;
        //tmp保存虚拟头节点
        ListNode tmp = dummpy;
        //如果当前节点的下个节点和下下个节点都不为null,那么这两个节点就要交换
        while(tmp.next != null && tmp.next.next!=null){
            //保存第一、二个节点
            ListNode firstNode = tmp.next;
            ListNode secondNode = tmp.next.next;
            //将tmp的next从一节点改为二节点
            tmp.next = tmp.next.next;
            //一节点的next改为二节点的next
            firstNode.next = secondNode.next;
            //将tmp的二节点位置改为一节点
            tmp.next.next = firstNode;
            //更新tmp节点到该交换的位置
            tmp = tmp.next.next;
        }
        return dummpy.next;
    }
}

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

力扣题目链接

解题思路

这道题目比较简单但要读清题,是要删除倒数第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) {
        ListNode dummpy = new ListNode();
        dummpy.next = head;
        int size = 0;
        ListNode countNode = dummpy;
        //循环去算出链表的长度
        while(countNode.next != null){
            size++;
            countNode = countNode.next;
        }
        countNode = dummpy;
        //移动相应次数,然后进行删除操作
        for(int i = 0;i < size - n;i++){
            countNode = countNode.next;
        }
        countNode.next = countNode.next.next;
        return dummpy.next;
    }
}
双指针法

这道题目用双指针只是为了计数。

让一个指针先走n步,然后两个指针同时走,当快指针的next为null时,此时慢指针就走到了要删除的位置。

举个例子更明显一些,比如一个链表1->2->3->4,我们现在删除倒数第2位。

从虚拟节点开始,让快指针先走2步,此时快指针是在数字2的位置,此时慢指针也一起走,慢指向1的时候快指向3,慢2快4,此时快指针的next为null,慢指针走到了要操作的位置,删除下一个节点3即可。

/**
 * 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 dump = new ListNode(-1);
        dump.next = head;
        ListNode slow = dump;
        ListNode fast = dump;
        for(int i = 0;i<=n;i++){
            fast = fast.next;
        }
        while(fast!=null){
            slow = slow.next;
            fast = fast.next;
        }
        slow.next=slow.next.next;
        return dump.next;
    }
}

面试题 02.07. 链表相交

力扣题目链接

解题思路

这道题代码简单,但思路跟其余链表题不太一样。刚开始做这道题怎么都想不到如何能找到两个链表在哪里相交,因为这样是需要比较某两个节点是否相同,难不成我要遍历两个链表一个一个节点去比吗?

后来才发现是我傻了,如果链表相交,那他们相交之后的链表是一样的,即节点数也一样。也就是说一个长度为5的链表和一个长度为3的链表,你只需要让长度为5的链表移动到剩3的位置开始与另一个链表比较即可。

因此,只需要得出两个链表的长度,让长的那个先移动到对应位置,然后两个链表一起移动比较节点是否相同即可,只要相同,就说明他俩相交了。

/**
 * 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 cur1 = headA;
        int count1 = 0;
        ListNode cur2 = headB;
        int count2 = 0;
        while(cur1!=null){
            cur1 = cur1.next;
            count1++;
        }
        while(cur2!=null){
            cur2 = cur2.next;
            count2++;
        }
        cur1 = headA;
        cur2 = headB;
        if(count1>count2){
            for(int i = 0;i<count1-count2;i++){
                cur1 = cur1.next;
            }
        }else{
            for(int i = 0;i<count2-count1;i++){
                cur2 = cur2.next;
            }
        }
        while(cur1!=null){
            if(cur1==cur2){
                return cur1;
            }
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return null;
    }
}

142.环形链表II

力扣题目链接

解题思路

这道题在我开始看的时候一头雾水,这怎么操作才能知道环的起点呢?

在我看了代码随想录的讲解后恍然大悟,原来这不仅是一道链表题,还是一道数学题。

以后遇到环形问题,两步走:是否有环,环的相交点在哪

是否有环

我们可以让一个快指针和慢指针同时从头节点走,快指针一次2步,慢指针一次1步,如果是环形链表则一定会相遇。

这个不难理解,自己实操一下模拟一下即可。

环的相交点

遇到这样的题目一看就不是光思考就能解决的,上图,上数学!
在这里插入图片描述

因此就明了了,我们只需做两件事。

一是从头节点出发两个指针,一个步长为1一个为2。当他们相遇时,从相遇点和头节点分别出发一个步长为1的指针,当他们再次相遇,那么相遇点就是环入口。

/**
 * 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 slowNode = head;
        ListNode fastNode = head;
        ListNode index1;
        ListNode index2 = head;
        while(fastNode!=null&&fastNode.next!=null){
            fastNode=fastNode.next.next;
            slowNode=slowNode.next;
            if(slowNode==fastNode){
                index1 = fastNode;
                while(index1!=index2){
                    index1 = index1.next;
                    index2 = index2.next;
                }
                return index1;
            }
        }
        return null;

    }
}

感想

坚持刷题第四天,明天周日休息日我应该会发一下这周的总结,我们下周一见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值