链表反转
欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot
链表
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
反转链表
/**
* 反转链表:头节点插入法
*
* 时间复杂度:O(n)。
* 空间复杂度:O(1)。
*/
class Solution1 {
public static ListNode reverse(ListNode head) {
//newHead为头节点
ListNode newHead = null;
//当前节点
ListNode cur = head;
while (cur != null) {
//保存当前节点的下一个节点
ListNode next = cur.next;
/**
* 处理当前节点
*/
//将处理好的节点添加到当前节点后面
cur.next = newHead;
//当前节点变为头节点
newHead = cur;
cur = next;
}
return newHead;
}
}
/**
* 反转链表:递归法
*
* 时间复杂度:O(n)。
* 空间复杂度:O(n),由于使用递归,将会使用隐式栈空间。递归深度可能会达到 n 层。
*/
class Solution2 {
public static ListNode reverse(ListNode head) {
if (head == null || head.next == null) {
return head;
}
/**
* 返回最后一个节点,作为head节点(当head.next为最后一行节点,会返回head.next)
*
* 反转head.next之后的节点
*/
ListNode p = reverse(head.next);
/**
* 反转head节点
*
* 将后一个节点的前一个节点反转。
*
* head.next为后一个节点,head为前一个节点。
* 后一个节点的next指向前一个节点,前一个节点指向null。
*
* 以此向前推
*/
head.next.next = head;
head.next = null;
return p;
}
}
头插法
给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数
/**
* 给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数
*
* 思路:
* 将链表闭合成环,然后在合适的地方断开(移动k位就从结尾截取k位到头节点)
*
* 时间复杂度:O(N)。
* 空间复杂度:O(1)。
*/
class Solution3 {
public ListNode rotateRight(ListNode head, int k) {
//k==0则返回
if (k == 0) {
return head;
}
//非空链表
int len = 0;
if (head != null) {
//计算链表长度
len++;
ListNode cur = head;
while (cur.next != null) {
len++;
cur = cur.next;
}
//闭合成环
cur.next = head;
//找到何时的位置并断开
ListNode pre = head;
for (int i = 0; i < len - k % len - 1; i++) {
pre = pre.next;
}
head = pre.next;
pre.next = null;
return head;
}
//空链表直接返回
return head;
}
}
移位
反转从位置 m 到 n 的链表。请使用一趟扫描完成反转(1 ≤ m ≤ n ≤ 链表长度)
/**
* 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转(1 ≤ m ≤ n ≤ 链表长度):递归法
* <p>
* 思路:
* 创建两个指针,一个开头,一个结尾。不断地交换这两个指针的值,并将两个指针向中间移动。
*
* 时间复杂度: O(N)。对每个结点最多处理两次。递归过程,回溯。
* 空间复杂度: 最坏情况下为 O(N)。
*/
class Solution4 {
ListNode left;
boolean flag;
/**
* 只有rigth需要往回走
*/
public void recursionAndReverse(ListNode rigth, int m, int n) {
//n需要走n步才能到达n的位置,每走一步n-1
if (n == 1) {
return;
}
//m只需要走m步
if (m > 1) {
left = left.next;
}
rigth = rigth.next;
recursionAndReverse(rigth, m - 1, n - 1);
//两个指针重合说明已经交换完毕,不需要再交换了。
if (left == rigth || rigth.next == left) {
flag = true;
}
if (!flag) {
int tmp = left.val;
left.val = rigth.val;
rigth.val = tmp;
left=left.next;
}
}
public ListNode reverseBetween(ListNode head, int m, int n) {
if (head == null || m == n || n == 1) {
return head;
}
left = head;
flag = false;
recursionAndReverse(head, m, n);
return head;
}
}
递归交换