代码随想录算法训练营第四天| LeetCode24. 两两交换链表中的节点、19.删除链表的倒数第N个节点、面试题02.07. 链表相交、142.环形链表II
LeetCode24. 两两交换链表中的节点
● 今日学习的文章链接和视频链接
题目链接
● 自己看到题目的第一想法
主要是把这个过程想清楚,链表交换的题目主要想明白要动几个指针,指针改变的顺序也要注意,如果有需要就要提前要保存一些指针
public ListNode swapPairs3(ListNode head) { //交换两个结点到底要改变几个指针? //两个结点之间的指针要反向,并且这对节点的前一个结点要重新指向新结点,这对结点指向后一个结点的指针也会改变 //所以要提前保存前一个结点和后一个结点 //既然涉及到前一个结点的操作了,那么就可以构造一个虚拟头节点 ListNode tmpHead = new ListNode(0, head); ListNode cur = head; ListNode pre = tmpHead; ListNode next; while (cur != null && cur.next != null) { next = cur.next.next; //指针一个一个改 pre.next = cur.next; cur.next.next = cur; cur.next = next; pre = cur; cur = cur.next;//交换之后指针的位置已经相当于往后挪动了 } return tmpHead.next; }
● 看完代码随想录之后的想法
我的cur指针指向的是当前pairs中的第一个,所以保存的是前后的指针,卡尔用的是pairs前一个指针作为当前指针,保存的是pairs中的第一个后pairs后的一个结点。我还尝试了一下别的改指针顺序,发现至少还是要保存两个结点的
● 自己实现过程中遇到哪些困难
● 今日收获,记录一下自己的学习时长
1h
LeetCode19.删除链表的倒数第N个节点
● 今日学习的文章链接和视频链接
题目链接
19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)
● 自己看到题目的第一想法
public ListNode removeNthFromEnd2(ListNode head, int n) { //怎么删除倒数第n个结点,关键在于如何判断当前结点是倒数第n个,倒数第n个就是从尾巴往回走n步 //一般来说,正数第n个很好判断,倒数第n个就需要两个指针了 //慢指针和快指针之间相差n步,让快指针走到头,慢指针所在的位置就是倒数第n个 ListNode fast = head; ListNode slow=head; while (n > 1) { fast = fast.next; n--; } ListNode tmpHead = new ListNode(0, head); ListNode pre = tmpHead; while (fast.next != null) { fast = fast.next; slow = slow.next; pre = pre.next;//保存前一个指针 } pre.next = slow.next; return tmpHead.next; }
● 看完代码随想录之后的想法
指针冗余了,直接让快慢指针相差n+1步就行,快指针走到头,慢指针正好是要删除结点的前一个
ListNode fast = head; // ListNode slow=head; while (n > 1) { fast = fast.next; n--; } ListNode tmpHead = new ListNode(0, head); ListNode pre = tmpHead; while (fast.next != null) { fast = fast.next; // slow = slow.next; pre = pre.next;//保存前一个指针 } // pre.next = slow.next; pre.next = pre.next.next; return tmpHead.next;
● 自己实现过程中遇到哪些困难
对于n个步长的理解,其实就是指针往后移动n次,然后倒数第几个是从倒数第一个开始算的,所以n=1时步长为0;让快指针挪动n步时的循环条件怎么写,还是具体带入两个数值检验一下
● 今日收获,记录一下自己的学习时长
0.5h
LeetCode面试题02.07. 链表相交
● 今日学习的文章链接和视频链接
题目链接
面试题 02.07. 链表相交 - 力扣(LeetCode)
● 自己看到题目的第一想法
public ListNode getIntersectionNode2(ListNode headA, ListNode headB) { //两个链表在一个地方相交,那么链表A的长度假设是a+c,链表B的长度假设是b+c //那么A走到头之后再走b步,B走到头之后再走a步;两个指针走的距离一定是相等的,妙不妙 //妙啊 if (headA == null || headB == null) { return null; } ListNode a = headA; ListNode b = headB; int count = 0; while (count < 2) {
} if (count == 2) { return null; } return a; }
● 看完代码随想录之后的想法
卡尔的做法是让两个链表尾端对齐,然后开始移动指针,这样也挺直观的。可以用前面那道题找到链表的倒数第n个结点,不过要先遍历两个链表看哪个更长,长度短的那个链表长度为size,长度长的链表的快指针走size-1步。
● 自己实现过程中遇到哪些困难
我写的时候通过debug,才发现判断条件是有先后顺序的。第一,如果先移动指针再判断两个结点是否相等,就会漏掉头指针。第二,如果先判断指针是否为null再移动到另一个链表头部,再移动指针,这就相当于指针跳过了一个结点;因此需要先移动指针,再判断是否为null,为null就跳到另一个链表的头节点,这样才不会漏掉任何一个结点
总结要点是不能漏掉链表中每个要遍历的结点。
● 今日收获,记录一下自己的学习时长
1h
LeetCode142.环形链表II
● 今日学习的文章链接和视频链接
题目链接
● 自己看到题目的第一想法
记得这道题是用快慢指针,但是不知道为什么快慢指针一定会相遇
● 看完代码随想录之后的想法
public ListNode detectCycle2(ListNode head) { //这道题的主要思路是用快慢指针,一个指针每次走两步,一个指针每次走一步 //如果有环的话,这两个指针一定会相遇,为什么呢? // 因为快指针先进入环中,慢指针后进入环内,那么快指针相对于慢指针的移动速度是一步,快指针一定会追上慢指针 // 慢指针遍历完一圈环的时候,快指针一定走了两圈了,由于我们应该考虑相对运动速率 //所以在这个过程中快指针一定会经过慢指针 //综上,慢指针走过的路程=2(x+y)=快指针走过的路程=x+y+n(y+z) //化简一下:x+y=n(y+z)=> x=n(y+z)-y=> x=(n-1)(y+z)+z //这说明,一个指针从环内相遇的位置出发,另一个指针从头出发,两者一定会在环的入口相遇 //我们这里判断的依据就是指针走过的距离一定相等,所以此时指针移动的速率一定要保持一致 ListNode fast = head; ListNode slow = head; while (fast != null && fast.next!=null) { fast = fast.next.next; slow = slow.next; if (fast == slow) { slow = head; while (slow != fast) { fast = fast.next; slow = slow.next; } return fast; } } return null; }
● 自己实现过程中遇到哪些困难
主要是要想明白相遇的道理,以及为什么找到相遇点之后,从相遇的地方出发,两个指针一定会在结点的入口相遇
● 今日收获,记录一下自己的学习时长
1.5h
总结
- 链表的存储形式
链表与数组不同,在内存中不是连续的,因此每个结点都有一块区域用来存储下一块结点的地址
- 链表的增删改查
链表的增删都有需要注意的地方,也即要保留一些指针,并且经常涉及到对于目标位置的前一个结点的指针的改变
因此,对于头结点这种没有前置结点的处理还需要额外进行判断,为了让操作具有统一性,我们在头结点之前保留一个虚拟头结点。
- 设计链表
这里依旧是为了操作统一,增加一个虚拟头结点作为成员变量。否则增删的操作不统一。而且进行头插法尾插法还要判断当前是不是第一个结点,因为我们需要知道链表的头到底是哪个
- 反转链表
把链表每一个结点的指针都反向,指向前一个,所以要有前置结点,也要保存后一个结点
- 两两交换链表
主要要想清楚这个断开指针然后重连的过程
- 删除倒数第n个
主要在于如何找到这个结点,两个指针相隔n步,一起往后移动
- 链表相交
一个指针走到头后走到另一个链表的头,用图纸演示会很容易想明白距离上的等量关系
- 链表的环
为什么从相遇的地方出发一定能与从头出发的指针在环的入口相遇?这道题还比较复杂,所以需要多复习,主要是要想明白一些数学推理的过程
总的来说,前半部分的题主要是基础操作,后半部分的题目有两种,一种是只要想清楚链表的断开重联过程就好了,例如反转链表和交换链表的两个结点,另一种是要进行一些数学计算的过程推算,找到等量关系