🔥leetcode链表算法的通用解决思路

前言

最近在刷 leetcode 针对链表的算法题。在刷完 面试经典 150 题LeetCode 热题 100 中链表类型的算法题目之后,发现针对链表相关的算法题可以总结出通用思路进行解题。且将总结的思路用在后续刷链表的算法题时大概率场景下都可以通过。目前已经将面试经典 150 题LeetCode 热题 100 的链表类目的算法题都已经刷完了。

  1. 面试经典 150 题 链表
  2. LeetCode 热题 100 链表

解题思路

针对链表的数据结构 JavaScript 没有直接可用的数据类型进行表示,因此也就不存在对应的方法和操作可以直接使用。但是类比于链表的数据结构 JavaScript 的数组可以模拟,链表的数据单元 ListNode 包含一个 value 内容和一个 next 指针指向下一个节点,类比到 JavaScript Array 数组中每一项值就可以对应 value 而数组的索引 index 也恰可以表示这种指针的关系。因此换一种思路考虑,如果将链表转换成数组,而 JavaScript 针对 Array 这种基本数据类型提供了丰富的 API 可以使用。由此,我们将链表转换成数组进行算法求解,然后在将数组转换成链表做结果返回即可。解题思路可以总结成如下的步骤:

  1. 针对链表为 null 边缘场景直接返回。
typescript 复制代码
if (head === null) return null;
  1. 将链表转换为数组。
typescript 复制代码
cosnt nodes: ListNode[] = [];
while (head) {
    nodes.push(head);
    head = head.next;
}
  1. 针对题目描述运用数组相关的 Api 进行算法求解
typescript 复制代码
这里使用数组一系列的Api进行算法求解
  1. 将数组结构转换成链表并返回结果
typescript 复制代码
nums: ListNode[] = [];
for (let i = 0; i < nums.length; i++) {
    nums[i].next = i === nums.length - 1 ? null : nums[i + 1];
}
return nums[0];

总体思路如上,但针对不同的题目可能四个步骤并不需要都执行仅需要其中的几个步骤即可解题,需要针对不同的题目灵活运用上述步骤。总体思路就是将链表转换成数组熟练组合数组 Api 进行算法求解。

题目示例

这里我们从简单、中等、困难找三个 leetcode 上的链表算法题运用上面的步骤进行求解。

  1. 234. 回文链表
typescript 复制代码
描述:
给你一个单链表的头节点 `head` ,请你判断该链表是否为回文链表。如果是,返回 `true` ;否则,返回 `false` 。

示例:
输入: head = [1,2,2,1]
输出: true

约束:
1. 链表中节点数目在范围`[1, 105]` 内
2. `0 <= Node.val <= 9`

解题:
function isPalindrome(head: ListNode | null): boolean {
    const listVal = [];
    // 将链表转换成数组
    while (head) {
        listVal.push(head.val);
        head = head.next;
    }
    // 运用数组的 Api 进行解题
    return listVal.join('') === [...listVal].reverse().join('');
};

这是一道难度为简单的链表算法题,我们仅运用了上述总结的步骤 2 和 3 即完成了求解。 2. 148. 排序链表

typescript 复制代码
描述:
给你链表的头结点 `head` ,请将其按 `升序` 排列并返回 `排序后的链表` 。

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

约束:
1. 链表中节点的数目在范围 `[0, 5 * 104]` 内
2. `-105 <= Node.val <= 105`

解题:
function sortList(head: ListNode | null): ListNode | null {
    // 针对为 null 边缘场景直接返回
    if (head === null) return null;
    // 链表转换为数组
    const list: ListNode[] = [];
    while (head) {
        list.push(head);
        head = head.next;
    }
    // 进行算法求解,即是利用数组的 sort 方法进行排序
    list.sort((a, b) => a.val - b.val);
    // 将数组转换成链表并返回结果
    for (const [index, value] of list.entries()) {
        index === list.length - 1 ? value.next = null : value.next = list[index + 1];
    }

    return list[0];
};

这是一道难度为中等的链表算法题,我们充分运用了上述总结的步骤完成解题。 3. 25. K 个一组翻转链表

typescript 复制代码
描述:
给你链表的头节点 `head` ,每 `k` 个节点一组进行翻转,请你返回修改后的链表。

`k` 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 `k` 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

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

约束:
1. 链表中的节点数目为 `n`
2. `1 <= k <= n <= 5000`
3. `0 <= Node.val <= 1000`

解题:
function reverseKGroup(head: ListNode | null, k: number): ListNode | null {
    // 针对为 null 边缘场景直接返回
    if (head === null) return null;
    // 链表转换为数组
    const list: ListNode[] = [];
    while (head) {
        list.push(head);
        head = head.next;
    }
    // 进行算法求解
    const nums: ListNode[] = [];
    for (let i = 0; i < list.length; i += k) {
        const numbers = list.slice(i, Math.min(k + i, list.length));
        const len = numbers.length;
        if (len === k) numbers.reverse();
        nums.push(...numbers.flat());
    }
    // 将数组转换成链表并返回结果
    for (let i = 0; i < nums.length; i++) {
        nums[i].next = i === nums.length - 1 ? null : nums[i + 1];
    }
    return nums[0];
};

这是一道难度为困难的链表算法题,我们充分运用了上述总结的步骤也完成了解题。

总结

本文只是针对链表该类型的算法题提供一种可行的通用解决思路,但可能不是最优解,如果有更优解法也欢迎文章下留言讨论。

相关推荐
天宇&嘘月1 小时前
web第三次作业
前端·javascript·css
小王不会写code2 小时前
axios
前端·javascript·axios
尼尔森系3 小时前
排序与算法:希尔排序
c语言·算法·排序算法
发呆的薇薇°3 小时前
vue3 配置@根路径
前端·vue.js
小钊(求职中)3 小时前
Java开发实习面试笔试题(含答案)
java·开发语言·spring boot·spring·面试·tomcat·maven
luckyext3 小时前
HBuilderX中,VUE生成随机数字,vue调用随机数函数
前端·javascript·vue.js·微信小程序·小程序
小小码农(找工作版)3 小时前
JavaScript 前端面试 4(作用域链、this)
前端·javascript·面试
AC使者4 小时前
A. C05.L08.贪心算法入门
算法·贪心算法
冠位观测者4 小时前
【Leetcode 每日一题】624. 数组列表中的最大距离
数据结构·算法·leetcode
前端没钱4 小时前
前端需要学习 Docker 吗?
前端·学习·docker