【JavaScript 算法】-- 链表问题整理和解决思路总结

本文深入探讨了链表数据结构,包括其与数组的区别、结点创建、常见链表操作如合并、删除重复元素、链表反转以及链表环形检测的解题策略。通过实例解析了LeetCode上的相关真题,总结了解决链表问题的关键技巧,如使用dummy节点、双指针法和标志位法。
摘要由CSDN通过智能技术生成

一、链表

链表和数组相似,它们都是有序的列表、都是线性结构(有且仅有一个前驱、有且仅有一个后继)。不同点在于,链表中,数据单位的名称叫做“结点”,而结点和结点的分布,在内存中可以是离散的。

在链表中,每一个结点的结构都包括了两部分的内容:数据域和指针域。JS 中的链表,是以嵌套的对象的形式来实现的:

{
    // 数据域
    val: 1,
    // 指针域,指向下一个结点
    next: {
        val:2,
        next: ...
    }
}  

大概是这个样子:

二、链表结点的创建

创建链表结点,咱们需要一个构造函数,大概是这种形式:

function ListNode(val) {
    this.val = val;
    this.next = null;
}

const node = new ListNode(1)  
node.next = new ListNode(2)

三、链表的考点

记住在处理链表问题时:处理链表的本质,是处理链表结点之间的指针关系,也就是next指针

链表的考点一般分为以下三类:

  • 链表的处理:合并删除等(删除是重点中的重点!)
  • 链表的反转及其衍生题目
  • 链表成环问题及其衍生题目

1、合并或删除问题

合成问题:

真题描述:将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。 (leetcode  21)

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} l1
 * @param {ListNode} l2
 * @return {ListNode}
 */
var mergeTwoLists = function (l1, l2) {
    let node = new ListNode();
    let cur = node;
    while (l1 && l2) {
        if(l1.val <= l2.val){
            cur.next = l1;
            l1 = l1.next
        } else {
            cur.next = l2;
            l2 = l2.next;
        }
        cur = cur.next
    }
    cur.next = l1 !== null ? l1:l2;
    // 返回node.text 很关键
    return node.next
};

删除问题:

真题描述:给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。(leetcode 83)

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
// 输入:head = [1,1,2]
// 输出:[1,2]
var deleteDuplicates = function (head) {
    let cur = head
    while (cur && cur.next) {
        if (cur.val === cur.next.val) {
            cur.next = cur.next.next
        } else {
            cur = cur.next
        }
    }
    return cur.next
};

真题描述:给定一个排序链表,删除所有含有重复数字的结点,只保留原始链表中 没有重复出现的数字。(leetcode 82)

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {ListNode}
 */
const deleteDuplicates = function(head) {
    // 极端情况:0个或1个结点,则不会重复,直接返回
    if(!head || !head.next) {
        return head
    }
    let dummy = new ListNode() 
    dummy.next = head   
    let cur = dummy 
    while(cur.next && cur.next.next) {
        if(cur.next.val === cur.next.next.val) {
            let val = cur.next.val
            while(cur.next && cur.next.val===val) {
                cur.next = cur.next.next 
            }
        } else {
            cur = cur.next
        }
    }
    // 返回链表的起始结点
    return dummy.next;
};

2、链表反转问题

一般情况下这类问题的关键时通过双指针法来解决(答案稍微有点复杂,我就不写自己答案了)

提示:第一个问题是一个经典的使用快慢指针来解决的链表问题,可以通过这个问题学习双指针。接下来再来带着双指针的思路来解决反转问题

真题描述:给定一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。(leetcode 22)

真题描述:定义一个函数,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。(完全反转  leetcode  203)

真题描述:反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。(局部反转 leetcode 92)

3、链表成环问题

真题描述:给定一个链表,判断链表中是否有环。(判断是否成环  leetcode 141)

提示:解决这类问题的核心是设 标识(flag),两道题的思路都是一样的

/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function (head) {
    while (head) {
        if (head.flag) {
            return true
        } else {

            head.flag = true;
            head = head.next
        }
    }
    return false
};

真题描述:给定一个链表,返回链表开始入环的第一个结点。 如果链表无环,则返回 null。(定位环启动 leetcode 142)

四、解决思路总结 !!!

  1. 链表问题(一般都是使用 while循环遍历
  2. 如果题目输入是整个链表时,对于这种问题。它的链路循环,一般是通过创建一个新的指向头部的节点(dummy节点),以它为头开始循环。dummy节点可以帮我们处理掉头结点为空的边界问题,帮助我们简化解题过程
  3. 对于链表反转问题 -- 通过双指针或者三指针的方式
  4. 对于链表成环问题 -- 通过设立标识(flag)的方式来解决

带着这个思路解决链表问题,一般的题目应该都能解决

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值