栈 (先进后出)
实现栈的基础功能
- push
- pop
- top
- size
- clear
class Stack {
constructor() {
this.data = [];
this.count = 0;
}
push(value) {
this.data[this.count++] = value;
return 'success';
}
pop() {
if (this.count <= 0) return 'no data';
let temp = this.data[this.count - 1];
delete this.data[--this.count];
return temp;
}
top() {
if (this.count <= 0) return 'no data';
return this.data[this.count - 1];
}
size() {
return this.count;
}
clear(){
this.data = [];
this.length = 0;
}
}
const s = new Stack();
栈的应用
力扣题目 最小栈
题目描述:
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/min-stack
实现思路:采用两个栈,一个用于存储所有数据,一个用于存储最小数据的内容
class MinStack {
constructor() {
// 用于存储所有数据
this.stackA = [];
this.countA = 0;
// 用于记录最小数据
this.stackB = [];
this.countB = 0;
}
push(val) {
this.stackA[this.countA++] = val;
if (this.countB === 0 || this.stackB[this.countB - 1] >= val) {
this.stackB[this.countB++] = val;
}
}
pop() {
if (this.countA <= 0) return -1;
if (this.stackB[this.countB - 1] === this.stackA[this.countA - 1]) {
delete this.stackB[--this.countB];
}
const temp = this.stackA[this.countA - 1];
delete this.stackA[--this.countA];
return temp;
}
top() {
if (this.countA <= 0) return -1;
return this.stackA[this.countA - 1];
}
getMin() {
if (this.countB <= 0) return -1;
return this.stackB[this.countB - 1];
}
}
队列 (先进先出)
队列基础功能
- enQueue
- deQueue
- top
- size
- clear
'use strict';
class Queue{
constructor(){
this.queue = {};
this.count = 0; // 数量
this.head = 0; // 头部位置
}
enQueue(val){
this.queue[this.count++] = val;
}
deQueue(){
if(this.count-this.head<=0)return 'no data';
const temp = this.queue[this.head];
delete this.queue[this.head++];
this.count--;
return temp
}
top(){
if(this.count-this.head<=0)return 'no data';
return this.queue[this.head];
}
size(){
return this.count-this.head;
}
clear(){
this.head = 0;
this.count = 0;
this.queue = {};
}
}
队列的应用
题目描述:
请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/dui-lie-de-zui-da-zhi-lcof
实现:
class MaxQueue {
constructor() {
this.queue = {};
this.doubleQueue = {};
this.headQ = this.countQ = this.headD = this.countD = 0;
}
push_back(val) {
this.queue[this.countQ++] = val;
while (this.countD - this.headD > 0 && this.doubleQueue[this.countD - 1] < val) {
delete this.doubleQueue[--this.countD];
}
this.doubleQueue[this.countD++] = val;
}
pop_front() {
if (this.countD - this.headD <= 0) return -1;
const temp = this.queue[this.headQ];
delete this.queue[this.headQ++];
if(temp === this.doubleQueue[this.headD]){
delete this.doubleQueue[this.headD++];
}
return temp;
}
max_value(){
if (this.countD - this.headD <= 0) return -1;
return this.doubleQueue[this.headD];
}
}
题目描述:
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sliding-window-maximum
程序:
'use strict';
// 请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的均摊时间复杂度都是O(1)。
// 若队列为空,pop_front 和 max_value 需要返回 -1
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
// https://leetcode-cn.com/problems/sliding-window-maximum/
var maxSlidingWindow = function (nums, k) {
if (k <= 1) return nums;
const queue = {};
let count = 0;
let head = 0;
const result = [];
for (let i = 0; i < k; i++) {
if(count - head === 0)queue[count++] = nums[i];
else{
while(count - head !== 0 && queue[count-1]<nums[i]){
delete queue[--count];
}
queue[count++] = nums[i];
}
}
result.push(queue[head]);
for(let j=k;j<nums.length;j++){
// 出队
if(queue[head] === nums[j-k]){
delete queue[head++];
}
// 入队
while(count - head !== 0 && queue[count-1]<nums[j]){
delete queue[--count];
}
queue[count++] = nums[j];
result.push(queue[head]);
}
return result;
};
链表
基础功能
- addAtTail
- addAtHead
- get (根据索引获取数据)
- addIndex
- reverseList (迭代法)
- reverseList_head (头插法)
- reverseList_d (递归)
'use strict';
// 链表的概念 : 链表是有序的数据结构
// 数组在内存中占用一段连续的内存
// 数组添加、移除会导致后续元素位移和性能开销大
// 链表和数组的区别
// 场景:获取、修改元素时,数组效率高。
// 添加、删除元素时,链表效率高
// 链表的实现方式
class LinkedNode {
constructor(value) {
this.value = value;
this.next = null;
}
}
class LinkedList {
constructor() {
this.head = null;
this.count = 0;
}
addAtTail(value) {
const node = new LinkedNode(value);
if (this.count === 0) {
this.head = node;
} else {
let cur = this.head;
while (cur.next !== null) {
cur = cur.next;
}
cur.next = node;
}
this.count++;
}
addAtHead(value) {
const node = new LinkedNode(value);
if (this.count === 0) {
this.head = node;
} else {
node.next = this.head;
this.head = node;
}
this.count++;
}
get(index) {
if (this.count === 0 || index < 0 || index >= this.count) return;
let cur = this.head;
for (let i = 0; i < index; i++) {
cur = cur.next;
}
return cur.value;
}
// 根据索引添加节点
addIndex(value, index = 0) {
if (index > this.count) return '超出索引';
index = index < 1 ? 0 : index;
const node = new LinkedNode(value);
if (index === 0) {
node.next = this.head;
this.head = node;
} else {
let cur = this.head;
for (let i = 0; i < index - 1; i++) {
cur = cur.next;
}
let pre = cur;
node.next = cur.next;
pre.next = node;
}
this.count++;
}
// 迭代法
reverseList() {
// 申明变量记录 pre next
let pre = null;
let cur = this.head;
while (cur) {
const next = cur.next;// 保存当前节点的下一个节点
cur.next = pre;
pre = cur;
cur = next;
}
this.head = pre;
}
// 头插法
reverseList_head() {
if (!this.head || !this.head.next) return;
let cur = this.head;
let back = null;
while (cur) {
let temp = cur;
cur = cur.next;
temp.next = back;
back = temp;
}
this.head = back;
}
// 递归操作
reverseList_d(head){
if(head === null && head.next === null) return head;
const newHead = reverseList_d(head.next);
// 5->4->3->2->1->null
// 第一次执行的节点是 倒数第二个数据 此时 newHead = 1 head = 2
head.next.next = head;
head.next = null;
return newHead;
}
print() {
let h = this.head;
while (h) {
console.log(h.value);
h = h.next;
}
}
}
const l = new LinkedList();
l.addAtTail(1);
l.addAtTail(2);
l.addAtTail(3);
// l.print();
l.reverseList();
l.print();
l.reverseList_head();
l.print()
二叉树
题目:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
- 二叉树的前序遍历(递归)
var preorderTraversal = function (root) {
const arr = [];
const r = root => {
if (!root) return;
arr.push(root.val);
r(root.left);
r(root.right);
}
r(root);
return arr;
};
- 二叉树的前序遍历的迭代法
var preorderTraversal = function (root) {
const arr = [];
const stack = [];
while (root || stack.length>0) {
while (root) {
arr.push(root.val);
stack.push(root.right);
root = root.left;
}
root = stack.pop();
}
return arr;
};