前端算法与数据结构
1、算法和数据结构含义
- 数据结构:计算机存储,组织数据的方式
- 算法:一系列解决问题的清晰指令
1-1 关系
- 程序 = 数据结构 + 算法
- 数据结构为算法提供服务,算法围绕数据结构进行操作
1-2 数据结构
- 栈、队列、链表(有序)
- 集合、字典(无序)
- 树、堆、图(有一定连接关系)
1-3 算法
- 链表:遍历链表、删除节点链表
- 树、图:深度/广度优先遍历
- 数组:冒泡/选择/插入/快速排序等等
2、leetcode的介绍
2-1 功能
- 题库、社区、竞赛、模拟刷题
- 做题
- 查看题目描述,评论,题解,提交记录
3、时间复杂度
- 一个函数,用大写O来表示,比如:O(1)、O(n)、O(n^2)...等等
-
时间复杂度为O(1)
let i = 0; i = i + 1; -
时间复杂度为O(n)
for(let i = 0; i < n; i++) { console.log(i) } // 在一个for循环体里面,这个循环做了n次 -
时间复杂度为:O(n) + O(1) = O(n)
let i = 0;
i = i + 1;
for(let i = 0; i < n; i++) {
console.log(i)
}
- 时间复杂度为:O(n) * O(n) = O(n^2)
for(let i = 0; i < n; i++) {
for(let j = 0; j < n; j++) {
console.log(i,j)
}
}
- 时间复杂度为:O(logN)
let i = 1;
while(i < n) {
console.log(i)
i *= 2;
}
// 如果a^x =N(a>0,且a≠1),那么数x叫做以a为底N的对数,记作x=logaN
4、空间复杂度
-
一个函数,用大写O来表示,比如:O(1)、O(n)、O(n^2)...等等
-
算法在运行过程中临时占用存储大小的量度。你写的代码占用的空间大小
-
空间复杂度为O(1)
let i = 0;
i = i + 1;
- 空间复杂度为O(n)
let arr = [];
for(let i = 0; i < n; i++) {
arr.push(i);
}
- 空间复杂度为:O(n^2)
let arr = [];
for(let i = 0; i < n; i++) {
arr.push([]);
for(let j = 0; j < n; j++) {
arr[i].push(j);
}
}
// 矩阵,本质二维数组
5、栈
5-1栈简介
- 栈是一个后进先出的数据结构
- JavaScript中没有栈,可以用Array数组实现栈的所有功能
- 代码实现,定义一个stack的空数组,在push方法打上断点,按F5,编辑器自带的js调试,点击箭头执行下一步操作,左边控制面板可以看出:先入栈的元素是‘a’,先出栈的元素是'd',满足后进先出原则。
- 栈常用操作:push、pop、stack[stack.length - 1]
5-2栈应用
-
十进制转二进制
- 倒叙写二进制
-
判断字符串的括号是否有效
- 越靠后的左括号,对应的右括号越靠前。
- 从左到右遍历括号,遇到左括号入栈,遇到右括号出栈,最后栈空了就是合法的。
-
函数调用堆栈
- 最后调用的函数,最先执行完。
- JS解释器使用栈来控制函数的调用顺序
function run() {
console.log('1')
sayHello();
console.log('2')
}
function sayHello(){
console.log('hello')
}
run();
// 1
// hello
// 2
5-3栈算法题解析
-
对于没有闭合的左括号而言,越靠后的左括号,对应的右括号就越靠前
-
满足后进先出,考虑用栈解决。
-
解题步骤
- 1、新建一个栈
- 2、循环字符串,遇到左括号入栈,遇到右括号出栈,遇到类型不匹配判定为不合法。
- 3、最后栈空了就合法
var isValid = function (s) { const stack = []; // 新建一个栈 if (s.length % 2 == 1) { return false // 奇数的长度直接不合法 } for (let i = 0; i < s.length; i++) { const val = s[i] if (val === '(' || val === '{' || val === '[') { stack.push(val) // 判断左括号合法,入栈 } else { const top = stack[stack.length - 1]; // 定义栈顶元素 if ( // 栈顶元素的栈底元素匹配 (top === '(' && val === ')') || (top === '{' && val === '}') || (top === '[' && val === ']') ) { stack.pop(); // 出栈 } else { return false } } } return stack.length === 0; // 栈空了就合法 }; isValid("()"); isValid("()[]{}"); isValid("(]"); isValid("([)]");
5-4前端与栈
- 函数的调用(按循序去执行函数)
const fn1 = () => {
fn2();
}
const fn2 = () => {
fn3();
}
const fn3 = () => {}
fn1();
// 最先执行的函数是fn1 -> fn2 -> fn3
- 执行入栈
-
执行出栈
6、队列
6-1队列简介
-
队列是先进先出的数据结构
-
JavaScript中没有队列,可以用Array数组实现队列的所有功能
-
入队和出队
-
队列常用操作:push、shift、queue[0]
6-2队列应用
- 排队打饭
- JS异步中的任务队列
- JS是单线程的,无法同时处理异步中的并发任务。
- 使用队列任务先后处理异步任务
- 计算最近请求次数
6-3队列算法题解析
-
解题步骤
- 有新情求就入队,3000ms前发出的请求出队
- 队列的长度就是最近的请求次数
// 在这个时间 的 过去 3 秒 内, 不停的请求, 求在这个3秒内这个请求了多少下 var RecentCounter = function() { this.queue = []; }; /** * @param {number} t * @return {number} */ RecentCounter.prototype.ping = function(t) { this.queue.push(t) // 队头在 t - 3000ms内,出队 while(this.queue[0] < t - 3000) { this.queue.shift() } return this.queue.length; }; // 时间复杂度:O(n) , 空间复杂度O(n)
6-4前端与队列
-
Javascript语言的执行环境是单线程的。js异步原理解析
所谓"单线程",就是指一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推。
7、链表
7-1链表简介
- 多个元素组成的列表
- 元素存储不连续,用next指针连在一起
- JS没有链表
- 可以用Object模拟链表
-
遍历链表
var a = { val: 'a' } var b = { val: 'b' } var c = { val: 'c' } var d = { val: 'd' } a.next = b; b.next = c c.next = d; // 遍历链表 let p = a; while(p) { console.log(p.val) p = p.next; }
-
链表插入
- 链表删除
// 删除 c.next = d; // 把c的next指向d,就能删除e
7-2链表算法题解析
-
解题思路
- 无法直接获取被删除节点的上一个元素,将被删除节点的值改成下个节点的值
- 将被删除节点转移到下个节点(如果想要删除节点5,先把5的节点指向下个元素值,此时链表为4-1-1-9,再把节点1下个元素删除,即可得到4-1-9的链表)
/** * Definition for singly-linked list. * function ListNode(val) { * this.val = val; * this.next = null; * } */ /** * @param {ListNode} node * @return {void} Do not return anything, modify node in-place instead. */ var deleteNode = function(node) { node = 5 node.val = node.next.val; node.next = node.next.next; };
7-4前端与链表
7-4-1 JS原型链含义
- 原型链的本质是链表
- 原型链上的节点是各个原型对象,比如
Function.prototype、Object.prototype - 原型链通过
__proto__属性连接各种原型对象
7-4-2 原型链
obj -> Object.prototype -> null
fun -> Function.prototype -> Object.prototype -> null
arr -> Array.prototype -> Object.prototype -> null
7-4-3 原型链知识点
- 如果
A沿着原型链能找到B.prototype,那么Ainstanceof B为true
const obj = {}
const fun = ()=> {}
const arr = []
// 对于数组来说,arr即是Array的实例,也是Object的实例
arr instanceof Array // true
arr instanceof Object // true
fun instanceof Function // true
fun instanceof Object // true
obj instanceof Object // true
- 如果在A对象上没有找到X属性,那么会沿着原型链找到X的属性
const obj = {}
obj.name = undefined
Object.prototype.name = "张三"
obj.name = "张三"
// 函数原型链可以指向Object.prototype
Object.prototype.age = "16"
const fun1 = ()=> {}
fun1.age = 16