题目
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:
输入:head = [1,2], n = 1
输出:[1]
提示:
链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
进阶: 你能尝试使用一趟扫描实现吗?
来源:力扣(LeetCode)
链接:leetcode 19. 删除链表的倒数第 N 个结点
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题
方法一:顺着题意理解,计算链表长度
先遍历一遍整个链表计算链表长度L,再遍历链表到需要删除的结点的前一个结点:删除的结点是第L-n+1个,遍历到L-n停下
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeNthFromEnd(struct ListNode* head, int n)
{
struct ListNode dummyHead;
dummyHead.next = head;
dummyHead.val = 0; //储存链表元素个数
struct ListNode* p;
for(p=head;p;p=p->next,dummyHead.val++);
int i = 0;
for(p=&dummyHead;i < dummyHead.val-n;p=p->next,i++);
struct ListNode* temp = p->next;
p->next = temp->next;
free(temp);
return dummyHead.next;
}
方法二:前后双指针(本题最优解)(只需一次遍历)
双指针p,q 初始化指向虚拟表头;前指针q先走,当p,q之间间隔n个结点时,p,q都同时往后走;直到q遍历完,此时p所指的即为需要删除结点的前一个结点;
struct ListNode* removeNthFromEnd(struct ListNode* head, int n)
{
struct ListNode dummyHead;
dummyHead.next = head;
struct ListNode *front,*behind;
front = behind = &dummyHead;
int TheIntervalBetweenTwoPointers = -1;
while(behind){
if(TheIntervalBetweenTwoPointers != n){
behind = behind->next;
TheIntervalBetweenTwoPointers++;
}else{
front = front->next;
behind = behind->next;
}
}
struct ListNode* temp = front->next;
front->next = temp->next;
free(temp);
return dummyHead.next;
}
方法三:堆栈
由于是要删除的按倒数来的,很容易联想到堆栈,后进先出,将整个链表一次入栈,再出栈 寻找需要删除的结点的前结点;
数组堆栈:
typedef struct _Stack{
struct ListNode* A[31];
int Top;
}Stack;
void Push( Stack* S,struct ListNode* p )
{
S->Top++;
S->A[S->Top] = p;
}
struct ListNode* Pop( Stack* S )
{
return S->A[S->Top--];
}
struct ListNode* removeNthFromEnd(struct ListNode* head, int n)
{
struct ListNode dummyHead;
dummyHead.next = head;
Stack* S = malloc(sizeof(Stack));
S->Top = -1;
struct ListNode* p = &dummyHead;
while(p){
Push( S,p );
p = p->next;
}
while(n--){
Pop( S );
}
p = Pop( S );
struct ListNode* temp = p->next;
p->next = temp->next;
free(temp);
free( S );
return dummyHead.next;
}
链式堆栈:
方法四:递归
另一个按倒数来的方法就是递归了,事实上链表非常适合递归,比如递归在二叉树中的应用
struct ListNode* removeNthFromEnd(struct ListNode* head, int n)
{
static int K = 0;
if(head->next){
head->next = removeNthFromEnd( head->next,n );
}
K++;
if(K == n){
struct ListNode* temp = head->next;
free(head);
return temp;
}else{
return head;
}
}
测试用例:[1] 1 单独测试时,没有问题;但是提交的时候就是通不过,奇怪
参考别人的java代码:
class Solution {
int i=0;
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head.next!=null)
head.next=removeNthFromEnd(head.next,n);
i++;
if(i==n)
return head.next;
else return head;
}
}