js数组去重算法总结

一、去重

我在前端面试过程中遇到去重算法的概率为百分之九十,这里就总结下各种去重算法及其复杂度

1. new Set()

ES6中介绍了Set相关的概念,它可以实现数组和字符串去重的功能,代码量非常少,一行代码的事情

//数组去重
const arr = [1,1,2,2]
function unique1(arr){
  return [...new Set(arr)]  //[1,2]
}
//或者
function unique1(arr){
   return Array.from(new Set(arr))  //[1,2]
}
//补充 字符串去重
[...new Set('aabbccs')].join('') //'abcs'

2. filter + indexOf 过滤

indexOf有兼容性问题,支持ie8以上

这里我就假设传进来的一定是一个合法的数组,那些对入参的校验这里就不作处理了,直接写逻辑代码。

function unique2(arr){
   return arr.filter((item,index,arr)=>arr.indexOf(item) == index)
}
console.log(fn([1,1,2,2,3]))//[1,2,3]

这个方法利用了filter的第三个参数还是返回原数组,通过判断这个数组的第n个元素的位置是不是原始位置来过滤重复数字。例如,第一个1出现在0位置上,那么arr.indexOf(item) = 0 和index = 0 是匹配上的,第2个1出现在1位置上但是arr.indexOf(item) 还是等于0,而此时的index = 1 那么这时候 arr.indexOf(item) 不等于 index,这样重复的number就被过滤掉啦

3.object 对象属性不重复

该方法速度最快,以空间换时间。不过需要注意的是,该方法中判断数组元素是否为对象的键值

function unique3(arr){
    const obj = {}
    arr.map(item=> obj[item] = item)
    return Object.keys(obj)
}
console.log(unique3([1,1,2,2,3])) //['1','2','3']

注意:这个方法返回的值为字符串了,这里注意要转换下

4. indexOf + 新数组

新增一个数组,判断这个新数组中是否存在item元素,不存在就push,存在就忽略

function unique4(arr){
   const newArr = []
   arr.forEach(item=>{
       newArr.indexOf(item) === -1 ? newArr.push(item):null
   })
   return newArr
}
console.log(unique4([1,1,2,2,3])) //[1,2,3]

5. includes + 新数组

思路和方法4一样,只是使用方法由indexOf改为includes

function unique5(arr){
   const newArr = []
   arr.forEach(item=>{
       !newArr.includes(item)  ? newArr.push(item):null
   })
   return newArr
}
console.log(unique5([1,1,2,2,3])) //[1,2,3]

6.对象数组中id重复的去重

const repeatArr = [
  { id: 1, a: 1 },
  { id: 2, a: 2 },
  { id: 3, a: 3 },
  { id: 1, a: 4 },
];
const newArr = repeatArr.reduce((arr, cur) => {
    const ids = arr.map(item => item.id);
    return ids.includes(cur.id) ? arr : [...arr, cur];
}, []);
console.log(newArr); // -> [ { id: 1, a: 1}, {id: 2, a: 2}, {id: 3, a: 3} ]

二、将mxn矩阵的数组转换为nxm的数组

将数组中每个元素中的第一位组成新数组中第一个元素,数组中每个元素的第二位组成新数组中的第二个元素.....直到最后一位
题目描述可能有点绕,具体可以看看示例就能明白了
例如
示例一:arr = [ [1, 2, 3 ], [4, 5, 6 ],[7, 8, 9 ] ],将arr转换为 arr = [[1,4,7], [2,5,8],[3,6,9]]
示例二:arr = [ [1, 2, 3,4 ], [5, 6,7,8 ],[9,10,11,12 ] ],将arr转换为 arr = [[1,5,9], [2,6,10],[3,7,11],[4,8,12]]
参考解答方案

 let arr = [
            [1,  2,  3,  4],
            [5,  6,  7,  8],
            [9, 10, 11, 12],
            [13,14, 15, 16],
            [17,18, 19, 20],
        ]
function coverFun(arr) {
   //这里先定义一个新的空的数组,将新数组个长度先定义下
   //两种方法都可以
   let newArr = Array.apply(null,{length:arr[0].length})
                        .map((item,i)=>{return []})
    // let newArr = Array.from({length:arr[0].length})
    //                    .map((item,i)=>{return []})
    //外层遍历数组第一个元素的长度(这里随便哪个元素都行,因为都是一样的)
    //里层遍历数组长度
    for (let i = 0; i < arr[0].length; i++) {
         for (let j = 0; j < arr.length; j++) {
              newArr[i].push(arr[j][i])
          }
    }
    return newArr
}
console.log(coverFun(arr))

最后输出结果如图


js数组去重算法总结_第1张图片
输出结果

当时一紧张脑子啥也没想到,回来好好看了算法相关的题目,将js相关的算法汇总下。
当然上面的只是我想到的其中一种解题思路,肯定会有很多其他办法也可以实现的。

三、螺旋矩阵

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

例如输入
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]
输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]

这题跟上面的点相似之处

四、判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例 1:
输入: 121
输出: true

示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。
参考解答方案

var isPalindrome = function(x) {
    if((x+'').indexOf('-') >-1){
        return false
    }
    let str = String(x)
    str = str.split('').reverse().join('')
    if(str === String(x) ){
        return true
    }else {
        return false
    }
};

五、盛最多水的容器

给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。


js数组去重算法总结_第2张图片
图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例:

输入: [1,8,6,2,5,4,8,3,7]
输出: 49
参考解答方案

var maxArea = function(height) {
    let max = 0//假设最大为0
    for(let i= 0;i<=height.length-1;i++){
        for(let j=1+i;j<=height.length-1;j++){
            if(Math.min(height[i],height[j])*Math.abs(i-j)>max)
               max =  Math.min(height[i],height[j])*Math.abs(i-j)
        }
    }
    return max
};

六、最大公共前缀

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""。

示例 1:

输入: ["flower","flow","flight"]
输出: "fl"
示例 2:

输入: ["dog","racecar","car"]
输出: ""
解释: 输入不存在公共前缀。
说明:

所有输入只包含小写字母 a-z 。
参考解答方案

var longestCommonPrefix = function(strs) {
    if(strs.length ===0){
        return ''
    }else if(strs.length ===1){
        return strs[0]
    }
    let index = ''//假设index是公共字符串
     for(let i = 0;i

七、三数之和

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

参考解答方案

var threeSum = function(nums) {
    let arr = []
     for(let i=0;i{
        return item.sort().join(',')
    })
    let lastArr = [...new Set(a)]
    
    return  lastArr.map(item=>{
          return item.split(',').map(item=>{
              return Number(item)
          })
    })
};

八、最大子序和

描述

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

九、最接近的三数之和

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.
与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).

十、爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。

例如:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶
var climbStairs = function(n) {
    let arr = [],index=0
  //1.首先先算出有多少1和2的组合
    for( let i = 0; i <= n; i++ ){
        for( let j = 0; j<=n;j++){
            if(i*1 + 2*j === n){  //i 个1, j个2
                arr.push([i,j]) //
            }
        }
    }
    //这是一个实现乘积的递归算法
    function getCJ(n){
        if(n=1){
            return 1
        }
        return n*getCJ(n-1)
    }
   //2.在计算每一种组合内部有多少排列方式
    for (let n =0;n-1){
            index +=1
      //2.1当组合中的1或者2只有1个的时候排列方式为 当前数组元素相加的和
        }else if((item.indexOf(1)>-1)){
            index += item[0] +item[1]
        }else{
           //2.3最复杂的情况 m个1和n个2的情况(m,n>=2) 排列方式 有(m+n)!/(m!*n!)种
            index += getCJ(item[0]+item[1])/(getCJ(item[0])*getCJ(item[1]))
        }
    }
    return index
};
console.log(climbStairs(7)) //21

你可能感兴趣的:(js数组去重算法总结)