链表算法的技巧和方法
常用技巧:
1、画图
2、引入虚拟的头节点
3、不要害怕浪费空间,要勇于定义变量,eg:当链表的插入和删除的时候,为了便于结构体指针的连续性,就需要定义一个新的结构体指针,能更加方便;
4、使用快慢双指针(适用于,判环,找环的入口,找环中倒数第n个节点)。
常用操作:
1、创建一个新节点;
2、尾插;
3、头插。
第一题:
题解代码:
/**
* Definition for singly-linked list.
* 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) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
// 新建一个头节点
ListNode* newHead = new ListNode(0);
ListNode* rail = newHead; // 尾节点
// 建立两个工作节点
ListNode* cur1 = l1;
ListNode* cur2 = l2;
int res = 0;
while (cur1 || cur2 || res) {
if (cur1) {
res += cur1->val;
cur1 = cur1->next;
}
if (cur2) {
res += cur2->val;
cur2 = cur2->next;
}
ListNode* newNode = new ListNode(res % 10);
res = res / 10;
rail->next = newNode;
rail = rail->next;
}
ListNode* ret = newHead->next;
delete newHead;
return ret;
}
};
第二题:
题解代码:
循环➕迭代
/**
* Definition for singly-linked list.
* 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) {}
* };
*/
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(head == nullptr||head->next == nullptr) return head;
ListNode* newHead = new ListNode(0);
newHead->next = head;
ListNode* prev = newHead;
ListNode* cur = prev->next;
ListNode* next = cur->next;
ListNode* Nnext = next->next;
while (cur && next) {
//交换节点
prev->next = next;
next->next = cur;
cur->next = Nnext;
// 移动指针
prev = cur;
cur = Nnext;
if(cur)
next = cur->next;
if (next)
Nnext = next->next;
}
//注意这里不能返回head这个节点,因为head这个节点的在整个链表中的相对位置已经改变
//应该返回ewhead的->next节点
return newHead->next;
}
};
第三题:
题解代码:
/**
* Definition for singly-linked list.
* 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) {}
* };
*/
class Solution {
public:
void reorderList(ListNode* head) {
// 处理边界的情况(只有0,1,2,个时就应该返回)
if (head == nullptr || head->next == nullptr ||
head->next->next == nullptr)
return;
// 快慢双指针找中间节点
ListNode* fast = head;
ListNode* slow = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
// 将slow后面的分开并用头插法逆序
ListNode* head2 = new ListNode(0);
ListNode* cur = slow->next; // 工作指针
slow->next = nullptr;
while (cur) {
// 先将cur的下一个节点存起来
ListNode* tail = cur->next;
cur->next = head2->next;
head2->next = cur;
cur = tail;
}
// 链接两个链表;(双指针)
ListNode* cur1 = head;
ListNode* cur2 = head2->next;
// 定义最终的返回的节点
ListNode* ret = new ListNode(0);
ListNode* last = ret;
while (cur1) {
// 先放第一个链表的;
last->next = cur1;
cur1 = cur1->next;
last = last->next;
// 再放第二个链表的
if (cur2) {
last->next = cur2;
cur2 = cur2->next;
last = last->next;
}
}
delete head2;
delete ret;
}
};