// 缓存对象
var cache = {};
// 创建一个函数,功能是返回下标为n的这项的数字
function fib(n) {
// 判
真题解析、进阶学习笔记、最新讲解视频、实战项目源码、学习路线大纲
详情关注公中号【编程进阶路】
断缓存对象中有没有这个值,如果有,直接用
if (cache.hasOwnProperty(n)) {
return cache[n];
}
// 缓存对象没有这个值
// 看下标n是不是0或者是不是1,如果是,就返回常数1
// 如果不是,就递归
var v = n == 0 || n == 1 ? 1 : fib(n - 1) + fib(n - 2);
// 写入缓存。也就是说,每算一个值,就要把这个值存入缓存对象。
cache[n] = v;
return v;
}
for (let i = 0; i <= 9; i++) {
console.log(fib(i));
}
=====================================================================
-
栈(stack )又名堆栈,它是一种运算受限的线性表,仅在表尾能进行入和删除操作。这一端被称为栈顶,相对地,把另一端称为栈底。
-
向一个栈插入新元素又称作进栈、入栈或压栈;从一个栈删除元素又称作出栈或退栈。
-
后进先出(LIFO )特点:栈中的元素,最先进栈的必定是最后出栈,后进栈的一定会先出栈
-
JavaScript 中,栈可以用数组模拟。需要限制只能使用push() 和pop() ,不能使用unshift() 和shift()。即,数组尾是栈顶。
-
当然,可以用面向对象等手段,将栈封装的更好。
利用"栈"的题目
试编写"智能重复"smartRepeat函数,实现:
-
将3[abc]变为abcabcabc
-
将3[2[a]2[b]]变为aabbaabbaabb
-
将2[1[a]3[b]2[3[c]4[d]]]变为abbbcccddddcccddddabbbcccddddcccdddd
不用考虑输入字符串是非法的情况,比如:
-
2[a3[b]]是错误的,应该补一个1,即2[1[a]3[b]]
-
[abc]是错误的,应该补一个1,即1[abc]
====================================================================
-
词法分析的时候,经常要用到栈这个数据结构;
-
初学者大坑:栈的题目和递归非常像,这类题目给人的感觉都是用递归解题。信心满满动手开始写了,却发现递归怎么都递归不出来。此时就要想到,不是用递归,而是用栈。
=====================================================================
=======================================================================
==================================================================
===============================================================
import parse from ‘./parse.js’;
var templateString = `
你好
- A
- B
- C
- `;
const ast = parse(templateString);
console.log(ast);
import parseAttrsString from ‘./parseAttrsString.js’;
// parse函数,主函数
export default function (templateString) {
// 指针
var index = 0;
// 剩余部分
var rest = ‘’;
// 开始标记
var startRegExp = /<([a-z]+[1-6]?)(\s[<]+)?>/;
// 结束标记
var endRegExp = /^</([a-z]+[1-6]?)>/;
// 抓取结束标记前的文字
var wordRegExp = /([<]+)</[a-z]+[1-6]?>/;
// 准备两个栈
var stack1 = [];
var stack2 = [{ ‘children’: [] }];
while (index < templateString.length - 1) {
rest = templateString.substring(index);
// console.log(templateString[index]);
if (startRegExp.test(rest)) {
// 识别遍历到的这个字符,是不是一个开始标签
let tag = rest.match(startRegExp)[1];
let attrsString = rest.match(startRegExp)[2];
// console.log(‘检测到开始标记’, tag);
// 将开始标记推入栈1中
stack1.push(tag);
// 将空数组推入栈2中
stack2.push({ ‘tag’: tag, ‘children’: [], ‘attrs’: parseAttrsString(attrsString) });
// 得到attrs字符串的长度
const attrsStringLength = attrsString != null ? attrsString.length : 0;
// 指针移动标签的长度加2再加attrString的长度,为什么要加2呢?因为<>也占两位
index += tag.length + 2 + attrsStringLength;
} else if (endRegExp.test(rest)) {
// 识别遍历到的这个字符,是不是一个结束标签
let tag = rest.match(endRegExp)[1];
// console.log(‘检测到结束标记’, tag);
let pop_tag = stack1.pop();
// 此时,tag一定是和栈1顶部的是相同的
if (tag == pop_tag) {
let pop_arr = stack2.pop();
if (stack2.length > 0) {
stack2[stack2.length - 1].children.push(pop_arr);
}
} else {
throw new Error(pop_tag + ‘标签没有封闭!!’);
}
// 指针移动标签的长度加3,为什么要加2呢?因为</>也占3位
index += tag.length + 3;
} else if (wordRegExp.test(rest)) {
// 识别遍历到的这个字符,是不是文字,并别不能是全空
let word = rest.match(wordRegExp)[1];
// 看word是不是全是空
if (!/^\s+$/.test(word)) {
// 不是全是空
// console.log(‘检测到文字’, word);
// 改变此时stack2栈顶元素中
stack2[stack2.length - 1].children.push({ ‘text’: word, ‘type’: 3 });
}
总结
三套“算法宝典”
算法刷题LeetCode中文版(为例)
人与人存在很大的不同,我们都拥有各自的目标,在一线城市漂泊的我偶尔也会羡慕在老家踏踏实实开开心心养老的人,但是我深刻知道自己想要的是一年比一年有进步。
最后,我想说的是,无论你现在什么年龄,位于什么城市,拥有什么背景或学历,跟你比较的人永远都是你自己,所以明年的你看看与今年的你是否有差距,不想做咸鱼的人,只能用尽全力去跳跃。祝愿,明年的你会更好!
由于篇幅有限,下篇的面试技术攻克篇只能够展示出部分的面试题,详细完整版以及答案解析,有需要的可以关注