反转链表基本分为三种类型:1.反转整个链表;2.反转前N个节点;3.反转中间第M到第N个节点。(第2种类型可以看作是第3种类型在M=1的一种情况)
链表反转两种常用思路:1.遍历链表直接修改节点next指针(借助临时节点);2.递归。
如果节点有value值,输出的结果是以节点value值衡量,那么还有第三种解法:直接交换节点的value值(类似数组反转?)。本质上还是跟上面说到的类型1相似。
思路1:遍历链表直接修改next
/**
* 非递归遍历链表
* @param head
* @param left
* @param right
* @return
*/
public ListNode reverseBetween(ListNode head, int left, int right) {
if (head.next == null || right == left) {
return head;
}
int index = 1;
ListNode leftpre = new ListNode(-1, head);
while (index < left) {
leftpre = leftpre.next;
index++;
}
// 1->|2->3->4|->5
// leftpre->left->right->rightSuc
ListNode leftNode = leftpre.next;
ListNode rightNode = leftNode.next;
ListNode rightsuc = rightNode.next;
while (left < right) {
rightNode.next = leftNode;
leftNode = rightNode;
rightNode = rightsuc;
rightsuc = rightNode == null? null : rightNode.next;
left++;
}
if (leftpre.next == head) {
leftpre.next.next = rightNode;
return leftNode;
}
leftpre.next.next = rightNode;
leftpre.next = leftNode;
return head;
}
思路2:递归
class Solution {
ListNode rightsuc = null;
public ListNode reverseBetween(ListNode head, int left, int right) {
if (left == 1) {
return reverseNRecursion(head, right);
}
head.next = reverseBetween(head.next, left - 1, right - 1);
return head;
}
/**
* 递归
* 反转前N个
* @param head
* @param left
* @param right
* @return
*/
public ListNode reverseNRecursion(ListNode head, int right) {
// 1->|2->3->4|->5
// leftpre->left->right->rightSuc
if (right == 1) {
rightsuc = head.next;
return head;
}
ListNode lastNode = reverseBetween(head.next, 1, right - 1);
head.next.next = head;
head.next = rightsuc;
return lastNode;
}
}
从结果看,两种思路总体上差不多。