题目:重排链表
描述:将给定的单链表 L:L0→L1→…→Ln−1→Ln重新排序为:L0→Ln→L1→Ln−1→L2→Ln−2→…L_0→L_n要求使用原地算法,不能只改变节点内部的值,需要对实际的节点进行交换。
示例1:输入:{1,2,3,4},返回值:{1,4,2,3}
说明:给定head链表1->2->3->4,重新排列为1->4->2->3,会取head链表里面的值打印输出
解法一:
思路分析:我们可以使用快慢指针的方法来解决该问题,首先将链表一分为二,将第二部分反转,反转的这一步非常重要,最后将两个链表连接起来,在使用快慢指针将链表分成两段的情况下,采用这种方式会导致链表结点个数为奇数的情况下,后半段比前半段多一个,前半段一结束,后半段就开始,所以在第三部分将两个链表连接起来的时候,要注意后半段是否结束,如果没有,则连接上剩余部分即可。
实例分析:输入:{1,2,3,4}
首先将链表反转以后就是{4,3,2,1},将链表按照规律重新赋值一次,将链表反转后重新连接起来。
1—2—3—4
4—3—2—1
重新连接起来就是1—4—2—3—3—2—4—1
具体如下图所示:
若是,结点的值都不相同,则当遇到相同时,就断开,首先统计结点个数,然后判断终止条件,这样就需要重新建一个链表,将链表一分为二,反转后半段,重新连接。反转以后,要在新的链表结尾加上next=NULL。
其具体C++程序如下所示:
/** * 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) { if(head == NULL || head->next == NULL) return; //分成两段 ListNode *preSlow = NULL;//设置一个初始链表 ListNode *slow = head,*fast = head;//分别设置快慢指针 while(fast && fast->next)//循环停止条件 { preSlow = slow; slow = slow->next; fast = fast->next->next; } preSlow->next = NULL; //前半段 //反转后半段 ListNode *newBeg = slow; ListNode *last = newBeg->next; while(last) { ListNode *temp = last->next; last->next = newBeg; newBeg = last; last = temp; } slow->next = NULL; //合并 fast = head; preSlow = NULL; while(fast)//以前半段为条件 { ListNode *tem = newBeg->next; newBeg->next = fast->next; fast->next = newBeg; fast = newBeg->next; preSlow = newBeg; newBeg = tem; } if(newBeg != NULL) //因节点个数为奇数时,后段比前段多一个,所以最后要判断 preSlow->next = newBeg; } };
重排链表在该程序中要不断循环链表值来进行判断,在原链表的基础上进行排列,故时间复杂度为O(N),空间复杂度为O(N)。
解法二:
1、首先创建一个空的链表对象,将原链表内的所有元素都添加到新的链表当中:
链表对象 | 1 | 2 | 3 | 4 |
2、设置两个指针分别指向队首和队尾元素
链表对象 | 1 | 2 | 3 | 4 |
| i |
|
| j |
3、循环判断条件为i始终小于j,令i的下一个元素直接指向j,然后进行判断i与j是否相等,不相等的话,就令j继续指向i++所指的元素,第一轮判断结束。
链表对象 | 1 | 4 | 2 |
|
4、最后一轮循环,让元素2指向3,最后将结尾指向null即可。
链表对象 | 1 | 4 | 2 | 3 | null |
Java代码如下所示:
import java.util.*; import java.util.List; /** * 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) return ; Listlist = new ArrayList<>(); while(head != null){//将元素添加到链表当中 list.add(head); head = head.next; } //设置两个指针 int i = 0; int j = list.size() - 1; while(i < j){ //前面的结点指向最后的结点 list.get(i).next = list.get(j);//1-4 i++; if(i == j) break; list.get(j).next = list.get(i);//4-2 j--; } list.get(i).next = null;//最后一个节点的下一个节点为null } }
因为要将链表的所有值都访问一次,所以其时间复杂度为O(N),只有两个指针变量。其空间复杂度为O(1)。