方法一:头插法。
示例:
输入:head=[9,7,2,5,4,3,6],left=3,right=6
输出:[9,7,3,4,5,2,6]
思路: 在需要反转的区间里,遍历每一个结点,将节点移动到区间的第一个位置上,如下图:
具体代码如下:
//指定区间反转链表
private static Node reverseBetween(Node head,int left,int right) {
Node dumpNode = new Node(0);
dumpNode.next = head;
Node preNode = dumpNode;
for(int i=0;i<left-1;i++) {
preNode = preNode.next;
}
Node curNode = preNode.next;
Node nextNode=null;
for(int i=0;i<right-left;i++) {
nextNode = curNode.next;
curNode.next = nextNode.next;
nextNode.next = preNode.next;
preNode.next = nextNode;
}
return dumpNode.next;
}
方法二:穿针引线法
示例:
输入:head=[9,7,2,5,4,3,6],left=3,right=6
输出:[9,7,3,4,5,2,6]
思路:确定反转区域,以反转区域为风隔将整个链表分成三段:反转区域前部分,反转区域部分,反转区域后部分。单独对反转区域进行反转,然后将三部分链接在一起。
//指定区域反转链表,穿针引线法
private static Node reverBetween1(Node head,int left,int right) {
//创建虚拟头节点
Node dummyNode =new Node(0);
dummyNode.next = head;
Node pre = dummyNode;
//使pre代表指定区域的前面一个结点
for(int i=0;i<left-1;i++) {
pre = pre.next;
}
//使rightNode代表指定区域的最后一个结点
Node rightNode = pre;
for(int i=0;i<right-left+1;i++) {
rightNode = rightNode.next;
}
//使leftNode代表指定区域的第一个结点
Node leftNode = pre.next;
//使nextNode代表指定区域后一个结点
Node nextNode = rightNode.next;
//切出指定区域
pre.next = null;
rightNode.next = null;
//使用方法反转指定区域的链表
reverseNode(leftNode);
//将三个部分链接起来
pre.next = rightNode;
leftNode.next = nextNode;
return dummyNode.next;
}
//构造虚拟结点进行,反转结点
private static Node reverseNode(Node headNode) {
Node node = new Node(0);
node.next = headNode;
Node cur = headNode;
while(cur != null) {
Node next = cur.next;
cur.next = node.next;
node.next = cur;
cur = next;
}
return node.next;
}