一,反思
冷不丁的一天没碰力扣,因为在做项目和完善自己的知识点,真是懈怠了,怎么都能给自己找到不学习的借口,一整天因为鼻炎昨天熬夜,10点起,起来先想吃啥,把炉石每日任务做了,做完任务上了点分快到一点,准备上课了,算了不学了,去上课因为羞愧于没学习,上课小看了一会面试重点和c#基础,学了一节课感觉进度很慢,又搓上炉石了。整个人的学习状态就是一个字-烂。下午回来终于是把前面几天题看下来了,但还是有很多地方啃不动,但是又不敢在群里发言,因为我也不知道我哪里不会写,一看思路能明白,一写就是写不动,尤其是这几天这个构造链表和那个最后一道那个环形链表,完全不知道怎么来下这个手,但是我最近没有太多时间放在这,也许我得等这个面试完了的再说,把鼻炎治好,然后在这个上面再多花时间,自己作图自己硬啃。顺便一问,大家有没有跟我一样的鼻炎啊,每天在室内就堵死,在室外还能好一点。希望吃点中药能好。
二,正文
力扣203,移除链表元素
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
方法1,虚拟头节点
说实话,我在学c的时候那个指针就感觉也是没太学明白,一点也写不出来,但是能看懂,而我们考试甚至学到指针之前都能考过,今天做这个题理解了好一阵子,总的来说是这样,我们要删除链表里的元素呢,先要想它的位置,如果它是第一个,就要把头结点移一位,然后删掉原来的第一个节点,如果他是中间的,就要把他前一个结点的next指向它的next,如果它是最后一个,我们就要将它的前一个结点指向它的next,也就是null,那我们发现,中间的和最后的跟第一个的操作有些不同之处,不是一个逻辑,如果要专门处理一下第一个节点的操作,那也太麻烦了,于是有虚拟头节点可以用,我们另设一个dummyhead为头节点,它的next再指向原来的头节点,这样的话我们所有的删除操作就是一个逻辑了。c#
public class Solution {
public ListNode RemoveElements(ListNode head, int val) {
ListNode newHead = new ListNode(-1);
// 虚拟头节点,将所有特殊情况统一变成一般情况
// 这里的特殊情况主要是:空链表、链表开头第一个就为需要移除的元素
newHead.next = head;
// 遍历链表
for(ListNode p1 = newHead; p1 != null; p1 = p1.next)
{
ListNode p2 = p1.next; // 下一个结点
if(p2 == null) // 判断是否到末尾
{
break;
}
// 下一个结点若为val,则直接连接到下一个不为val的结点
while(p2.val == val)
{
p2 = p2.next;
p1.next = p2;
if(p2 == null) // 如果后面全为val了,就连null
{
break;
}
}
}
return newHead.next; // 返回真正的头
}
}
力扣206,反转链表
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
方法1,双指针
这题理解上不算难,但还是内个问题,我自己没什么写出来的能力,图我能画出来,就是写上寸步难行,利用两个指针,一个pre指向null,一个cur指向第一个节点,这里关键的来了,要把第一个cur。next先保存下,然后将cur指向等于null的pre,后面再给pre赋cur的值,即pre→移,然后再把刚刚存好的cur。next赋给cur,即→移一位,直到cur指向null,循环结束,返回这个时候的头节点pre就行
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode prev = null, curr = head;
while (curr != null) {
ListNode next = curr.next; //先储存curr。next的值
curr.next = prev; //让curr。next指向等于null的prev,
prev = curr; //现在给prev赋curr的值,即prev→移一位
curr = next; //现在再把之前存好的next的值赋给curr,即curr→移一位。
} //直到curr指向null循环结束
return prev; //返回此时数组的头节点prev
}
}
力扣24两两交换链表节点!
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
换节点,而非改数字,要两两换,则只要链表长度不够,就换不了,所以只要头节点和头节点。next为空,这个事就办不成,直接返回头节点,这题我用了递归的方法哈,先来一个新头节点,然后给他赋head。next,然后递归的给head。next赋new。head。next的值,最后再让newhead指向head,再返回newhead,一直递归下去,最后到head指向null或者head。next指向null的时候即代表递归完成
public class Solution {
public ListNode SwapPairs(ListNode head) {
if (head == null || head.next == null) {//只要head为空,还有head的下一个节点为空,即链表长度不够换的,此时直接返回
return head;
}
ListNode newHead = head.next; //设newhead然后将head.next赋给它
head.next = SwapPairs(newHead.next); //递归的给head.next赋newhead.next的值,
newHead.next = head;//此时令newHead指向head
return newHead; //此时返回的newhead节点就是数组的头节点
}
}
力扣19删除链表倒数第n个节点,
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
首先我们想删除,前面提到过怎么删哈,要用到前一个,所以这题也是需要虚拟头节点比较好理解,好操作,找n就是我们的下个问题,双指针来解决,快指针先走n+1步,然后慢指针再跟上,最后当快指针指向null时,慢指针就指向要删除的下一个节点,我们直接让慢指针指向。next。next,问题就解决了
public class Solution {
public ListNode RemoveNthFromEnd(ListNode head, int n) {
ListNode dummpHead = new ListNode(0);
dummpHead.next = head;
var fastNode = dummpHead;
var slowNode = dummpHead;
while(n-- != 0 && fastNode != null)
{
fastNode = fastNode.next;
}
while(fastNode.next != null)
{
fastNode = fastNode.next;
slowNode = slowNode.next;
}
slowNode.next = slowNode.next.next;
return dummpHead.next;
}
}
这几天少了几道题哈,全都是我难以理解的,我在有更多的时间之后会补档,望大家监督