js递归函数_js递归函数详细介绍
js两个数组排列组合
}else {var aArr = ['a', 'b', 'c'];
js递归函数_js递归函数详细介绍
js递归函数_js递归函数详细介绍
var cArr = ['西瓜', '冬瓜', '葡萄'];
var dArr = [{name:'hello'},{name:'look'}];
// 装载所有需要组合的数组
var totalArr = [aArr, bArr, cArr,dArr];
// 最终得到的所有的元素组合数组
var targetList = [];
// 所有的数组组合放在一起计算
function countList(allArr) {
if (allArr && allArr.length > 0) {
if (allArr.length > 1) {
var iArr = allArr[0];
var jArr = allArr[1];
var newArr = twoArrComp(iArr, jArr);
var leftArr = [];
for(var m = 0;m if(m>1){ leftArr.push(allArr[m])}} else { }} leftArr.unshift(newArr); if(leftArr.length>1){ countList(leftArr); targetList = leftArr; targetList = allArr[0]; }} }countList(totalArr); console.log(targetList); // 数组两两组合 var _resultArr = []; function twoArrComp(aArr, bArr) { var listArrelm = arr[i]; = []; if (aArr && aArr.length > 0 && bArr && bArr.length > 0) { aArr.forEach(function (aItem) { bArr.forEach(function (bItem) { _resultArr = []; splitArrToOneDir(aItem); splitArrToOneDir(bItem); listArr.push(_resultArr) }) }) }return listArr; }// 函数递归,把数组拆成一维平面数组 function splitArrToOneDir(){ if(isArray() == true){ .forEach(function(childItem){ if(isArray(childItem) == true){ splitArrToOneDir(childItem) _resultArr.push(childItem); }}) _resultArr.push(); }} // 判断是否是Array数组 var _isArray = false; if (Array.isArray) { _isArray = Array.isArray(); _isArray = Object.prototype.toString().call() === "[object Array]" }return _isArray; } var c=new Array(); var k=0,as="",bs=""; //A1,A2...... 赋值给数组c for(var i=0;i {for(var j=0;j {c[k]=a[i]+b[j]; k++; }} //求a中字符和 for(var m=0;m }//求b中字符和 for(var n=0;n {bs+=b[n]; }// AB1,AB2赋值给数组c for(n=0;n {c[k]=as+b[n]; k++; }//A12,B12赋值给数组c {c[k]=a[m]+bs; k++; }c[k]=as+bs;//将AB12赋值给数组c for(k=0;k alert(c[k]); 一、树结构 定义一颗树,JS中常见的树形数据结构如下,children属性对应的是子树 let tree = [ {id: '1', name: '1', children: [ {id: '1-1', name: '1-1' 主流的流行框架}] }, {id: '2', name: '2', children: [ {id: '2-1', name: '2-1' }, {id: '2-2', name: '2-2', children: [ name: '2-2-1' }] }] }, {id: '3', name: '3' }] 二、深度优先遍历(DFS) 1、递归实现 function treeIterator(tree, func) { tree.forEach((node) => { func(node) node.children && treeIterator(node.children, func) }) }实现逻辑简述:定义treeIterator函数,传入tree(树)和func(回调函数)两个参数,遍历tree数组,执行回调函数,如果当前存在children,则递归调用。 treeIterator(tree, (node) => { console.log(node.name) }) 控制台打印结果如下: 2、循环实现 function treeIterator(tree, func) { let node, curTree = [...tree] while ((node = curTree.shift())) { func(node) node.children && curTree.unshift(...node.children) }}Q: 你会如何找到两个数字的公约数? 实现逻辑简述: (1)定义node作为当前,curTree为传入的树(不影响原数组tree); (3)①执行回调函数;②如果当前存在子树,则追加到curTree数组的开头,继续执行循环,直到curTree没有元素为止。 函数调用验证:参考上述递归实现验证,方式和结果一致。 三、广度优先遍历(BFS) function treeIterator(tree, func) { let node, curTree = [...tree] while ((node = curTree.shift())) { func(node) }} 实现逻辑简述:和上述深度优先遍历的循环实现不多。区别在于如果当前存在子树,则追加到list数组的末尾。 意思是说你的内存不足!! 建议先杀毒 修复IE 实在不行试试下面的方法 先装Macromedia Flash Player (是版本) 再打开IE--工具--INTERNET选项--安全--自定义级别 ActiveX一栏分别选 禁用--启用--禁用--启用--禁用--启用--启用 我也遇到过,把它想复杂了,用了各种工具修复都不行,后来这样解决了 Internet选项--高级--还原默认设置 然后重启浏览器 用360修复一下 前端学习的主要内容包含三个部分:基础部分、设计部分还有代码部分。学习前端课程【达内教育】,该机构致tree(file_path);力于面向IT互联网行业培养人才,达内大型T专场会每年定期举行,为学员搭建快捷高效的双选绿色通道。 WEB前端虽然说在编程语言中属于轻量级的开发语言,但它却有着重量级语言的地位,可以说WEB前端对我们生活的影响是无处不在,从手表到手机、从网页到APP。WEB前端全栈工程师的能力得到了充分的发挥,而具体的WEB前端培训课程也是分阶段的。千锋教育就有web前端培训公开课, WEB前端虽然说在编程语言中属于轻量级的开发语言,但它却有着重量级语言的地位,可以说WEB前端对我们生活的影响是无处不在,从手表到手机、从网页到APP。WEB前端全栈工程师的能力得到了充分的发挥,而具体的WEB前端培训课程也是分阶段的。千锋教育就有web前端培训公开课," Web前端: 1、精通HTML,能够书写语义合理,结构清晰,易维护的HTML结构; 2、精通console.log(file_path);CSS,能够还原视觉设计,并兼容业界承认的主流浏览器; 3、熟悉JaScript,了解ECMAScript基础内容,掌握1到2种js框架,如JQuery; 4、对常见的浏览器兼容问题有清晰的理解,并有可靠的解决方案; 5、对性能有一定的要求,了解yahoo的性能优化建议,并可以在项目中有效实施; 前端学的东西比较多一点,可以先从html css JaScript 开始,之后学习一些ui库,bootstrap这种的然后就可以学点类似于jquery这样的js库,等前面学的熟练了,就可以去尝试学习vue这种else响应式框架了 ES6的特性比较多,在 ES5 发布近 6 年(2009-11 至 2015-6)之后才将其标准化。两个发布版本之间时间跨度很大,所以ES6中的特性比较多。 在这里列举几个常用的: 1.类(class) 对熟悉Ja,object-c,c#等纯面向对象语言的开发者来说,都会对class有一种特殊的情怀。ES6 引入了class(类),让JaScript的面向对象编程变得更加简单和易于理解。 2.模块化(Module) ES5不支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。模块的功能主要由 export 和 import 组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过 export 来规定模块对外暴露的接口,通过import来引用其它模块提供的接口。同时还为模块创造了命名空间,防止函数的命名冲突。 导出(export) 导出变量 ES6将一个文件视为一个模块,上面的模块通过 export 向外输出了一个变量。一个模块也可以同时往外面输出多个变量。 导出函数 导入(import) 定义好模块的输出以后就可以在另外一个模块通过import引用。 3.箭头(Arrow)函数 这是ES6中最令人激动的特性之一。=>不只是关键字function的简写,它还带来了其它好处。箭头函数与包围它的代码共享同一个this,能帮你很好的解决this的指向问题。有经验的JaScript开发者都熟悉诸如var self = this;或var that = this这种引用外围this的模式。但借助=>,就不需要这种模式了。 箭头函数的结构 箭头函数的箭头=>之前是一个空括号、单个的参数名、或用括号括起的多个参数名,而箭头之后可以是一个表达式(作为函数的返回值),或者是用花括号括起的函数体(需要自行通过return来返回值,否则返回的是undefined)。 卸载时的陷阱 除上述的做法外,我们还可以这样做: 4.函数参数默认值 ES6支持在定义函数的时候为其设置默认值: 这样写一般没问题,但当参数的布尔值为false时,就会有问题了。比如,我们这样调用foo函数: foo(0, "") 因为0的布尔值为false,这样height的取值将是50。同理color的取值为‘red’。 所以说,函数参数默认值不仅能是代码变得更加简洁而且能规避一些问题。 5.模板字符串 ES6支持模板字符串,使得字符}else{串的拼接更加的简洁、直观。 在ES6中通过${}就可以完成字符串的拼接,只需要将变量放在大括号之中。 6.解构赋值 解构赋值语法是JaScript的一种表达式,可以方便的从数组或者对象中快速提取值赋给定义的变量。 获取数组中的值 从数组中获取值并赋值到变量中,变量的顺序与数组中对象顺序对应。 如果没有从数组中的获取到值,你可以为变量设置一个默认值。 通过解构赋值可以方便的交换两个变量的值。 获取对象中的值 7.延展作符(Spread operator) 延展作符...可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造对象时, 将对象表达式按key-value的方式展开。 语法 应用场景 没有展开语法的时候,只能组合使用 push,spl,concat 等方法,来将已有数组元素变成新数组的一部分。有了展开语法, 构造新数组会变得更简单、更优雅: 和参数列表的展开类似, ... 在构造字数组时, 可以在任意位置多次使用。 展开语法和 Object.assign() 行为一致, 执行的都是浅拷贝(只遍历一层)。 在ECMAScript 2018中延展作符增加了对对象的支持 8.对象属性简写 在ES6中允许我们在设置一个对象的属性的时候不指定属性名。 对象中必须包含属性和值,显得非常冗余。 对象中直接写变量,非常简洁。 9.Promise Promise 是异步编程的一种解决方案,比传统的解决方案callback更加的优雅。它最早由社区提出和实现的,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。 嵌套两个setTimeout回调函数: 上面的的代码使用两个then来进行异步编程串行化,避免了回调地狱: 10.支持let与const 在之前JS是没有块级作用域的,con扩展运算符可以在其他对象内使用,例如:st与let填补了这方便的空白,const与let都是块级作用域。 ES2016添加了两个小的特性来说明标准化过程: 1.Array.prototype.includes() includes() 函数用来判断一个数组是否包含一个指定的值,如果包含则返回 true,否则返回false。 includes 函数与 indexOf 函数很相似,下面两个表达式是等价的: 接下来我们来判断数字中是否包含某个元素: 使用indexOf()验证数组中是否存在某个元素,这时需要根据返回值是否为-1来判断: 使用includes()验证数组中是否存在某个元素,这样更加直观简单: 2.指数作符 在ES7中引入了指数运算符,具有与Math.pow(..)等效的计算结果。 使用自定义的递归函数calculateExponent或者Math.pow()进行指数运算: 使用指数运算符,就像+、-等作符一样: 1.async/await ES2018引入异步迭代器(asynchronous iterators),这就像常规迭代器,除了next()方法返回一个Promise。因此await可以和for...of循环一起使用,以串行的方式运行异步作。例如: 2.Object.values() Object.values()是一个与Object.keys()类似的新函数,但返回的是Object自身属性的所有值,不包括继承的值。 设我们要遍历如下对象obj的所有值: 从上述代码中可以看出Object.values()为我们省去了遍历key,并根据这些key获取value的步骤。 3.Object.entries() Object.entries()函数返回一个给定对象自身可枚举属性的键值对的数组。 接下来我们来遍历上文中的obj对象的所有属性的key和value: 4.String padding 在ES8中String新增了两个实例函数String.prototype.padStart和String.prototype.padEnd,允许将空字符串或其他字符串添加到原始字符串的开头或结尾。 5.函数参数列表结尾允许逗号 主要作用是方便使用git进行多人协作开发时修改同一个函数减少不必要的行变更。 6.Object.getOwnPropertyDescriptors() Object.getOwnPropertyDescriptors()函数用来获取一个对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。 返回obj对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。 7.SharedArrayBuffer对象 SharedArrayBuffer 对象用来表示一个通用的,固定长度的原始二进制数据缓冲区,类似于 ArrayBuffer 对象,它们都可以用来在共享内存(shared memory)上创建视图。与 ArrayBuffer 不同的是,SharedArrayBuffer 不能被分离。 8.Atomics对象 这些原子作属于 Atomics 模块。与一般的全局对象不同,Atomics 不是构造函数,因此不能使用 new 作符调用,也不能将其当作函数直接调用。Atomics 的所有属性和方法都是静态的(与 Math 对象一样)。 多个共享内存的线程能够同时读写同一位置上的数据。原子作会确保正在读或写的数据的值是符合预期的,即下一个原子作一定会在上一个原子作结束后才会开始,其作过程不会中断。 wait() 和 wake() 方法采用的是 Linux 上的 futexes 模型(fast user-space mutex,快速用户空间互斥量),可以让进程一直等待直到某个特定的条件为真,主要用于实现阻塞。 1.异步迭代 在async/await的某些时刻,你可能尝试在同步循环中调用异步函数。例如: 这段代码不会正常运行,下面这段同样也不会: 这段代码中,循环本身依旧保持同步,并在在内部异步函数之前全部调用完成。 ES2018引入异步迭代器(asynchronous iterators),这就像常规迭代器,除了next()方法返回一个Promise。因此await可以和for...of循环一起使用,以串行的方式运行异步作。例如: 2.Promise.finally() 一个Promise调用链要么成功到达一个.then(),要么失败触发.catch()。在某些情况下,你想要在无论Promise运行成功还是失败,运行相同的代码,例如清除,删除对话,关闭数据库连接等。 .finally()允许你指定最终的逻辑: 属性 ES2015引入了Rest参数和扩展运算符。三个点(...)仅用于数组。Rest参数语法允许我们将一个不定数量的参数表示为一个数组。 展开作符以相反的方式工作,将数组转换成可传递给函数的单独参数。例如Math.max()返回给定数字中的值: ES2018为对象解构提供了和数组一样的Rest参数()和展开作符,一个简单的例子: 或者你可以使用它给函数传递参数: 可以使用扩展运算符拷贝一个对象,像是这样obj2 = {...obj1},但是 这只是一个对象的浅拷贝 。另外,如果一个对象A的属性是对象B,那么在克隆后的对象cloneB中,该属性指向对象B。 4.正则表达式命名捕获组 JaScript正则表达式可以返回一个匹配的对象——一个包含匹配字符串的类数组,例如:以YYYY-MM-DD的格式解析日期: 这样的代码很难读懂,并且改变正则表达式的结构有可能改变匹配对象的索引。 ES2018允许命名捕获组使用符号? 任何匹配失败的命名组都将返回undefined。 命名捕获也可以使用在replace()方法中。例如将日期转换为美国的 MM-DD-YYYY 格式: 5.正则表达式反向断言 目前JaScript在正则表达式中支持先行断言(lookahead)。这意味着匹配会发生,但不会有任何捕获,并且断言没有包含在整个匹配字段中。例如从价格中捕获货符号: ES2018引入以相同方式工作但是匹配前面的反向断言(lookbehind),这样我就可以忽略货符号,单纯的捕获价格的数字: 6.正则表达式dotAll模式 正则表达式中点.匹配除回车外的任何单字符,标记s改变这种行为,允许行终止符的出现,例如: 7.正则表达式 Unicode 转义 到目前为止,在正则表达式中本地访问 Unicode 字符属性是不被允许的。ES2018添加了 Unicode 属性转义——形式为p{...}和P{...},在正则表达式中使用标记 u (unicode) 设置,在p块儿内,可以以键值对的方式设置需要匹配的属性而非具体内容。例如: 此特性可以避免使用特定 Unicode 区间来进行内容类型判断,提升可读性和可维护性。 8.非转义序列的模板字符串 之前,u开始一个 unicode 转义,x开始一个十六进制转义,后跟一个数字开始一个八进制转义。这使得创建特定的字符串变得不可能,例如Windows文件路径 C:uuuxxx111。更多细节参考模板字符串。 1.行分隔符(U + 2028)和段分隔符(U + 2029)符号现在允许在字符串文字中,与JSON匹配 以前,这些符号在字符串文字中被视为行终止符,因此使用它们会导致SyntaxError异常。 2.更加友好的 JSON.stringify 如果输入 Unicode 格式但是超出范围的字符,在原先JSON.stringify返回格式错误的Unicode字符串。现在实现了一个改变JSON.stringify的第3阶段提案,因此它为其输出转义序列,使其成为有效Unicode(并以UTF-8表示) 3.新增了Array的flat()方法和flatMap()方法 flat()和flatMap()本质上就是是归纳(reduce) 与 合并(concat)的作。 Array.prototype.flat() flat() 方按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。 Array.prototype.flatMap() flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 和 深度值1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。 这里我们拿map方法与flatMap方法做一个比较。 4.新增了String的trimStart()方法和trimEnd()方法 5.Object.fromEntries() Object.entries()方法的作用是返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环也枚举原型链中的属性)。 而Object.fromEntries() 则是 Object.entries() 的反转。 Object.fromEntries() 函数传入一个键值对的列表,并返回一个带有这些键值对的新对象。这个迭代参数应该是一个能够实现@iterator方法的的对象,返回一个迭代器对象。它生成一个具有两个元素的类似数组的对象,个元素是将用作属性键的值,第二个元素是与该属性键关联的值。 通过工厂函数Symbol()创建符号时,您可以选择通过参数提供字符串作为描述: 以前,访问描述的方法是将符号转换为字符串: 现在引入了getter Symbol.prototype.description以直接访问描述: 7.String.prototype.matchAll matchAll() 方法返回一个包含所有匹配正则表达式及分组捕获结果的迭代器。 在 matchAll 出现之前,通过在循环中调用regexp.exec来获取所有匹配项信息(regexp需使用/g标志: 如果使用matchAll ,就可以不必使用while循环加exec方式(且正则表达式需使用/g标志)。使用matchAll 会得到一个迭代器的返回值,配合 for...of, array spread, or Array.from() 可以更方便实现功能: matchAll可以更好的用于分组 8.Function.prototype.toString()现在返回字符,包括空格和注释 9.修改 catch 绑定 在 ES10 之前,我们必须通过语法为 catch 子句绑定异常变量,无论是否有必要。很多时候 catch 块是多余的。 ES10 提案使我们能够简单的把变量省略掉。 不算大的改动。 之前是 现在是 10.新的基本数据类型BigInt 现在的基本数据类型(值类型)不止5种(ES6之后是六种)了哦!加上BigInt一共有七种基本数据类型,分别是: String、Number、Boolean、Null、Undefined、Symbol、BigInt 这次给大家带来Js基础算法有哪些,使用Js基础算法的注意事项有哪些,下面就是实战案例,一起来看一下。 素数 Q:你将如何验证一个素数? A:一个素数只能被它自己和1整除。所以,我将运行一个while循环并加1。(看代码示例,如果你无法理解,那这不是你的菜。先回去学习jaScript基础知识然后再回来吧。) 方法1 function isPrime(n){ var pisor = 2; while (n > pisor){ if(n % pisor == 0){ return false; }else pisor++; }return true; }isPrime(137); // = true isPrime(237); // = falseQ:你能做得更好吗? A:可以。除数一次增加1个。 在3之后我可以增加2.如果一个数可以被任何偶数整除,它将被2整除。 补充:如果你不需要把除数增加到这个数。你可以更早停止。让我在下面的步骤中解释一下(如果需要可以多读几遍) 步,任何数字都不能被大于它的一半的数字整除。 例如,13将永远不能被7,8,9整除??它甚至可以是偶数的一半。 例如,16将被8整除,但永远不会被9,10,11,12 ?? 结论:一个数字将永远不能被一个大于其一半数值的数字整除。 所以,我们可以少循环50%。 第二步,现在,如果一个数字不能被3整除。(如果它可被3整除,那么它就不是质数)。然后,它不可以被大于其值1/3的任何数整除。例如,35不能被3整除。因此,它永远不会被大于35/3的数整除,永远不能被12, 13, 14整除?如果你取一个像36一样的偶数,它将永远不能被13, 14, 15整除。 结论: 一个数字可以被其数值的三分之一整除。 第三步,例如,你有一个数字127。127不能被2整除,因此你最多应该检查63.5。其次,127不能被3整除。因此,您将检查到127/3大约42。它不能被5整除,除数应该小于127/5大约25,而不是7。那么,我们该在哪里停下来? 结论: 除数将小于math.sqrt(N) 方法2 如果你不能理解也不用担心,别管它。如果那你不是一个研究人员就没关系。 function isPrime(n) {var pisor = 3, limit = Math.sqrt(n); //check cases if (n == 2 || n == 3) return true; return false; while (pisor <= limit) {if (n % pisor == 0) return false; pisor += 2; }return true; }isPrime(137); // = true isPrime(237); // = false素数因子 Q:如何求出一个数的所有素以上是 肯定反向断言 ,非数字D必须存在。同样的,还存在 否定反向断言 ,表示一个值必须不存在,例如:数因子? A:执行一个while循环。开始除以2,如果不能整除,记录这个除数,直到完成。 function primeFactors(n){ var factors = [], pisor = 2; while(n>2){ if(n % pisor == 0){ factors.push(pisor); n= n/ pisor; pisor++; }} return factors; }primeFactors(69); // = [3, 23]Q:运行时间复杂度是多少? 你能做得更好吗? A:O(n)。可以将除数从3开始,累加2。因为,如果一个数被任何偶数整除,它将被2整除。因此,你不需要除以偶数。此外,你不会有一个大于其价值一半的因素。如果你想让它变得复杂,那就用题的补充概念吧。 Fibonacci(斐波那契) Q:如何获得第n个斐波纳契数字? A: 我创建一个数组并从迭代开始。 斐波那契系列是面向初学者的的面试问题之一。 所以,你必须学习这一个。 方法1 function fibonacci(n){ var fibo = [0, 1]; if (n <= 2) return 1; for (var i = 2; i <=n; i++ ){ fibo[i] = fibo[i-1]+fibo[i-2]; }return fibo[n]; A: O(n); Q: 你能让它递归吗? 方法2 function fibonacci(n){ if(n < =1) { return n; return fibonacci(n-1) + fibonacci (n-2); }} fibonacci(12); // = 144Q: 运行时间复杂度是多少? A: O(2n);关于时间复杂度的细节 公约数 function greatestCommonpisor(a, b){ var pisor = 2, greatestpisor = 1; //if u pass a -ve number this will not work. fix it dude!! if (a < 2 || b < 2) return 1; while(a >= pisor && b >= pisor){ if(a %pisor == 0 && b% pisor ==0){ greatestpisor = pisor; }pisor++; }return greatestpisor; }greatestCommonpisor(14, 21); // 7 greatestCommonpisor(69, 169); // = 1算法范式 很抱歉。我也无法解释它。 因为我自己80%的情况下都不能理解它。 我的算法分析教练告诉我这个,又从课堂笔记偷走(我是一个好学生,顺便说一句!) function greatestCommonpisor(a, b){ if(b == 0) return a; }注意:用你的大脑来理解它。 去重 Q:你将如何从数组中删除重复的成员? A: 执行一个循环,并保存一个对象/关联数组。如果我次找到一个元素,我会设置它的值为真(这将告诉我元素添加一次)。如果我在对象中找到这个元素,我不会将它插入到返回数组中。 function removeDuplicate(arr){ var exists ={}, outArr = [], elm; for(var i =0; i if(!exists[elm]){ outArr.push(elm); exists[elm] = true; }} return outArr; }removeDuplicate([1,3,3,3,1,5,6,7,8,1]); // = [1, 3, 5, 6, 7, 8]合并两个排序的数组 Q: 怎样合并两个已排序数组? A: 我将为每个数组保留一个指针(看代码,并注意这个)。 function mergeSortedArray(a, b){ var merged = [], aElm = a[0], bElm = b[0], i = 1, j = 1; if(a.length ==0) return b; if(b.length ==0) return a; / if aElm or bElm exists we will insert to merged array (will go inside while loop) to insert: aElm exists and bElm doesn't exists or both exists and aElm < bElm this is the critical part of the example / while(aElm || bElm){ if((aElm && !bElm) || aElm < bElm){ merged.push(aElm); aElm = a[i++]; merged.push(bElm); bElm = b[j++]; }} return merged; }mergeSortedArray([2,5,6,9], [1,2,3,29]);// = [1, 2, 2, 3, 5, 6, 9, 29]不通过临时变量交换两个数的值 Q:如何在不使用临时变量的情况下交换两个数字? function swapNumb(a, b){ console.log('before swap: ','a: ', a, 'b: ', b); b = b -a; a = a+ b; b = a-b; }swapNumb(2, 3); // = before swap: a: 2 b: 3 // = after swap: a: 3 b: 2位作:对不起,我无法向你解释这一点。 Kinjal De建议到 logical conjunction理解它。将浪费您30分钟。 function swapNumb(a, b){ console.log("a: " + a + " and b: " + b); a = a ^ b; b = a ^ b; a = a ^ b; console.log("a: " + a + " and b: " + b); }swapNumb(2, 3); // = a: 2 and b: 3 // = a: 3 and b: 2字符串反向 Q:如何在JaScript中反转字符串? A:可以遍历字符串并将字母连接到新字符串。 方法1 function rrse(str){ var rtnStr = ''; for(var i = str.length-1; i>=0;i--){ rtnStr +=str[i]; }return rtnStr; }rrse('you are a n dude'); // = "edud ecin a era uoy"Q:你知道在现代浏览器中串联效果很好,但在像IE8这样的旧浏览器中会变慢。 还有什么不同的方法,可以扭转一个字符串? A:当然.我可以使用数组,也可以添加一些检查。如果字符串是NULL或其他字符串,这将失败。让我也做一些类型检查。使用此数组类似于在某些端语言中使用字符串缓冲区。 方法2 function rrse(str){ var rtnStr = []; if(!str || typeof str != 'string' || str.length < 2 ) return str; for(var i = str.length-1; i>=0;i--){ rtnStr.push(str[i]); }return rtnStr.join(''); }Q: 运行时间复杂度是多少? A: O(n); Q:可以做得更好? A:我可以遍历索引的一半,它会节省一点点。 (这是没用的,可能不会打动面试官) 方法3 function rrse(str) { str = str.split(''); var len = str.length, halfIndex = Math.floor(len / 2) - 1, revStr; for (var i = 0; i <= halfIndex; i++) { revStr = str[len - i - 1]; str[len - i - 1] = str[i]; str[i] = revStr; }return str.join(''); }Q:这有效,但你可以做递归的方式吗? A:可以。 方法4 function rrse (str) { if (str === "") { return ""; return rrse(str.substr(1)) + str.charAt(0); }}方法5 Q:你可以在方法中使用任何构建,使它更清洁吗? function rrse(str){ if(!str || str.length <2) return str; return str.split('').rrse().join(''); }方法6 Q:你可以做反向函数作为字符串扩展吗? A:我需要将这个函数添加到String.prototype,而不是使用str作为参数,我需要使用this String.prototype.rrse = function (){ if(!this || this.length <2) return this; }'abc'.rrse(); // = 'cba'单词反转 Q:你如何在句子中颠倒单词? A:您必须检查整个字符串的空白区域。确定是否可能有多个空格。 //he a tailing white space //fix this later //now i m sleepy function rrseWords(str){ var rev = [], wordLen = 0; for(var i 函数调用验证:调用treeIterator函数,传入上文定义好的树结构数组,打印出每个的name值。= str.length-1; i>=0; i--){ if(str[i]==' ' || i==0){ rev.push(str.substr(i,wordLen+1)); wordLen = 0; }else wordLen++; }return rev.join(' '); }内置方法的快速解决方案: function rrseWords(str){ return str.split(' ').rrse(); }原位反转 Q: 如果你有一个字符串如”I am the good boy”, 怎样变为 “I ma eht doog yob”? 注意这些单词位置不变但是被反转了。 A: 要做到这一点,我必须做字符串反向和字反转。 function rrseInPlace(str){ return str.split(' ').rrse().join(' ').split('').rrse().join(''); }rrseInPlace('I am the good boy');// = "I ma eht doog yob"Q: ok。好的,你能不使用内置反向函数做到吗? A: (内心独白)有没有搞错!! //sum two mods. //you can simply split words by ' ' //and for each words, call rrse function //put rrse in a separate function //if u cant do this, //he a glass of water, and sleep个非重复字符 Q: 怎么在字符串中找到个非重复字符? A: 有什么条件吗? A: 比如是否区分大小写? 面试官可能会说No。 A: 是长字符串还是短字符串? Q: 这些有什么关系吗? A:例如,如果它是一个非常长的字符串,说一百万个字符,我想检查是否有26个英文字符正在重复。 我可能会检查是否所有字符都在每200个字母中重复(例如),而不是循环遍历整个字符串。 这将节省计算时间。 Q: 简单起见, 这个字符串是 “the quick brown fox jumps then quickly blow air”。 function firstNonRepeatChar(str){ var len = str.length, char, charCount = {}; for(var i =0; i char = str[i]; if(charCount[char]){ charCount[char]++; }else charCount[char] = 1; }for (var j in charCount){ if (charCount[j]==1) return j; }} firstNonRepeatChar('the quick brown fox jumps then quickly blow air');// = "f"这有一个问题,不能再循环中及时退出。 删除重复的字符 Q: 怎样删除字符串中的重复字符? A: 这与个非重复字符非常相似。你应该问一些类似的问题。它是区分大小写的吗?。 function removeDuplicateChar(str){ var len = str.length, char, charCount = {}, newStr = []; for(var i =0; i char = str[i]; if(charCount[char]){ charCount[char]++; }else charCount[char] = 1; }for (var j in charCount){ if (charCount[j]==1) newStr.push(j); }return newStr.join(''); }removeDuplicateChar('Learn more jascript dude'); // = "Lnmojvsciptu"回文检查 Q: 如何检查一个字符串是否是回文? A: 把字符串反转,如果反转前后相等,那么它就是回文。 function isPalindrome(str){ var i, len = str.length; for(i =0; i if (str[i]!== str[len -1 -i]) return false; }return true; }isPalindrome('madam') // = true isPalindrome('toyota') // = false或者 function checkPalindrom(str) { return str == str.split('').rrse().join(''); }类似的:在 O(n)时间复杂度内判断一个字符串是否包含在回文字符串内。你能在O(1)时间解决问题吗? 找缺失的数字 Q: 在一个1到100的未排序数组中找到缺失的数,你怎么做? 说明:数组中的数字为1到100。 数组中只有一个数字缺 // using nodejs let path = require('path'); let fs = require('fs'); const tree = ($path)=>fs.readdir($path,(err,files)=>{ files.forEach(f => { let file_path = path.join($path,f); let state = fs.lstatSync(file_path); if(state.isDirectory()){ }else if(state.isFile()){ }}); }); tree(path.join(__dirname,'./')); title: JS树结构数据的遍历 date: 2022-04-14 description: 针对项目中出现树形结构数据的时候,我们怎样去作他 项目中我们会经常出现对树形结构的遍历、查找和转换的场景,比如说DOM树、族谱、机构、组织架构、权限、菜单、省市区、路由、标签等等。那针对这些场景和数据,我们又如何去遍历和作,有什么方式或者技巧可以简化我们的实现思路。下面我们将针对常规出现的场景function isArray() {去总结一下我们的遍历方式 树的特点 1、每个都只有有限个子或无子; 2、没有父的称为根; 3、每一个非根有且只有一个父; 4、除了根外,每个子可以分为多个不相交的子树; 5、树里面没有环路 在下面的JS中我们由多棵树组成我们的数据 在这数据中我们如何评判数据是否为叶(也就是一级),我们每个都会存在children属性,如果不存在children属性或者children不是一个数组或者children为数组且长度为0我们则认为他是一个叶 我们针对树结构的作离不开遍历,遍历的话又分为广度优先遍历、深度优先遍历。其中深度优先遍历可以通过递归和循环的方式实现,而广度优先遍历的话是非递归的 从上往下对每一层依次访问,在每一层中,从左往右(也可以从右往左)访问结点,访问完一层就进入下一层,直到没有结点可以访问为止。即访问树结构的第n+1层前必须先访问完第n层。 简单的说,BFS是从根开始,沿着树的宽度遍历树的。如果所有均被访问,则算法中止。 所以我们的实现思路是,维护一个队列,队列的初始值为树结构根组成的列表,重复执行以下步骤直到队列为空: 取出队列中的个元素,进行访问相关作,然后将其后代元素(如果有)全部追加到队列。 1、先序遍历 访问子树的时候,先访问根再访问根的子树 2、后序遍历 访问子树的时候,先访问子树再访问根 1、先序遍历 先序遍历与广度优先循环实现类似,要维护一个队列,不同的是子不追加到队列,而是加到队列最前面 2、后序遍历 后序遍历就略微复杂一点,我们需要不断将子树扩展到根前面去,执行列表遍历,并且通过一个临时对象维护一个id列表,当遍历到某个如果它没有子或者它本身已经存在于我们的临时id列表,则执行访问作,否则继续扩展子到当前前面 对于树结构的遍历作,其实递归是最基础,也是最容易理解的。递归本身就是循环的思想,所以可以用循环来改写递归,以上的方式在项目中已经廊括了大部分的场景了,我们在日常开发中可以根据场景或者需要去选择我们的遍历方式,或者基于此对他进行调整和优化,至于每种方式的空间复杂度和时间复杂度我们在这个地方就不去尝试了,各位感兴趣可以自己去验证。 广度优先搜索 树的遍历 深度优先搜索 图文详解两种算法:深度优先遍历(DFS)和广度优先遍历(BFS) 二叉树遍历(前序,后序,中序,层次)递归与迭代实现JaScript JS树结构作:查找、遍历、筛选、树和列表相互转换 你那个是递归调用,而且没有条件结束递归。所以导致“堆栈溢出”。 在JS中,全局的变量与函数实际都window对象的属性与方式,也就是说你定义function print这个就是window对象的一个方法,就相当于function window.print,所以你的代码成了: window.onload=function window.print(){ window.print(); }这就是递归调用,会一直调用下去,直到堆栈溢出js树形结构如何从最深层往上匹配
如果面试官说,这是区分大小写的,那么你就很轻松了。 如果他说不。你可以使用string.toLowercase()来把字符串。面试官可能不喜欢这个方法。 因为返回字符串不会拥有相同的大小写。 所以打开浏览器老是出来这个
}fibonacci(12); // = 144Q: 运行时间复杂度是多少?前端学习需要学些什么?
ES6、ES7、ES8、ES9、ES10新特性一览
for(m=0;mJs基础算法有哪些
{id: '2-2-1',jascript递归查询功能中怎样实现查找当前目录下的及子级目录下的所有文件
Atomic下面的表示一颗树s 对象提供了一组静态方法用来对 SharedArrayBuffer 对象进行原子作。JS树结构数据的遍历
6.Symbol.prototype.descriptionjs脚本打印的问题 代码如下 window.onload=function print(){ wi
var obj// ... = {