链表的局部反转题目
- 题目描述:给定一个单链表,和指定的长度 k,将链表内 k 长度的节点进行反转;
- 节点类
public class Node {
public int value;
public Node next;
public Node(int value) {
this.value = value;
}
}
- 主方法
public static Node reverseGroup(Node head, int k){
if(head==null){
return head;
}
// 先单独处理第一次反转,获取k个长度后的末尾节点
Node end = getKLength(head, k);
if(end==null){
return head;
}
Node start = head;
// 第一次反转,是为了获取反转后,新的头结点
reverse(start,end);
head = end;
Node lastListNode = start;
while(lastListNode.next!=null){
start = lastListNode.next;
end = getKLength(start,k);
if(end==null){
return head;
}
reverse(start,end);
lastListNode.next = end;
lastListNode = start;
}
return head;
}
通过一些图辅助说明
4. 辅助方法:获取 k 长度内的最末尾节点
// 比如1-3-5-7-9 k=3,那么返回的是5这个节点
public static Node getKLength(Node start, int k){
while(--k!=0 && start!=null){
start = start.next;
}
return start;
}
- 辅助方法:给定局部链表的头节点和尾节点,进行反转
/**
实现功能:反转局部单链表,以及将反转后的单链表,链接上后面的节点
1,2,3,4,5,6,7 原始顺序,k=3
3,2,1,4,5,6,7 第一次反转后的顺序
3,2,1,6,5,4,7 第二次反转后的顺序
*/
public static void reverse(Node start, Node end){
end = end.next;
Node cur = start;
Node pre = null;
Node next = null;
while(cur!=end){
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
// 将反转后的新尾节点,链到主链表剩余节点的第一个节点上
start.next = end;
}
- 为什么
reverse方法中执行end = end.next,在主方法中,还可以将end作为头结点呢?
逻辑应该是这样的,对象被创建后是存在于堆区的,而方法的参数是在虚拟机栈中的某个栈帧的局部变量表中,所以在方法中的end其实是一个引用,它指向堆区的对象;当执行end = end.next 只是表示end这个变量指向新的目标,并未修改原对象。我们在平常业务开发中,很少遇到类似的场景,所以下意识的认为end = end.next 改变了原始end对象。