上回了解了链表的反转,接下来深入了解下链表指定区间的反转。
指定区间反转比链表的反转稍微难一点,但也差不多,这里采用2种方法解决,1.头插法 2.穿针引线法。
1.头插法
头插法的缺点是如果left和right的区间间隔很大,找到left和right需要遍历依次,反转还要再遍历依次。虽然时间复杂度为O(n),但是可以只遍历一遍吗?答案是肯定的。
只需要在反转的区间内,每遍历一个节点,就让这个节点到反转部分的开始位置。
实现代码:
public static Node invertListBetweenNode(Node node,int left,int right){
Node dummyNode = new Node();
dummyNode.next = node;
Node res = dummyNode;
for (int i = 0; i < left - 1; i++){
res = res.next;
}
Node cur = res.next;//开始反转节点的位置
Node next;//下一个要反转节点
for (int i = 0; i < right - left; i++){
next = cur.next;//反转节点位置为要反转节点位置
cur.next = next.next;//
next.next = res.next;//指向开始反转的节点
res.next = next;//指向开始
}
return dummyNode.next;
}
2.穿针引线法
这种方式同样适用于之前的链表反转方式,确定需要反转的部分,然后将三个链表连接起来,第一部分是left前的部分,第二部分是left到right之间的部分,第三部分是right后的部分。
实现代码:
public static Node invertListBetweenNode2(Node node,int left, int right){
Node dummyNode = new Node();
dummyNode.next = node;
Node res = dummyNode;
//第一部分
for (int i = 0; i < left - 1; i++){
res = res.next;
}
//第二部分
Node rightNode = res;
for (int i = 0; i < right -left + 1; i++){
rightNode = rightNode.next;
}
Node leftNode = res.next;
//第三部分
Node end = rightNode.next;
rightNode.next = null;//把反转区间的链表最后一个节点的下一个指向null
//反转leftNode链表;
invertLinkedList(leftNode);
//三部分链表结合
res.next = rightNode;
leftNode.next = end;
return dummyNode.next;
}