1.链表常用操作

  1. const a = { val: 'a' };
  2. const b = { val: 'b' };
  3. const c = { val: 'c' };
  4. const d = { val: 'd' };
  5. a.next = b;
  6. b.next = c;
  7. c.next = d;
  8. // 遍历链表
  9. let p = a;
  10. while (p) {
  11. console.log(p.val);
  12. p = p.next;
  13. }
  14. // 插入
  15. const e = { val: 'e' };
  16. c.next = e;
  17. e.next = d;
  18. // 删除
  19. c.next = d;

2.原型链与链表

  • 原型链的本质是链表
  • 原型链上的节点是各种原型对象,比如Function.prototype,Object.prototype…
  • 原型链通过proto属性链接各种原型对象
  • 如果A沿着原型链能找到B.prototype,那么A instanceof B为true
  • 如果A沿着原型链没有找到X属性,那么会沿着原型链找X属性

    3.使用链表指针获取JSON的节点

    ```javascript const json = { a: {
    1. b: {
    2. c: 1
    3. }
    }, d: {
    1. e: 2
    } } const path = [‘a’, ‘b’, ‘c’]

let p = json path.forEach(k => { p = p[k] })

  1. <a name="NOxWC"></a>
  2. # 题目
  3. <a name="uhiVd"></a>
  4. ## 1.删除链表中的节点
  5. 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点。传入函数的唯一参数为 要被删除的节点 。
  6. 现有一个链表 -- head = [4,5,1,9],它可以表示为:
  7. 示例 1:
  8. 输入:head = [4,5,1,9], node = 5<br />输出:[4,1,9]<br />解释:给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.<br />示例 2:
  9. 输入:head = [4,5,1,9], node = 1<br />输出:[4,5,9]<br />解释:给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
  10. 提示:
  11. 链表至少包含两个节点。<br />链表中所有节点的值都是唯一的。<br />给定的节点为非末尾节点并且一定是链表中的一个有效节点。<br />不要从你的函数中返回任何结果。
  12. ```javascript
  13. /**
  14. * Definition for singly-linked list.
  15. * function ListNode(val) {
  16. * this.val = val;
  17. * this.next = null;
  18. * }
  19. */
  20. /**
  21. * @param {ListNode} node
  22. * @return {void} Do not return anything, modify node in-place instead.
  23. */
  24. var deleteNode = function(node) {
  25. // 将被删除元素的val赋值为下个元素的val
  26. node.val = node.next.val
  27. // 删除下个元素
  28. // 将下个元素的指针指向下下个元素
  29. node.next = node.next.next
  30. };

2.反转链表

反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

/**
 * 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}
 */
var reverseList = function(head) {
      // 双指针遍历
      // (1)p1 = {val: 1, next:{val: 2, next: {val: 3, next:{val: 4: next: {val: 5, next: null}}}}}
      // (2)p1 = {val: 2, next: {val: 3, next:{val: 4: next: {val: 5, next: null}}}}
    let p1 = head
    // (1)p2 = null
    // (2)p2 = {val: 1, next: null}
    let p2 = null
    while(p1) { 
          // (1)定义变量存储下个节点的元素,即{val: 2, next: {val: 3, next:{val: 4: next: {val: 5, next: null}}}}
        // (2)定义变量存储下个节点的元素,即{val: 3, next: {val: 4, next:{val: 5: next: null}}}}
          const tmp = p1.next
        // (1)让p1的next指向为p2(空), 即p1={val: 1, next: null}
        // (2)让p1的next指向为p2,即p1={val: 2, next: {val: 1, next: null}}
        p1.next = p2
          // (1)让p2赋值为 p1 即p2={val: 1, next: null}
          // (2)让p2赋值为 p1 即p2={val: 2, next: {val: 1, next: null}}
        p2 = p1
          // (1)让p1变成tmp p1={val: 2, next: {val: 3, next:{val: 4: next: {val: 5, next: null}}}}
          // (2)让p1变成tmp p1={val: 3, next: {val: 4, next:{val: 5: next: null}}}}
        p1 = tmp
    }
      // 返回p2
    return p2
};

3.两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:
image.png

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.
示例 2:

输入:l1 = [0], l2 = [0]
输出:[0]
示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

提示:

  • 每个链表中的节点数在范围 [1, 100] 内
  • 0 <= Node.val <= 9
  • 题目数据保证列表表示的数字不含前导零
/**
 * 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 addTwoNumbers = function(l1, l2) {
      // 创建一个链表
    const l3 = new ListNode(0)
    // 创建执政
    let p1 = l1
    let p2 = l2
    let p3 = l3
    // 定义十位上的进位值
    let carry = 0
    // 遍历链表
    while(p1 || p2) {
          // 取到遍历过程中的值
        const v1 = p1 ? p1.val : 0
        const v2 = p2 ? p2.val : 0
        // 算出来链表的个位相加结果
        const val = v1 + v2 + carry
        // 如果相加结果大于0
        // 就把十位数上的进位值赋值给carry
        carry = Math.floor(val / 10)
          // 给定义的新链表的next赋值一个新的链表
        p3.next = new ListNode(val % 10)
          // 处理两个链表不一样长的情况
          // 如果有值就准备遍历链表的下一个next
        if(p1) p1 = p1.next
        if(p2) p2 = p2.next
          // 指针指向新链表的下一位
        p3 = p3.next
    }
      // 处理新链表最后一位大于10的情况
      // carry有值就说明需要给新链表的next重新赋值一个新的链表
    if(carry) p3.next = new ListNode(carry)
      // 返回新链表的next
    return l3.next

};

4.删除排序链表中的重复元素

给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。

示例 1:
输入: 1->1->2
输出: 1->2
示例 2:

输入: 1->1->2->3->3
输出: 1->2->3

思路:

  • 链表是有序的,所以重复元素一定相邻
  • 遍历链表,如果发现当前元素和下个元素值相同,就删除下个元素
/**
 * 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}
 */
var deleteDuplicates = function(head) {
    let p = head
    // 遍历链表,
    // 但是会出现链表的最后一个元素的next为null,p.next.val会出错
    while(p && p.next) {
          // 如果发现当前元素和下个元素值相同,就删除下个元素
        if(p.val === p.next.val) {
            p.next = p.next.next
        } else {
              // [1,1,1]
              // 如果发现当前元素和下个元素值相同,就不移动指针,直接删除下个元素
            p = p.next
        }

    }
      // 返回头部就行
    return head

};

5.环形链表

给定一个链表,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

如果链表中存在环,则返回 true 。 否则,返回 false 。

进阶:
你能用 O(1)(即,常量)内存解决此问题吗?

示例 1:
image.png
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:
image.png
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:
image.png
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos 为 -1 或者链表中的一个 有效索引 。

思路:

  • 两个人在圆形操场上起点同时起跑,速度快的人会超过速度慢的人一圈
  • 用一快一慢两个指针遍历链表,如果指针相逢,那么链表就有圈,返回true
  • 遍历结束后,还没有相逢就返回false
/**
 * Definition for singly-linked list.
 * function ListNode(val) {
 *     this.val = val;
 *     this.next = null;
 * }
 */

/**
 * @param {ListNode} head
 * @return {boolean}
 */
var hasCycle = function(head) {
      // 定义两个指针
    let p1 = head
    let p2 = head
    // 有环的话,最后一个指针的next指向别的链表元素
    while(p1 && p2 && p2.next) {
          // 一块一慢
        p1 = p1.next
        p2 = p2.next.next
          // 相遇则有环
        if(p1 === p2) {
            return true
        }
    }
    return false

};

6.instanceof的原理,并用代码实现

  • 如果A沿着原型链能找到B.prototype,那么A instanceof B为true
  • 解法:遍历A的原型链,如果能找到B.prototype,返回true,否则返回false ```javascript const instanceOf = (A, B) => { let p = A while (p) {

        // 遍历A的原型链,如果能找到B.prototype,返回true
      if (p === B.prototype) {
          return true
      }
        // 移动指针
      p = p.__proto__
    

    } return false } console.log(instanceOf([], Array));

```

7.场景题

image.png

  • foo.a - value a
  • foo.b - undefined
  • F.a - value a
  • F.b - value b