递归思想和数组扁平化

466 阅读4分钟

前言

在面试中我们常常会被问到数组的扁平化,把多维数组降维被称为扁平化。在这过程中我们会使用到递归,接下来我们来好好聊聊。

递归

首先我们先来看一个例子,数字的阶乘

function mul(num){
    let res=1;
    for(let i=1;i<=num;i++){
          res=res*i;
    }
      return res;
}
let a=mul(5);
console.log(a);

这里我们使用了for循环,从1开始不断相乘直到i等于num,而这里我们就可以引入递归的思想,递归说白了就是自己调用自己,还是这个题目我们可以这么想:

mul(5)=5*mul(4);

mul(4)=4*mul(3);

mul(3)=3*mul(2);

mul(2)=2*mul(1);

mul(1)=1

递归思想最重要就是两点:1.找公式 2.找出口

公式就是mul(num)=mun*mul(num-1),而出口就是当num=1或者0的时候

function mul(num){
   if(num==1 || num==0){
   return 1;
   }else{
   return num*mul(num-1);
   }
}

console.log(mul(5));//120

接下来我们看另一个例子,斐波那契数列

斐波那契数列:1,1,2,3,5,8,13,21.....除了第一位和第二位,后一位数为前两位之和

因此公式为fb(n)=fb(n-1)+fb(n-2) (n>2)

出口就为n=1或n=2

代码如下:

function fb(n){
   if(n==1 || n==2){
   return 1;
   }else{
   return fb(n-1)+fb(n-2)
   }
}

数组扁平化

在面试中扁平化是一个高频考点,接下来我们聊聊一些扁平化的方法

方法一: flat()

flat()是js自带的一种方法,专门解决数组扁平化的问题

const arr=[1,2,[3,4,[5]]]

 const newarr=arr.flat()
 
 console.log(newarr);//[1, 2, 3, 4, [5]]

QQ截图20240605092801.png

其中flat()里的值默认为1,代表降一次维,填2就降两次维,但在实际应用时我们可能不知道数组到底有几维想把它降成一维时,一般使用flat(Infinity),无限大,无限小就是flat(-Infinity)

方法二:递归

const arr=[1,2,[3,4,[5]]]

function flatten(arr){
     let res=[]
     for(let i=0;i<arr.length;i++){
        if(Array.isArray(arr[i])){
            res=res.concat(flatten(arr[i]))
        }else{
            res.push(arr[i])
        }
     }
     return res
}
const newarr=flatten(arr)
console.log(newarr);//[ 1, 2, 3, 4, 5 ]

这里我们先创造一个空数组,通过Array.isArray(arr[i])判断子元素是否是数组,如果不是则将元素放入空数组,是则进行递归,再创造一个新的空数组,进行判断放值,在最里层的循环结束再将数组return出来,和上一层的数组用concat拼接,最后return出这个数组

concat()可以将两个数组拼接起来

 let arr=[1,2]
 let arr2=[3,4]

 let allArr=arr.concat(arr2)//[1,2,3,4]
//也可以 let allarr=[...arr,...arr2]

方法三:toString()

逻辑:toString可以将数组转换为字符串,再用splict()将字符串变为数组,最后使用map遍历数组

toString是一个神奇的方法,不管你是几维数组,它都可以变成字符串,如:

const arr=[1,2,[3,4,[5]]]
let str=arr.toString()
console.log(str);

QQ截图20240605142416.png

split()里面写什么就以什么分割字符串 QQ截图20240605142233.png

完整代码如下:

const arr=[1,2,[3,4,[5]]]

let str=arr.toString()//split()里面写什么就以什么分割字符串
const newarr=str.split(',').map((item)=>{//map()遍历数组,返回一个新数组 
    return Number(item)
})
console.log(newarr);

QQ截图20240605142832.png return Number(item)将数组里的字符串变为num类型,这个方法有一点需要注意,就是数组里不能出现非数字类型的元素,否则就会出现NaN(NaN也是数字类型,代表not a number)

方法四:reduce()

reduce()中要放两个参数,如:

arr.reduce(function(pre,item,index,arr){},initalValue)
let arr=[1,2,3,4,5,6,7]

let sum=arr.reduce(function(pre,item,index,arr){
       return pre+item//第一次是0+1,第二次是1+2.。。。。
},0)//reduce用于累计,第二个参数是初始值
console.log(sum)//28

这里的代码中初始值为0,所以第一次return出0+1=1,1就变成了第二次的初始值,所以第二次return出1+2=3......如此重复,所以最后的sum为28

用reduce实现扁平化如下:

const arr=[1,2,[3,4,[5]]]

function flatten(arr){
   return arr.reduce((pre,item)=>{
       return pre.concat(Array.isArray(item)?flatten(item):item)
    },[])
}
console.log(flatten(arr));

这里的初始值是一个空数组,利用三元运算符判断arr中的元素是否是数组,如果不是则通过concat拼接到空数组中,如果是则将数组元素递归,再次创建空数组,再次进行判定。当内部全部判断结束,将数组返回上一层进行拼接

QQ截图20240605151411.png

方法五:some

数组中的some可以判断数组中是否存在某个值,并且返回布尔类型(true or false)

具体代码如下:

const arr=[1,2,[3,4,[5]]]

function flatten(arr){
    while(arr.some(item=>Array.isArray(item))){
        arr=[].concat(...arr) //第一次【1,2,3,4,【5】】
}
return arr
}
console.log(flatten(arr)) 

...arr是解构,将arr的每一项解构返回出来,...arr结果为1,2,[3,4,[5]]

arr=[].concat(...arr)的结果为[1,2,3,4,[5]],主要数组中还存在数组元素,arr.some(item=>Array.isArray(item))就为true,while就会循环,进行降维

QQ截图20240605152623.png

结语

今天我们聊了递归思想和数组扁平化的几个方法,希望在你看完这篇文章之后面对hr的“刁难”可以多几分从容和自信,华丽的拿下,好好学习,天天向上。