文章目录
链表需要我们掌握的题目不是很多,只要掌握这20几道最最经典的题目,应对面试绝对绰绰有余。
题目链接
1.两数相加:完成题解
2.合并两个有序链表:完成题解
3.排序链表:完成题解(需要再做)
4.反转链表:完成题解
5.两两交换链表中的节点:完成题解
6.相交链表:完成题解(需要再做)
7.K 个一组翻转链表
8.反转链表 II回顾的时候再做,不太会啊。
9.删除排序链表中的重复元素:完成题解
10.删除链表的倒数第N个节点:完成题解
11.回文链表:完成题解(需要再做)
12.分隔链表
13.奇偶链表:完成题解(需要再做)
14.合并K个排序链表:完成题解(分治算法需要再做)
15.重排链表:完成题解。
16.有序链表转换二叉搜索树
17.环形链表 II
18.对链表进行插入排序:完成题解(需要再做)
题目分类
链表基础
1.两数相加
思路
非常简单的一道链表题,我们需要考虑的就是当前链表的值相加后是否会大于等于10,我们设置一个boolean变量addone,如果大于10就赋值为true。
整体思路先是
1.两个链表同时判断,每次都将链表向后移,直到一个链表为空
2.分别判断两个链表是否还不为空,不为空就逐个后移(注意这里不能直接让我们的result.next=不空的链表,因为可能我们的addone为true,所以要加上1)
3.最后还要继续判断addone是否为true,为true,继续向result添加一个为1的ListNode。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode result =new ListNode(-1);
ListNode res = result;
//设置一个进位变量
boolean addone = false;
while(l1!=null&&l2!=null){
int l1num = l1.val;
int l2num = l2.val;
int now = l1num+l2num;
if(addone)
now+=1;
if(now>=10){
result.next = new ListNode(now-10);
addone = true;
}else{
result.next = new ListNode(now);
addone = false;
}
result = result.next;
l1 = l1.next;
l2 = l2.next;
}
//l1还有剩余(不能直接result.next=l1,要一个一个往后去判断,因为addone可能为true)
while(l1!=null){
int l1num = l1.val;
int now = l1num;
if(addone)
{
now+=1;
}
if(now>=10){
result.next = new ListNode(now-10);
addone = true;
}else{
result.next = new ListNode(now);
addone = false;
}
l1 = l1.next;
result = result.next;
}
//l2还有剩余
while(l2!=null){
int l2num = l2.val;
int now = l2num;
if(addone)
{
now+=1;
}
if(now>=10){
result.next = new ListNode(now-10);
addone = true;
}else{
result.next = new ListNode(now);
addone = false;
}
l2 = l2.next;
result = result.next;
}
//防止addone还存在,还需要继续进位
if(addone)
{
result.next = new ListNode(1);
}
return res.next;
}
}
2.反转链表
思路
这个问题比较简单,只要指定一个pre指针就好,每次首先提取出head的下一个指针并付给next,让head的next指向pre,然后pre移动到当前的head,最后head赋值next即可,持续循环。直到找到我们head的next为null时,就不将head赋值为next,直接返回。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
while(head!=null){
ListNode next = head.next;
head.next = pre;
pre = head;
if(next==null)
break;
head = next;
}
return head;
}
}
3.相交链表
思路
这道题有很多思路,比如HashMap之类的思路,我们这里只考虑最优解。
考虑最优解:让a节点走到a链表尾部的时候,去指向b链表的头部
当b节点指向b链表的尾部时,去指向a链表的头部,这样最终会在相交点相遇。
虽然起点不同,但路程是相同的,最终会相遇。
A在前面比B少走1个格,所以会先到终点,然后再走B的路,
B虽然在前面比A多走一个格,但再走A的路时,会比A少走一格,因此最终会在c1相遇。
再来一个图就更加清晰,假如两个链表相交,我们可以设第一个链表不相交的部分为a1长度,第二个链表不相交的部分为b1长度,设相交长度为c。那么可以看出a走的是a1+c+b1,而b走的是b1+c+a1,因此是相同的路径。
代码
这里要注意一下,
1.有可能有不相交的链表,相交的话,就是a,b节点在第二次走的过程肯定会相遇,那么只要有一个节点第二次走到终点,那么就说明他们肯定是不想交的。
2.如果两个链表有一个为空就不可以相交。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
//一个为空就不可能相交
if(headA==null||headB==null)
return null;
ListNode a = headA;
ListNode b = headB;
//这里要注意,有可能是没有交点的,那么当一个节点第二次到达终点就说明没有交点
int atime = 0;
int btime = 0;
while(a!=b&&atime<2&&btime<2)
{
a = a.next;
b = b.next;
if(a==null){
a = headB;
atime++;
}
if(b==null){
b = headA;
btime++;
}
}
if(atime==2||btime==2)
return null;
return a;
}
}
4.回文链表
思路
需要首先找到链表的中点,并将链表中点之后的部分链表全部翻转,之后再比较两个链表是否完全相等。值得一提的是,如果链表长度为奇数,slow会指向中间元素,如果长度为偶数,则会指向中间两个值中的左边值,因此我们第二段链表的头都是slow.next。还需要注意要将两部分断开。
代码
注意边界条件,为空的情况。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
/*
分成两段即可,然后翻转后面那部分
使用快慢指针找到中点
*/
if(head==null)
return true;
ListNode fast = head;
ListNode slow = head;
while(fast.next!=null&&fast.next.next!=null){
fast = fast.next.next;
slow = slow.next;
}
//分开slow之后的
ListNode pre = null;
ListNode now = slow.next;
//System.out.println(now.val);
slow.next = null;
//翻转完成,以now为头部
while(now!=null)
{
ListNode next = now.next;
now.next = pre;
pre = now;
if(next==null)
break;
now = next;
}
//System.out.println(now.val);
//当奇数长度时,head链表的长度就多包含个最中间的节点,因此要判断当两个都不为空,而不是head不为空
while(head!=null&&now!=null)
{
if(head.val!=now.val){
System.out.println("now:"+now.val+"head:"+head.val);
return false;
}
head = head.next;
now = now.next;
}
return true;
}
}
5.删除排序链表中的重复元素
思路
可以判断当前head与head.next是否相等,如果相等的话就让head.next指向head.next.next,不断的更改head.next的值,直到head.next与head不同,再把head赋值给head.next。
代码
/**
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head==null)
return null;
ListNode res = head;
while(head!=null)
{
//一直往后走直到head.next与head不同,再把head赋给head.next
while(head.next!=null&&head.next.val==head.val)
{
head.next = head.next.next;
}
head = head.next;
}
return res;
}
}
6.删除链表的倒数第N个节点
思路一:两次遍历
首先遍历链表,得到链表的长度,就可以知道我们要往后走几步以找到我们要删除的节点。
代码一
这里要注意pre不是指向head,而是要指向一个新的节点,让这个节点的下一个指向head,防止要删除的是第一个节点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(n==0||head==null)
return head;
int deepth = finddeepth(head);
int times = deepth-n;
//这里用这个pre,省的要删除第一个节点。
ListNode pre = new ListNode(-1);
pre.next = head;
ListNode res = pre;
//让head指向需要删除的节点,让pre指向需要删除节点前面的节点
while(times>0){
pre = pre.next;
head = head.next;
times--;
}
pre.next = head.next;
return res.next;
}
public int finddeepth(ListNode head)
{
int i = 0;
while(head!=null)
{
i++;
head = head.next;
}
return i;
}
}
思路二:一次遍历(最优解)
上图来自程序员小吴的题解。
其实一个图就可以看明白思路了。
最优解:使用双指针,p与q
其实就想要q到达null的时候,p距离q为n+1(如果算上null的话),这样p指向的下一个节点就是倒数第n个节点了
初始的时候,我们让p和q都处于一个新的节点处,这个节点的next指向head
先让q向后移动n+1位,这样让p和q之间保持n+1的距离,之后在共同移动,直到q为null。
代码二
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//最优解:使用双指针,p与q
//其实就想要q到达null的时候,p距离q为n,这样p指向的下一个节点就是倒数第n个节点了
//初始的时候,我们让p和q都处于一个新的节点处,这个节点的next指向head
//先让q向后移动n+1位,之后共同移动,直到q为null。
ListNode p = new ListNode(-1);
p.next = head;
ListNode q = p;
ListNode res = p;
while(n+1>0)
{
q = q.next;
n--;
}
while(q!=null)
{
p = p.next;
q = q.next;
}
//已经找到倒数第n个节点,p为倒数第n个节点前面的节点
p.next = p.next.next;
return res.next;
}
}
7.两两交换链表中的节点
思路
其实就是两两交换链表中的节点,就注意这里要判断的和以往的不同,要判断head不为空同时head.next也不为空,这样才能交换head和head.next。还需要注意的就是pre节点要指向一个哑结点哦。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode swapPairs(ListNode head) {
if(head==null)
return null;
ListNode pre = new ListNode(-1);
pre.next = head;
ListNode res = pre;
//防止剩余单个,所以要判断当前以及当前的下一个是否都不为空。
while(head!=null&&head.next!=null){
ListNode secondnext = head.next.next;
ListNode second = head.next;
head.next = secondnext;
second.next = head;
pre.next = second;
pre = head;
head = head.next;
}
return res.next;
}
}
8.奇偶链表
思想
把奇数节点放到一个链表中,把偶数节点放到另一个链表,到时候让奇数的尾指向偶数的头即可
需要奇数头结点,尾结点,偶数头结点与偶数尾结点
奇数头结点和偶数头结点都需要指向一个新的节点,同时指向的节点不同,但两个节点的next都指向head。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode oddEvenList(ListNode head) {
if(head==null)
return null;
//把奇数放到一个链表中,把偶数放到另一个链表,到时候让奇数的尾指向偶数的头即可
//需要奇数头结点,尾结点,偶数头结点与偶数尾结点
//奇数头结点和偶数头结点都需要指向一个新的节点,同时指向的节点不同,但两个节点的next都指向head。
ListNode pre1 = new ListNode(-1);
ListNode pre2 = new ListNode(-2);
pre1.next = head;
pre2.next = head;
ListNode oddpre = pre1;
ListNode evenpre = pre2;
ListNode oddwei = pre1;
ListNode evenwei = pre2;
ListNode res = pre1;
int i =1;
while(head!=null){
if(i%2!=0){
oddwei.next = head;
oddwei = oddwei.next;
}
else{
evenwei.next = head;
evenwei = evenwei.next;
}
ListNode xiayige = head.next;
head.next = null;
head = xiayige;
i++;
}
//这里有可能偶数节点没有做操作,所以要区分一下(只有一个节点的时候,就不需要链接了)
if(oddwei!=evenpre.next)
oddwei.next = evenpre.next;
return res.next;
}
}
一些模板与总结
1.找链表中点
快慢指针一起走,结束后慢指针指向的就是中点。值得一提的是,如果链表长度为奇数,slow会指向中间元素,如果长度为偶数,则会指向中间两个值中的左边值。
ListNode fast = head;
ListNode slow = head;
while(fast.next!=null&&fast.next.next!=null){
fast = fast.next.next;
slow = slow.next;
}
2.反转链表
public ListNode reverseList(ListNode head) {
ListNode pre = null;
while(head!=null){
ListNode next = head.next;
head.next = pre;
pre = head;
if(next==null)
break;
head = next;
}
return head;
}
3.前节点
前节点要么是一个新的节点,然后新节点的next指向head,以便防止对链表的第一个节点有影响,要么就是一个null。
ListNode pre = new ListNode(-1);
pre.next = head;
要么就是空,方便翻转链表。
ListNode pre = null;
4.思路
基本要么直接就能求解,要么就需要反转一半链表,要么就是用双指针能有一些规律,最好多用笔画一画,链表的题目总涉及交换节点位置之类的,一不小心就会出现问题,因此切记用笔写一写。
对链表进行排序
1.合并两个有序链表
思路
很简单的题,使用归并排序就好,同时比较两个链表的当前值,谁比较小就把谁插入到新链表中,直至有一个链表长度为0。之后还需要两个判断,单独判断l1链表是否为空以及单独判断l2链表是否为空,因为有可能上一次判断中有链表还剩余值,直接把这个链表剩余的值都插入到新链表中即可。
代码
可能有人会问,不需要考虑一些特殊情况么,比如两个ListNode都为空,如果这种情况下,就会直接走到return result.next,也就是返回null。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode node = new ListNode(-1);
ListNode result = node;
//第一次判断
while(l1!=null&&l2!=null){
int left = l1.val;
int right = l2.val;
if(left<right){
node.next = l1;
l1 = l1.next;
}else{
node.next = l2;
l2 = l2.next;
}
node = node.next;
}
//第二次判断
if(l1!=null){
node.next = l1;
}
if(l2!=null)
{
node.next = l2;
}
return result.next;
}
}
2.排序链表
思路
这里偷一张图,这道题的思路分为三部分:(1)找中点,(2)分割,(3)合并。
(1)找中点,找中点是通过快慢指针来找到中间节点,当快指针到终点或无法跳两格,慢指针就找到了中间节点
(2)分割,将slow后面的断开,并将前后段继续带入函数继续对两段进行中断分割…
分割结束的条件是,当前链表只剩下一个节点,就直接返回这个节点即可。
(3)合并,当我们把链表{2,3}分开之后,会分别返回链表:{2}与链表:{3},我们需要将这个链表合并,合并后将结果返回上一层递归,以便到上一层继续合并。合并就是上一道题的归并合并算法。
例子:我们以3,2,4,6举例,递归(1)首先找中点,找到中点之后,将链表分为两个链表{3,2},以及{4,6}并分别代入递归(2)与递归(3),等待两个递归的结果并将两个链表合并;递归(2)首先找到中点,将链表分为{3}(递归4),{2}(递归5);递归(4)直接返回{3},递归(5)直接返回{2};回到递归(2),将两个链表进行合并,合并为{2,3},这就是递归(2)的返回值;继续走递归(3),同理,之后递归(3)会返回{4,6};回到递归(1),将{2,3}与{4,6}合并,就是{2,3,4,6}也就是我们的结果。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode sortList(ListNode head) {
/*
1.快慢指针找到中间节点(当快指针到终点或无法跳两格,慢指针就找到了中间节点)
2.断开成两段4-2,1-3
3.再断开为4,2;1,3
4.合并链表:4和2;1和3
5.合并链表:(2,4与1,3)使用归并排序
*/
if(head==null)
return null;
//只剩一个就直接返回吧(比如当前传入的链表中只剩下4自己)
if(head.next==null)
return head;
ListNode fast = head;
ListNode slow = head;
while(fast.next!=null&&fast.next.next!=null)
{
fast = fast.next.next;
slow = slow.next;
}
//断开两段
ListNode slowright = slow.next;
slow.next = null;
ListNode left = sortList(head);
ListNode right = sortList(slowright);
ListNode result = new ListNode(-1);
ListNode res = result;
//合并
while(left!=null&&right!=null)
{
int nowleft = left.val;
int nowright = right.val;
if(nowleft<nowright){
result.next = left;
left = left.next;
}
else{
result.next = right;
right = right.next;
}
result = result.next;
}
if(left!=null){
result.next = left;
}
if(right!=null){
result.next = right;
}
return res.next;
}
}
3.对链表进行插入排序
思路
其实思路很简单,但是代码写起来容易出现bug,先说下思路吧。插入排序就是将一个值插入到我们已经排序好的链表中。首先我们将这个值与最大值去比较,如果比最大值大,那么就放到最大值后面即可,然后更新最大值;如果比最大值小,那么就需要找他究竟要插入到哪里去,对于链表来说插入比较方便,将比他小的最大值节点找到即可,将这个节点与当前节点相连,当前节点与这个节点的后面相连就完成了。
以上叙述大致可以分为以下几个步骤
1.需要一个指针max指向当前已排序的最大值
2.当前指针对应的值如果大于最大值就直接插入即可,否则就进入内部循环
3.进入内部循环,可以使用一个指针pre,从头向后找,当找到比now小的最大node,
就可以让node的next指向now,now的next指向node.next即可。
注意事项:
1.我们如何找到比now小的最大node呢,可以判断while(pre.next.val<now.val)。这样结束循环时的pre就是比now小的最大node。
2.我们定义的节点(pre,max)不能是个null,要是个有具体值的节点,因为当我们链表中已经有4后,想继续加进来2,
我们需要让2加到4前面,如果我们定义的节点都是null就会在第一次判断head的时候,都赋值为head(null不能设next)。
这样就出现了问题,pre是4,就没办法把2添加到4前面。pre应该是指向一个不存在于head链表中的值,
如果pre.next第一次就比当前的now节点大,就应该直接把now插入到pre与pre.next之间。
3.我们设置一个ListNode res ,并让pre和max都指向他,我们让now就是head,最后返回的是res.next。
代码
这其中有个巨大的坑,就是
//为什么一定要加上这句呢?
max.next = headnext;
为什么要加上这句呢,还是以4,2,1,3举例,当我们head走到2的时候,此时链表为:
res->4->2->1->3
pre->res
max->4
head->2
进行判断后,我们要将2放到res与4之间,
(headnext为1)
ListNode headnext = head.next;
//找到一个比now小的node,就可以让node的next指向now,now的next指向node.next即可。
head.next = pre.next;
pre.next = head;
(pre归位)
pre = res;
(让head为1)
head = headnext;
看起来代码没什么问题,但你用手来画一下就会发现这里只是将res连接到2,2连接到4,4连接到2这条线根本没有断开!
所以当我们最后返回结果的时候就无法返回,因为链表出现了环。所以我们要是用max.next = headnext,来将4连接到2这条线断开,也就是将max与head的线断开,之前我们考虑的都是head后面的要断开,以及pre和pre后面的要断开,可是没有考虑前面连着head的也需要断开。
完整代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode insertionSortList(ListNode head) {
/*插入排序
1.需要一个指针指向当前已排序的最大值
2.当前指针对应的值如果大于最大值就直接插入即可,否则就进入内部循环
3.进入内部循环,可以使用一个指针,从头向后找,当找到一个比now小的node,就可以让node的next指向now,now的next指向node.next即可。
*/
ListNode res =new ListNode(Integer.MIN_VALUE);
ListNode pre= res;
ListNode max=res;
while(head!=null){
if(max.val<head.val){
max.next = head;
max = head;
head = head.next;
//max = head;
}
else{
while(pre.next.val<head.val){
pre = pre.next;
}
ListNode headnext = head.next;
//为什么一定要加上这句呢?
max.next = headnext;
//找到一个比now小的node,就可以让node的next指向now,now的next指向node.next即可。
head.next = pre.next;
pre.next = head;
pre = res;
head = headnext;
}
}
return pre.next;
}
}
4.合并K个排序链表
第一种算法
对2个链表合并K-1次,也就是先将第一个和第二个合并,然后将合并的结果在与第三个链表合并,相当于2个链表合并了K-1次。
合并的算法就是归并排序。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
//先尝试合并2个链表k-1次(合并第一个与第二个,然后用他们合并好的和第三个合并,直到最后一个)
if(lists.length==0)
return null;
ListNode res = lists[0];
for(int i=0;i<lists.length-1;i++)
{
ListNode node = merge(res,lists[i+1]);
res = node;
}
return res;
}
public ListNode merge(ListNode node1,ListNode node2){
ListNode res = new ListNode(-1);
ListNode head = res;
while(node1!=null&&node2!=null){
int val1 = node1.val;
int val2 = node2.val;
if(val1<val2){
res.next = node1;
node1 =node1.next;
}else{
res.next = node2;
node2 = node2.next;
}
res = res.next;
}
if(node1!=null){
res.next = node1;
}
if(node2!=null){
res.next = node2;
}
return head.next;
}
}
第二种算法
使用分治算法,上一种算法会导致一些节点多次重复判断,比如list0中的节点,以下图为例,list0中的节点如果以上面的算法就会比较5次,与每个list中的节点都要比较一次,而分治算法,就只比较三次,比较的复杂度由N,变成了log2N,在乘上链表的个数就是O(k*log2N)
代码
我们上面的思路用来理解思想,真实的方式是使用如下方法去解决,我们不合并左右的,我们去合并第一个与最后一个,第二个与倒数第二个,以此类推。
代码需要注意的就是奇数偶数的情况,可以稍微用例子试一试,很容易写错,注意外层循环的次数为(list.length+1)/2次循环,而不是list.length/2次循环,因为如果长度为3的话,要进行两次循环,而非3/2=1,一次循环。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
//分治算法,两个两个去归并
if(lists.length==0)
return null;
int times = lists.length;
//循环lists.length/2次(可以以中间分开对半合并,第一个与最后一个,第二个与倒数第二个,然后继续折半)
//剩余长度至少为2才可以做
while(times>1){
//奇数的话比如times为5,就只需要比较0,4;1,3,而2不需要,因此是times/2=2次
//但是如果是偶数4的话,也需要比较0,3;1,2,同样为times/2=2次
for(int i=0;i<times/2;i++){
lists[i] = merge(lists[i],lists[times-1-i]);
}
//而到了这里,如果奇数的话,5/2就是2了其实是三个,因此应该是(times+1)/2,,而4个的话,(4+1)/2也是2。
times = (times+1)/2;
}
return lists[0];
}
public ListNode merge(ListNode node1,ListNode node2){
ListNode res = new ListNode(-1);
ListNode head = res;
while(node1!=null&&node2!=null){
int val1 = node1.val;
int val2 = node2.val;
if(val1<val2){
res.next = node1;
node1 =node1.next;
}else{
res.next = node2;
node2 = node2.next;
}
res = res.next;
}
if(node1!=null){
res.next = node1;
}
if(node2!=null){
res.next = node2;
}
return head.next;
}
}
反转链表
1.反转链表 II
2.重排链表
思路
比较简单就不放思路了。
代码
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public void reorderList(ListNode head) {
if(head==null)
return;
//快慢指针找中间节点,然后翻转中间节点之后的链表,并与前面的链表拼接。
ListNode fast = head;
ListNode slow = head;
while(fast!=null&&fast.next!=null){
fast = fast.next.next;
slow = slow.next;
}
//断开中间节点之后的链表
ListNode second = slow.next;
slow.next = null;
//翻转链表
ListNode pre = null;
while(second!=null){
ListNode next = second.next;
second.next = pre;
pre = second;
if(next!=null)
second = next;
else
break;
}
/*连接第一段与翻转的第二段
第二段小于等于第一段的长度
比如奇数长度:12345,第二段就是54
偶数长度1234,第二段就是43
所以第二段不指向空即可
*/
while(second!=null){
ListNode onenext = head.next;
ListNode twonext = second.next;
head.next = second;
second.next = onenext;
head = onenext;
second = twonext;
}
return ;
}
}