题目
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reorder-list
思路
两种方法:1.数组表(把链表无法直接获取下标的缺点改善,根据下标直接重排节点)
2.快慢指针找中间节点+链表倒序+链表合并
注意点
- 变量的命名做好规范 方便编程,如prev,curr之类的链表排序常用命名。
- 循环结束的条件=》是否有等号很重要,可能会导致循环无终止。
- 代码的编写要简洁清晰。
/**
* 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;
}
ListNode mid=getMidNode(head);
ListNode head2=reverseList(mid);
mergeList(head,head2);
}
public ListNode getMidNode(ListNode head){
if(head==null){
return null;
}
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;
ListNode nextv;
while(curr!=null){
nextv=curr.next;
curr.next=prev;
prev=curr;
curr=nextv;
}
return prev;
}
public ListNode mergeList(ListNode h1,ListNode h2){
// 对两部分的链表进行重新排序
ListNode head=h1;
ListNode h1_temp;
ListNode h2_temp;
//这个重排这样子写相对简洁 清晰
while(h1!=null&& h2!=null){
h1_temp=h1.next;
h2_temp=h2.next;
h1.next=h2;
h1=h1_temp;
h2.next=h1;
h2=h2_temp;
}
return head;
}
}
数组法的解法:
class Solution {
public void reorderList(ListNode head) {
if(head==null){
return;
}
ArrayList<ListNode> arr=new ArrayList<>();
ListNode node=head;
while(node!=null){
arr.add(node);
node=node.next;
}
int i=0;
int j=arr.size()-1;
ListNode pre;
ListNode last;
// 循环结束的条件 不能用等号 不然会有同一个节点重复指向循环
while(i<j){
pre=arr.get(i);
last=arr.get(j);
pre.next=last;
i++;
// 为防止i++之后产生一个指针指向环,这里要break
if(i==j){
break;
}
last.next=arr.get(i);
j--;
}
arr.get(i).next=null;
}
}