链表算法题分析 - js篇(1)

893 阅读2分钟

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

定义

啥是链表??链表表示使用指针将一连串分散的内存块串联起来的数据结构。

js中没有链表的定义,也没有指针的定义,我们将指针想象成引用就可以。

常用的链表有三种:单链表,双向链表,循环链表。

image.png

image.png

image.png

具体定义我们不多赘述,网上资料很多,咱们直接做题~

如何实现一个链表

let data = [];
let next = [];

function add(cur, p, v) {
    next[p] = next[cur]
    next[cur] = p;
    data[p] = v;
}

function main() {
    const head = 100;
    add(head, 1, 10)
    add(1, 2, 20)
    add(2, 3, 30)
    add(3, 4, 40)

    add(2, 5, 50)
    data[head] = 1
    let p = head;
    while(p) {
        console.log('->', data[p])
        p = next[p]
    }
}

main()

算法题

剑指 Offer 06. 从尾到头打印链表

image.png

题解: 最简单的办法是将链表数据以此unshift()塞入数组中。

我使用先翻转链表的方式(纯粹为了顺便试试翻转链表)

var reversePrint = function(head) {
    const arr = [];
    let dump = null;
    let curIdx = head;
    while(curIdx) {
        const next = curIdx.next;
        curIdx.next = dump;
        dump = curIdx;
        curIdx = next;
    }
    let idx = dump;
    while(idx) {
        arr.push(idx.val)
        idx = idx.next;
    }
    return arr
};

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

image.png

题解:使用快慢指针,快指针走K个数,然后快慢指针同时出发,当快指针指向null时慢指针指向节点的值就是所求值

var kthToLast = function(head, k) {
    let slow = head, fast = head;
    while(k) {
        fast = fast.next;
        k--;
    }
    while(fast) {
        slow = slow.next;
        fast = fast.next;
    }
    return slow.val;
};

141. 环形链表

image.png

image.png

题解:快慢指针查找,快指针每次走两步,慢指针每次走一步,若有环,必定相交,否则会遍历完链表。

var hasCycle = function(head) {
    let slow = head;
    let fast = head;
    while (fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow === fast) {
            return true
        }         
    }
    return false
};

面试题 02.07. 链表相交

题解: 若两链表相交,A链表走完走从B链表的头节点开始走,B链表走完从A链表头开始走,必定会在相交处相遇。a+c+b = a+c+b。

若不相交,a+b = b+a,没有公共的C,两边都指向null。

循环跳出的条件是两节点相等,即相遇或不相交各走一遍a,b。

需要注意的是必须走下null节点,不然不相交的两个链表会永远不会相等,就进入死循环。

var getIntersectionNode = function(headA, headB) {
    let l = headA, r = headB;
    while(l !== r) {
        l = l ? l.next : headB;
        r = r ? r.next : headA;
    }
    return l;
};