开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
前言
本系列文章主要会总结一些常见的算法题目以及算法的易错点,难点,以及一些万用的公式,并且结合实际的 Leetcode 题目来进行加深理解以及实际应用,算法这种东西,属于是一到用时方恨少的类型,在平时总结一些常见的简单算法,经常磨练自己的算法思维,对于日常的开发还是能有不少的帮助的。
- 今天来介绍一下反转链表的操作
什么是反转链表
下面是一个正常的链表,里面有三个元素,最后指向null
进行翻回以后,应该变为:
头结点变成了 值为 3 的结点,尾结点变成了值为 1 的结点,这就是反转链表的一个大概操作。
假如说原理的对象为 :
const node = {
val:1,
next: {
val: 2,
next: {
val: 3,
next: null,
}
}
}
那么反转过后就会变成
const node = {
val: 3,
next: {
val: 2,
next: {
val: 1,
next: null,
}
}
}
Leetcode 206.反转链表
题目的解法存在双指针解法以及递归解法,双指针的解法会比较简单,所以这里先优先介绍双指针的解法。
双指针
看图,首先我们需要定义两个指针,其中一个cur指针,一开始指向头结点,还有一个pre指针,指向null,然后进行反转,头结点在反转过后一定是指向null的,所以第一次反转让cur改变指向,指向pre也就是null,然后cur指针向下移位,并且pre也向下以为,cur移动到值为2的结点处,pre移动到值为1的结点处,然后在让cur指向pre,也就是第二个结点的next就变为第一个结点,一直遍历下去,直到结束,也就完成了反转。
通过图也能够看出来,遍历的结束时刻为 cur 指针指向 null 的时候
需要注意的是,在cur要指向结点二的时候,上图中也能够看的出来,因为结点一的next已经指向null了那么cur要如何去找到结点二呢,它们之前原本存在的联系next已经被修改了,所以说,我们需要一个临时存储结点的参数,在一开始的时候,优先把当前结点的next结点保存下来,这样就可以在cur指向pre之后,为cur提供下一个遍历值。
那么综上所述,反转链表的双指针写法就已经可以很简单的完成了。
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function reverseList(head: ListNode | null): ListNode | null {
let pre: ListNode | null = null
let cur: ListNode | null = head
let tem: ListNode | null
while (cur) {
tem = cur.next;
cur.next = pre;
pre = cur;
cur = tem;
}
return pre;
};
递归
递归的思路其实和双指针是完全一样的,只不过是把双指针的比较容易看懂的写法,给改成了递归,我们可以根据上面的双指针的实现过程来一步步实现递归写法。
首先递归就需要一个递归函数,我们定义为 reverse,既然要在这个递归函数里面反转链表,那么它也需要转入cur和pre两个指针,在上面的定义当中,cur的初始值为head头结点,pre为null。
那么我们就定义好了递归的初始传入参数
function reverseList(head: ListNode | null): ListNode | null {
const reverse = (cur, pre) => {
...
}
return reverse(head,null)
};
并且前面的遍历结束条件为cur结点为null的时候,那么递归中的结束条件就也可以写出来了。
然后也是一样在递归当中去保存临时结点,并且进行方向改变。
function reverseList(head: ListNode | null): ListNode | null {
const reverse = (cur, pre) => {
if (cur === null) return pre;
let tem: ListNode | null = cur.next;
cur.next = pre;
pre = cur;
cur = tem;
return reverse(cur, pre);
}
return reverse(head,null)
};
这道到这里结束了,简单的把上面的双指针写法改为了递归,先理解双指针的写法思路再照着写递归会发现很简单。