• (Java) LeetCode 206. Reverse Linked List —— 反转链表


    Reverse a singly linked list.

    Example:

    Input: 1->2->3->4->5->NULL
    Output: 5->4->3->2->1->NULL

    Follow up:

    A linked list can be reversed either iteratively or recursively. Could you implement both?


    反转链表,链表算法里必备技能点,基础的重中之重。很多有关链表反转、翻转的问题都是在这个基础上进行思维的延伸。既然要求用两个方法做,那就先说迭代再说递归。

    解法一,迭代:

    首先,肯定知道最后返回的结果是输入链表的链表尾节点。但先找到尾节点是很难继续实现的,因为链表没有办法高效获取前驱。往往这类问题很多时候都要想到建立一个新的节点,之后在遍历输入的时候重新组织节点顺序,将节点挂在新节点上。所以高效的做法是在遍历链表的过程中,一个一个的把输入链表的节点放到一个新的链表头部。所以思路就是建立一个新的链表头,每次遍历输入链表的节点都把他放到新链表的头部,这样遍历完成后就获得了反转的链表。详细代码注释见下。

    解法二,递归:

    每次想着用递归解法我习惯于用数学归纳法的思维去思考。先想输入规模最小的情况,再想比较general的情况。就本题来说,如果输入的是null或者单节点链表,必然是返回其本身。如果至少有两个节点,那么才开始递归。想一下,递归后的结果一定是一个规模更小问题的结果。即如果输入有k个节点,那么递归调用程序,输入原链表第二个节点所返回的结果,是一个反转后的,拥有k-1个节点的链表的首节点 —— 规模更小的问题的结果。那么如果把这个递归调用后返回的头节点所指向链表的尾节点的next域,指向被调用的节点的前驱,就相当反转了k个节点的链表。即利用k-1的结果去完成了k的问题。所以想到这里,在递归函数里要做的就是三件事:第一,记录即将被递归调用节点的前驱(或者换句话说,建立个新的节点指向输入的下一个节点,之后递归调用那个新节点);第二,递归调用输入的下一个节点;第三,将返回结果的末尾指向记录好的前驱节点,完成反转。

    这里需要注意的只有第三步,如何找到返回的结果链表的末尾。还是要回归到递归的本质,即返回的结果是一个已经反转完成的链表的首节点。反转完成的意思就是我们输入一个以节点S为头结点,节点E为尾结点的链表,那么调用后返回的节点是E,而S经过调用后变成了尾节点。即,递归调用时的输入本身,即是调用完成后我们需要的尾节点!所以我们并不需要每一次都去寻找递归调用后结果的尾节点,只需要直接利用递归调用的输入即可,因为这个输入就是调用完成的尾节点。详细代码注释见下。


    解法一(Java)

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
        public ListNode reverseList(ListNode head) {
            ListNode first = head;
            ListNode reverseHead = null; //建立一个新的节点用来存放结果
            while (first != null) { //遍历输入链表,开始处理每一个节点
                ListNode second = first.next; //先处理第一个节点first,所以需要一个指针来存储first的后继
                first.next = reverseHead; //将first放到新链表头节点的头部
                reverseHead = first; //移动新链表的头指针,让它始终指向新链表头部
                first = second; //继续处理原链表的节点,即之前指针存放的后继,循环往复
            }
            return reverseHead;
        }
    }

    解法二(Java)

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) { val = x; }
     * }
     */
    class Solution {
        public ListNode reverseList(ListNode head) {
            if (head == null || head.next == null) return head; //处理最小输入的情况,即空链表和单节点链表
            ListNode second = head.next; //将即将被调用的下一个节点分离,即将下一个调用的输入存在second里
            ListNode reverseHead = reverseList(second); //将调用后的结果存储,这个结果就是最终结果。之后利用递归,调用刚才存好的输入
            second.next = head; //上面一步的调用已经完成以second为首的链表的反转,所以现在second变成了反转完成后的尾节点
                     //把这个尾节点的next指向一开始输入的前驱,即head,完成整个链表反转
    head.next = null; //最开始的头节点要变成尾节点,即在后面补null使链表终结 return reverseHead; } }
  • 相关阅读:
    mysql聚合函数
    轮播图与定时器
    3.23 参数 DOM 鼠标点击跟移入事件
    循环+数组
    for循环
    JS讲解跟遇到的问题
    CSS标签和属性回顾,JS初步了解
    2018.03.14理工大网站问题及解决办法
    2018.3.13 浮动 定位
    2018.3.12CSS样式
  • 原文地址:https://www.cnblogs.com/tengdai/p/9279421.html
Copyright © 2020-2023  润新知