Linked List 链表

1. 链表,常见的有单链表,双向链表,循环链表

 

2. 双向链表是常见的空间换时间的策略

3. 淘汰缓存的做法一般有几个,一般用链表结构,常见的策略有三种:先进先出策略 FIFO(First In,First Out)、最少使用策略 LFU(Least Frequently Used)、最近最少使用策略 LRU(Least Recently Used)。

链表定义
function ListNode(val) {
  this.val = val;
  this.next = null;
}
 
4. 常见的链表操作:
链表反转
链表中环的检测
两个有序链表合并
删除链表倒数第n个节点
求链表的中间节点
 
5. 合并多个链表
function ListNode(val) {
  this.val = val;
  this.next = null;
}

// way1 先找出最小,同时构造
var mergeKLists = function (lists) {
  if (lists == null || lists.length <= 1) {
    return lists;
  }

  let res = null;
  let tail = null;

  while (true) {
    let isAllNull = true;
    let curMin = Infinity;
    let curMinIndex = 0;
    for (let i = 0; i < lists.length; i++) {
      if (lists[i] && curMin > lists[i].val) {
        curMin = lists[i].val;
        curMinIndex = i;
      }

      if (lists[i]) {
        isAllNull = false;
      }
    }

    if (lists[curMinIndex]) {
      lists[curMinIndex] = lists[curMinIndex].next;
    }

    if (isAllNull) {
      break;
    }

    if (!res) {
      res = {};
      res.val = curMin;
      res.next = null;
    } else {
      let node = new ListNode(curMin);
      if (res.next === null) {
        res.next = node;
      } else {
        tail.next = node;
      }
      tail = node;
    }
  }

  return res;
};

var node1 = new ListNode(1);
var node3 = new ListNode(3);
node1.next = node3;

var node2 = new ListNode(2);
var node4 = new ListNode(4);
var node5 = new ListNode(5);
node2.next = node4;
node4.next = node5;

console.log(mergeKLists([node1, node2]));

//way2 先合并,排序,最后生成
var mergeKLists = function (lists) {
  if (!lists || lists.length == 0) return null;
  let arr = [];
  debugger;
  let res = new ListNode(0);
  lists.forEach(list => {
    let cur = list;
    while (cur) {
      arr.push(cur.val);
      cur = cur.next;
    }
  });
  let cur = res;
  arr
    .sort((a, b) => a - b)
    .forEach(val => {
      let node = new ListNode(val);
      cur.next = node;
      cur = cur.next;
    });
  return res.next;
};

 

6. 检测链表是否有环?

a. 散列表记录

var hasCycle = function(head) {
    let vistedSet = new Set();
    while(head != null){
        if(vistedSet.has(head.val)){
            return true;
        }else{
            vistedSet.add(head.val);
            head = head.next;
        }
    }

    return false;
};

b. 快指针一次走2步,慢指针一次走一步,如果慢能在某个时刻追到快指针,就说明有环,如果快指针走到了null,说明没有环。

var hasCycle = (head) => {
  let fastP = head;
  let slowP = head;
  while (fastP) {                         // 快指针指向真实节点
    if (fastP.next == null) return false; // 如果下一个为null,说明没有环
    slowP = slowP.next;                   // 慢的走一步
    fastP = fastP.next.next;              // 快的走两步
    if (slowP == fastP) return true;      // 快慢指针相遇,有环
  }
  return false;                           // fastP指向null了,也始终不相遇
}
posted @ 2020-08-19 19:05  lswtianliang  阅读(164)  评论(0编辑  收藏  举报