#143 重排链表
题目:
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4]
输出:[1,4,2,3]
示例 2:
输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]
提示:
链表的长度范围为 [1, 5 * 104]
1 <= node.val <= 1000
思路1:
使用双链表法
代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
/**
思路:使用线性表解决
因为链表不支持下标访问,所以无法随机访问链表中任意位置的元素
因此可以利用线性表存储该链表,然后利用线性表可以下标访问的特点,直接按顺序访问指定元素,重建该链表即可
*/
class Solution {
public void reorderList(ListNode head) {
// 如果链表为空或只有一个节点,无需重排
if (head == null) {
return;
}
// 创建一个列表来存储所有节点
List<ListNode> list = new ArrayList<ListNode>();
ListNode node = head;
// 将链表中的所有节点添加到列表中
while (node != null) {
list.add(node);
node = node.next;
}
// 使用双指针技巧重新排序
int i = 0; // 前指针,从列表开头开始
int j = list.size() - 1; // 后指针,从列表末尾开始
while (i < j) {
// 将前指针指向的节点的 next 指向后指针指向的节点
list.get(i).next = list.get(j);
i++; // 前指针向后移动
// 如果 i 和 j 相遇,说明已经处理完所有节点
if (i == j) {
break;
}
// 将后指针指向的节点的 next 指向新的前指针指向的节点
list.get(j).next = list.get(i);
j--; // 后指针向前移动
}
// 将最后一个处理的节点的 next 置为 null,避免出现环
list.get(i).next = null;
}
}
复杂度:
时间复杂度:O(n)
空间复杂度:O(n)
思路2:
1.链表原地反转
2.寻找链表中点
3.链表合并