题目
题目来源:https://leetcode-cn.com/problems/reorder-list/
思路
自己的思路
首先我们需要解读一下题目:先看题目限定条件:不能单纯的改变节点内部的值,而是需要实际进行节点交换,所以需要对原链表进行节点交换操作
- 起初自己分析了很多,一开始是想着快捷路径,先从第二个节点开始,没增加一个节点,那么就把它放到头节点的后面,然后再尝试看看能否通过进行依次的交换得到结果,后来发现这种思路对于节点少的链表可以,但是当链表数量多时,却行不通。
- 第二个思路还是盯着最后一个节点永远在头节点之后这个条件,也是尝试着通过一次遍历就能得到正确结果,结果发现这样子也行不通
- 第三个思路就比较接近正确的思路的,通过对链表进行分割,将链表分割为两份,然后将后面的链表一次插入到前面的链表中间去,但是到后面的思路也出现了偏差:一方面我始终只盯着头尾,想着不用对后面的链表进行反转(好像这样子也行,但是存在一个问题就是:如果你从后面开始插入,那么就需要一个判断:比如第一个例子,链表分为两份,一份是1 2 3,后面的链表就为4,如果从后面开始插入的话,那么结果就不正确),而且寻找链表中点我采用的是一种比较笨的方法:遍历整个链表,求出链表的节点个数,然后再通过除2的方法得到中点
参考思路
首先,我们需要解决三个问题:
- 问题一:如何寻找到链表的中点,我采用的就是笨方法,那么还有一种巧妙的方法就是利用快慢指针进行,因为快指针所走的路程永远是慢指针的两倍,那么等到快指针走完的时候,那么慢指针所在的节点就是链表中点,代码如下:
ListNode* fast = head, * slow = head;
while (fast && fast->next) { //利用快慢指针寻找中点
slow = slow->next;
fast = fast->next->next;
}
- 问题二:如何进行链表的反转。这个问题我们就得复习一下关于链表反转的相关知识了:链表的反转有常用的两种方法,第一种就是依次将每个节点放到新的头节点的头部;第二种方法就是保存第一个节点,然后再每次的交换中,都是将第一个节点后面的节点放到新的头节点的后面。相关知识在https://blog.csdn.net/clearLB/article/details/104035215,代码如下,这里采用的是第一种方法:将每个节点放在新链表的头部
ListNode* res = slow->next;
slow->next = NULL;
//对后边的链表进行反转
ListNode* start = NULL;
ListNode* temp;
while (res != NULL) {
temp = res->next;
res->next = start;
start = res;
res = temp;
}
- 问题三:如何插入。我们现在已经得到了分离的两个链表,最后一个步骤就是将后边反转的链表插入到前面的链表中,先直接上代码吧:
ListNode* H = head;
ListNode* ch;
while (start != NULL) {
temp = H->next;
ch = start->next;//保存下一个要插入的点
H->next = start;//将点插入
start->next = temp;
H = temp;
start = ch;
}
这里我们将后面的链表是否为空作为循环条件(因为后面链表肯定都要插入到前面的链表当中,所以我们只需要判断后面的链表是否为空即可)
完整代码如下:
class Solution {
public:
void reorderList(ListNode* head) {
if(head==NULL)
return;
ListNode* fast = head, * slow = head;
while (fast && fast->next) { //利用快慢指针寻找中点
slow = slow->next;
fast = fast->next->next;
}
ListNode* res = slow->next;
slow->next = NULL;
//对后边的链表进行反转
ListNode* start = NULL;
ListNode* temp;
while (res != NULL) {
temp = res->next;
res->next = start;
start = res;
res = temp;
}
//进行插入
ListNode* H = head;
ListNode* ch;
while (start != NULL) {
temp = H->next;
ch = start->next;//保存下一个要插入的点
H->next = start;//将点插入
start->next = temp;
H = temp;
start = ch;
}
}
};
总结
这道题其实就是几个之前的知识点的组合,如快慢指针的灵活运用,链表的反转,和链表的插入,关键在于是否懂得灵活运用组合来解题。