重排链表小结
又发现一道好玩的题目,顺带来复习一下之前学过的知识吧!
Leetcode题目:
143. 重排链表
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln 请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → … 不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
这道题当然可以直接遍历链表,然后将每一个节点都放在vector里面,然后再进行后续操作:
额外空间做法(线性表存储)
/**
* 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) {
if(!head||!head->next)return; // 当head头节点为空或者只有一个节点时,直接返回
vector<ListNode*> Ans; // 建立vector容器进行存储节点
ListNode* newHead = head; // 直接遍历head节点也可以的,这里我习惯不直接操作head节点
while(newHead){ // 当head没有遍历完就一直遍历下去
Ans.emplace_back(newHead); // 节点存在vector里头
newHead=newHead->next; // 下一个节点
}
int i=0,j=Ans.size()-1; // 来个双指针
while(i<j){
Ans[i++]->next=Ans[j]; // 根据题目意思 L0 -> Ln -> L1 -> Ln-1 -> L2 -> Ln-2
if(i==j)break; // 当i++之后,i=j时就退出循环,直接让最后一个节点指向nullptr
Ans[j--]->next=Ans[i];
}
Ans[i]->next=nullptr;
}
};
上面并不是一个能很好考察我们所学知识的做法:
简单思考一下,能不能不用额外空间来处理这个问题呢?
我们之前学过链表寻找中间节点、翻转链表、两链表合并等基础知识,能不能将这些运用起来?
上述提到的题目链接如下:
876. 链表的中间结点
206. 翻转链表
21. 合并两个有序链表
上面三道题都挺简单,这里记录一下。
然后对于这道题,我们可以先找到中间节点,切断翻转后半链表,最后两个链表一个接着一个进行合并即可。
常数空间做法(寻找中间节点&&翻转链表)
/**
* 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) {
// 找中间节点,然后分隔,然后后半段逆序输出,然后两链表合并
if(!head)return;
ListNode* mid = middleNode(head);
ListNode* l1 = head;
ListNode* l2 = mid->next;
mid->next=nullptr;
l2 = reverseList(l2);
mergeList(l1,l2);
}
// 寻找链表中点
ListNode* middleNode(ListNode* head){
ListNode* slow = head;
ListNode* fast = head;
while(fast&&fast->next){
slow=slow->next;
fast=fast->next->next;
}
return slow;
}
// 翻转链表
ListNode* reverseList(ListNode* head){
ListNode* pre = nullptr;
ListNode* cur = head;
while(cur){
ListNode* next = cur->next;
cur->next = pre;
pre = cur;
cur = next;
}
return pre;
}
// 两链表合并
void mergeList(ListNode* list1,ListNode* list2){
ListNode* l1_temp;
ListNode* l2_temp;
while(list1&&list2){
l1_temp=list1->next;
l2_temp=list2->next;
list1->next=list2;
list1=l1_temp;
list2->next=list1;
list2=l2_temp;
}
}
};