链表题的解题技巧
- 额外数据结构记录,哈希表
- 快慢指针
快慢指针的技巧
- 【技巧】通过快慢指针得到链表的中间节点
快指针一次走两步,慢指针一次走一步;
a) 对于奇数个节点的链表,快慢指着从指着首节点的位置开始,快指针一次 走两步,慢指针一次走一步;当快指针走到最后一个节点的时候,满指针刚好指向正中间的一个节点
b) 对于奇数个节点的链表,慢指针和快指针分别从首节点位置和第二个节点的位置出发,快指针一次走两步,慢指针一次走一步;当快指针走到最后一个节点的时候,满指针刚好指向正中间位置的前一个节点
c) 注意当连链表的长度是1,2或者3的时候也要对;
快慢指针在链表中的经典例题
【例题1】反转链表1
【例题2】反转链表2
【例题3】回文链表
【例题4】
- 解法1
将链表里边的值放进数组,然后再数组里边快速排序;然后再遍历排序以后的数组,放进链表
再排序总结的文章里提到快速排序是没有稳定性的,然后再交换数字的时候,就导致数字的相对顺序已经变了;但是链表不会;再链表里边使用快速排序也可以保证稳定性
利用六个变量求解;分别记录小于区域大于区域和等于区域的头尾;相当于用三个辅助链表来完成任务;但是下边的代码只使用了六个变量,没有使用额外的空间,相比使用三个额外的
- code
#include<vector>
#include<iostream>
#include<math.h>
#include<climits>
#include<set>
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* get_res(ListNode* head,int piovt)
{
ListNode* sH = new ListNode(0);
ListNode* sT = new ListNode(0);
ListNode* eH = new ListNode(0);
ListNode* eT = new ListNode(0);
ListNode* mH = new ListNode(0);
ListNode* mT = new ListNode(0);
ListNode* cur = head;
while (cur)
{
if (cur->val < piovt)
{
if (sH == nullptr)
{
sH = cur;
sT = cur;
}
else
{
sT->next = cur;
sT = cur;
}
}
else if (cur->val == piovt)
{
if (eH == nullptr)
{
eH = cur;
eT = cur;
}
else
{
eT->next = cur;
eT = cur;
}
}
else
{
if (mH == nullptr)
{
mH = cur;
mT = cur;
}
else
{
mT->next = cur;
mT = cur;
}
}
}
if (sT) //如果有小于区域
{
sT->next = eH;
eT = eT == nullptr ? sT : eT;//下一步谁去连接大于去区域的头,谁就是eT
}
if (eT != nullptr)//如果小于区域和等于区域没有全军覆没
eT->next = mH;
return sH != nullptr ? sH : (eH != nullptr ? eH : mH);
}
【例题5】
- 解题思路1
构建map,原始链表节点作为key,对应的value就是自身节点的属性value构建的新的节点;
然后遍历原始节点,将原始节点的next和rand属性传递给自身的vlaue节点; - 解题思路1 code(使用哈希表)
#include<iostream>
#include<map>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode* rand;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode* next) : val(x), next(next) {}
};
ListNode* copy_list(ListNode* head)
{
map<ListNode*, ListNode*> hashmap;
ListNode* cur = head;
while (cur)
{
hashmap[cur] = new ListNode(cur->val);
cur = cur->next;
}
ListNode* cur = head;
while (cur)
{
hashmap[cur]->next = cur->next;
hashmap[cur]->rand = cur->rand;
}
return hashmap[head];
}
- 解题思路2
-解题思路2code(不使用哈希表)
#include<iostream>
#include<map>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode* rand;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode* next) : val(x), next(next) {}
};
ListNode* copy_list(ListNode* head)
{
ListNode* cur = head;
//将copy的结点插入原始结点的后边
// |-------
// | |
// 1->1'->2->2'->3->3'->null
// | |
// |--------------
while (cur)
{
ListNode* temp = cur->next;
cur->next = new ListNode(cur->val);
cur = cur->next;
cur->next = temp;
cur = cur->next;
}
//为copy的结点加上rand指针
cur = head;
while (cur)
{
cur->next->rand = cur->rand == nullptr ? nullptr : cur->rand->next;
/*if (cur->rand == nullptr)
{
cur->next->rand = nullptr;
}
else
cur->next->rand = cur->rand->next;*/
cur = cur->next->next;
}
//更正原始结点和copy结点的next结点,分离两个链表
ListNode* res = head->next;
cur = head;
while (cur)
{
ListNode* next = cur->next->next;
ListNode* copycur = cur->next;
cur->next = next;
copycur->next = next->next;
cur = next;
}
return res;
}