24. 两两交换链表中的节点
文档讲解 : 代码随想录 - 24. 两两交换链表中的节点
状态:再次回顾。
虚拟头结点 + 双指针 (接下来的题目都可以用到双指针,双指针是链表题目中的常客,一般用于辅助判断索引位置)。
此题一定要画图,不然容易乱。
初始时,cur指向虚拟头结点,然后进行如下三步:
操作之后,链表如下:
本题代码(ACM):
#include <iostream>
#include <vector>;
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int val): val(val), next(NULL) {}
};
ListNode* swapPairs(ListNode* head) {
ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
ListNode* cur = dummyHead;
while (cur->next != nullptr && cur->next->next != nullptr) {
ListNode* tmp = cur->next; // 记录临时节点
ListNode* tmp1 = cur->next->next->next; // 记录临时节点
cur->next = cur->next->next; // 步骤一
cur->next->next = tmp; // 步骤二
cur->next->next->next = tmp1; // 步骤三
cur = cur->next->next; // cur移动两位,准备下一轮交换
}
return dummyHead->next;
}
int main() {
/*
输入描述:
第一行一个整数,表示链表长度。如果n <= 0, 链表为空链表;
第二行n个整数,表示链表内元素;
*/
int n;
cin >> n;
ListNode* head = NULL;
if (n > 0) {
vector<int> listNode(n);
for (int i = 0; i < n; i++) cin >> listNode[i];
head = new ListNode(listNode[0]);
ListNode* cur = head;
for (int i = 1; i < n; i++) {
ListNode* node = new ListNode(listNode[i]);
cur->next = node;
cur = cur->next;
}
cur->next = NULL;
}
head = swapPairs(head);
ListNode* newCur = head;
while (newCur != NULL) {
cout << newCur->val << " ";
newCur = newCur->next;
}
cout << endl;
return 0;
}
- 时间复杂度:O(n)
- 空间复杂度:O(1)
19.删除链表的倒数第N个节点
文档讲解 : 代码随想录 - 19.删除链表的倒数第N个节点
状态:再次回顾。注意快指针得再前进一步,才能使慢指针指向倒数第N个节点前节点。
掌握双指针法后,没啥难度
本题代码(ACM)
#include <iostream>
#include <vector>;
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int val) : val(val), next(NULL) {}
};
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* fast = dummyHead->next; // 快指针得前进一步才能让慢指针指向第n个结点前结点
ListNode* slow = dummyHead;
while (n-- && fast) {
fast = fast->next;
}
while (fast) {
slow = slow->next;
fast = fast->next;
}
ListNode* node = slow->next;
slow->next = node->next;
delete node;
head = dummyHead->next;
delete dummyHead;
return head;
}
int main() {
/*
输入描述:
第一行一个整数,表示链表长度。如果num <= 0, 链表为空链表;
第二行num个整数,表示链表内元素;
第三行一个整数,表示倒数第n个节点。
*/
int num;
cin >> num;
ListNode* head = NULL;
if (num > 0) {
vector<int> listNode(num);
for (int i = 0; i < num; i++) cin >> listNode[i];
head = new ListNode(listNode[0]);
ListNode* cur = head;
for (int i = 1; i < num; i++) {
ListNode* node = new ListNode(listNode[i]);
cur->next = node;
cur = cur->next;
}
cur->next = NULL;
}
int n;
cin >> n;
head = removeNthFromEnd(head, n);
ListNode* newCur = head;
while (newCur != NULL) {
cout << newCur->val << " ";
newCur = newCur->next;
}
cout << endl;
return 0;
}
面试题 02.07. 链表相交
文档讲解 : 代码随想录 - 面试题 02.07. 链表相交
状态:再次回顾。
非常经典的双指针题目,得想到链表相连
思路和算法(参考力扣官方题解)
本题代码
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if (headA == NULL || headB == NULL) return NULL;
ListNode* pA = headA;
ListNode* pB = headB;
while (pA != pB) {
pA = pA == NULL ? headB : pA->next;
pB = pB == NULL ? headA : pB->next;
}
return pA;
}
};
142.环形链表II
文档讲解 : 代码随想录 - 142.环形链表II
状态:再次回顾。
还是双指针法,链表题目基本离不开双指针法,双指针法起到定位索引作用。
具体解题思路看 代码随想录 - 142.环形链表II
本题代码
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
// 快慢指针相遇,此时从head 和 相遇点,同时查找直至相遇
if (slow == fast) {
ListNode* index1 = fast;
ListNode* index2 = head;
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index2; // 返回环的入口
}
}
return NULL;
}
};