前言
有些同学也许会被链表指针给搞的昏头转向,在纸上画出很久都没搞清楚。下面将介绍一种较为通用的方法:“新建链表法”,可以解决指针乱指等晕头转向的操作。只要掌握 删除节点和尾插法建表 ,大部分链表题目都可以转换为重新建表问题
“新建链表法”:即使用尾插法构建“新链表”,此处不是从新malloc链表节点,而是改变原节点的指针指向。其步骤如下:
- 根据问题需求判断头节点是否会被改变,若有则在原链表上加上哨兵节点作为「虚拟头节点」。
- 遍历原链表节点,把符合题意的节点“拆下来”,然后追加到“新链表”上。
- “新链表”尾节点指针处理。(这很关键,因为保证“新链表”尾节点指针必须为NULL)
解题思路
下面以本题举例上述思想:本题意思是两个节点一组,后一个节点处理后要在前一个节点前面。
判断当前链表是否构成两个节点一组:
当前没有节点:遍历结束,所有节点已处理。
只有一个“拆下来”,追加到新链表后;
两个节点:先“拆”第二个节点并追加到新链表后;再“拆”第一个节点并追加到新链表后。
最后对“新建链表”尾节点的next指针进行置空操作。
没有让人昏头转向的指针转向操作,只涉及到如何「拆节点」和「往新链表后添加拆下的节点」。
作者:boille
链接:https://leetcode-cn.com/problems/swap-nodes-in-pairs/solution/tong-yong-lian-biao-si-lu-xin-jian-lian-p4nm8/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
/* 定义一个哑结点
定义 end 指针表示链表最后一个元素, p 为交换的第一个元素, q 为交换的第二个元素, tmp 指向 p 的 下一次调换结点
算法如下:
首先将q 插入到 链表尾
然后将p 加入到 链表尾
更新end
更新tmp, 根据tmp 更新 p, q (可能不足两组)*/
复杂度分析
空间复杂度 O(1)
时间复杂度 O(N)
代码
/**
* 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) {
/* 定义一个哑结点
定义 end 指针表示链表最后一个元素, p 为交换的第一个元素, q 为交换的第二个元素, tmp 指向 p 的 下一次调换结点
算法如下:
首先将q 插入到 链表尾
然后将p 加入到 链表尾
更新end
更新tmp, 根据tmp 更新 p, q (可能不足两组)*/
ListNode* dummy = new ListNode(0);
ListNode* end = dummy;
ListNode* tmp = head;
if (tmp == nullptr) {
return dummy->next;
} else if (tmp->next == nullptr) {
end->next = tmp;
tmp->next = nullptr;
return dummy->next;
}
ListNode* p = tmp;
ListNode* q = tmp->next;
while (1) {
// 把 q p 加入到队列尾
end->next = q;
tmp = q->next;
q->next = p;
p->next = nullptr;
//更新end
end= end->next->next;
end->next = nullptr;
//更新tmp
if (tmp == nullptr) {
break;
} else if (tmp->next == nullptr) {
end->next = tmp;
tmp->next = nullptr;
break;
}
p = tmp;
q = tmp->next;
}
return dummy->next;
}
};
心得
- 新建链表法可以学习掌握一下
- 可以多找几个题目操作一下
来源:oschina
链接:https://my.oschina.net/u/4256940/blog/4917092