反转链表-力扣-迭代/递归

反转链表

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;
        }
    }

}

posted @ 2024-10-31 16:16  在天边偷看小天使  阅读(17)  评论(0)    收藏  举报  来源