LC.206.反转链表

题目描述

在这里插入图片描述

解法一:借助外部空间

  先申请一个集合,比如ArrayList,通过对链表的遍历将其节点进行存储记录,之后再对集合进行倒序循环,同时指定其指针域为前一个节点,这样就相当于重构链表。当然,利用其他集合,比如栈也是可以的,只不过使用到的方法不同。

public ListNode reverseList(ListNode head) {
    if(head == null)
         return null;
     List<ListNode> res = new ArrayList<>();
     ListNode cur = head;
     while(cur != null){
         res.add(cur);
         cur = cur.next;
     }
     head = res.get(res.size() - 1);
     for(int i =  res.size() - 1;i >= 0;i--){
         if(i == 0){
             res.get(i).next = null;
             break;
         }
         res.get(i).next = res.get(i-1);
     }
     return head;
 }

小结:
 该解法难免显得简单了点,并且你在面试中这么做的话,面试官 100% 会追问是否有更优的方式,比如不用外部空间。

解法二:双指针迭代

  双指针技巧是解决链表问题经常用到的方法,它可以在给定的链表上原地解决问题,也是我优先考虑到的方法。
  首先,通过对反转结果分析,将节点指针方向进行转变就可以解决问题。拆解问题的话,就是需要两个指针指向两个相邻的节点,一个作前指针,一个作后指针,将后指针的指针域指向前指针,接着将两个指针均后移一位,循环上述操作,直到不满足循环条件。
  步骤如下:

		1. 指针初始化:pre = null,cur = head;
		2. 记录当前节点的下一个节点
			tmp = cur.next;
			然后将当前节点指向pre
			cur.next = pre;
			pre和cur节点都前进一位
			pre = cur;
			cur = tmp;
		3. 当cur != null 时,一直循环操作2
		4. 最终的pre即为所求结果,返回即可。
public ListNode reverseList(ListNode head) {
     ListNode cur = head;
     ListNode prev = null;
     while(cur != null){
         ListNode temp = cur.next;
         cur.next = prev;
         prev = cur;
         cur = temp;
     }
     return prev;
 }

解法三:递归
  下面介绍我一开始所想到的递归思路,既然解法二在原地实现了解题,那么稍加改造是否就能改写成递归呢?
  我通过函数传递两个参数即两个节点,让其做指定操作,操作完成后再将之后符合条件的节点传进参数,进行下一次操作,直至递归结束。

class Solution {
    public ListNode reverseList(ListNode head) {
       return reverse(null,head);
    }

    public ListNode reverse(ListNode pre,ListNode cur){
        if(cur == null)
            return pre;
        ListNode temp = cur.next;
        cur.next = pre;
        pre = cur;
        return reverse(pre,temp);
    }
}

小结:
 这种递归像是对解法二循环的改造,虽然比较好理解,但是还是感觉不是纯正的递归解法(可能是,我所能想出来的我就觉得比较 low 吧,哈哈哈哈~)。

解法四:递归
  接下来介绍一种比较难理解的递归解法,步骤如下:
  首先确定递归终止条件:当前节点或者下一个节点 == null 即 head == null || head.next == null,此时返回头节点head;
  接下来实现递归体:改变节点的指向,也就是 head 的下一个节点指向 head 即 head.next.next = head;
  最后确定返回值:每层递归函数都返回cur,也就是最后一个节点,也可以理解为已经反转好的那一部分链表。

public ListNode reverseList(ListNode head) {
	if(head==null || head.next==null) {
		return head;
	}
	ListNode cur = reverseList(head.next);
	head.next.next = head;
	head.next = null;
	return cur;
}

小结:
 搞清楚这个递归代码后,我才恍然大悟,这不就是二叉树的后序遍历嘛(对节点操作的代码置于遍历代码后)。而这段递归代码就是先对链表进行遍历,遍历到最后一个节点时开始改变节点的指向,并返回已反转成功的部分链表的头节点。
 那么解法三的递归不就是前序遍历嘛,先对已遍历过的节点改变其节点的指向,接下来进行下一次的遍历,直到递归终止。
 反观该递归过程其实并不是很复杂,只不过是一时昏头,突然忘了递归函数的执行过程,还有对这句代码 ListNode cur = reverseList(head.next); 理解错误。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值