题目描述:
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
请将其重新排列后变为:
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例:
输入:head = [1, 2, 3, 4]
输出:[1, 4, 2, 3]
输入:head = [1, 2, 3, 4, 5]
输出:[1, 5, 2, 4, 3]
个人解法(双端队列):
首先进行遍历将链表节点依次入队,然后对该队列交替进行出队头元素,出队尾元素,直到队列为空,将每次取出的节点连接到结果链表上,最后将结果链表末尾节点的 next 置空,防止链表中出现环
public void reorderList(ListNode head) {
ListNode cur = head;
Deque<ListNode> nodeDeque = new LinkedList<>();
while (cur != null) {
nodeDeque.add(cur);
cur = cur.next;
}
ListNode temp;
cur = new ListNode(0, head);
int i = 0;
while (!nodeDeque.isEmpty()) {
if (i % 2 == 0) {
temp = nodeDeque.removeFirst();
} else {
temp = nodeDeque.removeLast();
}
cur.next = temp;
cur = cur.next;
i++;
}
cur.next = null;
}
官方解法1(线性表):
首先进行遍历将链表节点依次存入 ArrayList ,然后利用线性表可以随机访问的特性,用两个变量 i 、j 控制顺序访问即可
public void reorderList1(ListNode head) {
List<ListNode> list = new ArrayList<ListNode>();
ListNode node = head;
while (node != null) {
list.add(node);
node = node.next;
}
int i = 0, j = list.size() - 1;
while (i < j) {
list.get(i).next = list.get(j);
i++;
if (i == j) {
break;
}
list.get(j).next = list.get(i);
j--;
}
list.get(i).next = null;
}
官方解法2(寻找链表中点 + 链表逆序 + 合并链表):
目标链表为将原链表的左半端和反转后的右半端间隔合并后的结果
快慢指针法寻找中间节点,迭代法实现链表逆序,最后将两个链表间隔合并即可
public void reorderList2(ListNode head) {
if (head == null) {
return;
}
ListNode mid = middleNode(head);
ListNode l1 = head;
ListNode l2 = mid.next;
mid.next = null;
l2 = reverseList(l2);
mergeList(l1, l2);
}
public ListNode middleNode(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast.next != null && fast.next.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode nextTemp = curr.next;
curr.next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
public void mergeList(ListNode l1, ListNode l2) {
ListNode l1_tmp;
ListNode l2_tmp;
while (l1 != null && l2 != null) {
l1_tmp = l1.next;
l2_tmp = l2.next;
l1.next = l2;
l1 = l1_tmp;
l2.next = l1;
l2 = l2_tmp;
}
}