diff --git a/interview/algorithm/README.md b/interview/algorithm/README.md index abf6055..e322a59 100644 --- a/interview/algorithm/README.md +++ b/interview/algorithm/README.md @@ -27,3 +27,4 @@ 贪心得到结果是一个可以接受的解,不一定总是得到最优的解 [硬币找零](./greedy/coin.js) [饼干与小孩](./greedy/cookie.js) +[买卖股票的最佳时机](./greedy/shares.js) diff --git a/interview/algorithm/greedy/shares.js b/interview/algorithm/greedy/shares.js index 7cbd656..9897a08 100644 --- a/interview/algorithm/greedy/shares.js +++ b/interview/algorithm/greedy/shares.js @@ -18,7 +18,8 @@ var maxProfit = function(prices, fee) { min = prices[i] } else if ((t = prices[i] - min - fee) > 0) { r += t - min = prices[i] - fee + // TODO + min = prices[i] - fee } i++ } diff --git a/interview/algorithm/structer/tree/treeSum.js b/interview/algorithm/structer/tree/treeSum.js new file mode 100644 index 0000000..6097d69 --- /dev/null +++ b/interview/algorithm/structer/tree/treeSum.js @@ -0,0 +1,69 @@ +// 对于给定的二叉树,判断是否存在一条完整路径(从根节点开始,到叶节点结束的连线),其路径上节点的值之和为target,输出布尔值。 +// **举例:下面的树,是否存在一条完整路径,该路径上各个节点之和target=7? + +(() => { + //用多维数组代表题中示例的树,这个数组是按“前序遍历”后排序 + let arrSouce = [6, [2, [-1], [3]], [3, [0]]]; + + /** + * 定义二叉树的结点。根结点和树的数据结构一样, + * 因此只需要定义一个结点(Node)的数据结构即可 + */ + class Node { + /** + * 构造函数 + * @param {Number} value 当前结点的值 + * @param {Node} left 左子结点 + * @param {Node} right 右子结点 + */ + constructor(value, left, right) { + if (value != undefined) { + this.value = value; + if (left != undefined) this.left = left; + if (right != undefined) this.right = right; + } + } + } + + /** + * 创建一个树 + * @param {Array} arr 一个代表二叉树的多维数组 + */ + function makeBTree(arr) { + if (arr) { + if (arr.length == 1) { + return new Node(arr[0]); + } + //递归,创建二叉树 + return new Node(arr[0], makeBTree(arr[1]), makeBTree(arr[2])); + } + } + + //创建示例中的二叉树,简洁多了! + let bTree = makeBTree(arrSouce); + + /** + * 主逻辑函数,与第一种解法里代码一样 + * @param {Node} node 树的结点 + * @param {Number} target 题目要求的目标值 + */ + function hasPathSum(node, target) { + //若根节点无子结点 + if (!node.left && !node.right) { + //直接判断根结点额值是否等于target + return node.value == target; + } + //若有子结点 + else { + //如有左结点 左侧递归 + if (!!node.left) + return hasPathSum(node.left, /*关键*/ target - node.value); + //如有右结点 右侧递归 + if (!!node.right) + return hasPathSum(node.right, /*关键*/ target - node.value); + } + } + + console.log(hasPathSum(bTree, 7)); //>> true + })(); + \ No newline at end of file diff --git a/interview/css/width.md b/interview/css/width.md new file mode 100644 index 0000000..546e560 --- /dev/null +++ b/interview/css/width.md @@ -0,0 +1,4 @@ +1. 某 div 不设置宽度,那么 width 默认为 auto. +2. 某子元素 div 的 width 为 100%(或者设置为等于父元素宽度的具体值,比如父元素 width 为 100px, + 子元素 width 也设置为 100px),则此子元素的宽度 = 父元素 width 值(不包括父元素边框,内边距)+子元素的边框、内边距宽度 +3. 某个 div 的 width 不设置,或者设置为 auto, 子元素的宽度会包含在父元素内,子元素边框、内边距都在不会叠加到子元素的长度上 diff --git a/interview/function/promise1.js b/interview/function/promise1.js new file mode 100644 index 0000000..7e57222 --- /dev/null +++ b/interview/function/promise1.js @@ -0,0 +1,140 @@ +const PENDING = 'PENDING'; +const FULFILLED = 'FULFILLED'; +const REJECTED = 'REJECTED'; + +const resolvePromise = (promise2, x, resolve, reject) => { + // 自己等待自己完成是错误的实现,用一个类型错误,结束掉 promise Promise/A+ 2.3.1 + if (promise2 === x) { + return reject(new TypeError('Chaining cycle detected for promise #')) + } + // Promise/A+ 2.3.3.3.3 只能调用一次 + let called; + // 后续的条件要严格判断 保证代码能和别的库一起使用 + if ((typeof x === 'object' && x != null) || typeof x === 'function') { + try { + // 为了判断 resolve 过的就不用再 reject 了(比如 reject 和 resolve 同时调用的时候) Promise/A+ 2.3.3.1 + let then = x.then; + if (typeof then === 'function') { + // 不要写成 x.then,直接 then.call 就可以了 因为 x.then 会再次取值,Object.defineProperty Promise/A+ 2.3.3.3 + then.call(x, y => { // 根据 promise 的状态决定是成功还是失败 + if (called) return; + called = true; + // 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1 + resolvePromise(promise2, y, resolve, reject); + }, r => { + // 只要失败就失败 Promise/A+ 2.3.3.3.2 + if (called) return; + called = true; + reject(r); + }); + } else { + // 如果 x.then 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.3.4 + resolve(x); + } + } catch (e) { + // Promise/A+ 2.3.3.2 + if (called) return; + called = true; + reject(e) + } + } else { + // 如果 x 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.4 + resolve(x) + } +} + +class Promise { + constructor(executor) { + this.status = PENDING; + this.value = undefined; + this.reason = undefined; + this.onResolvedCallbacks = []; + this.onRejectedCallbacks= []; + + let resolve = (value) => { + if(this.status === PENDING) { + this.status = FULFILLED; + this.value = value; + this.onResolvedCallbacks.forEach(fn=>fn()); + } + } + + let reject = (reason) => { + if(this.status === PENDING) { + this.status = REJECTED; + this.reason = reason; + this.onRejectedCallbacks.forEach(fn=>fn()); + } + } + + try { + executor(resolve,reject) + } catch (error) { + reject(error) + } + } + + then(onFulfilled, onRejected) { + //解决 onFufilled,onRejected 没有传值的问题 + //Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4 + onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v; + //因为错误的值要让后面访问到,所以这里也要跑出个错误,不然会在之后 then 的 resolve 中捕获 + onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }; + // 每次调用 then 都返回一个新的 promise Promise/A+ 2.2.7 + let promise2 = new Promise((resolve, reject) => { + if (this.status === FULFILLED) { + //Promise/A+ 2.2.2 + //Promise/A+ 2.2.4 --- setTimeout + setTimeout(() => { + try { + //Promise/A+ 2.2.7.1 + let x = onFulfilled(this.value); + // x可能是一个proimise + resolvePromise(promise2, x, resolve, reject); + } catch (e) { + //Promise/A+ 2.2.7.2 + reject(e) + } + }, 0); + } + + if (this.status === REJECTED) { + //Promise/A+ 2.2.3 + setTimeout(() => { + try { + let x = onRejected(this.reason); + resolvePromise(promise2, x, resolve, reject); + } catch (e) { + reject(e) + } + }, 0); + } + + if (this.status === PENDING) { + this.onResolvedCallbacks.push(() => { + setTimeout(() => { + try { + let x = onFulfilled(this.value); + resolvePromise(promise2, x, resolve, reject); + } catch (e) { + reject(e) + } + }, 0); + }); + + this.onRejectedCallbacks.push(()=> { + setTimeout(() => { + try { + let x = onRejected(this.reason); + resolvePromise(promise2, x, resolve, reject) + } catch (e) { + reject(e) + } + }, 0); + }); + } + }); + + return promise2; + } +} diff --git a/interview/functional/partial.md b/interview/functional/partial.md index 71c73c8..07286ff 100644 --- a/interview/functional/partial.md +++ b/interview/functional/partial.md @@ -102,3 +102,21 @@ function bindFirstArg(fn, a) { }; } ``` +#### 偏函数是固定一个函数的一个或多个参数,然后返回一个新函数 +```js +//入参函数 +function add(a,b){ + return a + b; +} +//生产偏函数的工厂 +function partial(fn,a){ + return function(b){ + return fn(a,b); + } +} +var parAdd = partial(add,1);//变量parAdd接受返回的新函数 +console.log(parAdd(2));//在调用的时候传入剩余的参数 +console.log(parAdd(3));//在调用的时候传入剩余的参数 +console.log(parAdd(4));//在调用的时候传入剩余的参数 +console.log(parAdd(5));//在调用的时候传入剩余的参数 +``` \ No newline at end of file diff --git a/remember/interview.md b/remember/interview.md index f4d81a3..8f594e3 100644 --- a/remember/interview.md +++ b/remember/interview.md @@ -2,7 +2,7 @@ https://juejin.cn/post/6844903577220349959 -[hard](https://github.com/coffe1891/frontend-hard-mode-interview) +[hard-前端内参](https://github.com/coffe1891/frontend-hard-mode-interview) [33](https://github.com/stephentian/33-js-concepts) [real](https://i-want-offer.github.io/FE-Essay/) [collection](https://github.com/LiangJunrong/document-library) \ No newline at end of file diff --git a/tools/github-collection/frame-work.md b/tools/github-collection/frame-work.md index 237a618..6c38006 100644 --- a/tools/github-collection/frame-work.md +++ b/tools/github-collection/frame-work.md @@ -61,4 +61,6 @@ Isometric Sass #### framework [solid](https://github.com/solid/solid) -[google/Lit/web component]() \ No newline at end of file +[google/Lit/web component]() + +[markmap](https://github.com/dundalek/markmap) \ No newline at end of file