【剑指Offer】个人学习笔记_24_反转链表

难度简单205

刷题日期:20:5635 星期二2021年3月30日

个人刷题记录,代码收集,来源皆为leetcode

经过多方讨论和请教,现在打算往Java方向发力

主要答题语言为Java

题目:

剑指 Offer 24. 反转链表

难度简单 205

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

示例:

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

限制:

0 <= 节点个数 <= 5000
题目分析

因为链表的性质,如果是单向链表的话,是不能往前搜索的,所以乍一想只能新建一个链表,然后以特殊的形式把数据又后往前存储的新链表里。

或者参考书里的思路,想办法让每个指针都指向前面的数据,这期间需要防止链表断开。

初始解答:

/**
 * 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 pAhead = null, pCur = head, pBehind = null;
        if (head == null || head.next == null) return head; //特殊情况
        while (pCur.next != null) {
            pBehind = pCur.next;
            pCur.next = pAhead;
            pAhead = pCur;
            pCur = pBehind;
            // pBehind.next = pCur;
        }
        pBehind.next = pAhead;
        return pBehind;
    }
}

提交了几次分别卡在空链表和单个链表的输入,加入考虑特殊情况的if判断后实现了功能,值得深思考虑。

执行结果: 通过

显示详情

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户

内存消耗:38.2 MB, 在所有 Java 提交中击败了67.03%的用户

学习K神的迭代写法,最后发现自己想的其实大差不差的,一个临时变量又减少了空间占用,性能更好了。

/**
 * 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 pAhead = null, pCur = head; //其实两个常用就够了
        // if (head == null || head.next == null) return head; //特殊情况
        while (pCur != null) {
            ListNode pBehind = pCur.next; //存后继节点
            pCur.next = pAhead; //前面指向
            pAhead = pCur; //前面指中
            pCur = pBehind; //中访问下一节点
        }
        return pAhead;
    }
}

执行结果:通过

显示详情

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户

内存消耗:37.9 MB, 在所有 Java 提交中击败了94.37%的用户

递归写法也尝试了下,和他人的差不多:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        return recur(head,null); //直接进入递归,null是结果的最后一个值
    }
    private ListNode recur(ListNode cur, ListNode pre) {
        if (cur == null) return pre; //遇到说明已经到底了,示例输入时pre=5
        ListNode res = recur(cur.next, cur); //递归代码,不断访问下一套
        cur.next = pre; //修改指向
        return res; //返回当前指向的下一个
    }
}

执行结果: 通过

显示详情

执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户

内存消耗:38 MB, 在所有 Java 提交中击败了93.26%的用户

学习他人:

方法一:

sunchunleiL1

2020-07-16

    /**
     * 迭代法
     */
    public ListNode reverseList_1(ListNode head) {
        ListNode newHead = null;
        while (head != null){
            ListNode temp = head.next;
            head.next = newHead;
            newHead = head;
            head = temp;
        }
        return newHead;
    }

    /**
     * 递归法
     */
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) return head;
        ListNode newHead = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return newHead;
    }

    /**
     * 借助栈
     */
    public ListNode reverseList_stack(ListNode head) {
        if (head == null) return head;
        Stack<ListNode> stack = new Stack<>();
        while (head!=null){
            stack.push(head);
            head = head.next;
        }
        ListNode newHead = stack.pop();
        ListNode tailNode = newHead;
        while (!stack.isEmpty()){
            ListNode cur =  stack.pop();
            tailNode.next = cur;
            tailNode = cur;
        }
        tailNode.next = null;
        return newHead;
    }

方法二:

K神

作者:jyd
链接:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/solution/jian-zhi-offer-24-fan-zhuan-lian-biao-die-dai-di-2/
来源:力扣(LeetCode)

方法一:迭代(双指针)

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head, pre = null;
        while(cur != null) {
            ListNode tmp = cur.next; // 暂存后继节点 cur.next
            cur.next = pre;          // 修改 next 引用指向
            pre = cur;               // pre 暂存 cur
            cur = tmp;               // cur 访问下一节点
        }
        return pre;
    }
}

利用 Python 语言的平行赋值语法,可以进一步简化代码(但可读性下降):

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        cur, pre = head, None
        while cur:
            cur.next, pre, cur = pre, cur, cur.next
        return pre

递归

class Solution {
    public ListNode reverseList(ListNode head) {
        return recur(head, null);    // 调用递归并返回
    }
    private ListNode recur(ListNode cur, ListNode pre) {
/*
本递归方法返回的永远是最后一个节点,无论是哪一层递归
*/
        if (cur == null) return pre; // 终止条件,这里的pre是最后一个节点
        ListNode res = recur(cur.next, cur);  // 递归后继节点,res是最后一个节点
        cur.next = pre;//注意此pre一直在变化
        return res;                  // 返回反转链表的头节点,返回最后一个节点res
    }
}

总结

以上就是本题的内容和学习过程了,就递归和迭代两种解法,需要考虑边界输入,都值得学习,自己理清思路。

欢迎讨论,共同进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值