时间复杂度
时间复杂度是一个函数,用来定性描述算法的运行时间,用大写字母O表示,例如:O(1),O(n),O(logN)
空间复杂度
空间复杂度是一个函数,用来描述算法在运行过程中临时占用存储空间的大小,用大写字母O表示,例如:O(1),O(n),O(n^2)
1.数据结构---栈
一种后进先出的数据结构
经典场景
1. 十进制转二进制
// 封装一个 Stack 类,包括 push、pop、peek 方法。
class Stack {
constructor() {
this.stack = []
}
push(item) {
this.stack.push(item)
}
pop() {
return this.stack.pop()
}
peek() {
return this.stack[this.stack.length - 1]
}
length() {
return this.stack.length
}
}
const stack = new Stack()
console.log(stack.length()) // 0
stack.push('123')
stack.push('456')
console.log(stack.length()) // 2
console.log(stack.pop()) // 456
console.log(stack.length()) // 1
console.log(stack.peek()) // 123
// 将100这个十进制数字转为二进制。
function dec2bin(num) {
let res = '';
let stack = new Stack();
while (num) {
stack.push(num % 2);
num = parseInt(num / 2);
}
while (stack.length()) {
res += stack.pop()
}
return res;
}
console.log(dec2bin(100)) // 1100100
2. 有效的括号
力扣题目 20. 有效的括号
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function (s) {
const sLen = s.length
if (sLen % 2 === 1) return false
const stack = []
for (let i = 0; i < sLen; i++) {
const c = s[i]
if (c === '(' || c === '[' || c === '{') {
stack.push(c)
} else {
const t = stack[stack.length - 1]
if (
t === '(' && c === ')' ||
t === '{' && c === '}' ||
t === '[' && c === ']'
) {
stack.pop()
} else {
return false
}
}
}
return stack.length === 0
};
3. 函数调用堆栈
2.数据结构---队列
一种先进先出的数据结构
class Queue {
constructor() {
this.queue = []
}
push(item) {
this.queue.push(item)
return this.queue
}
shift() {
return this.queue.shift()
}
peek() {
return this.queue[0]
}
}
const queue = new Queue()
console.log(queue.push(1)) // [1]
console.log(queue.push(2)) // [1,2]
console.log(queue.shift()) // 1
console.log(queue.peek()) // 2
经典场景
1.食堂排队打饭
2.js异步中的任务队列
3.计算最近请求次数
力扣题目933. 最近的请求次数
var RecentCounter = function () {
this.queue = []
};
/**
* @param {number} t
* @return {number}
*/
RecentCounter.prototype.ping = function (t) {
this.queue.push(t)
while (this.queue[0] < t - 3000) {
this.queue.shift()
}
return this.queue.length
};
/**
* Your RecentCounter object will be instantiated and called as such:
* var obj = new RecentCounter()
* var param_1 = obj.ping(t)
*/
3.数据结构---链表
多个元素组成的列表,元素储存不连续,用next指针连在一起。
数组 VS 链表
- 数组:增删非首尾元素时,需要移动元素
- 链接:增删非首尾元素时,不需要移动元素,只要更改next的指向即可。
const a = { val: 'a' }
const b = { val: 'b' }
const c = { val: 'c' }
const d = { val: 'd' }
a.next = b
b.next = c
c.next = d
// 遍历链表
let p = a
while (p) {
console.log(p)
p = p.next
}
// 插入
const e = { val: e }
c.next = e
e.next = d
// 删除
c.next = d
力扣题目237. 删除链表中的节点
/**
* 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.val = node.next.val
node.next = node.next.next
};
力扣题目206. 反转链表
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
// 定义两个指针:pre 和 cur;pre 在前 cur 在后
// 每次让 pre.next 指向 cur,实现一次局部反转
// 局部反转完成之后,pre 和 cur 同时往前移动一个位置
// 循环上述过程,直至 pre 到达链表尾部
/**
* @param {ListNode} head
* @return {ListNode}
*/
var reverseList = function (head) {
let cur = null;
let pre = head;
while (pre) {
const temp = pre.next
pre.next = cur // 每次让 pre.next 指向 cur,实现一次局部反转
cur = pre // cur 往前移动一个位置
pre = temp // pre 往前移动一个位置
}
return cur
};
力扣题目2. 两数相加
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} l1
* @param {ListNode} l2
* @return {ListNode}
*/
var addTwoNumbers = function (l1, l2) {
const l3 = new ListNode(0)
let p1 = l1
let p2 = l2
let p3 = l3
let carry = 0
while (p1 || p2) {
const v1 = p1 ? p1.val : 0
const v2 = p2 ? p2.val : 0
const val = v1 + v2 + carry
carry = Math.floor(val / 10)
p3.next = new ListNode(val % 10)
if (p1) p1 = p1.next
if (p2) p2 = p2.next
p3 = p3.next
}
if (carry) {
p3.next = new ListNode(carry)
}
return l3.next
};
4.数据结构---集合
一种无序且唯一的数据结构
经典应用
// 去重
const arr1 = [1, 1, 2, 2]
const arr2 = [...new Set(arr1)]
console.log(arr2) // [1, 2]
// 判断元素是否在集合中
const set1 = new Set(arr1)
console.log(set1.has(1)) // true
console.log(set1.has(3)) // false
// 求交集
const set2 = new Set([2, 3])
const set3 = new Set([...set1, 3].filter(item => set2.has(item)))
console.log(...set3) // 2 3
力扣题目349. 两个数组的交集
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function(nums1, nums2) {
return [...new Set(nums1)].filter(n => nums2.includes(n))
};
5.数据结构---字典
与集合类似,字典也是一种存储唯一值的数据结构,但是它是以键值对的形式来存储。
力扣题目349. 两个数组的交集
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var intersection = function (nums1, nums2) {
const map = new Map()
nums1.forEach((n) => {
map.set(n, true)
})
const result = []
nums2.forEach((n) => {
if (map.get(n)) {
result.push(n)
map.delete(n)
}
})
return result
};
力扣题目1. 两数之和
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function (nums, target) {
const map = new Map()
for (let i = 0; i < nums.length; i++) {
const n = nums[i]
const n2 = target - n
if (map.has(n2)) {
return [i, map.get(n2)]
} else {
map.set(n, i)
}
}
};
力扣题目 20. 有效的括号优化
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function (s) {
const sLen = s.length
if (sLen % 2 === 1) return false
const stack = []
const map = new Map()
map.set('(', ')')
map.set('{', '}')
map.set('[', ']')
for (let i = 0; i < sLen; i++) {
const c = s[i]
if (map.has(c)) {
stack.push(c)
} else {
const t = stack[stack.length - 1]
if (map.get(t) === c) {
stack.pop()
} else {
return false
}
}
}
return stack.length === 0
};
6.数据结构---树
一种分层数据的抽象模型
1.树的深度遍历
- 访问根节点。
- 再对根节点的children进行深度优先遍历。
const tree = {
value: 'a',
children: [{
value: 'b',
children: [{
value: 'd',
children: []
}, {
value: 'e',
children: []
}]
}, {
value: 'c',
children: [{
value: 'f',
children: []
}, {
value: 'g',
children: []
}]
}]
}
function dfs(node) {
console.log(node.value)
// node.children.forEach(child => { dfs(child.children) })
node.children.forEach(dfs)
}
dfs(tree)
// 输出顺序
a
b
d
e
c
f
g
2.树的广度优先遍历
- 新建一个队列,把根节点入队。
- 把队头出队并访问。
- 把队头的children挨个入队。
- 重复第二,第三步,直到队列为空。
const tree = {
value: 'a',
children: [{
value: 'b',
children: [{
value: 'd',
children: []
}, {
value: 'e',
children: []
}]
}, {
value: 'c',
children: [{
value: 'f',
children: []
}, {
value: 'g',
children: []
}]
}]
}
function bfs(root) {
const queue = [root]
while (queue.length > 0) {
const node = queue.shift()
console.log(node.value)
node.children.forEach(child => {
queue.push(child)
});
}
}
bfs(tree)
// 输出顺序
a
b
c
d
e
f
g
3.二叉树:树的每个节点,最多只能拥有两个子节点
// 待更新。。。
7.数据结构---图
图是网络结构的抽象模型,是一组由边连接的节点。 图可以表示任何二元关系,比如道路,航班等。
图的表示法之---邻接矩阵
图的表示法之---邻接表
8.数据结构---堆
- 堆是一种特殊的完全二叉树。所有的节点都大于等于或小于等于它的子节点。
- 最大堆:所有的节点都大于等于它的子节点。
- 最小堆:所有的节点都小于等于它的子节点。