[路飞]_前端算法第八弹-206. 反转链表

103 阅读3分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

今天学习的是翻转链表相关的练习,本文一共有三道翻转链表的题目,由浅至深,和大家一起探讨遇到链表翻转问题的思路,如有问题,希望批评指正。

第一题是简单题,单纯的翻转链表。

206. 反转链表

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

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

这道题难度不大,只需要将当前节点指向前一个节点即可,由于节点无法直接引用前一个节点,所以我们需要提前创建一个空间,暂存前一个节点,更改引用,并且暂存其后一个节点,再向前引用

这是第一种迭代方法:

var reverseList = function (head) {
	// 创建额外空间
	let prev = null;
	// 遍历链表
	while (head) {
	    // 暂存有一个节点
	    let next = head.next;
	    // 当前节点向前指引
	    head.next = prev;
	    // 当前节点赋值给新空间
	    prev = head;
	    // 当前节点指向下一个结点
	    head = next
	}
	// 循环完毕,返回新空间第一个节点
	return prev
};

如上题中,1→2→3→4→5,while中第一次循环

next = 2→3→4→5,head = 1→null,prev = 1→null,head = 2→3→4→5

第二次循环

next = 3→4→5,head = 2→prev,prev = head = 2→1→null,head = 3→4→5

...

最后prev = 5→4→3→2→1。

一般情况下,如果有迭代方法,对应的就是递归方法,递归方法相比于迭代方法,就稍显复杂。递归的关键在于反向,从最后一个节点,向前查找,向前翻转。

n1->n2->n3->...->nk->n(k+1)->...->nm->null;
假定n(k+1)->...->nm已经反转
n1->n2->n3->...->nk->n(k+1)<-...<-nm;
假定n(k+1)->...->nm已经反转,此时需要将,n(k+1)->nk,
即,nk.next.next = nk,
但当翻转到n1时,我们需要将n1->null,否则将形成闭环。


var reverseList = function(head) {
    // 当遍历到最后时,代表翻转结束
    if (head == null || head.next == null) {
        return head;
    }
    // 翻转遍历,直到找到最后一项开始反转
    const newHead = reverseList(head.next);
    // 将翻转的前一项指向自己
    head.next.next = head;
    // 自己指向空
    head.next = null;
    // 返回当前已翻转链表
    return newHead;
};

原链表1→2→3→4→5

递归四次后,head = 5→null, return head

此时newHead = 5→null,head = 4→5→null ,head.next.next = head

⇒4→5→4,head.next = null ⇒4→null ⇒newHead ⇒ 5→4→null

返回第三次递归,此时 newHead ⇒ 5→4→null,

第三次递归的head ⇒ 3→4→null,因为此时3依旧指向4,4的指向已经变了

head.next.next = head⇒4→3,head.next = null⇒3→null,

由于newHead⇒5→4→null,4的指向发生变化,newHead⇒5→4→3→null

返回第二次递归...一次类推,最后,newHead ⇒5→4→3→2→1→null

下面是我的另一种解法,索性我就叫赋值法吧,就是每一次遍历都赋一个新值。

var reverseList = function (head) {
    // 简历一个新的赋值空间
    let link = null;
    // 遍历head
    while(head){
        // 每一次都赋值一个新的空间,把当前head的val,赋值给新的val,
        // 把上一个节点,转赋值给下一个结点
        link = new ListNode(head.val,ans)
        head = head.next
    }
    return link;
};

按照这个方法,

第一次循环:head ⇒2→3→4→5→null ,link⇒ 1→null

第二次循环:head ⇒3→4→5→null ,link ⇒ 2→1→null

...

直到head遍历完成,把val都赋值给了link。

上面就是链表反转的三种方法,如果有更多的解决方法,可以在留言区写出来。