链表7:超高频面试题——链表反转之一

链表反转是一个出现频率特别高的算法题,笔者过去这些年面试,至少遇到过七八次。其中更夸张的是曾经两天写了三次,上午YY,下午金山云,第二天快手。链表反转在各大高频题排名网站也长期占领前三。比如牛客网上这个No 1 好像已经很久了。

另外很多题目也都要用它来做基础, 例如指定区间反转、链表K个一组翻转。还有一些在内部的某个过程用到了反转,例如两个链表生成相加链表。还有一种是链表排序的,也是需要移动元素之间的指针,难度与此差不多。从今天开始,我们用3篇来专门研究一下这几个问题。第一篇,介绍反转的3种实现方法。第二篇介绍反转的几种变形,第三篇介绍两个链表生成相加的链表。

首先我们看一下题目要求:

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

如下图:

输入:head = [1,2,3,4,5]输出:[5,4,3,2,1]

1.实现

这个题目的关键点是如果再定义一个新链表,会对内存空间造成浪费,比较好的方式是将每个结点的指向都反过来就行,也就是下面这个样子:

那这里的问题就是如何准确的记录并调整指针,代码也不算很复杂:

class Solution {    public ListNode reverseList(ListNode head) {        ListNode prev = null;        ListNode cur = head;        ListNode temp = null;        while (cur != null) {            temp = cur.next;// 保存下一个节点            cur.next = prev;            prev = cur;            cur = temp;        }        return prev;    }}

建议你自己在纸上画画图、想一想,如果能想明白就不必看我下面的解释了。

二、迭代法解析

上面迭代法不算复杂,一般是能想清楚的,但是面试的时候可能会突然卡壳,怎么也搞不清楚指针到底怎么处理。我们可以通过图示来看一下:

在上图中,我们用cur来表示旧链表被访问的位置,pre表示新链表的表头。注意图中箭头方向,cur和pre都是两个表的表头,每移动完一个结点之后,我们必须准确知道两个链表的表头。

cur是需要接到pre的,那该怎么知道其下一个结点5呢?

很显然仅仅靠pre和cur是不够的,我们需要一个temp结点来临时保存cur的下一个指针(图中的5),然后将cur的next指针指向pre,然后将cur赋值给pre,最后将temp再赋值给cur。

上面这个过程不仅严密,而且顺序都不能错。也就是这几行代码:

           temp = cur.next;// 保存下一个节点            cur.next = prev;            prev = cur;            cur = temp;

 三.递归方法实现

这个题目还可以使用递归实现的,但是笔者强烈建议你将前面的方法想清楚,写清楚,最好闭着眼睛就能写,递归的方式就不考虑了。

因为每次cur移动之后仍然是旧的链表表头,prev移动之后仍然是新链表的表头。我们可以使用相同的操作继续处理,所以这里我们可以通过递归来做:

// 递归 class Solution {    public ListNode reverseList(ListNode head) {        return reverse(null, head);    }    private ListNode reverse(ListNode prev, ListNode cur) {        if (cur == null) {            return prev;        }        ListNode temp = null;        temp = cur.next;// 先保存下一个节点        cur.next = prev;// 反转        // 更新prev、cur位置        prev = cur;        cur = temp;        return reverse(prev, cur);    }} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵横千里,捭阖四方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值