19. Remove Nth Node From End of List
方法一:双指针
算法思想:我们可以用两个指针,p , q,分别指向最后一个结点,和指向需要被删除结点的前驱结点。我们先让p指向第n个结点,之后p,q一起向后同步移动,间隔不变。直到p到达最后一个结点。这个时候q为我们需要删除结点的前驱结点。
// C语言版本
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *removeNthFromEnd(struct ListNode *head, int n)
{
struct ListNode *K = malloc(sizeof(struct ListNode));
struct ListNode *p, *q;
K->next = head;
K->val = 0;
p = K;
q = K; //q指向被删除结点的前驱结点
int i = 0;
while (i != n)
{
p = p->next;
i++;
}
while (p->next != NULL)
{
p = p->next;
q = q->next;
}
p = q->next;
q->next = p->next;
free(p);
struct ListNode *k = K->next;
return k;
}
## python 版本
#Definition for singly - linked list.
#class ListNode:
#def __init__(self, val = 0, next = None):
#self.val = val
#self.next = next
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int):
dummy = ListNode(0, head)
first = head
second = dummy
for i in range(n):
first = first.next
while first:
first = first.next
second = second.next
second.next = second.next.next
return dummy.next
遇到的问题:
- 我们这里所给的head,不是头结点,里面也存储了信息,那么当结点数目为1个的时候,我们必须给它创建一个头结点。
- 用不同语言来做,会有些困难。多去换换语言。
方法二:栈
算法思想:我们可以利用栈的先进后出的思想,来做这到题目。将每个结点进栈,之后出栈,当出栈到第n个结点的时候,则这个时候这个出栈结点为我们要删除的结点,而栈顶元素为该需要被删除结点的前驱结点。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
typedef struct stacknode
{
struct ListNode *node;
struct stacknode *next;
} stacknode, *LiStack;
struct ListNode *removeNthFromEnd(struct ListNode *head, int n)
{
struct ListNode *L = (struct ListNode *)malloc(sizeof(struct ListNode));
stacknode *st = (stacknode *)malloc(sizeof(stacknode));
L->val = 0, L->next = head;
st->next = NULL;
struct ListNode *p = L;
while (p != NULL) //当p不为空的时候就进栈
{
stacknode *s = (stacknode *)malloc(sizeof(stacknode));
s->node = p;
s->next = st->next;
st->next = s;
p = p->next;
}
for (int i = 0; i < n; i++) //找到要删除的第n个位置
{
stacknode *q = st->next;
st->next = q->next;
free(q);
}
//这个时候我们找到 st->next->node 为我们要删除结点的前驱结点
// pre->next 为我们要删除的结点
struct ListNode *pre = st->next->node;
struct ListNode *de = pre->next;
pre->next = de->next;
free(de);
struct ListNode *l = L->next;
return l;
}
遇到的问题:
- 为什么这里用链栈而不用顺序栈?个人见解,是这里并没有给出链表的长度,如果用顺序栈,不知道需要开多大的空间,容易造成浪费或者栈溢出。
- C语言用栈写,实属复杂,不同语言,解题效率也有很大差别,学会灵活运用。
- 链栈之前很少做过,不知道怎么进栈和出栈。这个很重要。
最后补充下链栈的相关代码:
#include <stdio.h>
#include <stdlib.h>
//栈的链式存储
typedef struct Linknode{
int data;
struct Linknode *next;
}Linknode,*LiStack;
//初始化栈
void InitStack(LiStack &L){
L =(Linknode*)malloc(sizeof(Linknode));//创建头节点
L->next=NULL;//初始化为空
}
//栈判空
bool StackEmpty(LiStack L){
if(L->next==NULL){
printf("栈为空\n");
return false;
}
else{
printf("栈不为空\n");
return true;
}
}
//入栈
bool Push(LiStack &L,int e){
Linknode *s=(Linknode *)malloc(sizeof(Linknode));
s->data=e;
s->next=L->next;
L->next=s;
return true;
}
//出栈
bool Pop(LiStack &L,int &e){
if(L->next==NULL){
printf("栈已空\n");
return false;
}
Linknode *p=L->next;
e=p->data;
L->next=p->next;//成链
printf("出栈元素值为%d\n",e);
free(p);
return true;
}
bool GetTop(LiStack L,int x){
if(L->next==NULL){
printf("栈已空\n");
return false;
}
Linknode *p=L->next;
x=p->data;
printf("栈顶元素值为%d\n",x);
return true;
}
void PrintStack(LiStack L){
Linknode *n=L->next;
while(n!=NULL){
printf("|___%d___|\n",n->data);
n=n->next;
}
}