解题思路分析:考虑将链表分成三段,中间段反转后,反转后再拼接(前提引入虚拟头结点的情况下:可以使得在left=1,仍然分成三段----省去了分类讨论的麻烦;同时考虑如果是right是最后一个节点,第三段null也可以理解成第三段的情况)。很明显,当left==right不用反转。
注意:一个易错的地方,如果left=1时,leftpre是假头结点不属于原始的链表的部分,同时我们不能直接原始的头结点,因为它已经去了后面,只能返回假头节点的下一个!!!!;如果left!=1,那么可以直接返回原始的head!!!
class Solution {
//审题left和right是位置的值,不是具体的节点的值
public ListNode reverseBetween(ListNode head, int left, int right) {
if(left==right){//如果相等时,相当于不需要反转
return head;
}
//思想:断开为三个链表,中间那段需要反转一下
ListNode leftpre=new ListNode(-10000);//存放leftnode的前一个节点(第一段链表的尾结点)
leftpre.next=head;
ListNode rightnext=new ListNode();//存放右节点的下一个节点(第三段链表的头结点)
ListNode leftnode=null;
ListNode rightnode=head;
//注意如果是左节点是首节点,这个时候的leftpre还是是假头,不属于原始的链表,需要输出的时候分类讨论
for(int i=left-1;i>0;i--){
leftpre=leftpre.next;//找打了leftnode的前一个节点
}
leftnode=leftpre.next;//找到了中间链表的首结点
for(int i=right-1;i>0;i--){
rightnode=rightnode.next;//找到了中间链表的尾结点
}
rightnext=rightnode.next;//第三段链表的首结点
rightnode.next=null;//将中间链表的收尾为null
ListNode reverse=reverseLink(leftnode);//反转后的链表的头结点
leftpre.next=reverse;
leftnode=reverse;//反转后的左节点
while(leftnode.next!=null){
leftnode=leftnode.next;//找到非null尾结点
}
leftnode.next=rightnext;
if(leftpre.val==(-10000)){
return leftpre.next;//左节点从首个节点开始
}else{
return head;;//左节点不是从首个节点开始,返回原始的节点
}
}
//常用于反转链表
public ListNode reverseLink(ListNode head){
ListNode pre=null;//确保链表的结尾是个null
ListNode temp=head;
ListNode tnext=null;
while(temp!=null){
tnext=temp.next;
temp.next=pre;
pre=temp;
temp=tnext;
}
return pre;
}
}