经常能被单链表逆置给绕进去,此时把个人解释和代码放出,方便记忆
/**
* 反转链表
* 迭代实现
* @param p
* @return
*/
private ListNode reverseListByIter(ListNode p){
if(p == null || p.next == null){
return p;
}
// work为工作指针,跟随p的变化而变化
ListNode pre = null;
ListNode work = p;
while (work != null){
p = p.next;
// 更改指针指向,从后面的节点(work)指向步调慢的前驱节点(pre)
work.next = pre;
// 保证跳出循环后,pre一定是尾结点
pre = work;
work = p;
}
// 已经遍历到p,work都为null,此时pre为指向最后一个节点(逆置后的头结点)
p = pre;
return p;
}
/**
* 翻转链表
* 递归实现
* @param p
* @return
*/
private ListNode reverseList(ListNode p) {
if(p == null || p.next == null){
return p;
}
// 递归的含义是逆置p.next为头结点的链表,并返回新链表的头指针
ListNode newNode = reverseList(p.next);
// 此时p还是指向没逆置的第二个节点的,即该节点为p.next
// 但逆置后第二个节点变成了倒数第二个节点,p此时是倒数第一个节点
// 倒数第二个节点该指向p 所以是p.next.next = p
// p为尾结点后当然p的指针域为null,所以p.next = null
// 此时一定是newNode为新的头结点
p.next.next = p;
p.next = null;
return newNode;
}
/**
* 反转链表的前k个节点
*/
// 用于记录第k+1个节点的位置
private ListNode pNext = null;
private ListNode reverseK(ListNode p, int k){
if(k == 1){
pNext = p.next;
return p;
}
ListNode newNode = reverseK(p.next, k - 1);
p.next.next = p;
p.next = pNext;
return newNode;
}
// 逆置[m,n]范围内的节点
private ListNode reverseBetween(ListNode p, int m, int n){
if(m == 1){
return reverseK(p, n);
}
// 相当于往前推进了一步
p.next = reverseBetween(p.next, m - 1, n - 1);
return p;
}