学习目标:
60天训练营打卡计划!
学习内容:
24. 两两交换链表中的节点
- 如何保留虚拟头节点用于最后的输出?给原链表设置一个虚拟头节点,并保留其身份。
- 使用了双指针法!
- 如何确定结束的条件?
while(cur != null && cur.next != null):
其中的cur和 cur.next(tmp1)就是要交换的两个节点,所以最后移动的时候pre赋值为cur,而cur的赋值为tmp2。 - 本题中pre节点是维持要交换的节点前的顺序(因此虚拟头节点得以保留),而tmp2是维持要交换的节点后的顺序。
lass Solution {
public ListNode swapPairs(ListNode head) {
ListNode vir = new ListNode(-1,head);
ListNode pre = vir;
ListNode tmp1 = null;
ListNode tmp2 = null;
ListNode cur = vir.next;
// cur不为null是约束偶数节点,
// cur.next != null是为了约束奇数节点
while(cur != null && cur.next != null){
// 保存好cur的下一个和下下一个节点信息。
tmp1 = cur.next;
tmp2 = cur.next.next;
// 进行反转操作
pre.next = tmp1;
tmp1.next = cur;
cur.next = tmp2;
// 使pre和cur节点移动
// 在移动后cur已经成为tmp2的前一位了
pre = cur;
cur = tmp2;
}
return vir.next;
}
}
19.删除链表的倒数第N个节点
- 是我们熟悉的双指针法!
- 使用带虚拟头节点的链表来处理,保证对于头节点和其他节点之间的处理规则完全相同。
- 如何确定快慢指针的间距?距离为N + 1。当慢指针在虚拟节点时,快指针指向链表的第N个数。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode vir = new ListNode(-1,head);
ListNode pre = vir;
ListNode cur = head;
while( n-- > 0)
cur = cur.next;
while(cur != null){
cur = cur.next;
pre = pre.next;
}
pre.next = pre.next.next;
return vir.next;
}
}
- 从本题,我还学会了:
- 区别什么是链表的节点的递增:cur = cur.next;什么是节点删除:pre.next = pre.next.next;
142.环形链表II
- 第一遍实现时逻辑写错了,第一个结束的条件写成快慢指针不相遇,特别长的链表是无法处理的。另一方面是:快慢指针相遇后才找具体的节点,写成
错误逻辑!!!
while(fast != slow){
fast = fast.next.next;
slow = slow.next;
}
while(tmp != slow){
tmp = tmp.next;
slow = slow.next;
}
理论分析:假设快指针每次走两个节点,慢指针每次走一个节点,所以快指针相对于慢指针的速度是1个节点。
真实的逻辑应该是先循环判定是不是空?不是空才去找递增快慢指针,然后如果相遇,才会找具体的节点。
public class Solution {
public ListNode detectCycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null && fast.next.next != null){
fast =fast.next.next;
slow = slow.next;
// 快慢节点相遇
if(slow == fast){
ListNode tmp = head;
// 查找链表和环的交界
while(tmp != slow){
tmp = tmp.next;
slow = slow.next;
}
return tmp;
}
}
return null;
}
}
学习时间:
- 看视频一小时,下午两小时,整理文档半小时
- 12月7日复习,142不熟悉。