0
点赞
收藏
分享

微信扫一扫

LeetCode刷题day25


​​203. 移除链表元素​​

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

方法一:使用虚拟头结点

先为原始链表创建一个虚拟头结点,然后在下一个节点存在的情况下,判断下一个节点是否 == val,如果等于则进行删除操作.否则继续遍历.

参考代码1

//使用带虚拟头结点的方法. 
ListNode* removeElements(ListNode* l, int val) {
ListNode* L = new ListNode(-1,l);
ListNode* p = L,*q;//注意这里的指针定义.
while(p->next!=NULL){//如果当前节点的下一个节点不为空.
if(p->next->val==val){
q = p->next;
p->next = p->next->next;//指针方向进行变化.
delete q;//删除该节点.
}else{
p = p->next;//更新p
}
}
p = L->next;
delete L;
return p;
}

方法二:无虚拟头结点

因为头结点前面没有节点,所以如果头结点是我们的删除目标,删除的办法就和删除非头结点的不同,需要特殊处理.

所以基本思路是:

  • 先判断头结点是否 == val,如果等于则直接指针后移,并进行删除该节点.
  • 头结点处理完毕后,继续后序的处理,依次遍历节点,判断当前节点的下一个节点是否 == val,如果等于则进行删除下一个节点.不相等,则指针后移,继续遍历.

参考代码2

ListNode* removeElements(ListNode* l, int val) {
//删除头结点.
ListNode* temp;
while(l!=NULL&&l->val==val){
temp = l;
l = l->next;
delete temp;
}
if(l==NULL){//判断头结点是否为null了,如果是,则直接返回NULL.
return NULL;
}
//删除非头结点 (和第一种方法一样)
ListNode* cur = l;
while(cur->next!=NULL){
if(cur->next->val==val){
temp = cur->next;
cur->next = cur->next->next;
delete temp;
}else{
cur = cur->next;
}
}
return l;

}

​​206. 反转链表​​

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

LeetCode刷题day25_leetcode

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

LeetCode刷题day25_深度优先_02

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

方法一:双指针

基本思路:从前往后将指针的方向改变,返回最后一个节点

使用pre指向前一个节点,cur代表当前节点,从第一个节点开始进行遍历,每次让cur指向pre,之后cur继续遍历下一个节点,直至链表遍历完毕.

LeetCode刷题day25_算法_03

参考代码1

//双指针法 
ListNode* reverseList(ListNode* head) {
ListNode* cur = head;
ListNode* pre = NULL;
ListNode* temp;//用于保存当前节点的下一个节点.
while(cur){
temp = cur->next;
cur->next = pre;//改变当前节点的指针方向.
pre = cur;//pre指针后移
cur = temp;//当前节点后移.
}
return pre;
}

方法二:递归1(从前往后改变指针方向)

思路和方法一基本一致,递归实际上就是自己调用自己,每次的操作一致.

  • 每次我们需要改变指针指向,需要操作两个节点,当前节点cur和上一个节点pre,所以这就是递归函数的参数.
  • 递归的结束条件就是当前节点为NULL,则不再需要改变方向了.递归结束.

参考代码2

//递归本质上就是在做相同的操作,自己不断的调用自己. 
ListNode* reverse(ListNode* pre,ListNode* cur){
if(cur==NULL){
return pre;
}
ListNode* temp = cur->next;
cur->next = pre;
return reverse(cur,temp);//继续递归.
}


ListNode* reverseList(ListNode* head) {
return reverse(NULL,head);
}

方法三:递归2(从后往前改变指针方向)

后期进行完善…

​​24. 两两交换链表中的节点​​

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

LeetCode刷题day25_leetcode_04

输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

思路分析

题目的要求是交换相邻的节点,题目也说了是这两个节点的顺序发生改变,而不是仅仅交换下值.而且如果当前节点只有一个,则肯定不需要交换啦.

两个数进行交换我们需要一个中间值.而两个节点 1, 2 进行交换涉及到当前节点 0 的指向,A,B这两个节点的指针指向.

接下来我们用图解来表示:

LeetCode刷题day25_链表_05


根据图中,我们可以使用三个辅助变量便可完成操作.

参考代码

ListNode* swapPairs(ListNode* l) {
ListNode* head = new ListNode(-1,l);
ListNode* cur = head;
ListNode* temp1,temp2,temp3;//分别存放,当前节点后面的三个节点,便于操作.
while(cur->next!=NULL&&cur->next->next!=NULL){
temp1 = cur->next;
temp2 = cur->next->next;
temp3 = cur->next->next->next;
cur->next = temp2;//执行第一步:当前0节点指向2号节点
temp2->next = temp1;//执行第二步:当前2节点指向1号节点
temp1->next = temp3;//执行第三步:当前1节点指向3号节点.
cur = cur->next->next;//cur后移两位.
}
return head->next;

}

​​19. 删除链表的倒数第 N 个结点​​

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

LeetCode刷题day25_头结点_06

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

思路分析

快慢指针
先搞一个虚拟头结点,方便我们接下来的操作.

  • 第一步slow和fast都指向虚拟头结点.
  • 第二步fast向前移动n+1个节点
  • slow和fast同时向前移动,直至fast为空,则slow对应的便是目标节点的前一个节点.

为啥fast要先移动n+1个节点呢?why?

因为这样的话,之后当fast和slow同时移动,当fast为null时,slow对应的刚好是target前一个节点. 而如果是n,则slow对应的是目标节点.

LeetCode刷题day25_leetcode_07

参考代码

ListNode* removeNthFromEnd(ListNode* l, int n) {
ListNode* head = new ListNode(-1,l);
ListNode* fast = head,*slow= head;
while(n--&&fast){
fast = fast->next;
}
fast = fast->next;//fast再向前走一步,因为需要让slow指向删除节点的上一个节点
while(fast){
fast=fast->next;
slow = slow->next;
}
slow->next = slow->next->next;
return head->next;

}


举报

相关推荐

0 条评论