力扣题号:19. 删除链表的倒数第 N 个结点
一、题目描述
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
二、示例
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5] 示例 2:
输入:head = [1], n = 1 输出:[] 示例 3:
输入:head = [1,2], n = 1 输出:[1]
三、求解思路
双指针的经典应用,如果要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点就可以了。
四、代码实现
#include <stdio.h>
#include <stdlib.h>
/*
题意:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
*/
typedef struct ListNode // 定义链表的节点
{
int data;
ListNode* next;
}Node;
// 定义一个链表
typedef struct List
{
Node* head;
}List;
// 尾插法——插入节点
List tailInsert(List& L, int x) {
// 找到最后节点的上一个节点
if (L.head == NULL) {
Node* newnode = (Node*)malloc(sizeof(Node));
newnode->next = NULL;
newnode->data = x;
L.head = newnode;
}
else { // 如果不是空链表
Node* per = NULL, * cur = NULL;
cur = L.head;
while (cur) // 找到最后一个节点
{
per = cur;
cur = cur->next;
}
Node* newnode = (Node*)malloc(sizeof(Node));
newnode->next = NULL;
newnode->data = x;
per->next = newnode;
}
return L;
}
// 使用虚拟头结点的双指针法
void removeElement(List& L, int n) {
// 设置虚拟头结点
Node* HeadNode = (Node*)malloc(sizeof(Node));
HeadNode->next = L.head;
L.head = HeadNode;
// 设置快慢指针
Node* fast = HeadNode, * slow = HeadNode;
// 找到倒数第n个节点前面的节点
n++;
while (fast != NULL && n--) {
fast = fast->next;
}
while (fast != NULL) {
slow = slow->next;
fast = fast->next;
}
// 删除节点
if (slow != HeadNode) {
Node* p = slow->next;
slow->next = slow->next->next;
free(p);
}
// 删除虚拟头结点。
Node* p = L.head;
L.head = L.head->next;
free(p);
}
// 打印链表
void Print(List& L) {
if (L.head == NULL) {
return;
}
else {
Node* cur = L.head;
while (cur) {
printf("%3d", cur->data);
cur = cur->next;
}
printf("\n");
}
}
int main() {
List L;
L.head = NULL;
tailInsert(L, 0);
tailInsert(L, 1);
tailInsert(L, 2);
tailInsert(L, 3);
tailInsert(L, 4);
tailInsert(L, 3);
tailInsert(L, 3);
tailInsert(L, 5);
Print(L);
int x = 6;
removeElement(L, x);
printf("删除倒数第%2d 个元素\n", x);
Print(L);
return 0;
}