实现反转链表--递归、迭代、双指针、栈

1 篇文章 0 订阅
1 篇文章 0 订阅

描述

2021年,新年第二天,吃过晚饭,没想到一道简简单单的题把我卡了半天,于是乎记录一下。建议自己先写写试试。

题目:

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

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

链表结构:

class ListNode{
    int val;
    ListNode next;
    public ListNode(int val){
        this.val = val;
    }
}

public ListNode reverseList(ListNode head) {
	//实现代码
}

其实开始想法是遍历链表,用栈保存其中的int值,然后再从栈中取出int生成新的链表。确实可以实现,但是效率太低,肯定不是最优的。最后再贴出栈的实现方法。

递归

相信不少同学和我一样,遇到递归的问题总是很头疼,而一看解答,却发现大佬们几行递归代码就优雅的解决了问题。遇到递归问题很容易进入思维误区,所谓递归,程序反复调用自身即是递归。既然能够调用自身说明它每一级的功能都是一样的,因此我们只需要关注一级递归的解决过程即可。

递归把握好三个关键点就可以了:

  1. 找整个递归的终止条件:递归应该在什么时候结束?
  2. 找返回值:应该给上一级返回什么信息?
  3. 本级递归应该做什么:在这一级递归中,应该完成什么任务?

这里推荐一个博客,写的非常清晰,套路解决递归问题

对于该题分析:

终止条件:节点为空或者它的下一个节点为空
返回值:返回给上一级已经反转完成的链表
本级应该做什么:反转后面的节点,并且将当前节点插入到它后面节点的后面

class Solution {
    public ListNode reverseList(ListNode head) {
    	//终止条件
        if(head == null || head.next == null){
            return head;
        }
        //将后面的节点反转
        ListNode next = reverseList(head.next);
        //将当前节点插入它后面的节点
        head.next.next = head;
        //防止产生循环链表
        head.next = null;
        return next;
    }
}

记得上学时候数据结构老师告诉我们,关于链表的操作,一定要在纸上把过程先画出来,再写程序。不过这次画翻车了,这里记录下我进入的误区,因为head.next.next = head这行让我想了好久,画图表示一下当时我的理解:

在这里插入图片描述
假设当前传入的是2节点,假设它后面已经反转完成,所以画出了上面的图,而我一直再想怎么让5去指向2,想着想着就迷路了。这里就是一个思维误区了,下意识的以为2就是已经指向了5,但是实际应该是下面这样:

在这里插入图片描述
实际上2指向的是3节点,因为2的next并没有变啊,这样再看head.next.next = head是不是就瞬间明白了。而head.next = null;也懂了吧,就是防止3指向2,2又指向3。

在这里插入图片描述

迭代

一般来说递归能够实现的迭代也可以,可以使用双指针,也可以使用栈。先说双指针:

考虑遍历链表,并在访问各节点时修改 next 引用指向:

class Solution {
    public ListNode reverseList(ListNode head) {
        //记录前一个节点用的
        ListNode pre = null;
        //从头节点开始
        ListNode cur = head;
        //临时记录下一个节点
        ListNode temp = null;
        while(cur != null){
        	//记录下一个节点
            temp = cur.next;
            //将当前节点指向上前节点,实现反转
            cur.next = pre;
            //将当前节点交给pre,为下一次的循环做准备
            pre = cur;
            //移动到下一个节点
            cur = temp;
        }
        return pre;
    }
}

具体思路已经加到注释上了,不再赘述了,看下时间:

在这里插入图片描述
栈是一种先进后出的数据结构,下面是使用栈来实现反转,思路就是遍历保存到栈中,再遍历栈,生成新的链表:

class Solution {
    public ListNode reverseList(ListNode head) {
        Stack<Integer> stack = new Stack<>();
        while(head != null){
            stack.add(head.val);
            head = head.next;
        }
        ListNode temp = new ListNode(0),result = temp;
        while(stack.size() != 0){
            temp.next = new ListNode(stack.pop());
            temp = temp.next;
        }
        return result.next;
    }
}

栈没啥好说的大家随便看看,果然耗时最长。

在这里插入图片描述
记录完毕。
岁月流逝忽已暮,皆因惆怅不知路。
2021年加油吧,打工人!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值