算法-链表

18 阅读3分钟
17. 环形链表 II
var detectCycle = function(head) {
  let fast = head, slow = head;

  do{
    //检查是否有环 + 寻找相遇点 encounter point
    if(!fast || !fast.next) return null;
    fast = fast.next.next
    slow = slow.next
  }while(fast != slow)


  fast = head;

  //寻找入口 entrance
  //为什么这能寻找入口,请看下图
  while(fast != slow){
    fast = fast.next
    slow = slow.next
  }

  return fast;
    
};
58. 环形链表
var hasCycle = function(head) {
    let fast = head;
    let slow = head;
    while (fast &&fast.next&& slow){
        fast = fast.next.next
        slow = slow.next
        if(fast === slow){
            return true;
        }
    }
    return false
};
25. 删除链表的倒数第 N 个结点

Fast 先走k次,再一起走的的时候fast走没了 就是slow要删除节点的时候;返回值为head

var removeNthFromEnd = function(head, n) {
    let fast = head;
    let slow = head;
    for(let i=0;i<n;i++){
        fast = fast.next
    }
    // 如果fast为null 说明删除第一个 直接取第二个即可
    if(fast == null)return head.next;
    while (fast&&fast.next!=null){
        fast = fast.next
        slow = slow.next
    }
    // .next时候才能跳过  要不然相当改的是变量值
    slow.next = slow.next.next
    return head;
};
88.两两交换链表中的节点

给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

function swapPairs(head) {
    // 创建一个哨兵节点,它的next指针指向链表的头节点
    let dummy = new ListNode(0);
    dummy.next = head;
    
    // 当前节点指针初始化为哨兵节点
    let current = dummy;

    while (current.next !== null && current.next.next !== null) {
        // 初始化两个待交换节点
        let firstNode = current.next;
        let secondNode = current.next.next;

        // 交换操作
        firstNode.next = secondNode.next;
        secondNode.next = firstNode;
        current.next = secondNode;

        // 移动当前节点指针至下一对待交换节点的前驱节点
        current = firstNode;
    }

    // 返回哨兵节点的下一个节点,即交换后的头节点
    return dummy.next;
}

19. 反转链表
var reverseList = function(head) {
    let pre = null // 反转链表
    let current = head
    while (current){
        // 临时存当前节点的下一个
        const tempCurrent = current.next
        // 当前的 下一个指向上一个 
        current.next = pre
        // 反转拼接
        pre = current
        // 当前继续循环
        current = tempCurrent
    }
    return  pre
};
30. K 个一组翻转链表

给你链表的头节点 head ,每 k **个节点一组进行翻转,请你返回修改后的链表。

var reverseKGroup = function(head, k) {
    let currentNode = head;
    let count = 0;
    // 计数检查是否有足够的节点进行下一次翻转
    while (currentNode != null && count != k) {
        currentNode = currentNode.next;
        count++;
    }
    // 如果有足够的节点进行翻转
    if (count == k) {
        // 翻转这 k 个节点
        currentNode = reverseKGroup(currentNode, k); // 翻转剩余部分,并将结果连接到当前部分
        while (count-- > 0) { // 翻转当前 k 个节点
            let temp = head.next; // 临时保存下一个节点
            head.next = currentNode; // 将当前节点的 next 指向翻转的剩余部分
            currentNode = head; // 将 currentNode 移动到当前节点
            head = temp; // 移动 head 到下一个节点
        }
        head = currentNode;
    }
    return head;
};
24. 合并两个有序链表
var mergeTwoLists = function(list1, list2) {
    let temp = new ListNode(0);
    // 存着这个链表节点 一直做赋值用
    let result = temp
    while (list1!==null&&list2!=null){
        if(list1.val<=list2.val){
          	// 赋值
            result.next = list1
            // 跳转
          	list1 = list1.next
        }else{
            result.next = list2
            list2 = list2.next
        }
      	// 跳转
        result = result.next
    }
  	// 没遍历完的直接拼接
    result.next = list1||list2
    return temp.next;
};
61. 相交链表
var getIntersectionNode = function(headA, headB) {
    let ap = headA,
        bp = headB;
    while (ap !== bp) {
      if (ap === null) {
        ap = headB;
      } else {
        ap = ap.next;
      }
      if (bp === null) {
        bp = headA;
      } else {
        bp = bp.next;
      }
    }
    return ap;
};
77.两个链表的第一个公共节点
var getIntersectionNode = function(headA, headB) {
  if(!headA||!headB) return null;
  // 走完自己的 在另一方一步一步走 相当于第二次循环必会相遇
  var a=headA,b=headB;
  while(a!=b){
    a=a?a.next:headB;
    b=b?b.next:headA;
  }
  return a;
};
62. 合并 K 个升序链表
var mergeKLists = function (lists) {
    const list = [];
    for (let i = 0; i < lists.length; i++) {
        let node = lists[i];
        while (node) {
            list.push(node.val);
            node = node.next;
        }
    }
    list.sort((a, b) => a - b);
    const res = new ListNode();
    let now = res;
    // console.log(list)
    for (let i = 0; i < list.length; i++) {
        now.next = new ListNode(list[i]);
        now = now.next;
    }
    return res.next;
};

// 分治
function mergeTwoLists(l1, l2) {
    if (!l1) return l2;
    if (!l2) return l1;
    if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
}

function mergeKLists(lists) {
    if (lists.length === 0) return null;
    if (lists.length === 1) return lists[0];
    
    const mid = Math.floor(lists.length / 2);
    const l1 = mergeKLists(lists.slice(0, mid));
    const l2 = mergeKLists(lists.slice(mid));

    return mergeTwoLists(l1, l2);
}

78.复杂链表的复制
var copyRandomList = function(head) {
     if (!head) {
        return null;
    }
    const map = new Map();
    let node = head; // 当前节点
    const newHead = new Node(node.val);
    let newNode = newHead; // 当前节点的copy
    map.set(node, newNode);

    while (node.next) {
        newNode.next = new Node(node.next.val);
        node = node.next;
        newNode = newNode.next;
        map.set(node, newNode);
    }

    newNode = newHead;
    node = head;
    while (newNode) {
        newNode.random = map.get(node.random);
        newNode = newNode.next;
        node = node.next;
    }

    return newHead;
};