javaScript面试题之编程题汇总

189 阅读2分钟

编程题汇总

学习过程中的简单记录,若问题敬请指教!文章持续更新中...

路过的朋友,可以点个赞,关注一下~~~

1. 编程题-链表合并

 /*
 * 构造两个以整型数字为值的链表,其中的值是单调递增的。
 * 将两个链表合并,保持递增。
 * 要求空间复杂度O(1)
 */
 ​
 ​
 function ListNode(x) {
   this.val = x;
   this.next = null;
 }
 ​
 // 要求空间复杂度O(1)
 function Merge(pHead1, pHead2) {
   // write code here
   if (!pHead1) return pHead2;
   if (!pHead2) return pHead1;
   let cur = new ListNode(0);
   let headNode = new ListNode(0);
   if (pHead1.val <= pHead2.val) headNode = pHead1;
   else headNode = pHead2;
   while (pHead1 && pHead2) {
     if (pHead1.val <= pHead2.val) {
       cur.next = pHead1;
       pHead1 = pHead1.next;
     } else {
       cur.next = pHead2;
       pHead2 = pHead2.next;
     }
     cur = cur.next;
   }
   cur.next = pHead1 ? pHead1 : pHead2;
   return headNode;
 }
 ​
 ​
 ​
 ​
 // 递归的空间复杂度为O(n) 循环几次复杂度为几次
 function Merge(pHead1, pHead2) {
   if (pHead1 === null) {
     return pHead2;
   }
   if (pHead2 === null) {
     console.log("pHead1:** ", pHead1);
     return pHead1;
   }
 ​
   if (pHead1.val <= pHead2.val) {
     pHead1.next = Merge(pHead1.next, pHead2);
     return pHead1;
   } else {
     pHead2.next = Merge(pHead1, pHead2.next);
     return pHead2;
   }
 }
 ​
 ​

测试

 let pHead1 = {
   val: 1,
   next: {
     val: 3,
     next: null,
   },
 };
 let pHead2 = {
   val: 2,
   next: {
     val: 4,
     next: null,
   },
 };
 
 
 console.log(Merge(pHead1, pHead2));

2. 编程题-单链表每隔k个元素做一次反转

 /**
  * 单链表每隔k个元素做一次反转
  *
  * Example:
  *  Inputs: 1->2->3->4->5->6->7->8->NULL and k = 3
  *  Output: 3->2->1->6->5->4->8->7->NULL.
  *
  *  Inputs: 1->2->3->4->5->6->7->8->NULL and k = 5
  *  Output: 5->4->3->2->1->8->7->6->NULL.
  *
  */
 ​
 // 反转
 function reverse(a, b) {
   let pre = null,
     cur = a,
     nxt = a;
   while (cur != b) {
     nxt = cur.next;
     cur.next = pre;
     pre = cur;
     cur = nxt;
   }
   return pre;
 }
 ​
 // 反转组
 function reverseKGroup(head, k) {
   let a = head,
     b = head;
   for (let i = 0; i < k; i++) {
     if (b == null) return head; //不足k个剩下的不需要反转
     b = b.next; //分组:每一组k个被反转的节点
   }
   let newHead = reverse(a, b); //调用反转函数
   a.next = reverseKGroup(b, k); //将每组被反转的组,连接到一起
   return newHead; //返回最后的链表
 }
 ​

测试

 let head = {
   val: 1,
   next: {
     val: 2,
     next: {
       val: 3,
       next: {
         val: 4,
         next: {
           val: 5,
           next: {
             val: 6,
             next: {
               val: 7,
               next: {
                 val: 8,
                 next: {
                   val: 9,
                   next: {
                     val: 10,
                     next: {
                       val: 11,
                       next: null,
                     },
                   },
                 },
               },
             },
           },
         },
       },
     },
   },
 };
 
 let result = reverseKGroup(head, 3);
 
 console.log("result: ", result);

3.编程题-扁平结构转嵌套结构

 // 将扁平化 数组 转换树的方法
 export function handleTree(data, id, parentId, children) {
   let config = {
     id: id || 'id',
     parentId: parentId || 'parentId',
     childrenList: children || 'children'
   }
 ​
   let childrenListMap = {}
   let nodeIds = {}
   let tree = []
 ​
   // 获取所有id的一个map 和 parentId的相同的一个数组
   for (let d of data) {
     let parentId = d[config.parentId]
     if (childrenListMap[parentId] == null) {
       childrenListMap[parentId] = []
     }
     nodeIds[d[config.id]] = d
     childrenListMap[parentId].push(d)
   }
 ​
   // 所有所有根节点
   for (let d of data) {
     let parentId = d[config.parentId]
     if (nodeIds[parentId] == null) {
       tree.push(d)
     }
   }
 ​
   // 所有的根节点挂载下级
   for (let t of tree) {
     adaptToChildrenList(t)
   }
 ​
   // 适配子节点列表
   function adaptToChildrenList(o) {
     if (childrenListMap[o[config.id]] !== null) {
       o[config.childrenList] = childrenListMap[o[config.id]]
     }
 ​
     // 存在子节点 循环子节点去挂载
     if (o[children.childrenList]) {
       for (let c of o[config.childrenList]) {
         adaptToChildrenList(c)
       }
     }
   }
 }
 ​

使用示例

 const data = [
   { name: '数据1', parentId: null, id: 1 },
   { name: '数据2', id: 2, parentId: 1 },
   { name: '数据3', parentId: 2, id: 3 },
   { name: '数据4', parentId: 3, id: 4 }
 ]
 
 let treeData = handleTree(data)

4. 编程题-JS异步并发调度器

javaScript中控制并发数量

源码

想到了解法其实很简单,我的代码看一遍就能会。

 class Scheduler {
     constructor(max) {
         this.max = max
         this.count = 0
         this.queue = []
     }
     add(p) {
         this.queue.push(p)
         this.start()
     }
     start() {
         if (this.count >= this.max || !this.queue.length) return
         this.count++
         this.queue.shift()().finally(() => {
             this.count--
             this.start()
         })
     }
 }
 复制代码

示例

 // 延迟函数
 const sleep = time => new Promise(resolve => setTimeout(resolve, time));
 ​
 // 同时进行的任务最多2个
 const scheduler = new Scheduler(2);
 ​
 // 添加异步任务
 // time: 任务执行的时间
 // val: 参数
 const addTask = (time, val) => {
     scheduler.add(() => {
         return sleep(time).then(() => console.log(val));
     });
 };
 ​
 addTask(1000, '1');
 addTask(500, '2');
 addTask(300, '3');
 addTask(400, '4');
 // 2
 // 3
 // 1
 // 4
 复制代码

5. 防抖

防抖主要是使用延时器来实现的,正常防抖可以分为两种分别是立即执行版本非立即执行版本。此处主要是结合两种形式的一个组合版本。

  • 立即执行版本:一般用在按钮点击上(比如提交表单),点击立即触发,单位时间内一直点击不会触发。当超过单位时间再次点击会再次触发。
  • 非立即执行版本:一般用在搜索联想功能中,输入内容的时候不触发,输入完后再请求后端获取数据。
 export function debounce(func, delay, immediate = true) {
   let timer = null;
   return function () {
     // 上下文参数
     const context = this;
     const args = arguments;
     // 清除延时器
     if (timer) clearTimeout(timer);
 ​
     if (immediate) {
       // 立即执行版本
       const canCall = !timer;
       timer = setTimeout(() => {
         timer = null;
       }, delay);
 ​
       if (canCall) func.canCall(context, ...args);
     } else {
       // 非立即执行版本
       timer = setTimeout(() => {
         func.call(context, ...args);
       });
     }
   };
 }

6. 设计节流

节流也是使用延时器来实现的

使用场景

常见的使用场景是在一些 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率。

 // 实现节流
 export function throttle(func, delay) {
   let timer = null;
   return function () {
     const context = this;
     const args = arguments;
     if (!timer) {
       timer = setTimeout(() => {
         timer = null;
         func.call(context, ...args);
       }, delay);
     }
   };
 }

后记

本文纯仅属于个人的一些简单的见解,比较浅显,若有不妥之处还请不吝赐教!!!(☆_☆)

如果本文对你有所帮助,欢迎点赞!!!

o( ̄▽ ̄)d