题目表述:给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
算法分析:
算法一:两次遍历算法,因为题目中给定链表的内容,并且告知删除倒数第n个结点。
所以基本思路是,第一次遍历得到结点的个数L,然后就是删除第L-n+1个结点的任务。所以任务就是找到L的值。
函数形参中给出的head指针指向的就是第一个结点,所有我们要添加一个哑巴结点辅助,位于列表的头部,哑巴结点用于简化某些极端情况,比如列表中只有一个结点或者删除列表的第一个结点,在第一遍历中,找出列表的L,然后设置一个哑巴结点的指针,移动遍历列表,直到它达到(L-n)个结点那里,我们把第 (L−n)个结点的 next 指针重新链接至第 (L−n+2)个结点,完成这个算法。
public ListNode removeNthFromEnd(ListNode head,int n)
{
ListNode dumm=new ListNode(0);
//ListNode list=new ListNode(0) 初始化一个节点值为0的空节点,最常用最正规写法
dumm.next=head;
int length=0;
ListNode first=head;
while(first!=null)
{
length++;
first=first.next;
}
length-=n;
first=dumm;
while(length>0)
{
length--;
first=first.next;
}
first.next=first.next.next;
return dumm.next;
}
假设不设置一个哑巴节点又该怎么做呢?
java语言实现
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
int length = 0;
ListNode first = head;
while (first != null) {
length++;
first = first.next;
}
length -= n;
first=head;
if(length==0)
return first.next;
else
{
while (length>1) {
length--;
first = first.next;
}
first.next = first.next.next;
first=head;
return first;
}
}
}
算法二进阶:
一次遍历算法
java语言实现
class Solution{
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode first = dummy;
ListNode second = dummy;
// Advances first pointer so that the gap between first and second is n nodes apart
for (int i = 1; i <= n + 1; i++) {
first = first.next;
}
// Move first to the end, maintaining the gap
while (first != null) {
first = first.next;
second = second.next;
}
second.next = second.next.next;
return dummy.next;
}
}
c语言实现
这里有几点需要注意
1.c语言中符号和java中的区别, - > 和.(点)的区别,java主要是以对象为主,所以(点).呢,代表的是访问对象的成员符号,而c语言呢?一般情况下
- 用“.”,只需要声明一个结构体。格式是,结构体类型名+结构体名。然后用结构体名加“.”加域名就可以引用域 了。因为自动分配了结构体的内存。
- 用“->”,则要声明一个结构体的指针,还要手动开辟一个该结构体的内存,然后把返回的指针给声明的结构体指针,才能用“->”正确引用。否则内存中只分配了指针的内存,没有分配结构体的内存,导致想要的结构体实际上是不存在。这时候用“->”引用自然出错了,因为没有结构体,自然没有结构体的域了。
此外,(*a).b 等价于 a->b。
".“一般情况下读作"的”。
“->”一般读作"指向的结构体的”。
同时还有我在编写c语言时遇到的error以及搜索到的博客解释
- . struct ListNode* dummy,最开始只定义了一个指向结构的指针,内存中只是分配了指针的内存,没有分配结构体的内存。所以会报错member access within null pointer of type ‘struct ListNode’。
错误出现原因: 因为试图使用空指针。
解决办法:使用c语言函数为结构体成员开辟空间,
dummy=(struct ListNode*)malloc(sizeof(struct ListNode));
- .问题场景描述:leetcode刷题时遇到报错(error:control reaches end of non-void function[-Werror=return-type]),代码没问题,可就是编译不通过。
问题解决:在函数的最后添加一条return语句,只要返回的数据类型对即可!记住,一定要返回,虽然永远也用不上。
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode* dummy;
dummy=(struct ListNode*)malloc(sizeof(struct ListNode));
dummy->val=0;
dummy->next=head;
struct ListNode* first=dummy;
struct ListNode* second=dummy;
for(int i=1;i<=n+1;i++){
first=first->next;
}
while(first!=NULL)
{
first=first->next;
second=second->next;
}
second->next=second->next->next;
return dummy->next;
}