From 8ce5fb4ac3f89556aa1de0f34c147613c1b51983 Mon Sep 17 00:00:00 2001 From: chendapeng Date: Fri, 4 Aug 2023 13:40:56 +0800 Subject: [PATCH] feat: handwriting0804 --- docs/interview/experiences/0717writing.js | 66 ++++++++ docs/interview/experiences/0index.md | 2 + .../experiences/4beforeHandwriting.md | 10 +- docs/interview/logic/dfs.md | 12 +- docs/interview/practise/0801.js | 16 ++ docs/interview/practise/0802.js | 155 ++++++++++++++++++ 6 files changed, 254 insertions(+), 7 deletions(-) create mode 100644 docs/interview/practise/0802.js diff --git a/docs/interview/experiences/0717writing.js b/docs/interview/experiences/0717writing.js index dc9d521..dc933b5 100644 --- a/docs/interview/experiences/0717writing.js +++ b/docs/interview/experiences/0717writing.js @@ -39,6 +39,14 @@ * 39.手写函数重载 * 40.二叉树前中后序遍历(迭代方式) * 41.冒泡排序和归并排序 + * 42.滑动窗口,无重复字符的最长子串 + * 43.实现一个带缓存斐波那契数列 + * 44.最大子序和 + * 45.实现简单的hash路由跟history路由 + * 46.二叉树的层序遍历 + * 47.二叉树前中后序遍历(递归方式) + * 48.如何实现无限累加的一个函数 + * 49.手写NOSSR **/ // > 定个小目标100个手写提 @@ -76,3 +84,61 @@ var obj = { for (var item of new MakeIterator(obj)) { console.log(item); } + +// 6.函数柯里化curry(参数固定和不固定) +// 参数不固定curry(1,2,3) +function curry(fn) { + var arr = []; + return function temp(...arg) { + if (arg.length) { + arr.push(...arg); + return temp; + } else { + var res = fn.apply(this, arr); + arr = []; + return res; + } + }; +} +// 参数固定 curry(1)(2)(3)() +function curry2(fn) { + var judge = (...rest) => { + if (rest.length === fn.length) { + fn.apply(this, rest); + } else { + return (...arg) => judge(...arg, ...rest); + } + }; + return judge; +} + +// 48 如何实现无限累加的一个函数 +function sum(...rest) { + var f = (...arg) => sum(...arg, ...rest); + f.valueOf = () => rest.reduce((a, b) => a + b, 0); + return f; +} + +sum(1, 2, 3).valueOf(); //6 +sum(2, 3)(2).valueOf(); //7 +sum(1)(2)(3)(4).valueOf(); //10 +sum(2)(4, 1)(2).valueOf(); //9 +sum(1)(2)(3)(4)(5)(6).valueOf(); // 21 + +// 49.手写NOSSR +import { useEffect, useState } from 'react'; + +function NoSSR(props) { + const { children } = props; + const [isMounted, setIsMounted] = useState(false); + + useEffect(() => { + setIsMounted(true); + }, []); + + if (!isMounted) { + return null; + } else { + return
{children}
; + } +} diff --git a/docs/interview/experiences/0index.md b/docs/interview/experiences/0index.md index c761a99..b65de8f 100644 --- a/docs/interview/experiences/0index.md +++ b/docs/interview/experiences/0index.md @@ -11,6 +11,8 @@ nav: > 20221229 开始积累面试经验!好久不背面试题,都快忘记了,记忆力真差 +- [山月的面经](https://q.shanyue.tech/interview) + > 20230105 感觉在面试方面没有自信心了,更多的是忧虑/恐慌/无助 ### 面试官:你确定多窗口之间 sessionStorage 不能共享状态吗??? diff --git a/docs/interview/experiences/4beforeHandwriting.md b/docs/interview/experiences/4beforeHandwriting.md index e6756a8..ff305cc 100644 --- a/docs/interview/experiences/4beforeHandwriting.md +++ b/docs/interview/experiences/4beforeHandwriting.md @@ -1186,7 +1186,7 @@ function makeGetRequest(url, cb) { // step two httpRequest.onreadystatechange = () => { // 检查请求的状态 4 - if (httpRequest.readyState === XMLHttpRequest.done) { + if (httpRequest.readyState === XMLHttpRequest.DONE) { // 检查请求状态码 if (httpRequest.status === 200) { cb(httpRequest.responsText); @@ -1195,12 +1195,14 @@ function makeGetRequest(url, cb) { }; // step two httpRequest.open('GET', url, true); - // 第三个参数可选,用于设置请求是否是异步的。如果设为 true (默认值),即开启异步,JavaScript就不会在此语句阻塞,使得用户能在服务器还没有响应的情况下与页面进行交互。 + // 第三个参数可选,表示是否执行异步操作,默认为true。如果设为 true (默认值),即开启异步,JavaScript就不会在此语句阻塞,使得用户能在服务器还没有响应的情况下与页面进行交互。如果值为 false,send() 方法直到收到答复前不会返回 httpRequest.send(); } ``` -如果你使用 POST 数据,那就需要设置请求的 MIME 类型。比如,在调用 send() 方法获取表单数据前要有下面这个: +如果你使用 POST 数据,那就需要设置请求的 **MIME** 类型。比如,在调用 send() 方法获取表单数据前要有下面这个: + +`httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')` ```js function makePostRequest(url, cb, userName) { @@ -1212,7 +1214,7 @@ function makePostRequest(url, cb, userName) { } } } - httpRequest.open('Post', url, true); + httpRequest.open('POST', url, true); httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); httpRequest.send('userName=' + encodeURIComponent(userName)); ``` diff --git a/docs/interview/logic/dfs.md b/docs/interview/logic/dfs.md index eba1cf0..5af8c77 100644 --- a/docs/interview/logic/dfs.md +++ b/docs/interview/logic/dfs.md @@ -11,10 +11,18 @@ nav: path: /interview --- +[二叉树](https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html#%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%81%8D%E5%8E%86%E6%96%B9%E5%BC%8F) + ## DFS depth First Search +这里前中后,其实指的就是中间节点的遍历顺序,只要大家记住 前中后序指的就是中间节点的位置就可以了。 + +前序遍历:中左右中序遍历:左中右后序遍历:左右中 + +![前中后序遍历](https://code-thinking-1253855093.file.myqcloud.com/pics/20200806191109896.png) + 测试案例 ```js @@ -49,7 +57,7 @@ var node = { }; ``` -- 前序遍历 **根左右** +- 前序遍历 **根左右** 先访问根节点,在访问左右节点 ```js var preTraversal = (root) => { @@ -77,10 +85,8 @@ function inorderTraversal(root) { let num = 1; var inorder = (node) => { if (node) { - console.log(node, num++); inorder(node.left); arr.push(node.val); - debugger; inorder(node.right); } }; diff --git a/docs/interview/practise/0801.js b/docs/interview/practise/0801.js index 222d458..bd41e96 100644 --- a/docs/interview/practise/0801.js +++ b/docs/interview/practise/0801.js @@ -156,3 +156,19 @@ function promisify(fn) { }; }); } + +// ?name=cpp&age=30&sex=huamn +// http://ops.ximalaya.com/api-manager-backend/router-page/projectApiLook/2161/103995?activeTab=0&name=cpp&age=30&sex=huamn +function UrlParam(url) { + var str = url.split('?')[1]; + var arr = str.split('&'); + var res = {}; + for (let i = 0; i < arr.length; i++) { + var item = arr[i].split('='); + res[item[0]] = item[1]; + } + return res; +} +UrlParam( + `http://ops.ximalaya.com/api-manager-backend/router-page/projectApiLook/2161/103995?activeTab=0&name=cpp&age=30&sex=huamn`, +); diff --git a/docs/interview/practise/0802.js b/docs/interview/practise/0802.js new file mode 100644 index 0000000..67f1911 --- /dev/null +++ b/docs/interview/practise/0802.js @@ -0,0 +1,155 @@ +/** + * 1.手写二叉树前中后序迭代遍历an + * 2.请求并发 + * 3.冒泡排序 + * 4.lRU + * 5.实现Iterator + * 6.async/await + * 7.选择排序和插入排序 + * 8.归并排序 + */ + +class LRU { + constructor(limit) { + this.limit = limit; + this.cache = new Map(); + } + get(key) {} + set(key, val) {} +} + +async function asyncPool(limit, array, fn) { + var res = []; + var executing = []; + for (let i = 0; i < array.length; i++) { + var p1 = Promise.resolve().then(() => fn(array[i])); + res.push(p1); + if (array.length >= limit) { + var p2 = p1.then(() => { + return executing.splice(executing.indexOf(p2), 1); + }); + executing.push(p2); + if (executing.length >= limit) { + await Promise.race(executing); + } + } + } + return Promise.all(res); +} + +function bubbleSort(arr) { + for (let i = 0; i < arr.length; i++) { + for (let j = 0; j < arr.length - i - 1; j++) { + if (arr[j] > arr[j + 1]) { + var temp = arr[j]; + arr[j] = arr[j + 1]; + arr[j + 1] = temp; + } + } + } + return arr; +} +bubbleSort([22, 111, 2, 3, 4, 3, 55, 6666, 1]); +// 但是选择排序是将最小的元素存放在数组起始位置,再从剩下的未排序的序列中寻找最小的元素,然后将其放到已排序的序列后面。以此类推,直到排序完成。 +function selectSort(arr) { + let minIndex = 0; + const len = arr.length; + for (let i = 0; i < len - 1; i++) { + minIndex = i; + for (let j = i + 1; j < len; j++) { + if (arr[minIndex] >= arr[j]) { + minIndex = j; + } + } + var temp = arr[i]; + arr[i] = arr[minIndex]; + arr[minIndex] = temp; + } + return arr; +} +selectSort([22, 111, 2, 3, 4, 3, 55, 6666, 1]); + +function insertSort(arr) { + var pre, cur; + var len = arr.length; + for (let i = 1; i < len; i++) { + cur = arr[i]; + pre = i - 1; + while (pre >= 0 && arr[pre] >= cur) { + arr[pre + 1] = arr[pre]; + pre--; + } + arr[pre + 1] = cur; + } + return arr; +} +insertSort([22, 111, 2, 3, 4, 3, 55, 6666, 1]); + +class MakeIterator { + constructor(obj) { + this.obj = obj; + this.index = 0; + this.len = Object.keys(obj).length; + } + [Symbol.iterator]() { + return this; + } + next() { + return this.index < this.length + ? { + done: false, + value: this.obj[this.index++], + } + : { + done: true, + value: undefined, + }; + } +} + +// 前序 +// 优先以后代节点的顺序访问每个节点的,跟中序不一样的是,先序遍历会优先访问节点本身,然后在访问她的左侧节点,最后是右侧子节点 +// 应用场景是打印一个结构化的文档 +// 根左右 +function preOrder(tree) { + var res = []; + var dfs = (node) => { + if (node) { + res.push(node.val); + dfs(node.right); + dfs(node.left); + } + }; + dfs(tree); + return res; +} +// 中序 +// 左根右 +function inOrder(tree) { + var res = []; + var dfs = (node) => { + if (node) { + dfs(node.left); + res.push(node.val); + dfs(node.right); + } + }; + dfs(tree); + return res; +} + +// 后序 先访问节点的后代节点,在访问节点本身 应用场景主要是计算一个目录及其子目录中所有文件所占空间的大小 +// 左右根 +function afterOrder(tree) { + var dfs = (node) => { + if (node) { + dfs(node.left); + dfs(node.right); + res.push(node.val); + } + }; + dfs(tree); + return res; +} + +function mergeSort(arr) {}