本周对链表操作进行了巩固
题目:
Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
You must do this in-place without altering the nodes' values.
For example,
Given {1,2,3,4}
, reorder it to {1,4,2,3}
.
题解:
这道题虽然看上去很复杂,但经过分析,可知实质上这道题就是将原链表对半分开,然后将后半部分逆置,合并插入到前半部分中。
对于链表的划分,是通过快慢指针来实现的:一开始将两个指针同时指向链表的头部,然后其中一个指针每次循环走1步,慢指针每次循环走2步,直到快指针触到了链表的末端。最终慢指针对应的就是链表的后半部分。在该题的情况下,只需要对满指针的下一个以及随后的节点进行逆置即可。
得到逆置后的后半部分以及前半部分之后,先将链表从快慢指针之间截断,然后进行循环遍历。在本题中,后半部分的节点个数,小于或等于前半部分,循环结束的标志也就是后半部分是否已经到达末尾。在插入的操作中,只需要注意变量值的交换(两个节点的next值)即可,代码如下:
1 /** 2 * Definition for singly-linked list. 3 * struct ListNode { 4 * int val; 5 * ListNode *next; 6 * ListNode(int x) : val(x), next(NULL) {} 7 * }; 8 */ 9 class Solution { 10 public: 11 ListNode* reverseList(ListNode* head) 12 { 13 //对链表进行逆置 14 if(head==NULL) return NULL; 15 ListNode* tail = head; 16 while(tail->next!=NULL) 17 tail = tail->next; 18 19 ListNode* curr = head; 20 while(curr!=tail) 21 { 22 ListNode* temp = curr->next; 23 curr->next = tail->next; 24 tail->next = curr; 25 curr = temp; 26 } 27 return tail; 28 } 29 30 void reorderList(ListNode* head) 31 { 32 if(head==NULL) return; 33 34 //通过快慢指针来找到链表的中点 35 ListNode *fast = head; 36 ListNode *slow = head; 37 while(fast->next!=NULL&&fast->next->next!=NULL) 38 { 39 fast = fast->next->next; 40 slow = slow->next; 41 } 42 //链表中如果只有一个或两个节点,无需进行下面的操作了,直接返回 43 if(fast==slow) return; 44 45 ListNode* slow_rev = reverseList(slow->next); 46 //将链表从中间断开 47 slow->next = NULL; 48 ListNode* curr = head; 49 //合并两个链表 50 while(slow_rev)//后半段的链表节点数比前半段的少 51 { 52 ListNode* temp1 = slow_rev->next; 53 ListNode* temp2 = curr->next; 54 curr->next = slow_rev; 55 slow_rev->next = temp2; 56 slow_rev = temp1; 57 curr = temp2; 58 } 59 60 } 61 };