剑指leetcode—删除链表的倒数第N个结点

题目表述:给定一个链表,删除链表的倒数第 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)个结点,完成这个算法。
剑指leetcode—删除链表的倒数第N个结点_第1张图片

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;
}
}   
}

算法二进阶:
一次遍历算法

剑指leetcode—删除链表的倒数第N个结点_第2张图片

剑指leetcode—删除链表的倒数第N个结点_第3张图片
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语言呢?一般情况下

  1. 用“.”,只需要声明一个结构体。格式是,结构体类型名+结构体名。然后用结构体名加“.”加域名就可以引用域 了。因为自动分配了结构体的内存。
  2. 用“->”,则要声明一个结构体的指针,还要手动开辟一个该结构体的内存,然后把返回的指针给声明的结构体指针,才能用“->”正确引用。否则内存中只分配了指针的内存,没有分配结构体的内存,导致想要的结构体实际上是不存在。这时候用“->”引用自然出错了,因为没有结构体,自然没有结构体的域了。
    此外,(*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;
}

你可能感兴趣的:(leetcode刷题之路)