重排链表
方法一:暴力连接
思路:
1.观察排序后的序列我们可以发现,第一个节点后接最后一个节点,第二个节点后接倒数第二个节点,以此类推。故我们可以每次都找到最后一个节点并把它接在当前节点的后面
2.我们用一个指针p指向头节点,每次找到链表的最后一个节点并将它接在p所指节点的后面,然后p再指向下一个节点,直到p后面的节点数小于两个时停止
代码:
import java.util.*;
/**
* 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) {
//设置一个指针p指向链表的头结点
ListNode p=head;
//只要p还没有指向空,即只要链表中还有节点就继续
while(p!=null){
//分两种情况进行分类讨论,如果p节点的后面还有两个节点,就需要去找链表 的最后
//一个节点,将该节点从链表的尾部断开,再将该节点查到对应的p节点的后面,再更新
//p的值,进行下一轮的查找
//第二种情况,如果发现p节点后面没有节点了,就直接跳出,表示重排结束
if(p.next!=null&&p.next.next!=null){
ListNode pre=p.next;
ListNode cur=p.next.next;
while(cur.next!=null){
pre=cur;
cur=cur.next;
}
cur.next=p.next;
pre.next=null;
p.next=cur;
p=p.next.next;
}else{
break;
}
}
}
}
方法二:线性表(对撞指针)
思路:
1.先将链表中的节点的地址存在vector中
2,再在vector的左右两边设置两个对撞指针
3.每次将两个节点进行连接
代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode *head) {
//将链表中的节点的地址存在vector中
//再设置两个对撞指针,分别指向vector的左右区间的端点
//将左端点的节点指向右端点,再将两个小区间进行连接,更新pre
vector<ListNode*> vec;
ListNode *cur=head;
while(cur!=NULL){
vec.push_back(cur);
cur=cur->next;
}
int left=0;
int right=vec.size()-1;
ListNode *pre=nullptr;
while(left<=right){
vec[left]->next=vec[right];
//注意当pre指向空的时候,就不需要进行指向下一个区间
if(pre){
pre->next=vec[left];
}
pre=vec[right];
left++;
right--;
}
//不要忘记当最后pre不为nullptr的时候需要将其指向nullptr,否则会首尾相连
if(pre){
pre->next=nullptr;
}
}
};
方法三:(快慢指针、链表反转、链表交错合并)
思路:
1.先找到链表的中点,将链表一分为2
2.将链表的后半部分进行反转
3.将第一部分链表与反转后的链表交错合并
代码:
import java.util.*;
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
//设置两个指针fast和slow都指向head
//只要fast下一次走到的点不是空节点,那么就让fast两个两个节点节点走,让slow以一个节点
//一个节点的速度走,这样由于是在同一起点出发,速度又是相差两倍,所以当fast无路可走的时候
//slow的路程就是fast走的路程的一半,刚好到达链表的中点
public ListNode GetMid(ListNode head){
ListNode fast=head;
ListNode slow=head;
while(fast.next!=null&&fast.next.next!=null){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
public ListNode ReverseList (ListNode head){
//如果发现链表是空的,就不需要进行反转
if(head==null){
return head;
}
//反转链表操作
ListNode pre=null;
ListNode cur=head;
ListNode cur_next;
while(cur!=null){
cur_next=cur.next;
cur.next=pre;
pre=cur;
//注意cur要更新成cur_next而不是cur.next!!!
cur=cur_next;
}
return pre;
}
public void Merge(ListNode head1,ListNode head2){
//设置四个指针,分别指向需要合并的两个链表的头结点和第二个节点
//只要链表的前面一对节点还没有到达链表的最后,就继续
//每次将head1指向head2,将head2指向l1
//再更新head1和head2为l1和l2
ListNode l1;ListNode l2;
while(head1!=null&&head2!=null){
l1=head1.next;
l2=head2.next;
head1.next=head2;
head2.next=l1;
head1=l1;
head2=l2;
}
}
public void reorderList(ListNode head) {
//当链表为空的时候就不需要进行重排,直接结束
if(head==null){
return;
}
//否则就获得链表的中间的节点
ListNode mid=GetMid(head);
ListNode p=mid.next;
//将中点指向null,将链表一分为二
mid.next=null;
ListNode t1;
//将后半部分进行反转
t1=ReverseList(p);
//将链表的前半部分与后半部分交错合并
Merge(head,t1);
}
}