原题目
题目一
请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
现有一个链表 – head = [4,5,1,9],它可以表示为:
示例 1:
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例 2:
输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
说明:
链表至少包含两个节点。
链表中所有节点的值都是唯一的。
给定的节点为非末尾节点并且一定是链表中的一个有效节点。
不要从你的函数中返回任何结果。
题目二
删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-node-in-a-linked-list
题目三
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list
题目分析
题目一:
方法:将下一个的值赋给当前节点,将当前节点的指向下一节点的下一个,删除下一节点
node当前节点,要删除其值,将下一节点的值覆盖node,连接下一个节点的下一个
next下一个节点,用于传值和删除
题目二
方法一:删除头节点另做考虑
先循环判断第一个与给定值相等的节点在哪,相等就将头结点指针后移一位,如果为空,直接返回,不为空,保存当前节点,循环删除中间的相等节点。
head头结点,遍历到第一个与给定值不相等的节点处,用于返回
del保存当前节点,便于删除
pre遍历中间节点,判断是否与给定值相等
方法二:添加一个虚拟头结点
添加一个虚拟头节点,连接头结点,避免链表第一个节点是要删除的节点的情况,循环删除中间相等节点,返回虚拟头节点的下一个地址
res虚拟头结点,返回res->next
del保存当前节点,便于删除
pre遍历中间节点,判断是否与给定值相等
方法三:递归
递归到最后,回溯,每回溯一次,判断其值是否与给定值相等,相等则将当前节点后移一位,回溯到上一层连接递归的节点位置。
head头节点,用于递归
del保存每次递归位置的节点,便于删除
第三题
方法一:递归
递归到最后,回溯,从后向前统计个数,直到等于第n个,删除第n个即可
head头结点用于递归遍历
cur用于删除倒数第n个节点
方法二:两次遍历
先遍历第一遍,计算链表长度,然后倒数第n个,即为正数len-n+1个,定个虚拟头结点,方便操作
s_len第一次遍历统计链表长度
res用于返回地址
cur第二次遍历,到倒数第n个节点的上一个
del用于删除节点
方法三:一次遍历,双指针法
想象一下,两个人进行 100m 赛跑,假设他们的速度相同。开始的时候,第一个人就在第二个人前边 10m ,这样当第一个人跑到终点的时候,第二个人相距第一个人依旧是 10m ,也就是离终点 10m。
对比于链表,我们设定两个指针,先让第一个指针遍历 n 步,然后再让它俩同时开始遍历,这样的话,当第一个指针到头的时候,第二个指针就离第一个指针有 n 的距离,所以第二个指针的位置就刚好是倒数第 n 个结点。
head头结点
res返回的地址
slow开始指向头节点,用于找到删除节点的前一个
fast遍历到第n+1个节点,使其与slow相差n+1
del删除倒数第n个节点
完整代码
第一题
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
void deleteNode(struct ListNode* node) {
struct ListNode *next=node->next;
node->val=next->val;
node->next=next->next;
free(next);
}
第二题
方法一
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode *del,*pre;
while(head!=NULL&&head->val==val)
{
del=head;
head=head->next;
free(del);
}
if(head==NULL)return head;
pre=head;
while(pre->next!=NULL)
{
if(pre->next->val==val)
{
del=pre->next;
pre->next=pre->next->next;
free(del);
}
else
{
pre=pre->next;
}
}
return head;
}
方法二:
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode *res=(struct ListNode *)malloc(sizeof(struct ListNode)),*del,*pre=res;
res->next=head;
while(pre->next!=NULL)
{
if(pre->next->val==val)
{
del=pre->next;
pre->next=pre->next->next;
free(del);
}
else
{
pre=pre->next;
}
}
return res->next;
}
方法三:
struct ListNode* removeElements(struct ListNode* head, int val){
if(head==NULL)return head;
head->next=removeElements(head->next,val);
if(head->val==val)
{
struct ListNode *cur=head;
head=head->next;
free(cur);
}
return head;
}
第三题
方法一:递归
int m;
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
if(head==NULL){m=0;return head;}
head->next=removeNthFromEnd(head->next,n);
m++;
if(n==m)
{
head=head->next;
}
return head;
}
方法二:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
int len=0;
struct ListNode *s_len=head;
while(s_len!=NULL)
{
s_len=s_len->next;
len++;
}
struct ListNode *res=(struct ListNode*)malloc(sizeof(struct ListNode)),*cur=res;
res->next=head;
int k=0;
while(k<len-n)
{
k++;
cur=cur->next;
}
struct ListNode *del=cur->next;
cur->next=cur->next->next;
return res->next;
}
方法三:双指针
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode *res=(struct ListNode *)malloc(sizeof(struct ListNode)),*slow=res,*fast=res;
res->next=head;
for(int i=0;i<n+1;i++)
{
fast=fast->next;
}
while(fast!=NULL)
{
fast=fast->next;
slow=slow->next;
}
struct ListNode *del=slow->next;
slow->next=slow->next->next;
free(del);
return res->next;
}