赞
踩
给定一个单链表
L
L
L:L0→L1→…→Ln-1→Ln
,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…
你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
给定链表 1->2->3->4, 重新排列为 1->4->2->3.
示例 2:
给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.
(链表,模拟) O ( n ) O(n) O(n)
假设初始的链表是
L
1
→
L
2
→
L
3
→
…
→
L
n
L1→L2→L3→…→Ln
L1→L2→L3→…→Ln。
分两步处理:
找到链表的中点节点,将其后半段的指针都反向,变成:
L
1
→
L
2
→
L
3
→
…
→
L
⌈
n
/
2
⌉
←
L
⌈
n
/
2
⌉
+
1
←
…
←
L
n
L1→L2→L3→…→L⌈n/2⌉←L⌈n/2⌉+1←…←Ln
L1→L2→L3→…→L⌈n/2⌉←L⌈n/2⌉+1←…←Ln;
用两个指针分别从1
和n
开始往中间扫描,将后半段交替插入到前半段,变成:
L
1
→
L
n
→
L
2
→
L
n
−
1
→
L
3
→
L
n
−
2
…
L1→Ln→L2→Ln−1→L3→Ln-2…
L1→Ln→L2→Ln−1→L3→Ln−2…;
这里有几个需要注意的点:
如何将两个链表交错合并到一块?
进行完后半段链表的反向之后,a
指向后半段链表的首部。
a
指向head->next
,即a->next = head->next
;head
指向a
,即head->next = a
;head
在合并完的链表上后移两个位置,a
后移一个位置,重复上述过程。时间复杂度分析: 整个链表总共扫描三次,第一次求总长度,第二次将后半段反向,第三次将后半段交替插入前半段,所以总时间复杂度是 O ( n ) O(n) 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: void reorderList(ListNode* head) { int n = 0; //统计链表的节点个数 for(ListNode *p = head; p; p = p->next) n++; if(n <= 2) return ; //如果链表的节点个数小于等于2,就没有重新排列的必要了 ListNode *cur = head; //找到中点节点,由第一个节点跳(n+1)/2 -1步到达中点节点 for(int i = 0; i < (n+1)/2 -1; i++ ) cur = cur->next; ListNode *a = cur; //a指针指向链表中点 ListNode *b = cur->next; //b指针指向链表中点的下一个节点 while(b) //将链表的后半段反向 { ListNode *next = b->next; //保留b的next节点 b->next = a; a = b, b = next; } cur->next = 0; //给前半段链表添加一个结束标记 ListNode *tmp; while(head && head != a)//一个是遇到中点停止,一个是head, a左右两指针相遇停止 { tmp = a->next; a->next = head->next; head->next = a; head = head->next->next; a = tmp; } } };
原题链接: 143. 重排链表
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。