JavaScript刷LeetCode拿offer-高频链表题

首先需要了解链表的概念

先把 next 记录下来

无论是插入,删除,还是翻转等等操作,先把 next 指针用临时变量保存起来,这可以解决 90% 重组链表中指向出错的问题,

如果不知道什么时候需要用到守卫,那就都用

类型守卫 emptyNode 是创建的一个空的节点,并将它连接到 head 节点之前,无论链表进行任何操作, emptyNode 都指向最后的头节点,是一个很实用的小方法,如果不知道什么时候用,什么时候不用,那就先都用起来吧;

其实在大部分时候,emptyNode 都是能用上,即便只是遍历查找值,用上作为第 0 个值,当要找第 k 个值的时候,也不需要再判空处理啊

头节点判空处理

如果懒或者经常忘记看题目的给定条件,头节点判空都做起来,对于一些翻转题,还得将 head.next 也判断起来;

到熟练之后,其实可以不做,但是用上最多就浪费一段代码,也还好

画图,画图,画图

遇事不决的时候,还是要画图,一步一步的连起来,总能够捋清楚的,画图是链表的关键所在

链表的节点是保存在内存中的一个数据结构

链表是一个特定的数据结构,在 JS 中可以表现为一个拥有 val 和 next 属性的对象,所以遇到形如交换两个链表节点的时候,千万不能交换两个链表的 val 值,虽然 LC 有一些题是可以过,但是实际上是不合理的,而且一旦出现这种思想,对于一些经典题 160. 相交链表 就会理解不了;

记住,链表是一个数据结构,不是一个值,可以类比成一个对象,交换链表比如不是简单交换值;

都是中等题

这里选的都是按照 LC 火热排序,中等难度的题,感觉纯链表学习做特别难没太大必要,毕竟我只是一个菜鸟,大佬们可以自由选择,一起 💪,进大厂;

具体题解

剑指 Offer 24. 反转链表

分析

  1. 注意保护好下一个节点 next
  2. 然后不断维护上一个节点和当前阶段,不断往后推即可
var reverseList = function (head) {
   
  let prev = null;
  while (head) {
   
    const next = head.next;
    head.next = prev;
    prev = head;
    head = next;
  }
  return prev;
};

面试题 02.05. 链表求和

分析

  1. 这题是头对齐,445. 两数相加 II 是尾对齐,对于头对齐而已,链表比较容易进行进位后直接构建成链表。
  2. 当两个链表都存在的时候,共有三个值需要相加,分别是 l1.val + l2.val + isUpper
  3. 当其中一个链表走完了,就只剩下一个链表和 isUpper, 需要注意的是,我们不知道哪个链表更长,所以需要判断一下
  4. 链表遍历完了,还要判断一下 isUpper 是否还有,还有就得再进一个节点
  5. 反转的数据结构就是 O(n+m)
/** * @分析 * 1. 这里的返回值是按照十进制计算后的 `链表` */
var addTwoNumbers = function (l1, l2) {
   
  const emptyNode = new ListNode();
  let current = emptyNode;
  let isUpper = 0; // 是否满10,为后面的位+1
  while (l1 && l2) {
   
    let sum = l1.val + l2.val + isUpper;
    if (sum >= 10) {
   
      isUpper = 1;
      sum = sum % 10;
    } else {
   
      isUpper = 0;
    }
    current.next = new ListNode(sum);
    current = current.next;
    l1 = l1.next;
    l2 = l2.next;
  }
  let l3 = l1 || l2; //剩余的那个链表
  while (l3) {
   
    let sum = l3.val + isUpper;
    if (sum >= 10) {
   
      isUpper = 1;
      sum = sum % 10;
    } else {
   
      isUpper = 0;
    }
    current.next = new ListNode(sum);
    current = current.next;
    l3 = l3.next;
  }
  if (isUpper) {
   
    // 遍历完了,如果还有进位
    current.next = new ListNode(isUpper);
    current = current.next;
  }
  return emptyNode.next;
};

参考视频:传送门

445. 两数相加 II

分析

  1. 这题是尾对齐,面试题 02.05. 链表求和 是头对齐,对于头对齐而已,链表比较容易进行进位后直接构建成链表。
  2. 所以这题先把两个链表反转,然后用面试题 02.05. 链表求和 方式组合完,再反转回去即可
  3. 当然我们可以用数组或其他额外的数据结构来保存两数之和,最后再统一处理,但是因为是链表专题,所以除了不用额外的数据结构处理
  4. 反转的数据结构就是 O(n+m)
var addTwoNumbers = function (l1, l2) {
   
  const emptyNode = (current = new ListNode());
  // 翻转量个链表,让他们头节点对齐
  let temp1 = reverseList(l1);
  let temp2 = reverseList(l2);

  let isUpper = 0; // 是否满10,为后面的位+1
  while (temp1 && temp2) {
   
    let sum = temp1.val + temp2.val + isUpper;
    if (sum >= 10) {
   
      isUpper = 1;
      sum = sum % 10;
    } else {
   
      isUpper = 0;
    }
    current.next = new ListNode(sum);
    current = current.next;
    temp1 = temp1.next;
    temp2 = temp2.next;
  }
  let l3 = temp1 || temp2; //剩余的那个链表
  while (l3) {
   
    let sum = l3.val + isUpper;
    if (sum >= 10) {
   
      isUpper = 1;
      sum = sum % 10;
    } else {
   
      isUpper = 0;
    }
    current.next = new ListNode(sum);
    current = current.next;
    l3 = l3.next;
  }
  if (isUpper) {
   
    // 遍历完了,如果还有进位
    current.next = new ListNode(isUpper);
    current = current.next;
  }

  return reverseList(emptyNode.next);
};

// 反转链表
var reverseList = function (head) {
   
  let prev = null;
  while (head) {
   
    const next = head.next;
    head.next = prev;
    prev = head;
    head = next;
  }
  return prev;
};

61. 旋转链表

分析:

  1. 从链表尾部阶段 k 长度,拼在前面即可 – 其中 k = (K %len) ,如果移动了 len 的位置,就又回到了原来的位置了
  2. 需要注意的是一些边界条件,但是这里直接定义 prev 为安全守卫,一切需要保存或者拼接的节点都应用 prev 来处理,就可以避免 cur 为 null 的时候无法获取 next 指针的尴尬,因为 cur 是实际走的指针,prev 只是一个安全守卫,它始终是存在的。
  3. 时间复杂度O(N)
var rotateRight = function (head, k) {
   
  // 先求链表的长度
  let len = 0,
    tempNode = head;
  while (tempNode) {
   
    len++;
    tempNode = tempNode.next;
  }
  // 需要位移 size 到头节点
  let size = len - (k % len);
  let prev = new ListNode();
  prev.next = head;
  let cur = head;
  while (size
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值