【前端面试】七、算法-递归

news2024/12/26 21:14:29

遍历方法总结

链式调用

  • 数组的很多操作可以构成链式操作,类似这样的格式:…map().filter(…).sort(…).map(….)
  • 链式操作就是对象方法返回类型是自身的。比如map是属于数组的方法,它返回数组,所以构成了链式操作
  • 优势:语义清晰、思考方便,数据量小的时候很有用(<1W)
  • 问题:性能、空间

递归

递归通常需要初始条件和递归表达式

阶乘:n! = n x (n-1) !   

斐波那契:f(1) = 1, f(2) = 1,f(n) = f(n-1) + f(n-2), n>2 

拷贝

push/pop/shift/unshift/splice:都在原始数据上进行修改

concat/slice/map/reduce:都会对原始数据进行浅拷贝

DOM结点的绝对位置

offsetLeft、offsetRight相对于offsetParent的位置
Element.getBoundingClientRect()相对于视窗的位置,受滚动的影响

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>递归</title>
</head>
<body>
  <script>

    // 阶乘
    function factorial(n) {
      if (n === 1) return 1
      return n * factorial(n - 1)
    }

    // 斐波那契数列 1 1 2 3 5 8 13 21 34 55 89 144
    function fibonacci(n) {
      if (n === 1 || n === 2) return 1
      return fibonacci(n - 1) + fibonacci(n - 2)
    }

    // 从底端构造递归
    function fibonacci1(n) {
      let [a,b] = [1,1]
      for(let i = 3; i <= n; i++) {
        [a,b] = [b, a + b]
      }
      return b
    }
    // console.log('测试 fibonacci1=============');
    // console.log(fibonacci1(10));

    function fibonacci2(n) {
      return Array(n - 2).fill(0).reduce(([a,b],_) => {
        return [b, a + b]
      }, [1,1])[1]
    }
    // console.log('测试 fibonacci2=============');
    // console.log(fibonacci2(10));

    // 递归实现深拷贝
    function deepClone(obj) {
      if (typeof obj !== 'object' || obj === null) return obj
      // const newObj = Array.isArray(obj) ? [] : {}
      // const newObj = obj instanceof Array ? [] : {}
      // const newObj = obj.constructor === Array ? [] : {}
      // const newObj = Object.prototype.toString.call([]) === '[object Array]' ? [] : {}
      const newObj = new obj.constructor()
      for(let key in obj) {
        if(obj.hasOwnProperty(key)) {
          newObj[key] = deepClone(obj[key])
        }
      }
      return newObj
    }

    // 测试用例  
    function testDeepClone() {  
      console.log("测试普通对象:");  
      const obj1 = { a: 1, b: { c: 2 } };  
      const clonedObj1 = deepClone(obj1);  
      console.assert(obj1 !== clonedObj1, "对象应该是不同的引用");  
      console.assert(obj1.b !== clonedObj1.b, "嵌套对象也应该是不同的引用");  
      console.assert(obj1.b.c === clonedObj1.b.c, "嵌套对象的属性值应该相等");  
      
      console.log("测试数组:");  
      const arr1 = [1, 2, [3, 4]];  
      const clonedArr1 = deepClone(arr1);  
      console.assert(arr1 !== clonedArr1, "数组应该是不同的引用");  
      console.assert(arr1[2] !== clonedArr1[2], "嵌套数组也应该是不同的引用");  
      console.assert(arr1[2][0] === clonedArr1[2][0], "嵌套数组的元素值应该相等");  
      
      console.log("测试特殊对象(Date):");  
      const date1 = new Date();  
      const clonedDate1 = deepClone(date1);  
      console.assert(date1 !== clonedDate1, "Date 对象应该是不同的引用");  
      console.assert(date1.getTime() === clonedDate1.getTime(), "Date 的时间戳应该相等");  
      
      // console.log("测试特殊对象(RegExp):");   // 失败 
      // const reg1 = /hello/g;  
      // const clonedReg1 = deepClone(reg1);  
      // console.assert(reg1 !== clonedReg1, "RegExp 对象应该是不同的引用");  
      // console.assert(reg1.source === clonedReg1.source && reg1.global === clonedReg1.global, "RegExp 的属性和标志应该相等");  
      
      // console.log("测试循环引用:");   // 失败 
      // const obj2 = {};  
      // obj2.self = obj2;  
      // const clonedObj2 = deepClone(obj2);  
      // console.assert(obj2 !== clonedObj2, "对象应该是不同的引用");  
      // console.assert(clonedObj2.self === clonedObj2, "循环引用应该被正确处理");  
      
      console.log("所有测试通过!");  
    }  
      
    // testDeepClone();

    // 深度比较
    function deepCompare(a,b){
      if (a === null || typeof a !== 'object' || b === null || typeof b !== 'object') {
        return a === b
      }
      // Object.getOwnPropertyDescriptors 方法会返回对象自身的所有属性描述符,包括不可枚举的属性
      const propsA = Object.getOwnPropertyDescriptors(a)
      const propsB = Object.getOwnPropertyDescriptors(b)
      if(Object.keys(propsA).length !== Object.keys(propsB).length) return false
      return Object.keys(propsA).every(key => deepCompare(a[key],b[key]))
    }
    // 测试用例  
    function testDeepCompare() {  
      console.log("测试基本相等性:");  
      console.assert(deepCompare(1, 1), "1 应该等于 1");  
      console.assert(!deepCompare(1, 2), "1 不应该等于 2");  
      console.assert(deepCompare(null, null), "null 应该等于 null");  
      console.assert(deepCompare(undefined, undefined), "undefined 应该等于 undefined");  
      console.assert(!deepCompare(null, undefined), "null 不应该等于 undefined");  
      
      console.log("测试对象比较:");  
      const obj1 = { a: 1, b: { c: 2 } };  
      const obj2 = { a: 1, b: { c: 2 } };  
      const obj3 = { a: 1, b: { c: 3 } };  
      console.assert(deepCompare(obj1, obj2), "obj1 应该等于 obj2");  
      console.assert(!deepCompare(obj1, obj3), "obj1 不应该等于 obj3");  
      
      console.log("测试数组比较:");  
      const arr1 = [1, 2, [3, 4]];  
      const arr2 = [1, 2, [3, 4]];  
      const arr3 = [1, 2, [3, 5]];  
      console.assert(deepCompare(arr1, arr2), "arr1 应该等于 arr2");  
      console.assert(!deepCompare(arr1, arr3), "arr1 不应该等于 arr3");  
      
      // console.log("测试循环引用(此实现可能无法正确处理):");  
      // const obj4 = {};  
      // obj4.self = obj4;  
      // const obj5 = {};  
      // obj5.self = obj5;  
      // 注意:此实现可能无法正确处理循环引用,因为它会陷入无限递归  
      // 这里我们假设它不会处理循环引用,并跳过这个测试  
      // console.assert(deepCompare(obj4, obj5), "循环引用对象应该相等(但这里不测试)");  
      
      console.log("所有测试通过!");  
    }  
      
    // testDeepCompare();

   // DOM节点的绝对位置
   function getLayout1(el) {
     if (!el) return;
     const layout = {
      width: el.offsetWidth,
      height: el.offsetHeight,
      top: el.offsetTop,
      left: el.offsetLeft
     }
     if(el.offsetParent) {
       const parentLayout = getLayout1(el.offsetParent)
       layout.top += parentLayout.top
       layout.left += parentLayout.left
     }
    return layout
   }

   function getLayout2(el) {
      if (!el) return;
      let left = el.offsetLeft
      let top = el.offsetTop
      let p = el.offsetParent
      while(p) {
        left += p.offsetLeft
        top += p.offsetTop
        p = p.offsetParent
      }
      return {
        width: el.offsetWidth,
        height: el.offsetHeight,
        top,
        left
      }
   }

  </script>
  
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1960537.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【iOS】——持久化

在iOS开发中&#xff0c;数据持久化是非常重要的&#xff0c;因为它允许应用程序在不同会话之间保存用户数据、设置、偏好等信息。 为什么数据持久化 数据保存&#xff1a; 目的&#xff1a;将应用程序中的数据保存到非易失性存储中&#xff0c;以便在应用程序关闭或重启后仍…

眼镜清洗机哪个品牌好?性价比高的超声波眼镜清洗机

清洁眼镜、化妆刷、项链等物品其实是挺麻烦的&#xff0c;尤其是化妆刷这种经常使用的物品&#xff0c;需要用专门的清洁剂并保持一定的清洗频率。眼镜的日常清洁主要是用眼镜布擦拭镜片上的灰尘和指纹&#xff0c;但对于顽固的污渍或油脂&#xff0c;只有超声波清洗机能提供快…

六西格玛管理法

六西格玛管理法是一种旨在提高业务流程效率和减少缺陷的管理策略。它最初由摩托罗拉公司在1980年代末期提出&#xff0c;并随后被通用电气等公司广泛应用和发展。六西格玛的核心理念是通过减少过程变异性来提高产品质量和服务水平。 六西格玛的含义&#xff1a; 统计学概念&am…

一款功能全面的卸载工具,强大,免费,小巧

HiBit Uninstaller是一款功能全面的卸载工具&#xff0c;它不仅可以卸载Windows程序&#xff0c;还提供了诸如注册表清理、垃圾文件清理等多种系统优化功能。该软件以其小巧、强大、免费的特点受到用户的欢迎&#xff0c;尤其适合处理顽固软件和流氓程序的卸载问题。 主要功能…

WPF的MVVM架构:如何通过数据绑定简化UI逻辑

WPF的MVVM架构&#xff1a;如何通过数据绑定简化UI逻辑 目录 MVVM模式概述数据绑定在MVVM中的作用实现MVVM模式的步骤MVVM模式中的常见问题与解决方案实践示例总结 MVVM模式概述 MVVM&#xff08;Model-View-ViewModel&#xff09;是一种设计模式&#xff0c;用于WPF应用程序…

机器学习(五) -- 无监督学习(2) --降维1

系列文章目录及链接 上篇&#xff1a;机器学习&#xff08;五&#xff09; -- 无监督学习&#xff08;1&#xff09; --聚类2 下篇&#xff1a;机器学习&#xff08;五&#xff09; -- 无监督学习&#xff08;2&#xff09; --降维2 前言 tips&#xff1a;标题前有“***”的内…

热门超声波清洗机有哪些?小型超声波清洗机推荐

在繁忙的工作和生活中&#xff0c;许多人常常会因为种种原因忽略日常的小事&#xff0c;比如忘记清洁手表、眼镜、首饰等常用物品。实际上&#xff0c;这些物品表面不仅积累了灰尘和污垢&#xff0c;特别是跟眼部朝夕相处的眼镜&#xff0c;还可能滋生各种致病细菌&#xff0c;…

Vue3-如何自己写一个“返回顶部”功能

功能描述&#xff1a; 在屏幕的右下角固定一个“返回顶部”按钮&#xff0c;只有当用户滚动屏幕一定程度后出现&#xff0c;否则隐藏。 点击按钮&#xff0c;网页平滑的滚动到页面顶部。 环境&#xff1a;Vue3,js&#xff0c;antd 具体思路&#xff1a; 1、给窗口挂载滚动事…

Python 学习中的 API,如何调用API ?

1.1 API的定义 API&#xff0c;全称是Application Programming Interface&#xff08;应用程序编程接口&#xff09;。它是一组定义好的协议和工具&#xff0c;用于在软件应用程序之间进行通信。API可以简化软件开发&#xff0c;使不同的应用程序能够相互协作。它是软件开发中…

阿里云服务器 Ubuntu18.04 安装 mysql8.0并允许外部连接

参考教程&#xff1a; 官网教程 参考教程一 首先彻底删除mysql5.7 dpkg --list|grep mysql #查看 sudo apt-get remove mysql-common #卸载 sudo apt-get autoremove --purge mysql-server-5.7 #版本自己修改 dpkg -l|grep ^rc|awk {print$2}|sudo xargs dpkg -P #清除残留数…

LeetCode Hot100 将有序数组转换为二叉搜索树

给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡 二叉搜索树。 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#xff1a;[0,-10,5,null,-3,null,9] 也将被视为正确…

电商老司机教您批量下载1688高清主图、详情图、sku及视频信息

图片在电商中至关重要&#xff0c;高质量的商品图片能吸引顾客注意&#xff0c;提升购买欲望。它们是展示商品特性和细节的主要方式&#xff0c;有助于增强消费者信任&#xff0c;减少退换货率。好的图片还能优化搜索排名&#xff0c;提高转化率。简而言之&#xff0c;图片是电…

Luma AI的战略转向:从Nerf到视频生成领域的背后故事

引言 今天我们将深入探讨Luma AI近期引发关注的视频生成模型——Dream Machine。Luma AI从最初的3D重建和生成业务逐步转向视频生成领域的背后&#xff0c;隐藏着什么样的战略考量和技术演进&#xff1f;让我们通过Luma AI首席科学家宋佳铭的最新访谈&#xff0c;揭开这场技术…

【每日一题 | 数据结构】时间复杂度计算

题目 解题方法 对于二重循环求时间复杂度&#xff1a; 写出外层i的变化值写出内层循环语句执行次数&#xff08;看j&#xff09;对次数求和找到频度和n的关系 笔记 视频跳转&#xff1a; 【每日一题 | 数据结构】时间复杂度计算

手写操作系统:二级引导程序

项目简介 在上篇博客&#xff0c;我们完成了主引导扇区的编写&#xff0c;在主引导扇区我们初始化了寄存器&#xff0c;加载了二级引导程序到内存地址 0x8000处&#xff0c;并跳转至0x8000处执行&#xff0c;在本文我们将继续编写二级引导程序。 在二级引导程序将完成以下任务…

Unity UGUI 实战学习笔记(6)

仅作学习&#xff0c;不做任何商业用途 不是源码&#xff0c;不是源码! 是我通过"照虎画猫"写的&#xff0c;可能有些小修改 不提供素材&#xff0c;所以应该不算是盗版资源&#xff0c;侵权删 因为注册和登录面板的逻辑与数据存储方面已经相对完善 服务器面板逻辑…

为什么现在的家具很多带缓冲器?

在当今的家具市场中&#xff0c;我们不难发现&#xff0c;很多的家具配备了缓冲器。这一现象的背后&#xff0c;有着多方面的原因。首先&#xff0c;随着人们生活水平的提高&#xff0c;对于生活品质的追求也日益增强。缓冲器能够有效地减少家具关闭时产生的噪音&#xff0c;为…

如何通过✅ IPIDEA代理IP,轻松实现数据采集和市场拓展工作(下)

如何通过✅ IPIDEA代理IP&#xff0c;轻松实现数据采集和市场拓展工作 如何通过✅ IPIDEA代理IP&#xff0c;轻松实现数据采集和市场拓展工作前言IPIDEA爬虫实战实战Demo演示总结 如何通过✅ IPIDEA代理IP&#xff0c;轻松实现数据采集和市场拓展工作 前言 在当今全球化市场的…

【Qt】QTextEdit

QTextEdit是Qt中用于编辑和显示文本内容的类。其提供了丰富的用户界面控件&#xff0c;可以用于创建和包含格式化文本、图片和链接的文本编辑器 常用属性 属性说明markdown输入框内持有的内容。支持markdown格式&#xff0c;能自动的对markdown文本进行渲染成htmlhtml输入框持…

性能提升20%,字节跳动HTTPDNS从中心下沉到边缘

摘要&#xff1a;本文介绍了HTTPDNS服务从中心迁移至边缘详细的落地过程。主要内容为&#xff1a; HTTPDNS下沉边缘实践遇到的挑战&#xff0c;包括服务放置、流量调度 HTTPDNS下沉边缘解决方案 从性能、成本出发&#xff0c;谈谈HTTPDNS下沉边缘后的收益 传统的DNS流程中…