Day4
前言
又是后期补的一天
文章:代码随想录
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,虽然是后面补的,但是状态回暖,继续加油
前几题还算是简单,前提是直接去看视频的思路再写。最后的环形链表,真的还理解了好一下子