2021年flag-300+道算法~~~

  面对薄弱的算法,在此定一个flag,2021年实现300道+算法题,以此记录  时间2021-01-01 23:36:55开始

递归相关练习

  1、commentId  为空代表一级 不为空会等于上一条的_id 实现树状结构  代码如下

/**
 * @description 
 * @author cq
 * @Date 2021-01-01 22:48:23
 * @LastEditTime 2021-01-01 23:39:05
 * @LastEditors cq
 */

//  commentId 代表一级   不为空会等于上一条的_id
// 怎么 按照 h1 h2 h3的这种层级顺序渲染出来
const arr = [
  {
    commentId: "98bb04175fef248a00f405f81c80d217",
    createTime: "2021-01-01 13:33:55",
    questionId: "a8831daa5fec73020126af6b2940f269",
    text: "回复1-1的1-1-2",
    user_id: "o2ml-5c_nKI2Tf9pLBJBCdnbu5v4",
    _id: "85ff8afa5fef24c401285c05361e3a60",
  },
  {
    commentId: "98bb04175fef248a00f405f81c80d217",
    createTime: "2021-01-01 13:33:35",
    questionId: "a8831daa5fec73020126af6b2940f269",
    text: "回复1-1的1-1-1",
    user_id: "o2ml-5c_nKI2Tf9pLBJBCdnbu5v4",
    _id: "2424fa985fef24af0106b8f77f917199",
  },
  {
    commentId: "2f6ab8515fef247600ebabef520933ce",
    createTime: "2021-01-01 13:33:13",
    questionId: "a8831daa5fec73020126af6b2940f269",
    text: "回复第三条3-1",
    user_id: "o2ml-5c_nKI2Tf9pLBJBCdnbu5v4",
    _id: "9f2a34705fef2499012c075e4669fe44",
  },
  {
    commentId: "2f6ab8515fef246400ebab0350bf130a",
    createTime: "2021-01-01 13:32:58",
    questionId: "a8831daa5fec73020126af6b2940f269",
    text: "回复第一条1-1",
    user_id: "o2ml-5c_nKI2Tf9pLBJBCdnbu5v4",
    _id: "98bb04175fef248a00f405f81c80d217",
  },
  {
    commentId: "",
    createTime: "2021-01-01 13:32:38",
    questionId: "a8831daa5fec73020126af6b2940f269",
    text: "我是第三条",
    user_id: "o2ml-5c_nKI2Tf9pLBJBCdnbu5v4",
    _id: "2f6ab8515fef247600ebabef520933ce",
  },
  {
    commentId: "",
    createTime: "2021-01-01 13:32:30",
    questionId: "a8831daa5fec73020126af6b2940f269",
    text: "我是第二条评论",
    user_id: "o2ml-5c_nKI2Tf9pLBJBCdnbu5v4",
    _id: "98bb04175fef246e00f4046a439f441b",
  },
  {
    commentId: "",
    createTime: "2021-01-01 13:32:20",
    questionId: "a8831daa5fec73020126af6b2940f269",
    text: "我是第一条评论",
    user_id: "o2ml-5c_nKI2Tf9pLBJBCdnbu5v4",
    _id: "2f6ab8515fef246400ebab0350bf130a",
  },
]


function deep(array = [], commentId = "", newArr = []) {
  let arr = array.filter(item => item.commentId == commentId);
  for (let index = 0; index < arr.length; index++) {
    const element = arr[index];
    newArr.push({
      item: element,
      children: []
    }); //第一次把第一条评论放进来
    const downObj = array.find(item => item.commentId == newArr[newArr.length - 1].item._id);
    if (downObj) {
      deep(array, element._id, newArr[index].children)
    } else {
      continue
    }
  }
  return newArr
}
console.log(deep(arr, "", []), "deep")
View Code

  2、实现数字的阶乘

/**
 * @description
 * @author cq
 * @Date 2021-01-03 19:59:32
 * @LastEditTime 2021-01-03 20:03:17
 * @LastEditors cq
 */

/*
    使用递归 求n的阶乘
    假设 写好了一个函数 factorial
    1:1
    2:1*2  ->fn(1)*2
    3:1*2*3 ->fn(2)*3
    4:1*2*3*4 ->fn(3)*4
    ...
    n:1*2*3...*n ->factorial(n-1)*n
*/

const factorial=(n)=>{
  // 条件是
  if (n == 1) {
    return 1;
  }
  return factorial(n - 1) * n;
}

console.log(factorial(2));
console.log(factorial(3));
console.log(factorial(4));
console.log(factorial(100));
View Code

    3、求两个数的最大公约数

/**
 * @description 求两个数最大公约数
 * @author cq
 * @Date 2021-01-05 17:26:05
 * @LastEditTime 2021-01-05 17:51:42
 * @LastEditors cq
 */

/*
例:48, 57
57 % 48=9     大数对小数求余
48 % 9=3       小数对上次的余数求余,重复这个过程直到余数为0

9 % 3=0         余数为0时,此次求余的小数就是最大公约数 
*/

//功能:求两个数的最大公约数 //参数:两个数: //返回值:最大公约数

// max 是大数 min 是小数
const commonDivisor = (min, max) => {

  if (max % min) {
    return commonDivisor(max % min, min)
  } else {
    return min
  }
}

console.log(commonDivisor(9, 12))
console.log(commonDivisor(4, 2))
console.log(commonDivisor(49, 7))
console.log(commonDivisor(16, 12))
View Code

    4、求前一百的和

/**
 * @description 求和
 * @author cq
 * @Date 2021-01-05 19:52:33
 * @LastEditTime 2021-01-05 20:14:41
 * @LastEditors cq
 */

// 求前一百的和

const add=(num)=>{
  if(num==1){
    return 1
  }
  return add(num - 1) + num
}

console.log(add(100));
View Code

    5、青蛙跳问题

/**
 * @description 青蛙跳
 * @author cq
 * @Date 2021-01-08 16:03:23
 * @LastEditTime 2021-01-08 16:34:54
 * @LastEditors cq
 */

// 一只青蛙一次可以跳上1级台阶,也可以跳上2级。
// 求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

// 1-1
// 4-5

// 1 - 1 - 1 - 1
// 2 - 2
// 1 - 2 - 1
// 1 - 1 - 2
// 2 - 1 - 1
let reccord = {};
function jumpFloor(number) {
  // 开局要么先跳1要么2
  if (number === 1) {
    return 1
  }
  if (number === 2) {
    return 2
  }
  console.log(reccord, "reccord");
  if (reccord[number]) {   //最小肯定是3开始计数
    return reccord[number]
  }
  let res = jumpFloor(number - 1) + jumpFloor(number - 2);
  console.log(res, "res", reccord);
  reccord[number] = res
  console.log(reccord, "--");
  return res
}

console.log(jumpFloor(5));
View Code

数组相关练习

  6、求任意两数之和在数组中查找

/**
 * @description 求任意数组中的两项之和
 * @author cq
 * @Date 2021-01-08 16:40:32
 * @LastEditTime 2021-01-08 17:35:01
 * @LastEditors cq
 */

/*
  给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
  你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的
  假设给出的数组中只存在唯一解
  例如:
  给出的数组为 [20, 70, 110, 150] , 目标值为90
  输出 index1 = 1, index2 = 2 
*/


// 79ms
const twoSum1 = (numbers, target) => {
  for (let index = 0; index < numbers.length; index++) {
    const element = numbers[index];
    let findIndex = numbers.findIndex((item, i) => item === (target - element) && i != index);  //循环太多余
    if (findIndex != -1) {
      return [index + 1, findIndex + 1]
    }
  }
}

// 46ms
const twoSum = (numbers, target) => {
  const map = new Map();
  for (let i = 0; i < numbers.length; i++) {
    console.log("进来几次", numbers[i]);
    // 初始话的map肯定是个空的
    // 第二次进来的就不是3了  而是第二次循环的2  所以对比之下就能排除了我们写的那个排除自身的逻辑了
    if (map.has(target - numbers[i])) {
      return [map.get(target - numbers[i]) + 1, i + 1]
    } else {
      // 第一次将3放进去 和他的下标i
      map.set(numbers[i], i)
    }
  }
}


console.log(twoSum([3, 2, 4], 6));  //[2,3]
// console.log(twoSum([0, 4, 3, 0], 0));  //[ 1, 4 ]
View Code

  7、数组的奇偶性分离

/**
 * @description 数组奇偶性分离
 * @author cq
 * @Date 2021-01-08 17:40:46
 * @LastEditTime 2021-01-11 10:18:59
 * @LastEditors cq
 */


/*
  输入一个整数数组,实现一个函数来调整该数组中数字的顺序,
  使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,
  并保证奇数和奇数,偶数和偶数之间的相对位置不变。
 */

function reOrderArray(array) {
  let arr1=[]
  let arr2=[]
  for (let index = 0; index < array.length; index++) {
    const element = array[index];
    if (element%2){
      // 奇数
      arr1.push(element)
    }else{
      arr2.push(element)
    }
  }
  return [...arr1,...arr2]
}

console.log(reOrderArray([1,2,3,4,5,6,7,9,8])); 
View Code

  8、加起来的值为目标值的组合

/**
 * @description 加起来的值为目标值的组合
 * @author cq
 * @Date 2021-01-11 10:39:34
 * @LastEditTime 2021-01-11 14:56:15
 * @LastEditors cq
 */

// function duplicate(array) {
//   let arr = []
//   for (let index = 0; index < array.length; index++) {
//     const element = array[index];
//     arr.push(element.sort().join(","))
//   }
//   return [...new Set(arr)]
// }

// function deep(num, target, arr) {
//   for (let index = 0; index < num.length; index++) {
//     const element = num[index];
//     // 第一次循环把直接两数相加等于目标值的数找出来
//     const i = num.indexOf(target - element);
//     if (i != -1) {
//       arr.push([element, num[i]]);
//     } else {
//       return deep(num, target - element)
//     }
//   }
//   return arr
// }


// function combinationSum2(num, target) {
//   let arr=[];
//   for (let index = 0; index < num.length; index++) {
//     const element = num[index];
//     // 第一次循环把直接两数相加等于目标值的数找出来
//     const i = num.indexOf(target - element);
//     if (i!=-1){
//       arr.push([element, num[i]]);
//     }else{
//       deep(num, target - element, arr)
//     }
//   }
//   return duplicate(arr).map(item=>item.split(","))
// }

function combinationSum2(num, target) {
  num.sort((a, b) => a - b);
  let res = [];  //最终结果
  let temp = [];
  find(num, 0, target, temp, res);
  return res;
}
function find(num, start, target, temp, res) {
  // 当目标值减到0了就终止整个递归
  if (target == 0) {
    res.push([...temp]);
    return;
  }
  // target >= num[i] 如果目标值不如当前值大了就没有意思了
  for (let i = start; i < num.length && target >= num[i]; i++) {
    // 当下标大于0的时候且上一项与当前项相等的时候直接跳过
    console.log(i, start,"i, start");
    if (i > start && num[i] == num[i - 1]) {
      continue;
    }
    temp.push(num[i]);  //依次push 10-10-20-50  不合适-50 (10-10-20)再进去此时start保留在了3 不合适-20 再往后 加60合适
    console.log(temp, "temp-start");
    find(num, i + 1, target - num[i], temp, res);
    console.log(temp,"temp");
    temp.pop();
    console.log(temp, "pop");
  }
}

// [100,10,20,70,60,10,50],80
console.log(combinationSum2([100, 10, 20, 70, 60, 10, 50], 80));
// 返回 [[10,10,60],[10,20,50],[10,70],[20,60]]
View Code

    9、数组中相加和为0的三元组

/**
 * @description 数组中相加和为0的三元组
 * @author cq
 * @Date 2021-01-11 15:07:04
 * @LastEditTime 2021-01-11 16:20:25
 * @LastEditors cq
 */

function threeSum(num) {
  let temp = [];
  let res = [];
  num.sort((a, b) => a - b);
  find(num, 0, temp, res);
  return res
  function find(num, start, temp, res) {
    if (temp.length == 3) {
      const [a, b, c] = temp;
      if (a + b + c == 0) {
        res.push([...temp])
        return
      }
    }
    for (let index = start; index < num.length; index++) {
      const element = num[index];
      // 主要目的就是去重
      if (index > start && element == num[index - 1]) {
        continue
      }
      temp.push(element)
      find(num, index + 1, temp, res)
      temp.pop()
    }
  }
}

function threeSum1(num) {
  // write code here
  num.sort((a, b) => a - b)
  let res = [], len = num.length
  for (let i = 0; i < len - 2; i++) {
    let j = i + 1, k = len - 1
    // k , j 分别表示尾部开始的最后一项和当前想的下一项
    if (i == 0 || num[i] != num[i - 1]) {
      while (k > j) {
        if (num[i] + num[j] + num[k] == 0) {
          // 满足条件 直接放进
          res.push([num[i], num[j], num[k]])
          // 头部去重(如果后面一个数跟当前的数字相等,则代表有重复的结果生成,跳过)
          while (j + 1 < k && num[j + 1] === num[j]) j++;
          // 尾部去重(如果前面一个数跟当前的数字相等,则代表有重复的结果生成,跳过)
          while (k - 1 > j && num[k - 1] === num[k]) k--;

          k--;
          j++
        } else if (num[i] + num[j] + num[k] > 0) {
          // 因为当前数组是按照从小到大排序的  所以如果三项大于0 肯定越往后越大于0
          // 反之一样
          k--
        } else if (num[i] + num[j] + num[k] < 0) {
          j++
        }
      }
    }
  }
  return res
}

console.log(threeSum([-2, 0, 1, 1, 2, -3, -4, 3, 4,-3,3]), "threeSum");  //[[-2,0,2],[-2,1,1]]
console.log(threeSum1([-2, 0, 1, 1, 2, -3, -4, 3, 4,-3,3]), "threeSum1");  //[[-2,0,2],[-2,1,1]]
View Code

  10、数组中未出现的最小正整数

/**
 * @description 数组中未出现的最小正整数
 * @author cq
 * @Date 2021-01-11 16:40:05
 * @LastEditTime 2021-01-11 17:08:54
 * @LastEditors cq
 */


/*
  给定一个无序数组arr,找到数组中未出现的最小正整数
  例如arr = [-1, 2, 3, 4]。返回1
  arr = [1, 2, 3, 4]。返回5
  [要求]
  时间复杂度为O(n)O(n),空间复杂度为O(1)O(1)
*/

// 废柴 错误
function minNumberdisappered(arr) {
  arr.sort((a, b) => a - b);
  let i = 0
  while (i < arr.length) {
    if (arr[i] >= 0) {
      // 从大于0的时候开始计算
      if ((arr[i] + 1) != arr[i + 1]) {
        return arr[i] + 1
      }
    } else {
      if (arr[i + 1] > 0) {
        return arr[i + 1] - 1
      }
    }
    i++
  }
}

// 经典35 正确
function minNumberdisappered1(arr) {
  // write code here
  const len = arr.length
  for (let i = 1; i <= len; i++) {
    if (arr.indexOf(i) === -1) {
      return i
    }
  }
  return len + 1
}

console.log(minNumberdisappered([-1, 2, 3, 4])); //1
console.log(minNumberdisappered([1, 2, 3, 4])); //5

console.log(minNumberdisappered([-1, 200, 300, 450]), "minNumberdisappered");
console.log(minNumberdisappered1([-1, 200, 300, 450]),"minNumberdisappered1");
View Code

  11、从0,1,2,...,n这n+1个数中选择n个数,组成有序数组,找出这n个数中缺失的那个数

/**
 * @description 缺失数
 * @author cq
 * @Date 2021-01-11 17:27:21
 * @LastEditTime 2021-01-11 17:31:32
 * @LastEditors cq
 */



/*
  从0,1,2,...,n这n+1个数中选择n个数,组成有序数组,
  找出这n个数中缺失的那个数,要求O(n)尽可能小。
 */

function solve(a) {
  for (let index = 0; index < a.length; index++) {
    const element = a[index];
    if ((element + 1) != a[index+1]){
      return element + 1
    }
  }
}

function solve1(a) {
  let index = 0
  while (a[index] + 1 === a[index + 1]) {
    index++
  }
  return a[index] + 1
}

function solve2(a) {
  // write code here
  let left = 0, right = a.length
  while (left < right) {
    const mid = left + Math.floor((right - left) / 2)
    if (a[mid] === mid) {
      left = mid + 1
    } else if (a[mid] > mid) {
      right = mid
    }
  }
  return left

}

console.log(solve([0, 1, 2, 3, 4, 5, 7])); //6
View Code

   13、数组中只出现一次的数字

/**
 * @description 数组中只出现一次的数字
 * @author cq
 * @Date 2021-01-13 20:18:49
 * @LastEditTime 2021-01-13 20:28:53
 * @LastEditors cq
 */

function FindNumsAppearOnce(array) {
  // write code here
  let res = [];
  for (let index = 0; index < array.length; index++) {
    const element = array[index];
    const arr = array.filter(el => el == element);
    if (arr.length == 1) {
      res.push(arr[0])
    } else {
      continue
    }
  }
  return res
}

function FindNumsAppearOnce1(array) {
  // write code here
  // return list, 比如[a,b],其中ab是出现一次的两个数字
  let arrObj = {}
  for (let i = 0; i < array.length; i++) {
    let stringItem = array[i].toString()
    let temp = arrObj[stringItem]
    if (temp) {
      delete arrObj[stringItem]
    } else {
      arrObj[stringItem] = 1
    }
  }
  return Object.keys(arrObj)
}

console.log(FindNumsAppearOnce([2, 4, 3, 6, 3, 2, 5, 5]));
console.log(FindNumsAppearOnce1([2, 4, 3, 6, 3, 2, 5, 5]),"FindNumsAppearOnce1");
View Code

   14、数组中的某一个数字超过了数组长度的一半

/**
 * @description 数组中的某一个数字超过了数组长度的一半
 * @author cq
 * @Date 2021-01-13 20:33:45
 * @LastEditTime 2021-01-13 20:44:39
 * @LastEditors cq
 */




/*
  数组中有一个数字出现的次数超过数组长度的一半,
  请找出这个数字。例如输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。
  由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
 */
function MoreThanHalfNum_Solution(numbers) {
  // write code here
  let res = 0
  for (let index = 0; index < numbers.length; index++) {
    const element = numbers[index];
    const arr = numbers.filter(el => el == element);
    if (arr.length > (numbers.length / 2)) {
      res = arr[0]
    } else {
      continue
    }
  }
  return res
}

// 真尼玛牛逼
function MoreThanHalfNum_Solution1(arr) {
  let sortArr = arr.sort()
  let count = 0;
  let midNum = sortArr[Math.floor(sortArr.length / 2)]
  console.log(midNum);
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] === midNum) {
      count++
    }
  }
  return count > Math.floor(sortArr.length / 2) ? midNum : 0
}

console.log(MoreThanHalfNum_Solution([2, 2, 2, 2, 2, 1, 3, 4, 5])); //2
console.log(MoreThanHalfNum_Solution1([2, 2, 2, 2, 2, 1, 3, 4, 5]),"MoreThanHalfNum_Solution1"); //2
View Code

闭包练习

  12、闭包打印

/**
 * @description 参杂一个闭包看看
 * @author cq
 * @Date 2021-01-11 18:05:16
 * @LastEditTime 2021-01-11 20:01:45
 * @LastEditors cq
 */

function fun(n, o) {
  console.log(o)
  return {
    fun: function (m) {
      return fun(m, n)
    }
  }
}

//注意看 最外层和最内层都有一个n
// var a = fun(0);//undefined  此时n=0  闭包
// a.fun(1);  //0
// a.fun(2);  //0
// a.fun(3)  //0

// undefined--0--1--2
// var b = fun(0).fun(1).fun(2).fun(3)


// undefined--0     1 1
var c = fun(0).fun(1); c.fun(2); c.fun(3)
View Code
原文地址:https://www.cnblogs.com/cq1715584439/p/14221296.html