leetcode-24.反转链表

108 阅读1分钟
/**
 * https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/
 * 定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
 * 示例:
 * 输入: 1->2->3->4->5->NULL
 * 输出: 5->4->3->2->1->NULL
 * 限制:
 * 0 <= 节点个数 <= 5000
 */
public class ReverseLinkedList {

    /**
     * 组装数据
     * @param args
     */
    public static void main(String[] args){
        ListNode node5 = new ListNode(5,null);
        ListNode node4 = new ListNode(4,node5);
        ListNode node3 = new ListNode(3,node4);
        ListNode node2 = new ListNode(2,node3);
        ListNode node1 = new ListNode(1,node2);
        System.out.println("source listNode:"+node1);
        // System.out.println("reverse listNode iterate :"+iterate(node1));
        // System.out.println("reverse listNode iterate1 :"+iterate1(node1));
        System.out.println("reverse listNode recursion :"+recursion(node1));
    }

    /**
     * 迭代思路完成翻转:
     * 从前往后遍历链表,将当前节点的next指向上一节点,因此需要一个变量存储上一个节点prev。
     * 当前节点处理完成需要寻找下一个节点,因此需要一个变量保存当前节点curr,
     * 处理完成后要将当前节点赋值给prev,并将next指针赋值给curr,
     * 因此需要一个变量提前保存下一个节点的指针next。
     * 于是引入两个变量
     *  使用变量next暂存当前节点的下一个节点,用于遍历过程中,记录下一个需要迭代的节点。
     *  使用变量prev暂存当前节点,用于迭代后当前节点指向上一个节点进行关联。
     * @param head
     * @return
     */
    public static ListNode iterate(ListNode head) {
        // 上一个节点,默认是null,之后随着迭代进行,当前节点将会作为下一次节点的上一个节点。
        ListNode prev = null;
        // 下一个节点,用于记录当前节点的下一个节点,当前节点被翻转后,将失去和原节点的下一个节点的指针,无法知道下一个需要迭代的节点。
        ListNode next;
        // 当前节点,用于记录正在迭代的节点
        ListNode curr = head;
        // 当前元素为空时,将结束迭代
        while(curr!=null){
            // 暂存当前节点的下一个节点
            next = curr.next;
            // 指针翻转,操作后就不知道原节点的下一个节点
            curr.next = prev;
            // 暂存当前节点,作为下一次迭代需要寻找的上一个节点,进行指针关联
            prev = curr;
            // 暂存当前节点的下一个节点,进行数据迭代
            curr = next;
        }
        return prev;
    }

    /**
     * 迭代思路完成翻转:
     * @param head
     * @return
     */
    public static ListNode iterate1(ListNode head) {
        // 用于记录翻转后的链表(也就是每次迭代的节点的上一个节点)
        ListNode newHead = null;
        // 当节点不为空时,进行迭代
        while(head!=null){
            // 获取当前节点的下一个元素进行暂存,由于翻转后就无法获取到
            ListNode temp = head.next;
            // 当前节点完成翻转,上一个节点指向当前节点
            head.next = newHead;
            // 当前节点记录,用于下一次迭代寻找上一个节点
            newHead = head;
            // 链表head赋值当前节点下一个节点,用于下次迭代
            head = temp;
        }
        return newHead;
    }

    /**
     * 递归实现:先从跟节点找到叶子节点,从叶子节点开始遍历。
     * 将大的问题(整个链表反转)拆分成性质相同的小问题(两个节点反转) curr.next.next = curr;
     * 只需要每个节点执行curr.next.next = curr,curr.next = null即可。
     * 既4->5,然后4->5->4 然后4->5断开,形成5->4。
     * 既3->4,然后3->4->3 然后3->4断开,形成5->4->3。
     * @param head
     * @return
     */
    public static ListNode recursion(ListNode head) {
        if(head== null|| head.next ==null){
            return head;
        }
        ListNode newHead = recursion(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }
}