leetcode19:删除链表的倒数第N个结点

题目链接

leetcode

题目描述

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

C++ 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <iostream>
#include <vector>
using namespace std;

// 链表结点的定义
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};

// 辅助函数:创建链表
ListNode* createList(const vector<int>& nums) {
ListNode* dummy = new ListNode(-1);
ListNode* cur = dummy;
for (int num : nums) {
cur->next = new ListNode(num);
cur = cur->next;
}
return dummy->next;
}

// 辅助函数:打印链表
void printList(ListNode* head) {
while (head != nullptr) {
cout << head->val;
if (head->next != nullptr) cout << " -> ";
head = head->next;
}
cout << endl;
}

// 辅助函数:释放链表内存
void deleteList(ListNode* head) {
while (head != nullptr) {
ListNode* temp = head;
head = head->next;
delete temp;
}
}

/*
第一次遍历:
求出链表长度 L
第二次遍历:
倒数第 N 个结点,就是正数第 L-N+1 个结点。
为了方便删除操作,添加虚拟头结点,从虚拟头结点开始遍历 L-N+1 个结点。
当遍历到第 L-N+1 个结点时,它下一个结点就是需要删除的结点。

时间复杂度:O(n)
其中 n 是链表的长度,对链表进行一次遍历。
空间复杂度:O(1)
只使用了固定的额外空间。
*/
class Solution_0 {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode();
dummy->next = head;

// 求链表长度
int length = 0;
ListNode* cur;
for (cur = head; cur != nullptr; cur = cur->next) {
length++;
}

// 倒数第N个节点,就是正数第L-N+1个节点
// 查找要删除节点的前一个位置
int pos = length-n;
cur = dummy;
for (int i = 0; i < pos; i++) {
cur = cur->next;
}

// 删除第N个节点
cur->next = cur->next->next;
return dummy->next;
}
};

/*
双指针,遍历一次

使用两个指针 fast 和 slow;
先让 fast 向前移动 n 步;
然后 fast 和 slow 一起移动,直到 fast 到达链表末尾;
此时 slow 指向要删除节点的前一个节点;

时间复杂度:O(n)
其中 n 是链表的长度,对链表进行一次遍历。
空间复杂度:O(1)
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummy = new ListNode();
dummy->next = head;

// 倒数第N个节点,就是正数第L-N+1个节点
// 查找要删除节点的前一个位置
ListNode *fast = dummy, *slow = dummy;
// 快指针先走 n 步
for (int i = 0; i < n; i++) {
if (fast->next != nullptr) {
fast = fast->next;
} else {
// 如果 n 超出链表长度,直接返回原链表
return head;
}
}
// 快慢指针一起前进,直到 fast 到达最后一个节点
while (fast->next != nullptr) {
fast = fast->next;
slow = slow->next;
}

// 删除第N个节点
slow->next = slow->next->next;
return dummy->next;
}
};

int main() {
Solution solution;
vector<vector<int>> head_cases = {
{1,2,3,4,5},
{1},
{1,2},
};
vector<int> n_cases = {2,1,1};

for (size_t i = 0; i < head_cases.size(); i++) {
// 创建链表
ListNode* head = createList(head_cases[i]);
int n = n_cases[i];
cout << "Input: ";
printList(head);

// 删除倒数第 n 个节点
head = solution.removeNthFromEnd(head, n);
cout << "Output: ";
printList(head);

// 释放内存
deleteList(head);
}

return 0;
}

leetcode19:删除链表的倒数第N个结点
https://lcf163.github.io/2023/09/23/leetcode19:删除链表的倒数第N个结点/
作者
乘风的小站
发布于
2023年9月23日
许可协议