链表反转

欢迎光临我的博客[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;
    }
}

递归交换

posted @ 2019-10-27 14:44  LittleDonkey  阅读(670)  评论(0编辑  收藏  举报