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

Day4

前言

又是后期补的一天

文章:代码随想录

视频:算法公开课-跟着Carl学算法

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

自己思路

遵循建议,先看视频

看完讲解

看完视频之后,感觉还是很好理解的,还是虚拟头节点,只要保持逻辑的清晰并结合画图把交换过程表示出来,应该就可以。过程中要注意三点:首先是,cur的指向,还是遵循要用的最前面的是谁就指向谁;然后是while循环的判断条件,结合画图可以很好的写出来,但是要注意两个判断条件的左右顺序,一定是先判断cur.next再判断cur.next.next,便于提前结束循环并避免出现空指针异常;最后就是交换过程中会造成链表断裂,需要提前对需要的但是可能获取不到的节点进行temp存储

class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy = new ListNode();
        dummy.next = head;
        ListNode cur = dummy;
        while ((cur.next != null) && (cur.next.next != null)) {
            ListNode temp = cur.next;
            ListNode temp1 = cur.next.next.next;
            cur.next = cur.next.next;
            cur.next.next = temp;
            cur.next.next.next = temp1;
            cur = cur.next.next;
        }
        return dummy.next;
    }
}

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

自己思路

好奇在不知道size的情况下,怎么从尾向前遍历呢,难道弄两次循环?遵循建议,先看视频

看完讲解

看完视频感觉找到n的位置的方法真的太妙了,还是虚拟头节点双指针,虚拟头节点感觉是几乎每道链表题都会遇到,用于统一对头部节点和后续节点的操作。双指针的思路具体体现在,一个slow指针,一个fast指针,fast先走,让两者的间距刚好就是n+1(多一位是为了好获取到被删节点的前一个节点,画图就懂)。相当于我先定好两者的间距,再去平移,移动到fast指向null就平移完毕,这个思路真的很值得学习,后面的删除操作就不再赘述

过程中一直报错空指针异常,但是我把特殊情况考虑后也没找到问题,后来发现我画图的时候slow和fast是从dummy开始,结果初始赋值赋的head,所以会报空指针异常,改过来就好了

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode();
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;
        for (int i = 0; i <= n; i++) {
            fast = fast.next;
        }
        while (fast != null) {
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummy.next;
    }
}

LeetCode 面试题 02.07 链表相交

自己思路

有个思路,但是感觉太复杂了,我想的是两层循环两个指针,一个指向A的虚拟头节点,一个指向B的虚拟头节点,然后A每移动一位,就遍历B的每一位看是否有节点相等的情况,循环往复,一直到A指向null结束,但是我想这应该不是一个简洁的思路,直接去看讲解

看完讲解

感觉还是可以概括为双指针思路,但是这个道题最关键的还是要想清楚,如果两个链表真的可以有相交的部分,那么一定是从相交位置一直到最后一位,这还是破题的关键。并且这个相交的长度,一定是小于等于短一点的链表长度的

所以说可以先求两个链表的长度(这里我还看了看答案,发现竟然真的是两次遍历去求长度),然后将链表尾巴对齐,短一点的链表指针指向head,长一点的链表指向对齐尾部后的同一位置(即从head向前移动差值位)。然后再开始从当前开始向后遍历,依次比较节点是否相等,相等就返回,一直到遍历完毕都不相等那就返回null(此处我的代码用的根据短的长度for循环,其实可以直接while循环)

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int sizeA = 0;
        int sizeB = 0;
        ListNode curA = headA;
        ListNode curB = headB;
        while (curA != null) {
            sizeA++;
            curA = curA.next;
        }
        while (curB != null) {
            sizeB++;
            curB = curB.next;
        }

        curA = headA;
        curB = headB;
        if (sizeA >= sizeB) {
            int length = sizeA - sizeB;
            for (int i = 0; i < length; i++) {
                curA = curA.next;
            }
        } else {
            int length = sizeB - sizeA;
            for (int i = 0; i < length; i++) {
                curB = curB.next;
            }
        }

        int length = sizeA >= sizeB ? sizeB : sizeA;
        for (int i = 0; i < length; i++) {
            if (curA == curB) {
                return curA;
            }
            curA = curA.next;
            curB = curB.next;
        }
        return null;
    }
}

LeetCode 142 环形链表II

自己思路

遵循建议,先看视频

看完讲解

看视频的过程中,真的是觉得又厉害又抽象,相遇问题理解了好一会。主要还是双指针的思路,把问题拆分成两个,一个是到底有没有环,一个是如果有环那么哪里是入环点。定义两个指针,一个fast,一个slow,fast一次走两步slow一次走一步(感觉可以想到这里才算是进入了解题的核心),这样的等fast和slow入环之后,可以理解成相当于slow静止fast每次走一步,那么如果有环,一定会有fast==slow相遇,以此来判断是否有环

上面第一个问题还算好理解,第二个问题如果有环那么哪里是入环点感觉真的很难自己想出来,纯数学问题,这里就直接用代码随想录的解释了

最后会发现,只要保证一个指针从起点出发,一个指针从相遇的点出发,那么他们一定会在环的入口相遇(相遇可能是一个走了x一个走了z,也可能是一个走了x一个走了z再加上好几圈)。这里面关于为什么一定是慢指针还没有走完一圈就会和快指针相遇(即为什么slow=x+y,不再加y+z),我是这样理解的:假设slow入环了,那么fast肯定也入环了,这里还是用速度差来看,我们就可以理解成slow入环后静止,fast一次移动一步,那么fast最多走完一圈也会和slow相遇了,而这一圈就相当于slow原本最多走了的一圈和fast相遇(slow以及fast的相对速度都是1),所以说他俩的第一次相遇时slow肯定还在第一圈内

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;
    }
}

总结

用时:4h,虽然是后面补的,但是状态回暖,继续加油

前几题还算是简单,前提是直接去看视频的思路再写。最后的环形链表,真的还理解了好一下子

  • 28
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值