Skip to content

js 算法 ​

提高性能的点 ​

  • 对象尽量使用 es6 解构方式,尽量少的去访问引用类型
  • 不要过多频繁的使用 push,会影响性能

数组去重 ​

  1. 两个循环判断

判断问题:拿第一个和每一个去做比较,所以需要用到两个循环;

(1)写两个循环,第一个循环数组第一个数据,第二个循环让每一个和第一个做比较。

(2)第二循环 j=i+1,再判断第二个循环的下标是否和第一个循环的下标的字符相同,如果是相同的,则删除一个

(3)删除之后数组变短,让 j 减一,重新做比较。

js
for (var i = 0; i < ary.length; i++) {
  for (var k = i + 1; k < ary.length; k++) {
    if (ary[i] === ary[k]) {
      if (i == k) {
        //如果k等于0,则需要这一步
        continue
      }
      ary.splice(k, 1)
      k--
      //前面删除一个之后数组的长度会进1,此时的k会直接跳到循环去加1,让k减1;
    }
  }
}
for (var i = 0; i < ary.length; i++) {
  for (var k = i + 1; k < ary.length; k++) {
    if (ary[i] === ary[k]) {
      if (i == k) {
        //如果k等于0,则需要这一步
        continue
      }
      ary.splice(k, 1)
      k--
      //前面删除一个之后数组的长度会进1,此时的k会直接跳到循环去加1,让k减1;
    }
  }
}
  1. 使用 set 去重
js
Array.from(new Set([1,2,2,3])
Array.from(new Set([1,2,2,3])
  1. 使用 reduce 去重
js
let arr = [1, 2, 3, 4, 4, 1]
let newArr = arr.reduce((pre, cur) => {
  if (!pre.includes(cur)) {
    return pre.concat(cur)
  } else {
    return pre
  }
}, [])
let arr = [1, 2, 3, 4, 4, 1]
let newArr = arr.reduce((pre, cur) => {
  if (!pre.includes(cur)) {
    return pre.concat(cur)
  } else {
    return pre
  }
}, [])
  1. 使用 filter 去重;
js
function unique(array) {
  var str = ''
  return array.filter((item) => {
    //利用filter过滤返回true的情况;
    // 判断字符串中有没有,如果有,则return;
    if (str.includes(typeof item + item)) return
    return (str += typeof item + item) // 如果没有,则存入,返回true;
  })
}
function unique(array) {
  var str = ''
  return array.filter((item) => {
    //利用filter过滤返回true的情况;
    // 判断字符串中有没有,如果有,则return;
    if (str.includes(typeof item + item)) return
    return (str += typeof item + item) // 如果没有,则存入,返回true;
  })
}

数组乱序 ​

  1. 原地洗牌,不需要声明额外的数组从而更加节约内存占用率,

原理:依次遍历数组的元素,将当前元素和之后的所有元素中随机选取一个,进行交换

js
function shuffle(arr){
    for(let i=0;i<arr.length;i++){
        // 由于下标从0开始,length从1开始因此使用floor向下取整;
        let index= i + Math.floor(Math.random()*arr.length);
        [arr[i],arr[index]] = [arr[index],arr[i]]; // 这里使用了es6的交换位置方法
    }
    return arr
}   // 传入一个数组则乱序
function shuffle(arr){
    for(let i=0;i<arr.length;i++){
        // 由于下标从0开始,length从1开始因此使用floor向下取整;
        let index= i + Math.floor(Math.random()*arr.length);
        [arr[i],arr[index]] = [arr[index],arr[i]]; // 这里使用了es6的交换位置方法
    }
    return arr
}   // 传入一个数组则乱序
  1. 非原地洗牌
js
function sort2(arr) {
  let arr2 = []
  while (arr.length) {
    // arr的长度会越来越少; 实现随机生成的乱序;
    let index = Math.floor(Math.random() * arr.length)
    arr2.push(arr.splice(index, 1)[0])
  }
  return arr2
}
function sort2(arr) {
  let arr2 = []
  while (arr.length) {
    // arr的长度会越来越少; 实现随机生成的乱序;
    let index = Math.floor(Math.random() * arr.length)
    arr2.push(arr.splice(index, 1)[0])
  }
  return arr2
}
  1. 使用 sort 进行乱序
js
let sort2 = (arr) => arr.sort(() => Math.random() - 0.5)
let sort2 = (arr) => arr.sort(() => Math.random() - 0.5)

数组排序 ​

  1. 选择数组排序

判断问题:拿第一个和每一个去做比较,如果大于第二个,则让第一个到第二个位置去;

(1)写两个循环,第二个循环 j=i+1;,不比较本身。

(2)判断数组的第一个字符 i 是否大于数组的第二个 j 字符,如果大于第一个字符,则调换位置。

  1. 冒泡数组排序
js
for (var i = 0; i < ary.length; i++) {
  for (var k = 0; k < ary.length; k++) {
    if (ary[k] > ary[k + 1]) {
      //2k > 1n 1n 2k
      var n = ary[k]
      ary[k] = ary[k + 1]
      ary[k + 1] = n
    } //自身和紧挨着的后一个比较;
  }
}
for (var i = 0; i < ary.length; i++) {
  for (var k = 0; k < ary.length; k++) {
    if (ary[k] > ary[k + 1]) {
      //2k > 1n 1n 2k
      var n = ary[k]
      ary[k] = ary[k + 1]
      ary[k + 1] = n
    } //自身和紧挨着的后一个比较;
  }
}
  1. sort()排序
js
arr.sort();
从大到小==>  arr.sort((a,b)=>b-a)
arr.sort();
从大到小==>  arr.sort((a,b)=>b-a)

对象拷贝方法 ​

浅拷贝:...扩展运算符浅拷贝;

js
var obj = { a: 'haha', b: { c: 'haha' } }
var obj2 = { ...obj }
obj.b.c = 'lalala'
console.log(obj2.b.c) // 'lalala'
var obj = { a: 'haha', b: { c: 'haha' } }
var obj2 = { ...obj }
obj.b.c = 'lalala'
console.log(obj2.b.c) // 'lalala'

深拷贝:

  1. JSON 方法
js
let obj = { name: 'zs', age: 18 }
let obj2 = JSON.parse(JSON.stringify(obj))
obj2.name = 'ww'
let obj = { name: 'zs', age: 18 }
let obj2 = JSON.parse(JSON.stringify(obj))
obj2.name = 'ww'
  1. jquery 深拷贝
js
var obj2 = $.extend(true, {}, obj3)
var obj2 = $.extend(true, {}, obj3)
  1. 浅拷贝+递归
js
// 第二个参数可传可不传;
function deepClone(origin,target={}){
    for(let prop in origin){
        // 不拷贝原型上的内容;
        if(origin.hasOwnProperty(prop){
            // 判断该值还是不是一个对象;
            if(typeof origin[prop] === 'object'){
                // 判断一下类型,并进行拷贝;
                target[prop] = Array.isArray(origin[prop]) ? [] : {}
                deepClone(origin[prop],target[prop])
            } else {
                target[prop] = origin[prop]
            }
        }
    }
    return target
}
// 第二个参数可传可不传;
function deepClone(origin,target={}){
    for(let prop in origin){
        // 不拷贝原型上的内容;
        if(origin.hasOwnProperty(prop){
            // 判断该值还是不是一个对象;
            if(typeof origin[prop] === 'object'){
                // 判断一下类型,并进行拷贝;
                target[prop] = Array.isArray(origin[prop]) ? [] : {}
                deepClone(origin[prop],target[prop])
            } else {
                target[prop] = origin[prop]
            }
        }
    }
    return target
}

对象合并 ​

  1. jquery
js
var obj2 = $.extend({}, obj1, obj3, obj4)
var obj2 = $.extend({}, obj1, obj3, obj4)
  1. vue 中
js
vm.userPro = Object.assign({}, obj1, obj2)
vm.userPro = Object.assign({}, obj1, obj2)

扁平化数组 ​

  1. reduce
js
let arr = [1, 2, [3, 4, [5, 6]]]
function fn(arr) {
  return arr.reduce((p, c) => {
    return p.concat(Array.isArray(c) ? fn(c) : c)
  }, [])
}
fn(arr) // [1,2,3,4,5,6]
let arr = [1, 2, [3, 4, [5, 6]]]
function fn(arr) {
  return arr.reduce((p, c) => {
    return p.concat(Array.isArray(c) ? fn(c) : c)
  }, [])
}
fn(arr) // [1,2,3,4,5,6]
  1. toString和split方法,仅对数字有效
js
let arr = [1, 2, [3, 4, [5, 6]]]
let arr2 = JSON.parse(`[${arr.toString()}]`)
let arr = [1, 2, [3, 4, [5, 6]]]
let arr2 = JSON.parse(`[${arr.toString()}]`)
  1. 使用递归遍历
js
let arr = [1,2,[3,4,[5,6]]]
function fn(arr){
    let res = []
    arr.map(item=>{
        if(Array.isArray(item){
            res = res.concat(fn(item))  // 将调用的结果合并
        }
        res.push(item)
    })
    return res
}
let arr = [1,2,[3,4,[5,6]]]
function fn(arr){
    let res = []
    arr.map(item=>{
        if(Array.isArray(item){
            res = res.concat(fn(item))  // 将调用的结果合并
        }
        res.push(item)
    })
    return res
}
  1. flat() 括号里面传入数字,表示扁平化几个,当传入 Infinity 时,会扁平所有的数组;
js
var arr = [1[,2,3,[4,5,6]]]
arr.flat(Infinity)
var arr = [1[,2,3,[4,5,6]]]
arr.flat(Infinity)
  1. 使用...扩展运算符,最实用的一个方法
js
let arr = [1, 2, [{ name: 'h' }, [{ age: 18 }]]]
while (arr.some(Array.isArray)) {
  arr = [].concat(...arr)
}
console.log(arr)
let arr = [1, 2, [{ name: 'h' }, [{ age: 18 }]]]
while (arr.some(Array.isArray)) {
  arr = [].concat(...arr)
}
console.log(arr)

力扣题 ​

查找下列数据 id 为 xx 的数据 ​

var arr = [{
    id: 3,
    name: "gao"
}, {
    id: 4,
    name: 4,
    child: [
        {
            id: 3,
            name: "gao3"
        }
    ]
}]
function getById(data,id){
    let arr = []
    for(var i = 0;i<data.length;i++){
        if(data[i].id==id){
            arr.push(data[i])
        }
        if(data[i].child){
            arr.push(...getById(data[i].child,id))
        }
    }
    return arr
}
console.log(getById(arr,3));
var arr = [{
    id: 3,
    name: "gao"
}, {
    id: 4,
    name: 4,
    child: [
        {
            id: 3,
            name: "gao3"
        }
    ]
}]
function getById(data,id){
    let arr = []
    for(var i = 0;i<data.length;i++){
        if(data[i].id==id){
            arr.push(data[i])
        }
        if(data[i].child){
            arr.push(...getById(data[i].child,id))
        }
    }
    return arr
}
console.log(getById(arr,3));

两数之和 ​

js
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1]
jsx
map解法
var twoSum = function (nums, target) {
  let map = new Map()
  for (let i = 0; i < nums.length; i++) {
    if (map.has(target - nums[i])) {
      return [map.get(target - nums[i]), i]
    } else {
      map.set(nums[i], i)
    }
  }
}
双for循环
var twoSum = function (nums, target) {
  for (let i = 0; i < nums.length; i++) {
    for (let j = i + 1; j < nums.length + 1; j++) {
      if (target - nums[i] === nums[j]) {
        return [i, j]
      }
    }
  }
}
map解法
var twoSum = function (nums, target) {
  let map = new Map()
  for (let i = 0; i < nums.length; i++) {
    if (map.has(target - nums[i])) {
      return [map.get(target - nums[i]), i]
    } else {
      map.set(nums[i], i)
    }
  }
}
双for循环
var twoSum = function (nums, target) {
  for (let i = 0; i < nums.length; i++) {
    for (let j = i + 1; j < nums.length + 1; j++) {
      if (target - nums[i] === nums[j]) {
        return [i, j]
      }
    }
  }
}

寻找两个正序数组的中位数 ​

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
jsx
var findMedianSortedArrays = function (nums1, nums2) {
  let arr = nums1.concat(nums2).sort((a, b) => a - b)
  return arr.length % 2
    ? arr[Math.floor(arr.length / 2)]
    : (arr[arr.length / 2] + arr[arr.length / 2 - 1]) / 2
}
var findMedianSortedArrays = function (nums1, nums2) {
  let arr = nums1.concat(nums2).sort((a, b) => a - b)
  return arr.length % 2
    ? arr[Math.floor(arr.length / 2)]
    : (arr[arr.length / 2] + arr[arr.length / 2 - 1]) / 2
}

回文数 ​

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
jsx
var isPalindrome = function (x) {
  if (x < 0 || (x > 0 && x % 10 === 0)) return false
  let x2 = x,
    res = 0
  while (x2) {
    res = res * 10 + (x2 % 10)
    x2 = Math.floor(x2 / 10)
  }
  return res === x
}
var isPalindrome = function (x) {
  if (x < 0 || (x > 0 && x % 10 === 0)) return false
  let x2 = x,
    res = 0
  while (x2) {
    res = res * 10 + (x2 % 10)
    x2 = Math.floor(x2 / 10)
  }
  return res === x
}

罗马数字转整数 ​

jsx
var romanToInt = function (s) {
  const map = {
    I: 1,
    IV: 4,
    V: 5,
    IX: 9,
    X: 10,
    XL: 40,
    L: 50,
    XC: 90,
    C: 100,
    CD: 400,
    D: 500,
    CM: 900,
    M: 1000,
  }
  let num = 0
  for (let i = 0; i < s.length; ) {
    if (map[s.substring(i, i + 2)]) {
      num += map[s.substring(i, i + 2)]
      i += 2
    } else {
      num += map[s[i]]
      i++
    }
  }
  return num
}
var romanToInt = function (s) {
  const map = {
    I: 1,
    IV: 4,
    V: 5,
    IX: 9,
    X: 10,
    XL: 40,
    L: 50,
    XC: 90,
    C: 100,
    CD: 400,
    D: 500,
    CM: 900,
    M: 1000,
  }
  let num = 0
  for (let i = 0; i < s.length; ) {
    if (map[s.substring(i, i + 2)]) {
      num += map[s.substring(i, i + 2)]
      i += 2
    } else {
      num += map[s[i]]
      i++
    }
  }
  return num
}

寻找两个正序数组的中位数 ​

jsx
var findMedianSortedArrays = function (nums1, nums2) {
  let arr = nums1.concat(nums2).sort((a, b) => a - b)
  const len = arr.length
  return len % 2 ? arr[Math.floor(len / 2)] : (arr[len / 2 - 1] + arr[len / 2]) / 2
}
var findMedianSortedArrays = function (nums1, nums2) {
  let arr = nums1.concat(nums2).sort((a, b) => a - b)
  const len = arr.length
  return len % 2 ? arr[Math.floor(len / 2)] : (arr[len / 2 - 1] + arr[len / 2]) / 2
}

判断一个字符串"{a(b[c]d)e}f"是否括号匹配 ​

jsx
function matchBracket(str) {
  let len = str.length
  if (len === 0) return true
  let stack = []
  let left = '{[('
  let right = '}])'
  for (let i = 0; i < len; i++) {
    let s = str[i]
    if (left.includes(s)) {
      stack.push(s)
    } else if (right.includes(s)) {
      let a = stack[stack.length - 1]
      if (isMatch(a, s)) {
        stack.pop()
      } else {
        return false
      }
    }
  }
  return stack.length === 0
}
function isMatch(left, right) {
  if (left === '{' && right === '}') return true
  if (left === '[' && right === ']') return true
  if (left === '(' && right === ')') return true
  return false
}
console.log(matchBracket('{a(b[c]d)e}}'))
function matchBracket(str) {
  let len = str.length
  if (len === 0) return true
  let stack = []
  let left = '{[('
  let right = '}])'
  for (let i = 0; i < len; i++) {
    let s = str[i]
    if (left.includes(s)) {
      stack.push(s)
    } else if (right.includes(s)) {
      let a = stack[stack.length - 1]
      if (isMatch(a, s)) {
        stack.pop()
      } else {
        return false
      }
    }
  }
  return stack.length === 0
}
function isMatch(left, right) {
  if (left === '{' && right === '}') return true
  if (left === '[' && right === ']') return true
  if (left === '(' && right === ')') return true
  return false
}
console.log(matchBracket('{a(b[c]d)e}}'))

实现数字千分位格式化 ​

jsx
function formatl(n) {
  n = Math.floor(n)
  let s = n.toString()
  let arr = s.split('').reverse()
  return arr.reduce((perv, val, index) => {
    if (index % 3 === 0) {
      s
      if (perv) {
        return val + ',' + perv
      } else {
        return val
      }
    } else {
      return val + perv
    }
  })
}
console.log(formatl(1234567895))
s
function formatl(n) {
  n = Math.floor(n)
  let s = n.toString()
  let arr = s.split('').reverse()
  return arr.reduce((perv, val, index) => {
    if (index % 3 === 0) {
      s
      if (perv) {
        return val + ',' + perv
      } else {
        return val
      }
    } else {
      return val + perv
    }
  })
}
console.log(formatl(1234567895))
s