链表相关算法复习

206 阅读4分钟

文章简要概述

  • 本篇主要是复习链表相关的内容,部分算法题之前可能写过,这里进行回顾,进一步加深印象。刷题不是目的,目的是理解与掌握

  • 本文一共有4道题,主要介绍leetcode中面试题 02.02. 返回倒数第 k 个节点剑指 Offer 22. 链表中倒数第k个节点剑指 Offer 35. 复杂链表的复制面试题 02.03. 删除中间节点的解题思路。

与链表相关算法

面试题 02.02. 返回倒数第 k 个节点

面试题 02.02. 返回倒数第 k 个节点 -- leetcode

题目大意:

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

注意: 本题相对原题稍作改动

示例

输入: 1->2->3->4->5 和 k = 2

输出: 4

解题思路:

  • 这道题和之前我们之前做的一道链表题基本一致
  • 解题方法可以用链表长度 - k + 1,得到移动的步数,然后正着从链表头部移动到对应位置
  • 本题采用链表解题的常用方式快慢指针,让快指针与慢指针之间间隔k,然后同时移动快慢指针,当快指针到达链表尾部时,慢指针所在位置就是倒数第k个节点。
  • 本题解题方法还有很多,递归和栈也都能解决,感兴趣可以去leetcode上寻找其他解题技巧。

代码:

/**
 * @param {ListNode} head
 * @param {number} k
 * @return {number}
 */
function kthToLast (head, k) {
   let first = head;
   let second = head;
   while(k > 0) {
       first = first.next;
       k--;
   }
   while(first) {
       first = first.next;
       second = second.next;
   }
   return second.val;
};

剑指 Offer 22. 链表中倒数第k个节点

剑指 Offer 22. 链表中倒数第k个节点 -- leetcode

题目大意:

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。这个链表的倒数第 3 个节点是值为 4 的节点。

示例:

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

解题思路:

  • 本题与上一题的解题思路很像,都属于找第k个节点的位置
  • 上面的说方法基本都可以实现,这里用链表长度 - k 去得到答案

代码:

/**
 * @param {ListNode} head
 * @param {number} k
 * @return {ListNode}
 */
function getKthFromEnd(head, k) {
   let first = head;
   let l = 0
   while(first) {
       first = first.next;
       l++;
   }
   let i = 0;
   while(i < l-k) {
       head = head.next;
       i++;
   }
   return head;
};

剑指 Offer 35. 复杂链表的复制

剑指 Offer 35. 复杂链表的复制 -- leetcode

题目大意:

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

示例:

e1.png

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]

输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

解题思路:

  • 本题和之前写的链表三中的复制带随机指针的链表的题目是一样的,具体解题思路可以看前面的文章。这里是加强练习,不做具体解析

代码:

/**
 * @param {Node} head
 * @return {Node}
 */
function copyRandomList (head) {
    if (!head) return head;
    let node = head;
    while(node) {
        const copyNode = new Node(node.val, node.next, null);
        node.next = copyNode;
        node = copyNode.next;
    }
    node = head;
    while(node) {
        const copyNode = node.next;
        copyNode.random = node.random !== null ? node.random.next : null;
        node = copyNode.next;
    }
    const res = head.next;
    node = head;
    while(node) {
        const copyNode = node.next;
        node.next = node.next.next;
        copyNode.next = copyNode.next !== null ? copyNode.next.next : null;
        node = node.next;
    }
    return res;
};

面试题 02.03. 删除中间节点

面试题 02.03. 删除中间节点 -- leetcode

题目大意:

若链表中的某个节点,既不是链表头节点,也不是链表尾节点,则称其为该链表的「中间节点」。

假定已知链表的某一个中间节点,请实现一种算法,将该节点从链表中删除。

例如,传入节点 c(位于单向链表 a->b->c->d->e->f 中),将其删除后,剩余链表为 a->b->d->e->f

示例:

输入: 节点 5 (位于单向链表 4->5->1->9 中)

输出: 不返回任何数据,从链表中删除传入的节点 5,使链表变为 4->1->9

解题思路:

  • 本题的代码超乎想象的短。
  • 题意解释一下:一个给定的链表,然后传进来链表中某一个节点,然后删除传进来的节点,原链表其他不变。
  • 解题方法,将传进来的节点内容替换成下一个节点的内容,然后next指针指向下一位的下一位节点,等于删除自身节点了。感觉这个操作还是比较骚的。

代码:

/**
 * @param {ListNode} node
 * @return {void} Do not return anything, modify node in-place instead.
 */
var deleteNode = function(node) {
    node.val = node.next.val;
    node.next = node.next.next;
};

结束语

数据结构与算法相关的练习题会持续输出,一起来学习,持续关注。当前是链表复习部分。后期还会有其他类型的数据结构,题目来源于leetcode。

往期文章:

数据结构与算法-栈一             数据结构与算法-栈二             数据结构与算法-队列一             数据结构与算法-队列二

数据结构与算法-链表一         数据结构与算法-链表二         数据结构与算法-链表三

有兴趣的可以一起来刷题,感谢点赞👍 , 关注!