返回

剖析链表:JavaScript实现LeetCode中的经典算法挑战

前端

链表的结构与操作

链表是一种线性的数据结构,由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表的优点在于其插入和删除操作的效率很高,但随机访问某个节点的效率较低。

链表划分

链表划分的目的是将链表中的节点根据某个值进行划分,使得所有小于该值的节点都在大于或等于该值的节点之前。

JavaScript实现:

function partition(head, x) {
  // 创建两个虚拟头节点,分别用于存放小于x和大于或等于x的节点
  let lessHead = new ListNode(0);
  let lessCur = lessHead;
  let greaterHead = new ListNode(0);
  let greaterCur = greaterHead;

  // 遍历原链表,将节点分别添加到lessHead或greaterHead之后
  while (head) {
    if (head.val < x) {
      lessCur.next = head;
      lessCur = lessCur.next;
    } else {
      greaterCur.next = head;
      greaterCur = greaterCur.next;
    }
    head = head.next;
  }

  // 将两个链表连接起来
  lessCur.next = greaterHead.next;

  // 返回lessHead作为新链表的头节点
  return lessHead.next;
}

环形链表

环形链表是指链表中存在一个环,即某个节点指向了前面的某个节点,导致链表形成一个闭环。

JavaScript实现:

function hasCycle(head) {
  // 创建两个指针,slow和fast,分别以不同的速度遍历链表
  let slow = head;
  let fast = head;

  // 如果fast和fast.next都为null,则链表中没有环
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;

    // 如果slow和fast相遇,则链表中存在环
    if (slow === fast) {
      return true;
    }
  }

  // 如果fast和fast.next都为null,则链表中没有环
  return false;
}

相交链表

相交链表是指两个链表在某个节点之后合并,形成一个公共的尾部。

JavaScript实现:

function getIntersectionNode(headA, headB) {
  // 计算两个链表的长度
  let lenA = 0;
  let lenB = 0;
  let curA = headA;
  let curB = headB;
  while (curA) {
    lenA++;
    curA = curA.next;
  }
  while (curB) {
    lenB++;
    curB = curB.next;
  }

  // 让较长的链表先走lenA-lenB步,这样两个链表的长度相同
  if (lenA > lenB) {
    for (let i = 0; i < lenA - lenB; i++) {
      headA = headA.next;
    }
  } else if (lenB > lenA) {
    for (let i = 0; i < lenB - lenA; i++) {
      headB = headB.next;
    }
  }

  // 同时遍历两个链表,直到找到相交的节点
  while (headA && headB) {
    if (headA === headB) {
      return headA;
    }
    headA = headA.next;
    headB = headB.next;
  }

  // 如果没有找到相交的节点,返回null
  return null;
}

结语

通过本文对链表的深入探讨,读者对链表的结构、操作和经典算法有了更深入的了解。JavaScript作为一门灵活且强大的语言,为链表的实现提供了丰富的支持。希望本文能激发读者对数据结构与算法的兴趣,并为他们未来的学习和实践打下坚实的基础。