第二章 链表问题
2.5 反转部分单向链表
【题目】
给定一个单向链表的头节点 head,以及两个整数 from 和 to,在单向链表上吧第 from 个节点到底 to 个节点这一部分进行反转。
【要求】
- 如果链表长度为 N,时间复杂度要求为 O(N),额外空间复杂度要求为 O(1)。
- 如果不满足 1≤from≤to≤N,则不需要调整。
【难度】
士 ★☆☆☆
【题解】
本题可能出现更换头节点的问题,整个处理过程如下:
- 先判断是否满足 1≤from≤to≤N,如果不满足,则无需调整。
- 找到第 from-1 个节点 fPre 和第 to+1 个节点 tPos。fPre 即反转部分的钱一个节点,tPos 即反转部分的的后一个节点。把反转的部分先反转,然后正确的连接 fPre 和 tPos。
- 如果 fPre 为空,说明反转部分是包含头节点的,则返回新的头节点,也就是没反转之前反转部分的最后一个节点,也是反转之后反转部分的第一个节点;如果 fPre 不为空,则返回就的头节点。
【实现】
- ReversePartLinkedList.java
public class ReversePartLinkedList {
private static class Node {
public int value;
public Node next;
public Node(int value) {
this.value = value;
}
}
private Node head;
public ReversePartLinkedList(int[] arr) {
buildSingleLinkedList(arr);
}
private void buildSingleLinkedList(int[] arr) {
if (arr != null && arr.length != 0) {
Node preNode = this.head = new Node(arr[0]);
for (int i = 1; i < arr.length; i++) {
preNode = preNode.next = new Node(arr[i]);
}
}
}
public void reversePartLinkedList(int from, int to) {
if (from >= to || from < 1) {
return;
}
if (this.head == null || this.head.next == null) {
return;
}
int len = 1;
Node curNode = this.head;
Node fPreNode = null;
Node tPosNode = null;
while (curNode != null) {
++len;
fPreNode = (len == from - 1) ? curNode : fPreNode;
tPosNode = (len == to + 1) ? curNode : tPosNode;
curNode = curNode.next;
}
if (to > len) {
return;
}
curNode = (fPreNode == null) ? this.head : fPreNode.next;
Node postNode = curNode.next;
curNode.next = tPosNode;
Node nextNode = null;
while (nextNode != tPosNode) {
nextNode = postNode.next;
postNode.next = curNode;
curNode = postNode;
postNode = nextNode;
}
if (fPreNode != null) {
fPreNode.next = curNode;
}
}
}
- Test.java
public class Test {
private ReversePartLinkedList partLinkedList;
public Test(int[] arr) {
this.partLinkedList = new ReversePartLinkedList(arr);
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
Test test = new Test(arr);
test.partLinkedList.reversePartLinkedList(2, 4);
}
}