链表常用技巧
1.画图,直观形象,便于我们理解
2.引入虚拟“头”节点
便于处理边界情况
方便我们对链表操作
3.不要吝啬空间,大胆定义变量
比如prev cur next,定义好之后把相应节点的指针存进去,然后就可以不用考虑前后顺序,不用担心找不到节点了
4.快慢双指针
判环,找链表中环的入口,找链表中倒数第n个节点
链表中常用操作
1.创建一个新节点 new
2.尾插
3.头插(链表逆序)
1.两数相加
/**
* 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* list1, ListNode* list2) {
ListNode* l1 = list1;
ListNode* l2 = list2;
ListNode* l3 = new ListNode;;
ListNode* ret = l3;
int up = 0;
while(l1 || l2 || up)
{
int num1 = 0;
int num2 = 0;
if(l1)
{
num1 = l1->val;
l1 = l1->next;
}
if(l2)
{
num2 = l2->val;
l2 = l2->next;
}
int Add = (num1 + num2 +up)%10;
up = (num1 + num2 + up)/10;
l3->val = Add;
if(l1 || l2 || up)
{
l3->next = new ListNode;
l3 = l3->next;
}
}
return ret;
}
};
总体就是一个简易版的高精度加法
(我们可以把进位一并放入循环中考虑)
2.两两交换链表中的节点
/**
* 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)
{
ListNode* headnode = new ListNode(0,head);
ListNode* prev = headnode;
ListNode* cur = head;
ListNode* next = nullptr;
ListNode* nnext = nullptr;
if(head)
{
next = head->next;
if(next)
{
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;
}
}
cur = headnode->next;
delete headnode;
return cur;
}
};
首先我们定义四个指针,但是在赋值的时候要判断是否有这个节点,从head开始判断,也可以特判然后返回。为了整体逻辑的统一,我们选择加上一个头节点。
有两种情况,一种是偶数个节点,一种是奇数个节点,结束条件分别对应cur为空和next
为空。
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:
void reorderList(ListNode* head) {
ListNode *slow = head;
ListNode *fast = head;
while(fast)//寻找中间节点
{
fast = fast->next;
if(fast)
{
fast = fast->next;
}
else break;
slow = slow->next;
}
ListNode *begin = slow->next;
slow->next = nullptr;
ListNode *relist = new ListNode ;
while(begin)//头插法使后一个链表逆序
{
ListNode* next = relist->next;
ListNode* tmp = begin->next;
relist->next = begin;
begin->next = next;
begin = tmp;
}
ListNode *ret = head;//不断插入
ListNode*prev = head;
ListNode*next = head->next;
ListNode*cur = relist->next;
while(cur)
{
prev->next = cur;
ListNode* tmp = cur->next;
cur->next = next;
cur = tmp;
prev = next;
if(prev)next = prev->next;
}
}
};
题目主要分为三个步骤。
因为链表的题目主要是模拟,所以我们只需要按部就班
第一个步骤是先找到链表中间节点,把链表一分为二
第二个步骤是把第二个链表逆序,方便后续插入
第三个步骤是把第二个链表插入到第一个链表中
4.k个一组翻转链表
/**
* 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* reverseKGroup(ListNode* head, int k) {
int n = 1;
ListNode* count = head;
while(count->next)
{
n++;
count = count->next;
}
n = n / k;
ListNode* newhead = new ListNode;
//ListNode* ret = newhead;
ListNode* prev = newhead;
ListNode* cur = head;
for(int i = 1; i <= n; i++)
{
ListNode* nexthead = cur;
for(int j = 1; j <= k; j++)
{
ListNode* next = cur->next;
cur->next = prev->next;
prev->next = cur;
cur = next;
}
prev = nexthead;
}
prev->next = cur;
cur = newhead->next;
delete newhead;
return cur;
}
};
这里我们先遍历一次链表,就可以得到翻转的次数,就不需要担心空指针问题了。
链表逆序的节点数是确定的,放在循环里即可。
然后后面只需要按部就班逆序链表即可
1898

被折叠的 条评论
为什么被折叠?



