题目的要求:要求使用原地算法,不能改变节点内部的值,需要对实际的节点进行交换。
这道题最后的结果将 l1—>l2—>l3---->ln变为
l1 ----> ln---->l2---->ln-1-------->
我们不难想到我们可以将序列分为两个部分:
第一步:
- 前半部分:l1-----> lp
- 后半部分:lp+1----->ln
第二步:
- 将后半部分的链表反转 成 ln----->lp+1
第三步:
- 将反转后的链表依次插入前半部分链表
解决思路:
第一步 | 利用快慢指针将链表分为两个部分 |
---|---|
第二步 | 将后半部分链表反转 |
第三步 | 将反转后的链表插入前半部分链表 |
第一步:当快指针走到最后的时候慢指针刚好走到链表中间的位置
public void reorderList(ListNode head) {
//快慢指针将列表分出一半;
if (head == null || head.next == null || head.next.next == null) {
return;
}
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode headList = head;
ListNode tailList = slow.next;
slow.next = null;
//此为反转链表和插入链表的操作
tailList = reverse(tailList);
insert(headList,tailList);
}
第二步:反转链表
没什么好解释的,利用迭代实现的;
public ListNode reverse(ListNode head){
//定义一个链表存储反转后的链表
ListNode dummy = new ListNode(0);
//保存当前head的值
ListNode node = head;
while (node != null){
//保存当前节点的下一个节点
ListNode nodeNext = node.next;
node.next = dummy.next;
dummy.next = node;
node = nodeNext;
}
return dummy.next;
}
第三步:具体细节可以看代码注释
public void insert(ListNode list1,ListNode list2){
ListNode node1 = list1;
ListNode node2 = list2;
while (node2 != null){
//保存当前节点de下一个节点
ListNode nodenext1 = node1.next;
ListNode nodenext2 = node2.next;
//让当前node1指向 node2
node1.next = node2;
//让node2指向保存的nodenext1
node2.next = nodenext1;
//让node1指向刚才的nodenext1
node1 = nodenext1;
//让node2指向刚才的nodenext2
node2 = nodenext2;
}
}
完整代码
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public void reorderList(ListNode head) {
//快慢指针将列表分出一半;
if (head == null || head.next == null || head.next.next == null) {
return;
}
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode headList = head;
ListNode tailList = slow.next;
slow.next = null;
//此为反转链表和插入链表的操作
tailList = reverse(tailList);
insert(headList,tailList);
}
public ListNode reverse(ListNode head){
//定义一个链表存储反转后的链表
ListNode dummy = new ListNode(0);
//保存当前head的值
ListNode node = head;
while (node != null){
//保存当前节点的下一个节点
ListNode nodeNext = node.next;
node.next = dummy.next;
dummy.next = node;
node = nodeNext;
}
return dummy.next;
}
public void insert(ListNode list1,ListNode list2){
ListNode node1 = list1;
ListNode node2 = list2;
while (node2 != null){
//保存当前节点de下一个节点
ListNode nodenext1 = node1.next;
ListNode nodenext2 = node2.next;
//让当前node1指向 node2
node1.next = node2;
//让node2指向保存的nodenext1
node2.next = nodenext1;
//让node1指向刚才的nodenext1
node1 = nodenext1;
//让node2指向刚才的nodenext2
node2 = nodenext2;
}
}
}