算法点滴yan测试+打印

基本的链表和常用的列表

基本的数据结构

//--------链表
class Node{ // 代表的是链表中的某一个节点
    constructor(element){
        this.val = element;
        this.next = null;
    }
}
class LinkList {
  constructor() {
    this.head = null;
    this.length = 0;
  }
  insert(val, position){
    let node = new Node(val);
    if(!this.head) {
      this.head = node;
    } else {
      let current = this.head;
      let cursor = 0;
      let pre;
      // 前++后++都行 
      while(++cursor < position) {
        pre = current;
        current = current.next;
      }
      pre.next =  node;
      node.next = current;
      this.length++
    }
  }
  append(val){
    let node = new Node(val);
    if(!this.head) {
      this.head = node;
    } else  {
      let current = this.head;
      let cursor = 0;
      // 前++后++都行 
      while(cursor++ < this.length) {
        current = current.next;
      }
      // let pre;
      // while(current) {
      //   pre = current;
      //   current = current.next;
      // }
      current.next = node;
    }
    this.length++
  }
}
let ll = new LinkList();
ll.append(1);
ll.append(2);
ll.append(3);
ll.insert(1,100);
// 实现删除 取值
console.log(JSON.stringify(ll));
//--------Set
class Set{
    constructor(){
        this.obj = {};
    }
    add(element){
        if(!this.obj.hasOwnProperty(element)){
            this.obj[element] = element;
        }
    }
}
let set = new Set(); // set的特点就是key value 相同
set.add(1);
set.add(1);
console.log(set);
//--------Map
class Map{ // 松散 重复的话可以在加上链表 
    constructor(){
        this.arr = [];
    }
    calc(key){
        let total = 0;
        for(let i = 0 ; i < key.length;i++){
            total += key[i].charCodeAt()
        }
        return total % 100
    }
    set(key,value){
        key = this.calc(key);
        this.arr[key] = value
    }
    get(key){
        key = this.calc(key);
        return  this.arr[key];
    }
}
// 模拟hash表
let map = new Map(); // hash 表
map.set({a:1},123);
map.set('bbq',456);
console.log(map)
//--------Tree
class Node {
    constructor(val){
        this.val = val;
        this.left = null;
        this.right = null
    }
}
class Tree{
    constructor(){
        this.root = null; // 树的根
    }
    insert(root,newNode){
        if(newNode.element < root.element){
            if(root.left == null){
                root.left = newNode
            }else{
                this.insert(root.left,newNode)
            }
        }else{
            if(root.right == null){
                root.right = newNode
            }else{
                this.insert(root.right,newNode)
            }
        }
    }
    add(element){
        let node = new Node(element);
        if(!this.root){
            this.root = node;
        }else{
            this.insert(this.root,node);
        }
    }
}
let tree = new Tree;
tree.add(100);
tree.add(60);
tree.add(150);
tree.add(50);
console.log(JSON.stringify(tree));
//--------先序中序后序递归遍历一个树
// 先序遍历一个树
function treeRecurse(tree) {
  if (!tree) return;
  console.log(tree.element);
  treeRecurse(tree.left);
  treeRecurse(tree.right);
}
// 中序遍历一个树
function treeRecurse(tree) {
  if (!tree) return;
  treeRecurse(tree.left);
  console.log(tree.element);
  treeRecurse(tree.right);
}
// 后序遍历一个树
function treeRecurse(tree) {
  if (!tree) return;
  treeRecurse(tree.left);
  treeRecurse(tree.right);
  console.log(tree.element);
}
//--------排序 自己的js排序
//--------冒泡
function BubbleSort(array) {
  var length = array.length;
  for (var i = length - 1; i > 0; i--) { //用于缩小范围
    for (var j = 0; j < i; j++) { // 在范围内进行冒泡,在此范围内最大的一个将冒到最后面
      if (array[j] > array[j+1]) {
        [array[j], array[j+1]] = [array[j+1], array[j]];
      }
    }
    console.log(array);
    console.log("-----------------------------");
  }
  return array;
}
var arr = [10,9,8,7,7,6,5,11,3];
var result = BubbleSort(arr);
console.log(result); 
//--------快速排序两数组实现
时间复杂度:平均O(nlogn),最坏O(n2),实际上大多数情况下小于O(nlogn)
空间复杂度:O(log1)(递归调用消耗),有的说是O(logn),我感觉也是O(logn)
function quickSort(array) {
  if (array.length < 2) {
    return array;
  }
  const target = array[0];
  const left = [];
  const right = [];
  for (let i = 1; i < array.length; i++) {
    if (array[i] < target) {
      left.push(array[i]);
    } else {
      right.push(array[i]);
    }
  }
  return quickSort(left).concat([target], quickSort(right));
}
//--------快速排序两指针实现
时间复杂度:平均O(nlogn),最坏O(n2),实际上大多数情况下小于O(nlogn)
空间复杂度:O(logn)(递归调用消耗)
 function quickSort(array, start = 0, end = array.length-1) {
  if (end - start < 1) {
    return;
  }
  const target = array[start];
  let left = start;
  let right = end;
  while (left < right) {
    while (left < right && array[right] >= target) {
      right--;
    }
    array[left] = array[right];
    while (left < right && array[left] < target) {
      left++;
    }
    array[right] = array[left];
  }
  array[left] = target;
  quickSort(array, start, left - 1);
  quickSort(array, left + 1, end);
  return array;
}
console.log(quickSort([3,1,9,2]))   

//--------归并排序(两数组实现)
时间复杂度:O(nlogn). 空间复杂度:O(n)
function mergeSort(array, left =0 , right = array.length -1, temp = []) {
  if (left < right) {
    const mid = Math.floor((left + right) / 2);
    mergeSort(array, left, mid, temp)
    mergeSort(array, mid + 1, right, temp)
    merge(array, left, right, temp);
  }
  return array;
}
function merge(array, start, end, temp) {
  const mid = Math.floor((start + end) / 2);
  let left = start;
  let right = mid + 1;
  let cursor = 0;
  while (left <= mid && right <= end) {
    if (array[left] < array[right]) {
      temp[cursor++] = array[left++]
    } else {
      temp[cursor++] = array[right++]
    }
  }
  while (left <= mid) {
    temp[cursor++] = array[left++]
  }
  while (right <= end) {
    temp[cursor++] = array[right++]
  }
  cursor = 0;
  for (let i = start; i <= end; i++) {
    array[i] = temp[cursor++];
  }
}
//--------多种查找方法
let obj = {
  children: [
    {
      index: 0,
      children: [
        {
          index: 1,
          children: [
            {
              index: 3,
            },
          ],
        },
      ],
    },
    {
      index: 4,
    },
    {
      index: 6,
    },
  ],
  index: 0
};
// 深度递归(递归实现)
function test(node, result = []) {
  if (node) {
    result.push(node);
    if (node.children) {
      node.children.forEach(item => {
        test(item, result)
      })
    }
  }
  return result
}
test(obj)
// 深度递归(非递归实现)
function test (node) {
  const cache = [node];
  const result = [];
  while(cache.length) {
    const item = cache.pop();
    result.push(item);
    item.children && item.children.forEach(i => {
      cache.push(i)
    })
  }
  return result;
}
test(obj)
// 广度遍历(非递归)
let test = (node) => {
  let result = []
  let cache = []
  cache.push(node)
  while (cache.length) {
    //取第一个
      let item = cache.shift()
      result.push(item)
      item.children && item.children.forEach(i => {
        cache.push(i)
      })
  }
  return result
}

//--------二分查找
示例 1:
输入: nums = [-1,0,3,5,9,12], target = 9
var search = function(nums, target) {
    // right是数组最后一个数的下标,num[right]在查找范围内,是左闭右闭区间
    let left = 0, right = nums.length - 1;
    // 当left=right时,由于nums[right]在查找范围内,所以要包括此情况
    while (left <= right) {
        let mid = left + Math.floor((right - left)/2);
        // 如果中间数大于目标值,要把中间数排除查找范围,所以右边界更新为mid-1;如果右边界更新为mid,那中间数还在下次查找范围内
        if (nums[mid] > target) {
            right = mid - 1;  // 去左面闭区间寻找
        } else if (nums[mid] < target) {
            left = mid + 1;   // 去右面闭区间寻找
        } else {
            return mid;
        }
    }
    return -1;
};
// 来个变形,target不在是数据中的值,而是随机值
var search = function(nums, target) {
    // right是数组最后一个数的下标,num[right]在查找范围内,是左闭右闭区间
    let left = 0, right = nums.length - 1;
    // 当left=right时,由于nums[right]在查找范围内,所以要包括此情况
    while (left <= right) {
        let mid = left + Math.floor((right - left)/2);
        // 如果中间数大于目标值,要把中间数排除查找范围,所以右边界更新为mid-1;如果右边界更新为mid,那中间数还在下次查找范围内
        if (nums[mid] > target) {
            right = mid - 1;  // 去左面闭区间寻找
        } else if (nums[mid] < target) {
            left = mid + 1;   // 去右面闭区间寻找
        } else {
            return mid;
        }
    }
    return right + 1;
};
const cursor = search([-1, 0, 3, 5, 9, 10], 9.5);
console.log(cursor);

//--------有效的完全平方数
var isPerfectSquare = function(num) {
    let left = 0;
    let right = num;
    while(left <= right){
        let mid = left + Math.floor((right - left) /2);
        let t = mid * mid;
        if(t == num) return true;
        else if(t < num) left = mid + 1;
        else right = mid - 1;
    }
    return false;
};

// 字符串
//--------反转字符串
示例 1:
输入:s = ["h","e","l","l","o"]
输出:["o","l","l","e","h"]
示例 2:
输入:s = ["H","a","n","n","a","h"]
输出:["h","a","n","n","a","H"]
----答案
var reverseString = function(s) {
    const n = s.length;
    for (let left = 0, right = n - 1; left < right; ++left, --right) {
        [s[left], s[right]] = [s[right], s[left]];
    }
};
//--------版本比较
function compare( version1 ,  version2 ) {
    let arr1=version1.split(".");
    let arr2=version2.split(".");
    let length=Math.max(arr1.length,arr2.length);
    for (let i = 0; i < length; i++) {
        const n1 = Number(arr1[i]||0)
        const n2 = Number(arr2[i]||0)
        if (n1 > n2) return 1
        if (n1 < n2) return -1
    }
    return 0
}
//--------最长回文子串
方法1:中心扩展算法
时间复杂度n*n, 枚举中心位置的个数是2(n-1),每一次向两边扩散检测是否回文;
空间复杂度O(1),只用到常数个临时变量
function longestPalindrome(s) {
  if (s == null || s.length < 1) {
    return "";
  }
  var start = 0, end = 0;
  for (var i = 0; i < s.length; i++) {
      var len1 = expandAroundCenter(s, i, i);
      var len2 = expandAroundCenter(s, i, i + 1);
      var len = Math.max(len1, len2);
      if (len > end - start) {
          start = i - (len - 1) / 2;
          end = i + len / 2;
      }
  }
  return s.substring(start, end + 1);
}
function expandAroundCenter(s,left,right) {
  while (left >= 0 && right < s.length && s.charAt(left) == s.charAt(right)) {
      --left;
      ++right;
  }
  return right - left - 1;
}


方法2:动态规划
时间复杂度n * n,这里的n为字符串的长度,
空间复杂度n*n
function longestPalindrome(s) {
  var len = s.length;
  if (len < 2) {
      return s;
  }
  var maxLen = 1;
  var begin = 0;
  // dp[i][j] 表示 s[i..j] 是否是回文串
  var dp = new Array(len).fill(false).map(w => new Array(len).fill(false));
  // 初始化:所有长度为 1 的子串都是回文串
  for (var i = 0; i < len; i++) {
      dp[i][i] = true;
  }
  var charArray = s.split('');
  // 递推开始
  // 先枚举子串长度
  for (var L = 2; L <= len; L++) {
      // 枚举左边界,左边界的上限设置可以宽松一些
      for (var i = 0; i < len; i++) {
          // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
          var j = L + i - 1;
          // 如果右边界越界,就可以退出当前循环
          if (j >= len) {
              break;
          }

          if (charArray[i] != charArray[j]) {
              dp[i][j] = false;
          } else {
              if (j - i < 3) {
                  dp[i][j] = true;
              } else {
                  dp[i][j] = dp[i + 1][j - 1];
              }
          }

          // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
          if (dp[i][j] && j - i + 1 > maxLen) {
              maxLen = j - i + 1;
              begin = i;
          }
      }
  }
  return s.substring(begin, begin + maxLen);
}

方法3:Manacher 算法

//--------无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度
方法一:滑动窗口
var lengthOfLongestSubstring = function (str) {
    if (str.length <= 1) { return str.length }
    let left = 0
    let right = 1
    let max = 0
    let temp
    while (right < str.length) {
        temp = str.slice(left, right)
        if (temp.indexOf(str.charAt(right)) > -1) {
            left++
            continue
        } else {
            right++
        }
        if (right - left > max) { max = right - left }
    }
    return max
};
------
function test (str) {
  let p1 = 0;
  let p2 = 1;
  let max = '';
  while(p2 <= str.length) {
    const tem = str.slice(p1, p2);
    if (tem.includes(str[p2])) {
      p1++;
      continue
    } else {
      p2++;
    }
    if (tem.length > max.length) {
      max = tem;
    }
  }
  return max;
}
console.log(test('asdfaqaw'))

//--------单词拆分
示例 1输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet""code" 拼接成。
示例 2输入: s = "applepenapple", wordDict = ["apple", "pen"]
输出: true
解释: 返回 true 因为 "applepenapple" 可以由 "apple" "pen" "apple" 拼接成。
     注意,你可以重复使用字典中的单词、--
-----答案
var wordBreak = function (s, wordDict) {
    // dp数组,表示前index为能否被拆分
    let dp = new Array(s.length + 1).fill(false);
    // 空子前缀串默认能被拆分
    dp[0] = true;
    for (let i = 1; i <= s.length; i++) {
        for (let j = 0; j <= i - 1; j++) {
            //存在一个字串能被拆分,并且剩余的字符串能在单词表中找到就表示当前单词能被拆分
            if (dp[j] && wordDict.indexOf(s.substring(j, i)) !== -1) dp[i] = true;
        }
    }
    return dp[s.length];
};

//--------最小覆盖子串
var minWindow = function(s, t) {
  var need = {}, tLength = t.length;
  for (var i = 0; i < tLength; i++) {
      var tItem = t[i];
      need[tItem] = need[tItem] === undefined ? 1 : need[tItem] + 1;
  }
  var cacheLeft = 0, cacheRight = 0;
  for (var left = 0, right = 0; right < s.length; right++) {
      var sItem = s[right];
      tLength -= need[sItem] > 0;
      need[sItem] = need[sItem] === undefined ? -1 : need[sItem] - 1;
      if (tLength === 0) {  //窗口中已经包含所需的全部字符
          while(left < right && need[s[left]] < 0) { // 缩减窗口
              need[s[left]]++;
              left++;
          }
          // 更新答案
          if (cacheRight === 0 || right - left < cacheRight - cacheLeft) {
            cacheRight = right + 1;
              cacheLeft = left;
          }
      }
  }
  return s.substring(cacheLeft, cacheRight);
};
//--------数组
//--------两数之和
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

// 答案一 双循环,暴力解法   
算法复杂度: O(n^2) O(1)
var twoSum = function(nums, target) {
    for(let i = 0, len = nums.length;i < len;i++){
        // 因为同一元素不允许重复出现,所以从i的下一位开始遍历
        for(let j = i + 1;j < len;j++) {
            if(nums[i] + nums[j] === target) {
                return [i, j];
            }
        }
    }
    // 所有样例都是有返回结果的,这里无所谓
    return [-1, -1];
};
// 答案二  一次循环,使用HashMap进行记录 
算法复杂度: O(n) O(n)
var twoSum = function(nums, target) {
    const map = new Map();
    for(let i = 0, len = nums.length;i < len;i++) {
        if(map.has(target - nums[i])) {
            return [map.get(target - nums[i]), i];
        }
        map.set(nums[i], i);
    }
    return [];
};
//--------数组反转
---反转字符串
var reverseString = function(s) {
    const n = s.length;
    for (let left = 0, right = n - 1; left < right; ++left, --right) {
        [s[left], s[right]] = [s[right], s[left]];
    }
}
//--------合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
示例 1:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3][2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
示例 2:
输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1][] 。
合并结果是 [1]----方法1 方法一:直接合并后排序
时间复杂度:(m+n)log(m+n)
空间复杂度:log(m+n)
var merge = function(nums1, m, nums2, n) {
	// 这里可以少定义一个变量,比起 [...nums1,...nums2]
    nums1.splice(m, nums1.length - m, ...nums2);
    nums1.sort((a, b) => a - b);
};

方法二:双指针
时间复杂度:O(m+n)
空间复杂度:O(m+n)
var merge = function(nums1, m, nums2, n) {
    let p1 = 0, p2 = 0;
    const sorted = new Array(m + n).fill(0);
    var cur;
    while (p1 < m || p2 < n) {
        if (p1 === m) {
            cur = nums2[p2++];
        } else if (p2 === n) {
            cur = nums1[p1++];
        } else if (nums1[p1] < nums2[p2]) {
            cur = nums1[p1++];
        } else {
            cur = nums2[p2++];
        }
        sorted[p1 + p2 - 1] = cur;
    }
    for (let i = 0; i != m + n; ++i) {
        nums1[i] = sorted[i];
    }
};
// 自己重写了
function merge2(nums1, nums2) {
  let p1 = 0, p2 = 0;
  let res = new Array(nums1.length + nums2.length).fill(0);
  let current;
  while(p1 < nums1.length || p2 < nums2.length) {
    if (p1 === nums1.length) {
      current = nums2[p2++];
    } else if (p2 === nums2.length) {
      current = nums1[p1++];
    } else if (nums1[p1] < nums2[p2]) {
      current = nums1[p1++];
    } else if (nums1[p1] >= nums2[p2]) {
      current = nums2[p2++];
    }
    res[p1+p2-1] = current;
  }
  return res;
}
console.log(merge2([2,4,7], [1,3,5,20]))
//--------寻找两个正序数组的中位数
----方法1.合并数组 排序
时间复杂度:遍历全部数组 (m+n)
空间复杂度:开辟了一个数组,保存合并后的两个数组 O(m+n)
```clike
function test(arr1, arr2) {
  arr1.splice(arr1.length, 0, ...arr2);
  arr1.sort((a, b) => a-b); // 这里必须传参数
  console.log(arr1)
  if (arr1.length % 2 === 0) {
    return (arr1[arr1.length / 2 - 1] + arr1[arr1.length / 2]) / 2
  } else {
    return arr1[arr1.length >> 1]
  }
}
console.log(test([2,5,7], [1,3,9,11]))

----方法2:方法二:划分数组(太复杂,不建议背诵)
时间复杂度:O(log(min(m,n)))
(官网上说空间复杂度O(1))
思路:
这道题如果时间复杂度没有限定在 O(log(m+n))O(log(m+n)),我们可以用 O(m+n)O(m+n) 的算法解决,用两个指针分别指向两个数组,比较指针下的元素大小,一共移动次数为 (m+n + 1)/2,便是中位数。
首先,我们理解什么中位数:指的是该数左右个数相等。
比如:odd : [1,| 2 |,3]2 就是这个数组的中位数,左右两边都只要 1 位;
even: [1,| 2, 3 |,4]2,3 就是这个数组的中位数,左右两边 1 位;
那么,现在我们有两个数组:
nums1: [a1,a2,a3,...an]
nums2: [b1,b2,b3,...bn]
[nums1[:left1],nums2[:left2] | nums1[left1:], nums2[left2:]]
只要保证左右两边 个数 相同,中位数就在 | 这个边界旁边产生。
如何找边界值,我们可以用二分法,我们先确定 num1 取 m1 个数的左半边,那么 num2 取 m2 = (m+n+1)/2 - m1 的左半边,找到合适的 m1,就用二分法找。
当 [ [a1],[b1,b2,b3] | [a2,..an],[b4,...bn] ]
我们只需要比较 b3 和 a2 的关系的大小,就可以知道这种分法是不是准确的!
例如:我们令:
nums1 = [-1,1,3,5,7,9]
nums2 =[2,4,6,8,10,12,14,16]
当 m1 = 4,m2 = 3 ,它的中位数就是median = (num1[m1] + num2[m2])/2

对于代码中边界情况,大家需要自己琢磨
function findMedianSortedArrays(nums1, nums2) {
  let length1 = nums1.length,
    length2 = nums2.length;
  if (length1 > length2) return findMedianSortedArrays(nums2, nums1); // 对nums1和nums2中长度较小的二分
  let left1 = 0,
    right1 = length1; // 进行二分的开始和结束位置
  let mid1, mid2;
  while (left1 <= right1) {
    mid1 = (left1 + right1) >> 1;
    // 这个是核心,不知道为啥要+1
    mid2 = ((length1 + length2 + 1) >> 1) - mid1;
    // 如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums1二分的位置左边一个
    let L1 = mid1 === 0 ? -Infinity : nums1[mid1 - 1];
    // 如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums2二分的位置左边一个
    let L2 = mid2 === 0 ? -Infinity : nums2[mid2 - 1];
    // 如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
    let R1 = mid1 === length1 ? Infinity : nums1[mid1];
    // 如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
    let R2 = mid2 === length2 ? Infinity : nums2[mid2];

    if (L1 > R2) { // 不符合交叉小于等于 继续二分
      right1 = mid1 - 1;
    } else if (L2 > R1) { // 不符合交叉小于等于 继续二分
      left1 = mid1 + 1;
    } else {  // L1 <= R2 && L2 <= R1 符合交叉小于等于
      return (length1 + length2) % 2 === 0
        ? (Math.max(L1, L2) + Math.min(R1, R2)) / 2
        : Math.max(L1, L2);
    }
  }
}
console.log(findMedianSortedArrays([-1,1,3,5,7,9], [2,4,6,8,10,12,14,16])) // 6.5

//--------两个数组的交集
方法1:两个集合
时间复杂度:O(m+n)
空间复杂度:O(m+n)
var intersection = function (arr1, arr2) {
    const set1 = new Set(arr1);
    const set2 = new Set(arr2);
    return handle(set1, set2);
};
function handle(set1, set2) {
    if (set1.size > set2.size) {
        return handle(set2, set1)
    }
    let result = new Set();
    for (let item of set1) {
        if (set2.has(item)) {
            result.add(item);
        }
    }
    return [...result];
}
// 空间换取时间
function test(arr1, arr2) {
	const set1 = new Set(arr1);
	const result = [];
	for(var i=0;i<arr2.length;i++) {
		if (set1.has(arr2[i])) {
			result.push(arr2[i])
		}
	}
	return result;
}
方法2:排序 + 双指针
时间复杂度 O(mlogm+nlogn)
空间复杂度 O(logm+logn)
var intersection = function (nums1, nums2) {
  nums1.sort((x, y) => x - y);
  nums2.sort((x, y) => x - y);
  const length1 = nums1.length,
    length2 = nums2.length;
  let p1 = 0,
    p2 = 0;
  const res = [];
  while (p1 < length1 && p2 < length2) {
    const num1 = nums1[p1],
      num2 = nums2[p2];
    if (num1 === num2) {
      // 保证加入元素的唯一性
      if (res.length > 0 || num1 !== res[res.length - 1]) {
        res.push(num1);
      }
      p1++;
      p2++;
    } else if (num1 < num2) {
      p1++;
    } else {
      p2++;
    }
  }
  return res;
};
console.log(intersection([2,3,5,7], [4,5,6]))
//--------三数之和
数组三数为flag的所有组合
---方法1 暴力3循环
---方法2 排序 + 双指针
时间复杂度:O(N^2)  空间复杂度O(N)
function test(nums, target) {
  nums.sort((a, b) => a - b)
  let result = []
  for (let i = 0; i < nums.length - 2; i++) {
      // 当遍历下一个target与前面的相同时,跳过
      if (i > 0 && nums[i] == nums[i - 1]) continue
      let left = i + 1, right = nums.length - 1;
      const rest = target - nums[i];
      while (left < right) {
          if (nums[left] + nums[right] === rest) {
            result.push([nums[i], nums[left], nums[right]])
            // 准备夹逼前,将左右俩边移到相同数值最紧处
            // 这里的两句其实不用看,用来处理重复的时候,一般测试用例不会重复
            // while (left < right && nums[left + 1] == nums[left]) left++
            // while (left < right && nums[right - 1] == nums[right]) right--
            left++
            right--
          } else if (nums[left] + nums[right]  > rest) {
              right--
          } else {
              left++
          }
      }
  }
  return result
};
//--------每个数右边第一个比他大的数组成的数组
/*
example:
输入:[3, 2, 1, 2, 6, 2, 3]
输出:[6, 6, 2, 6,-1, 3, -1]
*/
function findFirstLarge(arr) {
  const cache = [];
  const result = [];
  for(let i =0;i<arr.length;i++) {
    for(let j = cache.length-1;j>=0;j--) {
      // 只考虑最近的一个,不要考虑两层,每一个都考虑最近的一个,就不会有两层的问题
      if(cache[j].value < arr[i]) {
        result[cache[j].index] = arr[i];
        cache.splice(j, 1);
      }
    }
    cache.push({
      index: i,
      value: arr[i],
    });
  }
  cache.forEach((item) => {
    result[item.index] = -1;
  });
  return result;
}
console.log(findFirstLarge([3, 2, 1, 2, 6, 2, 3]));
// 6,6,2,6,-1,3,-1

//--------最大子数组和
方法一:动态规划
var maxSubArray = function(nums) {
    let cur = 0, maxCur = nums[0];
    nums.forEach((x) => {
        // 这句核心
        当前值:x
        之前和: cur
        当前和: cur +x
        最大和:当前和
        cur = Math.max(cur + x, x);
        maxCur = Math.max(maxCur, cur); 这里比较 maxCur, cur+x, x 三个值比较 
    });
    return maxCur;
};

方法二:分治
function Status(l, r, m, i) {
    this.lSum = l;
    this.rSum = r;
    this.mSum = m;
    this.iSum = i;
}

const pushUp = (l, r) => {
    const iSum = l.iSum + r.iSum;
    const lSum = Math.max(l.lSum, l.iSum + r.lSum);
    const rSum = Math.max(r.rSum, r.iSum + l.rSum);
    const mSum = Math.max(Math.max(l.mSum, r.mSum), l.rSum + r.lSum);
    return new Status(lSum, rSum, mSum, iSum);
}

const getInfo = (a, l, r) => {
    if (l === r) {
        return new Status(a[l], a[l], a[l], a[l]);
    }
    const m = (l + r) >> 1;
    const lSub = getInfo(a, l, m);
    const rSub = getInfo(a, m + 1, r);
    return pushUp(lSub, rSub);
}

var maxSubArray = function(nums) {
    return getInfo(nums, 0, nums.length - 1).mSum;
};
//--------链表
//--------链表的中间结点
var middleNode = function(head) {
    slow = fast = head;
    while (fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
    }
    return slow;
};
//--------环形链表
var hasCycle = function(head) {
    let slow = head, fast = head;
    while(fast && fast.next) {
        slow = slow.next;
        fast = fast.next.next;
        if(slow === fast) {
            return true;
        }
    }
    return false;
};
//-------反转链表
方法一:迭代
function test(head) {
  let prev = null;
  let curr = head;
  while (curr) {
    // 保存下一个迭代的节点
    const next = curr.next;
    // 下一个节点指向前一个节点
    curr.next = prev;
    // 调整prev为当前curr
    prev = curr;
    // 调整curr为当前next
    curr = next;
  }
  return prev;
}
方法二:递归
var reverseList = function(head) {
    if (head == null || head.next == null) {
        return head;
    }
    const newHead = reverseList(head.next);
    head.next.next = head;
    head.next = null;
    return newHead;
};

//-------合并两个有序链表
var mergeTwoLists = function(l1, l2) {
    if (l1 === null) {
        return l2;
    } else if (l2 === null) {
        return l1;
    } else if (l1.val < l2.val) {
        l1.next = mergeTwoLists(l1.next, l2);
        return l1;
    } else {
        l2.next = mergeTwoLists(l1, l2.next);
        return l2;
    }
};

//-------合并K个升序链表
//-------删除链表的倒数第 N 个结点
// 方法1:求链表长度
function test(head, n) {
  var prev = head;
  var length = getLength(head);
  var cur = prev;
  for (var i = 0; i < length - n; ++i) {
    cur = cur.next;
  }
  cur.next = cur.next.next;
  return prev.next;
}
function getLength(head) {
  var length = 0;
  while (head != null) {
      ++length;
      head = head.next;
  }
  return length;
}
// 方法2:栈
function test(head, n) {
  var prev = head;
  var cur = prev;
  while (cur != null) {
    stack.push(cur);
    cur = cur.next;
  }
  for (var i = 0; i < n; ++i) {
      stack.pop();
  }
  var prev = stack.shift();
  prev.next = prev.next.next;
  return prev.next;
}
//-------相交链表
function test(head1, head2) {
  const cache1 = new Set();
  let temp1 = head1;
  while(temp1) {
    cache1.add(temp1)
    temp1= temp1.next;
  }
  let temp2 = head2;
  while(temp2) {
    if (cache1.has(temp2)) {
      return temp2;
    }
    temp2= temp2.next;
  }
  return null;
}
//-------排序链表
入:head = [4,2,1,3]
输出:[1,2,3,4]
----答案
var sortList = function(head) {
    return mergeList(head, null); // 左闭右开区间,即右边界是最后一个元素的右边,即 null
};
function mergeList(start, end) {
    if(!start) return null;
    // 左闭右开区间
    if(start.next === end) {
        start.next = null; // 由于 end 属于右边那部分的,不关左边事,所以断开连接再返回
        return start;
    }
    let slow = start, fast = start;
    // 找中点
    while(fast !== end) {
        slow = slow.next;
        fast = fast.next;
        if(fast !== end) {
            fast = fast.next;
        }
    }
    let mid = slow;
    return merge(mergeList(start, mid), mergeList(mid, end)); // 对中点的左右两部分继续递归,然后对递归返回的结果 执行合并两个有序链表的算法
}
// 合并两个有序链表
function merge(head1, head2) {
    let newHead = new ListNode(0), now = newHead;
    while(head1 && head2) {
        if(head1.val <= head2.val) {
            now.next = head1;
            head1 = head1.next;
        } else {
            now.next = head2;
            head2 = head2.next;
        }
        now = now.next;
    }
    now.next = head1 ? head1 : head2;
    return newHead.next;
}
//-------LRU 缓存
var LRUCache = function(capacity) {
    this.map = new Map()
    this.capacity = capacity
};

LRUCache.prototype.get = function(key) {
    if(this.map.has(key)){
        let value = this.map.get(key)
        this.map.delete(key)
        this.map.set(key, value)
        return value
    }
    return -1
};
LRUCache.prototype.put = function(key, value) {
    if (this.map.has(key)) {
      this.map.delete(key) 
    }
    this.map.set(key, value)
    if(this.map.size > this.capacity){
        this.map.delete(this.map.keys().next().value)
    }
};

//-------动态规划
//-------64. 最小路径和
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
function test(grid) {
  const dp = new Array(grid.length).fill(null).map((item, itemIndex)  => new Array(grid[itemIndex].length));
  dp[0][0] = grid[0][0];
  for (let i = 0; i < grid.length; i++) {
    for (let j = 0; j < grid[0].length; j++) {
      if (i === 0 && j === 0) { continue; }
      else if (i === 0) { dp[0][j] = dp[0][j - 1] + grid[0][j]; }
      else if (j === 0) { dp[i][0] = dp[i - 1][0] + grid[i][0]; }
      else { dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j] }
    }
  }
  return dp.at(-1).at(-1)
};
console.log(test([[1,3,1],[1,5,1],[4,2,1]])) // 7
//-------62. 不同路径
m=3,n=7, 输出28
var uniquePaths = function(m, n) {
    const f = new Array(m).fill(0).map(() => new Array(n).fill(0));
    for (let i = 0; i < m; i++) {
        f[i][0] = 1;
    }
    for (let j = 0; j < n; j++) {
        f[0][j] = 1;
    }
    for (let i = 1; i < m; i++) {
        for (let j = 1; j < n; j++) {
            f[i][j] = f[i - 1][j] + f[i][j - 1];
        }
    }
    return f[m - 1][n - 1];
};
//-------121. 买卖股票的最佳时机
function test(prices) {
  let minprice = Infinity;
  let maxprofit = 0;
  for (let i = 0; i < prices.length; i++) {
    // 这里做了两点1.初始化minprice, 2.初始化minprice的时候确实不需要考虑max
    if (prices[i] < minprice) {
      minprice = prices[i];
    } else if (prices[i] - minprice > maxprofit) {
      maxprofit = prices[i] - minprice;
    }
  }
  return maxprofit;
}
console.log(test([7,1,5,3,6,4])) // 5

//-------打家劫舍
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4function test(nums) {
  if (nums == null || nums.length == 0) {
    return 0;
  }
  let length = nums.length;
  if (length == 1) {
      return nums[0];
  }
  let first = nums[0], second = Math.max(nums[0], nums[1]);
  for (let i = 2; i < length; i++) {
    let temp = second;
      second = Math.max(first + nums[i], second);
      first = temp;
  }
  return second;
}
console.log(test([1,2,3,1])) // 4
//-------不同的子序列
输入:s = "rabbbit", t = "rabbit"
输出:3
解释:
如下图所示,3 种可以从 s 中得到 "rabbit" 的方案。
rabbbit
rabbbit
rabbbit

function test(s, t) {
  const m = s.length, n = t.length;
  if (m < n) {
      return 0;
  }
  const dp = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(0));
  for (let i = 0; i <= m; i++) {
      dp[i][n] = 1;
  }
  for (let i = m - 1; i >= 0; i--) {
      for (let j = n - 1; j >= 0; j--) {
          if (s[i] == t[j]) {
  			 // 相同的时候,(+1+1) 另外和后边沿用
              dp[i][j] = dp[i + 1][j + 1] + dp[i + 1][j];
          } else {
            // 不同的时候,延用后边的一个(也可以说和后边的一个字母保持一致)
              dp[i][j] = dp[i + 1][j];
          }
      }
  }
  return dp[0][0];
};
console.log(test("rabbbit", "rabbit")) // 3
//-------贪心算法
买卖股票的最佳时机 II
方法二:贪心
var maxProfit = function(prices) {
    let ans = 0;
    let n = prices.length;
    for (let i = 1; i < n; ++i) {
        ans += Math.max(0, prices[i] - prices[i - 1]);
    }
    return ans;
};
方法一:动态规划
var maxProfit = function(prices) {
    const n = prices.length;
    let dp0 = 0, dp1 = -prices[0];
    for (let i = 1; i < n; ++i) {
        let newDp0 = Math.max(dp0, dp1 + prices[i]);
        let newDp1 = Math.max(dp1, dp0 - prices[i]);
        dp0 = newDp0;
        dp1 = newDp1;
    }
    return dp0;
};

//-------斐波那契数列
function Fibonacci(n) {
  if (n < 2) {
    return n;
  }
  return Fibonacci(n - 1) + Fibonacci(n - 2);
}
console.log(Fibonacci(6)) // 8
//-------组合总和
输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
var combinationSum = function(candidates, target) {
    const ans = [];
    const dfs = (target, combine, idx) => {
        if (idx === candidates.length) {
            return;
        }
        if (target === 0) {
            ans.push(combine);
            return;
        }
        // 直接跳过
        dfs(target, combine, idx + 1);
        // 选择当前数
        if (target - candidates[idx] >= 0) {
            dfs(target - candidates[idx], [...combine, candidates[idx]], idx);
        }
    }
    dfs(target, [], 0);
    return ans;
};
//-------全排列
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

function permute(nums) {
  var res = new Array();
  var output = new Array();
  for (var num of nums) {
      output.push(num);
  }
  var n = nums.length;
  backtrack(n, output, res, 0);
  return res;
}
function backtrack(n, output, res, first) {
  // 所有数都填完了
  if (first === n) {
      res.push(output);
  }
  for (var i = first; i < n; i++) {
      // 动态维护数组
      swap(output, first, i);
      // 继续递归填下一个数
      backtrack(n, output, res, first + 1);
      // 撤销操作
      swap(output, first, i);
  }
}
function swap(array, left, right) {
    let tem = array[left];
    array[left] = array[right];
    array[right] = tem;
}
console.log('---', permute([1,2,3]))
//-------只出现一次的数字
function singleNumber(nums) {
  var single = 0;
  for (var num of nums) {
      single = single^num;
  }
  return single;
}

//-------链表交集
var getIntersectionNode = function(headA, headB) {
    const visited = new Set();
    let temp = headA;
    while (temp !== null) {
        visited.add(temp);
        temp = temp.next;
    }
    temp = headB;
    while (temp !== null) {
        if (visited.has(temp)) {
            return temp;
        }
        temp = temp.next;
    }
    return null;
};

//-------寻找重复数
输入:nums = [1,3,4,2,2]
输出:2
var findDuplicate = function(nums) {
    const n = nums.length;
    let l = 1, r = n - 1, ans = -1;
    while (l <= r) {
        let mid = (l + r) >> 1;
        let cnt = 0;
        for (let i = 0; i < n; ++i) {
            cnt += nums[i] <= mid;
        }
        if (cnt <= mid) {
            l = mid + 1;
        } else {
            r = mid - 1;
            ans = mid;
        }
    }
    return ans;
};
---
方法2
var findDuplicate = function(nums) {
    const n = nums.length;
    let ans = 0;
    // 确定二进制下最高位是多少
    let bit_max = 31;
    while (!((n - 1) >> bit_max)) {
        bit_max -= 1;
    }
    for (let bit = 0; bit <= bit_max; ++bit) {
        let x = 0, y = 0;
        for (let i = 0; i < n; ++i) {
            if (nums[i] & (1 << bit)) {
                x += 1;
            }
            if (i >= 1 && (i & (1 << bit))) {
                y += 1;
            }
        }
        if (x > y) {
            ans |= 1 << bit;
        }
    }
    return ans;
};



=====================================================================================
以前的

// 求中位数
function test(arr) {
  arr.sort((a, b) => a - b);
  if (arr.length % 2 === 0) {
    return (arr[arr.length / 2 -1] + arr[arr.length / 2]) / 2
  } else {
    return arr[Math.floor(arr.length / 2)]
  }
}
test([2,3,4]);

// 二分法
function test(arr, target) {
  let left = 0;
  let right = arr.length;
  while(left <= right) {
    let mid = left + Math.floor((right - left) / 2);
    if (arr[mid] < target) {
      left = mid + 1;
    } else {
      right = mid -1;
    }
  }
  return right + 1;
}
console.log(test([2,5,7,9,20], 9.5))

// 先序中序后序递归遍历一个树
function treeRecurse(tree) {
  if (!tree) return;
  console.log(tree.element);
  treeRecurse(tree.left);
  treeRecurse(tree.right);
}
function treeRecurse(tree) {
  if (!tree) return;
  treeRecurse(tree.left);
  console.log(tree.element);
  treeRecurse(tree.right);
}
function treeRecurse(tree) {
  if (!tree) return;
  treeRecurse(tree.left);
  treeRecurse(tree.right);
  console.log(tree.element);console.log(tree.element);
}

// 写一个简单树类Tree,包含add, insert
class Node {
  constructor(element) {
    this.element = element;
    this.left = null;
    this.right = null;
  }
}

class Tree {
  constructor() {
    this.root = null;
  }
  insert(root, node) {
    if (root.element < node) {
      if (!root.left) {
        root.left = node;
      } else {
        this.insert(root.left, node)
      }
    } else {
      if (!root.right) {
        root.right = node;
      } else {
        this.insert(root.right, node)
      }
    }
  }
  add (data) {
    const node = new Node(data);
    if (this.root === null) {
      this.root = node;
    } else {
      this.insert(this.root, node)
    }
  }
}

const t = new Tree();
t.add(2);
t.add(4);
t.add(9);

// 写一个简单链表类LinkList,包含insert, append方法
class Node {
  constructor(element) {
    this.element = element;
    this.next = null;
  }
}

class LinkList {
  constructor(){
    this.head = null;
    this.length = 0;
  }
  insert(position, element) {
    let node = new Node(element);
    if(!this.head){
      this.head = node;
    } else {
      let index = 0;
      let current = this.head;
      let previous = null;
      while(index++ < position){ // 找到要在谁之前插入那一项
        previous = current; // 那到要插入到哪项之前
        current = current.next; // 插入到前一个后面
      }
      previous.next = node;
      node.next = current;
    }
  }
  append(l){
    const newNode = new Node(l);
    if (!this.head) {
      this.head = newNode;
    } else {
      let index = 0;
      let current = this.head;
      while(++index < this.length) {
        current = current.next;
      }
      current.next = node;
    }
  }
}

const l = new LinkList();
l.append(2);
l.append(4);
l.append(8);

// 一个简单的数据结构Set
class Set {
  constructor() {
    this.cache = {};
  }
  add(element) {
    this.cache[element] = element;
  }
}

// 写一个Map类,包含set,get,calc
class Map {
  constructor() {
    this.map = [];
  }
  calc(key) {
    let total = 0;
    for(let i=0;i<key.length;i++) {
      total += key[i].charCodeAt();
    }
    return total % 100;
  }
  set(key, element) {
    this.cache[this.calc(key)] = element;
  }
  get(key) {
    return this.cache[this.calc(key)];
  }
}

// 快速排序
function test(arr) {
  if (arr.length < 2) {
    return arr;
  }
  const target = arr[0];
  const left = [];
  const right = [];
  for (let i = 1; i< arr.length; i++) {
    if (arr[i] < target) {
      left.push((arr[i]))
    }
    if (arr[i] > target) {
      right.push((arr[i]));
    }
  }
  return test(left).concat([target], test(right));
}
console.log(test([3,23,13,90,45]));

// 递归node dfs 深度优先
let dfs = (node, result = []) => {
  if (node !== null) {
      result.push(node)
      node.children && node.children.forEach(item => {
        dfs(children[i], result)
      })
  }
  return result
}
// 递归tree dfs 深度优先
function dfsTree(tree, result = []) {
  if (tree) {
      dfsTree(tree.left, result)
      result.push(tree, result)
      dfsTree(tree.right, result)
  }
}
// dfs 非递归
function dfsTree2(tree, result = []) {
  const stack = [];
  if (tree) {
      stack.push(tree)
      while (stack.length) {
          const item = stack.pop();
          result.push(item);
          const children = [stack.left, stack.right].filter(w => w);
          children.forEach(i => {
            stack.push(i);
          })
      }
  }
}

// bfs
function bfs(tree, result = []) {
  const stack = [];
  if (tree) {
      stack.push(tree)
      while (stack.length) {
          const item = stack.shift();
          result.push(item);
          const children = [item.left, item.right].filter(w => w);
          children.forEach(i => {
            stack.push(i);
          })
      }
  }
}
二叉树的最大深度
function TreeDepth(pRoot) {
 return !pRoot ? 0 : 
 	(Math.max(TreeDepth(pRoot.left), TreeDepth(pRoot.right)) + 1)
}
二叉树的最小深度
var minDepth = function (root) {
  if (!root) {
    return 0;
  }
  if (!root.left) {
    return 1 + minDepth(root.right);
  }
  if (!root.right) {
    return 1 + minDepth(root.left);
  }
  return Math.min(minDepth(root.left), minDepth(root.right)) + 1
};

url 切割
// 方法一
var url = 'https://www.baidu.com/a/b?name=王小二&age=8&hobby=敲代码&hobby=soccer';
function fn(str) {
    let obj = {};
    var arr = str.split('?')[1].split('&');
    arr.forEach(item => {
        const key = item.split('=')[0];
        const value = item.split('=')[1];
        if (!obj[key]) {
            obj[key] = value;
        } else {
            obj[key] = [].concat(obj[key], value);
        }
    })

    return obj;
}
console.log(fn(url));
// 方法2
let str = 'sadf?key=14&key=24&key=34&test=44';
let result = {};
str.replace(/([^?=&]+)=([^&=]+)/g, function () {
    // console.log(arguments[0], arguments[1], arguments[2])
    // key=14 key 14
    if (!result[arguments[1]]) {
        result[arguments[1]] = arguments[2];
    } else {
        result[arguments[1]] = [].concat(result[arguments[1]], arguments[2])
    }
});

字符串每三位加一个逗号
---方法1// JS 自带的 toLocaleString
function formatNumber(num) {
  return Number(num).toLocaleString()
}
---方法2// 正则表达式
function formatNumber(num) {
  return num.toString().replace(/\d+/, function (n) {
    return n.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
  })
}
console.log(formatNumber(123456789.123)) // 123,456,789.123
---方法4// slice 截取分割
function formatNumber(num, char=',', length=3) {
  let result = ''
  let nums = num.toString().split('.')
  let int = nums[0];
  let decmial = nums[1] ? '.' + nums[1] : ''
  while (int.length > length) {
    result = char + int.slice(-length) + result
    int = int.slice(0, int.length - length)
  }
  if (int) { result = int + result }
  return result + decmial
}
console.log(formatNumber(123456789.123)) // 123,456,789.123
---反转字符串
var reverseString = function(s) {
    const n = s.length;
    for (let left = 0, right = n - 1; left < right; ++left, --right) {
        [s[left], s[right]] = [s[right], s[left]];
    }
}
---比较版本
function compare( version1 ,  version2 ) {
    let arr1=version1.split(".");
    let arr2=version2.split(".");
    let length=Math.max(arr1.length,arr2.length);
    for (let i = 0; i < length; i++) {
        const n1 = Number(arr1[i]||0)
        const n2 = Number(arr2[i]||0)
        if (n1 > n2) return 1
        if (n1 < n2) return -1
    }
    return 0
}
---两数之和
var twoSum = function(nums, target) {
    const map = new Map();
    for(let i = 0, len = nums.length;i < len;i++) {
        if(map.has(target - nums[i])) {
            return [map.get(target - nums[i]), i];
        }
        map.set(nums[i], i);
    }
    return [];
};
---三数之和为0
---方法2 排序 + 双指针
时间复杂度:O(N^2)  时间复杂度O(N)
var threeSum = function(nums) {
    let arr = []
    // 直接sort()是根据字母、数字大小排序,导致-1排在-3左边
    nums.sort((a,b) => a-b)
    for (let i = 0; i < nums.length-2; i++) {
        // 当遍历下一个target与前面的相同时,跳过
        if (i > 0 && nums[i] == nums[i-1]) continue 
        let target = nums[i], x = i + 1, y = nums.length - 1 
        while (x < y) {
            let sum = target + nums[x] + nums[y]
            if (sum == 0) {
                arr.push([target, nums[x], nums[y]])
                // 准备夹逼前,将左右俩边移到相同数值最紧处
                while (x < y && nums[x+1] == nums[x]) x++
                while (x < y && nums[y-1] == nums[y]) y--
                // 有了上述的准备过程,这里夹逼时,左右俩边数值与上次数值不同
                x++
                y--
            } else if (sum > 0) {
                y--
            } else {
                x++
            }
        }
    }
    return arr
};
---在排序数组中查找元素的第一个和最后一个位置
示例 1:
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]
示例 2:
输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]
示例 3:
输入:nums = [], target = 0
输出:[-1,-1]
----答案
const binarySearch = (nums, target, lower) => {
    let left = 0, right = nums.length - 1, ans = nums.length;
    while (left <= right) {
        const mid = Math.floor((left + right) / 2);
        if (nums[mid] > target || (lower && nums[mid] >= target)) {
            right = mid - 1;
            ans = mid;
        } else {
            left = mid + 1;
        }
    }
    return ans;
}
var searchRange = function(nums, target) {
    let ans = [-1, -1];
    const leftIdx = binarySearch(nums, target, true);
    const rightIdx = binarySearch(nums, target, false) - 1;
    if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] === target && nums[rightIdx] === target) {
        ans = [leftIdx, rightIdx];
    } 
    return ans;
};
合并两个有序数组
1. 直接合并然后排序
时间复杂度:(m+n)log(m+n)
空间复杂度:log(m+n)
2. 双指针
时间复杂度:O(m+n)
空间复杂度:O(m+n)
var merge = function(nums1, m, nums2, n) {
    let p1 = 0, p2 = 0;
    const sorted = new Array(m + n).fill(0);
    var cur;
    while (p1 < m || p2 < n) {
        if (p1 === m) {
            cur = nums2[p2++];
        } else if (p2 === n) {
            cur = nums1[p1++];
        } else if (nums1[p1] < nums2[p2]) {
            cur = nums1[p1++];
        } else {
            cur = nums2[p2++];
        }
        sorted[p1 + p2 - 1] = cur;
    }
    for (let i = 0; i != m + n; ++i) {
        nums1[i] = sorted[i];
    }
};

寻找两个正序数组的中位数
----方法1.合并数组
----方法2:方法二:划分数组(太复杂,不建议背诵)
数组
// 数组中存在两数之和为target,并且返回两数的下标
// 输入:nums = [3,2,4], target = 6
// 输出:[1,2]
function twoNum (nums, target) {
  const map = Map();
  for(let i; i<nums.length; i++) {
    if (map.has(target - nums[i])){
      return [ map.get(nums[i]), nums[i]];
    } else {
      map.set(nums[i], i);
    }
  }
}
// 三数之和
// ---方法2 排序 + 双指针
// 时间复杂度:O(N^2)  空间复杂度O(N)
var threeSum = function (nums, flag) {
    let arr = []
    // 直接sort()是根据字母、数字大小排序,导致-1排在-3左边
    nums.sort((a, b) => a - b)
    for (let i = 0; i < nums.length - 2; i++) {
        // 当遍历下一个target与前面的相同时,跳过
        if (i > 0 && nums[i] == nums[i - 1]) continue
        let target = nums[i], x = i + 1, y = nums.length - 1
        while (x < y) {
            let sum = target + nums[x] + nums[y]
            if (sum == flag) {
                arr.push([target, nums[x], nums[y]])
                // 准备夹逼前,将左右俩边移到相同数值最紧处
                // 这里的两句其实不用看,用来处理重复的时候,一般测试用例不会重复
                // while (x < y && nums[x + 1] == nums[x]) x++
                // while (x < y && nums[y - 1] == nums[y]) y--
                // 有了上述的准备过程,这里夹逼时,左右俩边数值与上次数值不同
                x++
                y--
            } else if (sum > flag) {
                y--
            } else {
                x++
            }
        }
    }
    return arr
};

// 数组反转
var reverseString = function(s) {
    const n = s.length;
    for (let left = 0, right = n - 1; left < right; ++left, --right) {
        [s[left], s[right]] = [s[right], s[left]];
    }
}
reverseString([2, 3, 10, 20])

// 合并两个有序数组
// ----方法1 方法一:直接合并后排序
// 时间复杂度:(m+n)log(m+n)
// 空间复杂度:log(m+n)
var merge = function(nums1, m, nums2, n) {
    nums1.splice(m, nums1.length - m, ...nums2);
    nums1.sort((a, b) => a - b);
};
// 方法二:双指针
var merge = function(nums1, m, nums2, n) {
  let p1 = 0, p2 = 0;
  const sorted = new Array(m + n).fill(0);
  var cur;
  while (p1 < m || p2 < n) {
      if (p1 === m) {
          cur = nums2[p2++];
      } else if (p2 === n) {
          cur = nums1[p1++];
      } else if (nums1[p1] < nums2[p2]) {
          cur = nums1[p1++];
      } else {
          cur = nums2[p2++];
      }
      sorted[p1 + p2 - 1] = cur;
  }
  for (let i = 0; i != m + n; ++i) {
      nums1[i] = sorted[i];
  }
};

// 寻找两个正序数组的中位数
var findMedianSortedArrays = (nums1, nums2) => {
  let len1 = nums1.length, len2 = nums2.length
  if (len1 > len2) return findMedianSortedArrays(nums2, nums1)//对nums1和nums2中长度较小的二分
  let len = len1 + len2//总长
  let start = 0, end = len1 //进行二分的开始和结束位置
  let partLen1, partLen2
  while (start <= end) {
      partLen1 = (start + end) >> 1 // nums1二分的位置
      partLen2 = ((len + 1) >> 1) - partLen1 //nums2二分的位置
      // L1:nums1二分之后左侧的结束位置,R1 nums1二分之后右侧的起始位置
      // L2,nums2二分之后左侧结束的位置,R2 nums2二分之后右侧的起始位置
          
      //如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums1二分的位置左边一个
      let L1 = partLen1 === 0 ? -Infinity : nums1[partLen1 - 1]
      //如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums2二分的位置左边一个
      let L2 = partLen2 === 0 ? -Infinity : nums2[partLen2 - 1]
      //如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
      let R1 = partLen1 === len1 ? Infinity : nums1[partLen1]
      //如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
      let R2 = partLen2 === len2 ? Infinity : nums2[partLen2]
      
      if (L1 > R2) {//不符合交叉小于等于 继续二分
          end = partLen1 - 1
      } else if (L2 > R1) {//不符合交叉小于等于 继续二分
          start = partLen1 + 1
      } else { // L1 <= R2 && L2 <= R1 符合交叉小于等于
          return len % 2 === 0 ?
              (Math.max(L1, L2) + Math.min(R1, R2)) / 2 : //长度为偶数返回作左侧较大者和右边较小者和的一半
              Math.max(L1, L2)	//长度为奇数返回作左侧较大者
      }
  }
}

// 两个数组的交集
// 方法1:两个集合
var intersection = function (arr1, arr2) {
  const set1 = new Set(arr1);
  const set2 = new Set(arr2);
  return handle(set1, set2);
};
function handle(set1, set2) {
  if (set1.size > set2.size) {
      return handle(set2, set1)
  }
  let result = new Set();
  for (let item of set1) {
      if (set2.has(item)) {
          result.add(item);
      }
  }
  return [...result];
}
// 方法2:排序 + 双指针
var intersection = function(nums1, nums2) {
  nums1.sort((x, y) => x - y);
  nums2.sort((x, y) => x - y);
  const length1 = nums1.length, length2 = nums2.length;
  let index1 = 0, index2 = 0;
  const intersection = [];
  while (index1 < length1 && index2 < length2) {
      const num1 = nums1[index1], num2 = nums2[index2];
      if (num1 === num2) {
          // 保证加入元素的唯一性
          if (!intersection.length || num1 !== intersection[intersection.length - 1]) {
              intersection.push(num1);
          }
          index1++;
          index2++;
      } else if (num1 < num2) {
          index1++;
      } else {
          index2++;
      }
  }
  return intersection;
};

// 在排序数组中查找元素的第一个和最后一个位置
var searchRange = function(nums, target) {
  let left = 0;
  let right = nums.length - 1; // 定义target在左闭右闭的区间里,[left, right]
  while(left<=right){
      while(left<right&&nums[left]<target){
          left++;
      }
      while(left<right&&nums[right]>target){
          right--;
      }
      if(nums[left] == target&&nums[right]==target){
          return [left,right];
      }else{
          break;
      }
      
  }
  return [-1, -1];
};

----打印

-------------函数科利华 curring
const curring = (fn,arr = [])=>{
  let len = fn.length
  return (...args)=>{
  arr = arr.concat(args);
  if(arr.length < len){
    return curring(fn,arr)
  }
  return fn(...arr)
  }
}
-------------订阅模式
class EventEmitTest {
  constructor() {
  this.cache = {};
  }
  on(type, fn) {
  if (!this.cache[type]) {
    this.cache[type] = [];
  }
  this.cache[type].push(fn);
  }
  emit(type) {
  this.cache[type].forEach(item => item.call(item, arguments));
  }
}
------------js处理扁平数组和树结构相互转换
function toTree(data) {
  const obj = {};
  data.forEach(item => {
  obj[item.id] = item; 
  })
  const result = [];
  data.forEach((item) => {
  const parent = obj[item.parentId];
  if (parent) {
  parent.children = parent.children || [];
  parent.children.push(item);
  } else {
  result.push(item)
  }
  })
  return result;
}
-------------深度克隆 deepCopy
function deepCopy(value, hash = new WeakMap){
  if(!value || typeof value !== 'object')
  return value;
  if (hash.has(value)) {
  return hash.get(value)
  }
  let newObject = Array.isArray(value) ? [] : {};
  hasn.set(value, newObject);
  //遍历对象中的key Object.keys 对数组一样可以用
  Object.keys(value).forEach(key => {
  newObject[key] = value[key];
  })
  return newObject;
}
-------------reduce
function reduceTest(fn, init) {
  let result;
  this.forEach((item, itemIndex) => {
  if (itemIndex === 0) {
  if (init) {
  result = fn(init, item, itemIndex)
  } else {
  result = item;
  }
  } else {
  result = fn(result, item, itemIndex);
  }
  });
  return result;
}
-------------compose
function compose(...args) {
  return function (...params) {
  const fn = args.pop();
  const first = fn(...params);
  return args.reduceRight((prev, item) => {
    return item(prev)
  }, first)
  }
}
-------------create 的原理
function create(parentProto,{constructor: Tiger}){
   function Fn(){}
   Fn.prototype = parentProto;
   let fn = new Fn();
   fn.constructor = Tiger
   return fn;
}
-------------new 的原理
function mockNew(A){
  let obj = {}
  let returnVal = A.call(obj);
  if (result instanceof Object) {
  return returnVal;
  }
  obj.__proto__ = A.prototype
  return obj;
}
-------------浅冻结和深冻结
function deepFreeze(obj){
  Object.keys(obj).forEach(item => {
  if (typeof item === 'object' && item !== null){
  deepFreeze(item)
  }
  })
  return Object.freeze(obj);
}
-------------数组的扁平化处理mockFlat
function mockFlat(arr, depth = 1){
  if (depth <=0) {
  return arr;
  }
  let res = [];
  arr.forEach(item => {
  if(Array.isArray(item)){
    res = res.concat(mockFlat(item));
  }else{
    res.push(item);
  }
  });
  depth--;
  return res;
}
------------instanceof
function newInstanceof(leftVaule, rightVaule) { 
  let rightProto = rightVaule.prototype; // 取右表达式的 prototype 值
  leftVaule = leftVaule.__proto__; // 取左表达式的__proto__值
  while (true) {
  if (leftVaule === null) {
    return false;  
  }
  if (leftVaule === rightProto) {
    return true;  
  } 
  leftVaule = leftVaule.__proto__ 
  }
}
-------------mock bind
Function.prototype.mockbind = function() {
  const [ctx, ...args] = arguments;
  // this为真正执行的函数
  const fun = this;
  function result (...args2) {
  // 考虑是否是构造
  ctx = this instanceof result ? this : ctx;
  fun.apply(ctx, args.concat(args2));
  }
  result.prototype = Object.create(fun.prototype);
  return result;
}
-------------call apply
function newCall() {
  let [ctx, ...args] = arguments;
  if (!ctx) {
  ctx = window;
  }
  ctx.func = this;
  let result = ctx.func(...args);
  delete ctx.func; // 为什么赋值后在删除,因为函数执行后的this指向函数作用域
  return result;
}
function newApply() {
  let [ctx, args] = arguments;
  if (!ctx) {
  ctx = window;
  }
  ctx.func = this;
  let result;
  // 这里因为args可能为undefined无法通过...运算符,所以必须区分
  if (args) {
  result = ctx.func(...args);
  } else {
  result = ctx.func();
  }
  delete result.func;
  return result;
}
-------------自己实现 UseState useEffect
const memoState = [];
const cursor = 0;
function mockUseState(initval) {
  state[cursor] = state[cursor] || initval;
  function setState(data) {
  state[cursor] = data;
  render();
  }
  return [state[cursor++], setState];
}
function mockUseEffect(render, deps) {
  const cacheDeps = state[cursor];
  const same = cacheDeps ? cacheDeps.every((item, itemIndex) => item === deps[itemIndex]) : false;
  if (!same) {
  render();
  state[cursor] = deps;
  }
  cursor++;
}
-------------useMemo
function mockUseMemo(render, deps) {
  if (state[cursor]) {
  const [cacheData, cacheDeps] = state[cursor];
  const same =  cacheDeps ? cacheDeps.every((item, itemIndex) => item === deps[itemIndex]) : false;
  if (same) {
  return cacheData;
  }
  }
  const data = render();
  // 第一次渲染 或者 不是第一次但是依赖项相同,都返回新的
  state[cursor++] = [data, deps];
  return data;
}
-------------useCallback
function mockUseCallback(render, deps){
  if (state[cursor]) {
  const [cacheRender, cacheDeps] = state[cursor];
  const same =  cacheDeps ? cacheDeps.every((item, itemIndex) => item === deps[itemIndex]) : false;
  if (same) {
  return cacheRender;
  }
  }
  // 第一次渲染 或者 不是第一次但是依赖项相同,都返回新的
  state[cursor++] = [render, deps];
  return render;
}
-------------求中位数
let _median = arr => {
  arr.sort((a, b) => {
  if (a < b) return -1;
  if (a > b) return 1;
  return 0;
  })
  //求中位数
  if (arr.length % 2 == 0) {
  return (arr[arr.length / 2 - 1] + arr[arr.length / 2]) / 2;
  } else {
  return arr[Math.floor(arr.length / 2)];
  }
};
-------------二分查找
var search = function(nums, target) {
  // right是数组最后一个数的下标,num[right]在查找范围内,是左闭右闭区间
  let left = 0, right = nums.length - 1;
  // 当left=right时,由于nums[right]在查找范围内,所以要包括此情况
  while (left <= right) {
  let mid = left + Math.floor((right - left)/2);
  // 如果中间数大于目标值,要把中间数排除查找范围,所以右边界更新为mid-1;如果右边界更新为mid,那中间数还在下次查找范围内
  if (nums[mid] > target) {
    right = mid - 1;  // 去左面闭区间寻找
  } else if (nums[mid] < target) {
    left = mid + 1;   // 去右面闭区间寻找
  } else {
    return mid;
  }
  }
  return -1;
};
-------------快速排序两数组实现
function quickSort(array) {
  if (array.length < 2) {
  return array;
  }
  const target = array[0];
  const left = [];
  const right = [];
  for (let i = 1; i < array.length; i++) {
  if (array[i] < target) {
  left.push(array[i]);
  } else {
  right.push(array[i]);
  }
  }
  return quickSort(left).concat([target], quickSort(right));
}
-------------两数之和
var twoSum = function(nums, target) {
  const map = new Map();
  for(let i = 0, len = nums.length;i < len;i++) {
  if(map.has(target - nums[i])) {
    return [map.get(target - nums[i]), i];
  }
  map.set(nums[i], i);
  }
  return [];
}
------------链表 快慢指针
var middleNode = function(head) {
  slow = fast = head;
  while (fast && fast.next) {
    slow = slow.next;
    fast = fast.next.next;
  }
  return slow;
};
------------数组反转
var reverseString = function(s) {
  const n = s.length;
  for (let left = 0, right = n - 1; left < right; ++left, --right) {
    [s[left], s[right]] = [s[right], s[left]];
  }
}
------------url 切割
function fn(str) {
  let obj = {};
  var arr = str.split('?')[1].split('&');
  arr.forEach(item => {
    const key = item.split('=')[0];
    const value = item.split('=')[1];
    if (!obj[key]) {
      obj[key] = value;
    } else {
      obj[key] = [].concat(obj[key], value);
    }
  })

  return obj;
}
-----方法2
let result = {};
str.replace(/([^?=&]+)=([^&=]+)/g, function () {
  // console.log(arguments[0], arguments[1], arguments[2])
  // key=14 key 14
  if (!result[arguments[1]]) {
    result[arguments[1]] = arguments[2];
  } else {
    result[arguments[1]] = [].concat(result[arguments[1]], arguments[2])
  }
});
------------字符串每三位加一个逗号
function formatNumber(num) {
  return Number(num).toLocaleString()
}
---方法2
function formatNumber(num) {
  return num.toString().replace(/\d+/, function (n) {
  return n.replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
  })
}
------------版本比较
function compare( version1 ,  version2 ) {
  let arr1=version1.split(".");
  let arr2=version2.split(".");
  let length=Math.max(arr1.length,arr2.length);
  for (let i = 0; i < length; i++) {
    const n1 = Number(arr1[i]||0)
    const n2 = Number(arr2[i]||0)
    if (n1 > n2) return 1
    if (n1 < n2) return -1
  }
  return 0
}
------------
数组
------------合并两个有序数组
方法二:双指针
时间复杂度:O(m+n)
空间复杂度:O(m+n)
var merge = function(nums1, m, nums2, n) {
  let p1 = 0, p2 = 0;
  const sorted = new Array(m + n).fill(0);
  var cur;
  while (p1 < m || p2 < n) {
    if (p1 === m) {
      cur = nums2[p2++];
    } else if (p2 === n) {
      cur = nums1[p1++];
    } else if (nums1[p1] < nums2[p2]) {
      cur = nums1[p1++];
    } else {
      cur = nums2[p2++];
    }
    sorted[p1 + p2 - 1] = cur;
  }
  for (let i = 0; i != m + n; ++i) {
    nums1[i] = sorted[i];
  }
};
------------两个数组的交集
时间复杂度 O(mlogm+nlogn)
空间复杂度 O(logm+logn)
var intersection = function(nums1, nums2) {
  nums1.sort((x, y) => x - y);
  nums2.sort((x, y) => x - y);
  const length1 = nums1.length, length2 = nums2.length;
  let index1 = 0, index2 = 0;
  const intersection = [];
  while (index1 < length1 && index2 < length2) {
    const num1 = nums1[index1], num2 = nums2[index2];
    if (num1 === num2) {
      // 保证加入元素的唯一性
      if (!intersection.length || num1 !== intersection[intersection.length - 1]) {
        intersection.push(num1);
      }
      index1++;
      index2++;
    } else if (num1 < num2) {
      index1++;
    } else {
      index2++;
    }
  }
  return intersection;
};
------------寻找两个正序数组的中位数
var findMedianSortedArrays = (nums1, nums2) => {
  let len1 = nums1.length, len2 = nums2.length
  if (len1 > len2) return findMedianSortedArrays(nums2, nums1)//对nums1和nums2中长度较小的二分
  let len = len1 + len2//总长
  let start = 0, end = len1 //进行二分的开始和结束位置
  let partLen1, partLen2
  while (start <= end) {
    partLen1 = (start + end) >> 1 // nums1二分的位置
    partLen2 = ((len + 1) >> 1) - partLen1 //nums2二分的位置
    // L1:nums1二分之后左侧的结束位置,R1 nums1二分之后右侧的起始位置
    // L2,nums2二分之后左侧结束的位置,R2 nums2二分之后右侧的起始位置  
    //如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums1二分的位置左边一个
    let L1 = partLen1 === 0 ? -Infinity : nums1[partLen1 - 1]
    //如果左边没字符了,就定义成-Infinity,让所有数都大于它,否则就是nums2二分的位置左边一个
    let L2 = partLen2 === 0 ? -Infinity : nums2[partLen2 - 1]
    //如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
    let R1 = partLen1 === len1 ? Infinity : nums1[partLen1]
    //如果右边没字符了,就定义成Infinity,让所有数都小于它,否则就是nums1二分的位置
    let R2 = partLen2 === len2 ? Infinity : nums2[partLen2]
    
    if (L1 > R2) {//不符合交叉小于等于 继续二分
      end = partLen1 - 1
    } else if (L2 > R1) {//不符合交叉小于等于 继续二分
      start = partLen1 + 1
    } else { // L1 <= R2 && L2 <= R1 符合交叉小于等于
      return len % 2 === 0 ?
        (Math.max(L1, L2) + Math.min(R1, R2)) / 2 : //长度为偶数返回作左侧较大者和右边较小者和的一半
        Math.max(L1, L2)	//长度为奇数返回作左侧较大者
    }
  }
}
------
二叉搜索树学习
------------二叉树的最大深度
function TreeDepth(pRoot) {
  return !pRoot ? 0 : 
  (Math.max(TreeDepth(pRoot.left), TreeDepth(pRoot.right)) + 1)
 }
 ------------二叉树的最小深度
 var minDepth = function (root) {
  if (!root) {
  return 0;
  }
  if (!root.left) {
  return 1 + minDepth(root.right);
  }
  if (!root.right) {
  return 1 + minDepth(root.left);
  }
  return Math.min(minDepth(root.left), minDepth(root.right)) + 1
};
------------二叉搜索树中的搜索
var searchBST = function(root, val) {
  if (!root || val===undefined) return null;
  if (root.val === val) return root;
  return root.val > val ? searchBST(root.left, val) : searchBST(root.right, val);
};
-----------二叉树展开为链表
var flatten = function(root) {
  const list = [];
  preorderTraversal(root, list);
  const size = list.length;
  for (let i = 1; i < size; i++) {
    // 这里利用了每一项curr其实还是一个tree node含有left,right
    const prev = list[i - 1], curr = list[i];
    prev.left = null;
    prev.right = curr;
  }
};

const preorderTraversal = (root, list) => {
  if (root != null) {
    list.push(root);
    preorderTraversal(root.left, list);
    preorderTraversal(root.right, list);
  }
}
-----------二叉搜索树中两个节点之和
var findTarget = function(root, k) {
  const set = new Set();
  const helper = (root, k) => {
    if (!root) {
      return false;
    }
    if (set.has(k - root.val)) {
      return true;
    }
    set.add(root.val);
    return helper(root.left, k) || helper(root.right, k);
  }
  return helper(root, k);
};
-----------将有序数组转换为二叉搜索树
function TreeNode(val) {
  this.val = val;
  this.left = this.right = null;
}

function toTreeNode(arr, left, right) {
  let mid = Math.floor((right + left) / 2);
  let node = new TreeNode(arr[mid]);
  if (left === right) return node;
  node.right = toTreeNode(arr, mid + 1, right);
  if (right - left === 1) return node;
  node.left = toTreeNode(arr, left, mid - 1);
  return node;
}
var sortedArrayToBST = function(nums) {
  if (nums.length === 0) {
    return null
  }
  return toTreeNode(nums, 0, nums.length - 1);
};
-----------验证二叉搜索树
const helper = (root, lower, upper) => {
  if (root === null) {
    return true;
  }
  if (root.val <= lower || root.val >= upper) {
    return false;
  }
  return helper(root.left, lower, root.val) && helper(root.right, root.val, upper);
}
var isValidBST = function(root) {
  return helper(root, -Infinity, Infinity);
};
------------路径总和
var hasPathSum = function(root, targetSum) {
  if(!root) {
    return false;
  }
  if(!root.left && !root.right) {
    return targetSum === root.val;
  }
  return hasPathSum(root.left, targetSum - root.val) || 
    hasPathSum(root.right, targetSum - root.val);
};
----------
其他算法
----------LRU 缓存
var LRUCache = function(capacity) {
  this.map = new Map()
  this.capacity = capacity
};
LRUCache.prototype.get = function(key) {
  if(this.map.has(key)){
    let value = this.map.get(key)
    this.map.delete(key)
    this.map.set(key, value)
    return value
  }
  return -1
};
LRUCache.prototype.put = function(key, value) {
  if (this.map.has(key)) {
  this.map.delete(key) 
  }
  this.map.set(key, value)
  if(this.map.size > this.capacity){
    this.map.delete(this.map.keys().next().value)
  }
};
----------KMP算法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值