美文网首页
算法练习1:链表算法的解题思路

算法练习1:链表算法的解题思路

作者: miao8862 | 来源:发表于2021-04-04 02:25 被阅读0次

    一般追赶问题,环大小,都可以使用链表的双指针问题解决。

    判断一个链表是否有环?

    创建两个指针,一个快指针,一个慢指针,快指针每次移动两步,慢指针每次移到一步,当它们能在某个节点相遇,代表着这个链表有环;当快指针走完链表时,还没有相遇的节点,就代表着这是个无环的链表

    // 链表节点
    function LinkNode(val) {
      this.val = val;
      this.next = null;
    }
    
    // 判断单向链表是否有环
    function hasLoop(link) {
      let fast = link
      let slow = link
      while(fast && fast.next) {
        fast = fast.next.next
        slow = slow.next
        if(fast && fast.val === slow.val) {
          return true;
        }
      }
      return false;
    }
    
    const node1 = new LinkNode(1)
    const node2= new LinkNode(2)
    const node3 = new LinkNode(3)
    const node4 = new LinkNode(4)
    const node5 = new LinkNode(5)
    node1.next = node2
    node2.next = node3
    node3.next = node4
    node4.next = node5
    
    let isLoop = hasLoop(node1)
    console.log(isLoop); // false;
    
    node5.next = node2
    isLoop = hasLoop(node1)
    console.log(isLoop); // true;
    

    判断环的长度

    在判断有环的基础上,在第一次环的相交点,继续让快指针和慢指针往下走,当他们再次相交时,慢指针所走的步骤就是环的长度。因为快指针的步长是2,慢指针的步长是1,当它们再次相交时,快指针刚好比慢指针多走一圈,这时慢指针走的次数,就是这个环的长度。

    function getCycleLength(link) {
      let fast = link
      let slow = link
      let len = 0;
      let isCycle = false;
      while(fast && fast.next) {
        fast = fast.next.next
        slow = slow.next
        if(isCycle) {
          len++;
        }
        if(fast && fast.val === slow.val) {
          if(!isCycle) { 
            isCycle = true; 
          }else {
            return len;
          }
        }
      }
      return 0;
    }
    
    const node1 = new LinkNode(1)
    const node2= new LinkNode(2)
    const node3 = new LinkNode(3)
    const node4 = new LinkNode(4)
    const node5 = new LinkNode(5)
    node1.next = node2
    node2.next = node3
    node3.next = node4
    node4.next = node5
    node5.next = node2
    
    console.log(getCycleLength(node1)); // 4
    

    判断入环点

    链表头结点到入环点的距离 = 快慢指针首次相交点到入环点的距离
    假设头结点到入环点的距离为D,入环点到首次相交点的距离为D1,首次相交点到入环点的距离为D2:

    1. 当首次相交时,慢指针走的距离是:D + D1,快指针走的距离是:D + D1 + D2 + D1 = D + D2 + 2D1
    2. 因为快指针走的步长为2,是慢指针的2倍,所以 2(D + D1) = D + D2 + 2D1,推导出D = D2

    解题思路:

    1. 第一步,还是用快慢指针解决:让快指针走2步,让慢指针走1步,找到它们第一次的相交点
    2. 相交时,让慢指针指向头节点,让快指针停留在相交点,并改为快指针的的步长为1,当快慢指针再次相交时,就是这个环的入环点
    // 获取单链表环的入环节点
    function getCycleEntry(link) {
      let fast = link
      let slow = link
      let isCycle = false;
      while(fast && fast.next) {
        // 如果还未相交过,则快指针步长为2
        if(!isCycle) {
          fast = fast.next.next
          // 如果相交过一次,则快指针步长改为1
        }else {
          fast = fast.next
        }
        slow = slow.next
    
        if(fast && fast.val === slow.val) {
          // 如果是首次相遇,将有环标识设为true,并将慢指针指向头节点
          if(!isCycle) { 
            isCycle = true;
            slow = link;
            // 如果为第二次相交,则为入环点
          }else {
            return fast;
          }
        }
      }
      return null;
    }
    
    
    const node1 = new LinkNode(1)
    const node2= new LinkNode(2)
    const node3 = new LinkNode(3)
    const node4 = new LinkNode(4)
    const node5 = new LinkNode(5)
    node1.next = node2
    node2.next = node3
    node3.next = node4
    node4.next = node5
    node5.next = node2
    
    console.log(getCycleEntry(node1));  // LinkNode {2, next: node5 }
    

    求一个单链表倒数第k个节点到最后一个节点的链表

    比如 1=>2=>3=>4=>5,求倒数第2个到最后一个节点的链表:4=>5, k < 链表长度。
    解题思路:使用两个指针,一个指针从第一个节点开始,第二个指针第k个节点开始,当第二个指针走到终点时,第一个指针所指的节点开始,就是所求的链表

    function getLastLink(link, k) {
      let p1 = link
      let p2 = link
      for(let i = 0; i < k; i++) {
        if(p2) {
          p2 = p2.next
        }
      }
      while(p2) {
        p2 = p2.next
        p1 = p1.next
      }
      return p1
    }
    const node1 = new LinkNode(1)
    const node2= new LinkNode(2)
    const node3 = new LinkNode(3)
    const node4 = new LinkNode(4)
    const node5 = new LinkNode(5)
    node1.next = node2
    node2.next = node3
    node3.next = node4
    node4.next = node5
    
    console.log(getLastLink(node1, 2));  // LinkNode { val: 4, next: LinkNode { val: 5, next: null } }
    

    相关文章

      网友评论

          本文标题:算法练习1:链表算法的解题思路

          本文链接:https://www.haomeiwen.com/subject/shmkkltx.html