反转链表-力扣-迭代/递归
反转链表
package com.caoii.LinkedList;/*
*@program:labu-pratice-study
*@package:com.caoii.LinkedList
*@author: Alan
*@Time: 2024/4/18 9:56
*@description: 反转链表-递归/迭代
*/
public class ReverseLinkedList {
/*力扣206 迭代法(头插法)
反转整个链表*/
public static ListNode reverseListIterate(ListNode head) {
ListNode dummy = new ListNode(-1);
// 虚拟头节点
ListNode q = head;//遍历节点
ListNode temp1;
// 用来存储每个访问到的节点的next引用
while (q != null) {
temp1 = q.next;
q.next = dummy.next;
dummy.next = q;
q = temp1;
}
return dummy.next;
}
public static ListNode reverseListIterate(ListNode head, int left, int right) {
ListNode dummy = new ListNode(-1);
// 虚拟头节点
dummy.next = head;
ListNode q = head;//遍历节点
ListNode temp1 = null;
// 存储反转部分的遍历时的当前访问节点的next引用
ListNode temp2 = new ListNode(-1);
// 作虚拟头结点来串联需要反转的部分
ListNode temp3 = dummy;
// 链接左侧不用反转的部分
ListNode temp4 = null;
// 链接右侧不用反转的部分
int count = 1;
if (left == right) {
// left == right 不用反转了
return dummy.next;
}
// left < right 时
while (q != null) {
if (count < left) {
// 如果left>1
// 则 temp3 指向 第left-1个元素
// 如果left==1
// 则 temp3 指向 dummy 虚拟头结点
temp3 = q;
q = q.next;
// q 指向 第left个元素
count++;
} else {
if (count <= right) {
// 在访问 第left到第right个节点时
temp1 = q.next; // temp1 记录下一个可能访问的q 节点
// 初始时
// 如果left == 1 则 q 指向head 也即left节点
// 如果left > 1 则 q 指向 第left个节点
q.next = temp2.next;
// temp2 作反转部分链表的虚拟头节点 作头插法
// 让 q的指针 指向反转链表头结点的下一个元素
if (count == left + 1) {
// 在right != left的条件下 必有 count == left + 1
// 即当前访问第 left+1 个节点且 left+1<=right
// 则 反转链表已经有了一个有用的节点,即反转后的末尾节点
// 用temp4 记录反转链表的末尾节点
temp4 = temp2.next;
// 所以 temp4 一定不为空
}
temp2.next = q;
// 反转链表的虚拟头结点指向 在头部 新插入的 q节点
// 完成头插法
q = temp1;
// q 向后遍历一个位置
// 最后一次循环时 q == 第right+1个节点
count++;
// 记录反转链表元素个数
} else {
// 即将访问right+1 退出循环
break;
}
}
}
temp3.next = temp2.next;
// temp3 指向第left-1个有效节点或虚拟头结点 令temp3.next 为将反转链表第一个有效元素
temp4.next = q;
// 已知temp4 一定不为空 且temp4 存储反转链表的末尾节点
// 则让反转链表末尾节点的next = q 此时 q 为 第right+1个节点
// 完成链表反转 返回head
return dummy.next;
}
/*反转链表迭代法
* 定义:输入一个单链表头结点,将该链表反转,返回新的头结点*/
public static ListNode reverseListRecursion(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode last = reverseListRecursion(head.next);
// 当节点数>2时 传入第二个节点 直到 (head.next).next == null 返回 head.next 即最后一个节点
// 当节点数 == 2 时 传入第二个节点 (head.next).next == null 返回 head.next 即返回第二个节点
// 当节点数 == 1 传入 null (head.next) == null 返回第一个节点
// 当节点数为0 直接整个函数返回head==null
//已经拿到last为最后一个节点
//函数外的head 会在递归中依次指向倒数第二个/倒数第三个....正数第一个节点 head.next 为 last
//令(head.next).next指向head本身,即last节点.next指向原来它前面的节点
head.next.next = head;
// head.next 为 head 指向 last 现在已经存在last指向head 将此next置空
head.next = null;
return last;
}
/*反转链表迭代法
* 定义:输入一个单链表头结点,将该链表前N个节点,返回头结点*/
static ListNode sucessor = null;
public static ListNode reverseListRecursion(ListNode head, int N) {
if (N == 1) {
sucessor = head.next;// successor 记录第N+1个节点
return head;
} else {
ListNode last = reverseListRecursion(head.next, N - 1);
// 从head.next 开始 反转N-1个节点 所反转的第一个节点依然是总的函数要反转的第一个节点
// 当(N-1)== 1 的时候 所要反转的只有一个节点 head^n ==(head^n-1.next) N == (N-1) == 1
// 在 last == 末尾节点 N==2时 head == head^n-1
// head.next == 末尾节点
head.next.next = head;
// 末尾节点的next指向它的前一个节点
// 末尾节点的前一个节点 依次指向第N+1个节点 然后自己做末尾节点 再指向自己的前一个节点
// 直到head == 第一个节点 递归到函数结束 刚好 head.next 指向第N+1个节点
head.next = sucessor;
// 倒数第二个节点/倒数第三个/倒数第.../正数第一个节点 指向第N+1个节点
return last;
}
}
public static ListNode reverseListRecursion(ListNode head, int left, int right) {
if (left == 1) {
// 返回前right个元素反转的链表
return reverseListRecursion(head, right);
} else {
/*
// 向前走到left的位置 验证成功
int count = 1;
ListNode p = head;
ListNode dummy = new ListNode(-1);
dummy.next = head;
while (count < left) {
count++;
dummy.next = p;
p = p.next;
}
ListNode newHead = reverseListRecursion(p, right - left + 1);
dummy.next.next = newHead;
return head;*/
// 递归
// 如果left!=1 则 right > left > 1
head.next = reverseListRecursion(head.next, left - 1, right - 1);
return head;
}
}
}