数据结构-栈队列篇

275 阅读1分钟

栈数据结构

栈的定义

数据结构中的栈是一种特殊的线性表, 遵循后进先出原则(LIFO: Last In First Out), 只能在数据的一端进行入栈(push)和出栈(pop)的操作, 该端称为栈顶。栈顶用远是最新的元素。

栈的实现

栈常用方法如下:

push 添加一个(或几个)新元素到栈顶
pop 溢出栈顶元素,同时返回被移除的元素
peek 返回栈顶元素,不对栈做修改
isEmpty 栈内无元素返回true,否则返回false
size 返回栈内元素个数
clear 清空栈

// @ts-check

export default class Stack {
  constructor() {
    this.count = 0;
    this.items = {};
  }
  push(element) {
    this.items[this.count] = element;
    this.count++;
  }
  pop() {
    if (this.isEmpty()) {
      return undefined;
    }
    this.count--;
    const result = this.items[this.count];
    delete this.items[this.count];
    return result;
  }
  peek() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.items[this.count - 1];
  }
  isEmpty() {
    return this.count === 0;
  }
  size() {
    return this.count;
  }
  clear() {
    /* while (!this.isEmpty()) {
    this.pop();
    } */
    this.items = {};
    this.count = 0;
  }
  toString() {
    if (this.isEmpty()) {
      return '';
    }
    let objString = `${this.items[0]}`;
    for (let i = 1; i < this.count; i++) {
      objString = `${objString},${this.items[i]}`;
    }
    return objString;
  }
}

栈的应用

有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串,判断字符串是否有效。

输入: "()"
输出: true

输入: "()[]{}"
输出: true

输入: "(]"
输出: false

来源: leetcode-cn.com/problems/va…

var isValid = function(s) {
    let stack = [];
    for (let i = 0; i < s.length; i++) {
        let ch = s[i];
        if(ch == '(' || ch == '{' || ch == '[' ) {
            stack.push(ch)
        }
        if(!stack.length) return false;
        if(ch === ')' && stack.pop() !== '(') return false;
        if(ch === '}' && stack.pop() !== '{') return false;
        if(ch === ']' && stack.pop() !== '[') return false;
    }
    return stack.length === 0;
};

删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。 在 S 上反复执行重复项删除操作,直到无法继续删除。 在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。  

输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除
操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最
后的字符串为 "ca"。

输入:"abbbaca"
输出:"abaca"

来源: leetcode-cn.com/problems/re…

var removeDuplicates = function(S) {
    let stack = [];
    for (let c of S) {
        let prev = stack.pop();
        if(c !== prev) {
            stack.push(prev);
            stack.push(c)
        }
    }
    return stack.join('');
};

删除字符串中的所有相邻重复项 II

给你一个字符串 s,「k 倍重复项删除操作」将会从 s 中选择 k 个相邻且相等的字母,并删除它们,使被删去的字符串的左侧和右侧连在一起。 你需要对 s 重复进行无限次这样的删除操作,直到无法继续为止。 在执行完所有删除操作后,返回最终得到的字符串。 本题答案保证唯一。

输入:s = "deeedbbcccbdaa", k = 3
输出:"aa"
解释: 
先删除 "eee""ccc",得到 "ddbbbdaa"
再删除 "bbb",得到 "dddaa"
最后删除 "ddd",得到 "aa"

输入:s = "pbbcggttciiippooaais", k = 2
输出:"ps"

来源: leetcode-cn.com/problems/re…

var removeDuplicates = function(s, k) {
    let stack = [];
    for (let c of s) {
        let prev = stack.pop();
        if(!prev || c !== prev[0]) {
            stack.push(prev);
            stack.push(c)
        } else if(prev.length < k - 1) {
            stack.push(prev + c)
        }
    }
    return stack.join('');
};

删除字符串中出现次数大于等于k次的相邻字符

输入:s = "abbbaca", k = 2
输出:"ca"

var removeDuplicates = function(s, k) {
    let stack = [];
    for (let i = 0; i < s.length; i++) {
        let prev = stack.pop();
        if(!prev || prev[0] != s[i]) {
            stack.push(prev);
            stack.push(s[i]);
        } else if(prev.length < k - 1 || prev[0] === s[i + 1]) {
            stack.push(prev + s[i])
        }
    }
    return stack.join('');
} 

下一个更大元素 II

给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。

输入: [1,2,1]
输出: [2,-1,2]
解释: 第一个 1 的下一个更大的数是 2;
数字 2 找不到下一个更大的数; 
第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

来源: leetcode-cn.com/problems/ne…

// 1.将数组中所有元素全部置为-1
// 2.遍历两次,相当于循环遍历
// 3.第一遍遍历,入栈索引i
// 4.只要后面元素比栈顶索引对应的元素大,索引出栈,更改res[sta.pop()]的数值
// 5.最后栈里面剩余的索引对应的数组值,都为默认的-1(因为后面未找到比它大的值)
var nextGreaterElements = function(nums) {
    let n = nums.length;
    let res = new Array(n).fill(-1);
    let stack = [];
    for (let i = 0; i < n*2; i++) {
        let num = nums[i%n];
        while(stack.length !== 0 && num > nums[stack[stack.length - 1]]) {
            res[stack.pop()] = num;
        }
        if(i < n) {
            stack.push(i)
        }
    }
    return res;
};

字符串解码

给定一个经过编码的字符串,返回它解码后的字符串。 编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。  

输入:s = "3[a]2[bc]"
输出:"aaabcbc"

输入:s = "3[a2[c]]"
输出:"accaccacc"

输入:s = "abc3[cd]xyz"
输出:"abccdcdcdxyz"

来源: leetcode-cn.com/problems/de…

var decodeString = function(s) {
    let stack_num = [], stack_char = [], res = '', num_str = '';
    for (let item of s) {
        if(item >= '0' && item <= '9') {
            num_str += item;
        } else if(item === '[') {
            stack_char.push(res);
            stack_num.push(num_str);
            res = '';
            num_str = '';
        } else if(item === ']') {
            let count = Number(stack_num.pop());
            res = stack_char.pop() + res.repeat(count)
        } else {
            res += item;
        }
    }
    return res;
};

删除最外层的括号

输入:"(()())(())"
输出:"()()()"
解释:
输入字符串为 "(()())(())",原语化分解得到 "(()())" + "(())",
删除每个部分中的最外层括号后得到 "()()" + "()" = "()()()"。

输入:"(()())(())(()(()))"
输出:"()()()()(())"
解释:
输入字符串为 "(()())(())(()(()))",原语化分解得到 "(()())" + "(())" + "(()(()))",
删除每个部分中的最外层括号后得到 "()()" + "()" + "()(())" = "()()()()(())"。

输入:"()()"
输出:""
解释:
输入字符串为 "()()",原语化分解得到 "()" + "()",
删除每个部分中的最外层括号后得到 "" + "" = ""。

来源: leetcode-cn.com/problems/re…

var removeOuterParentheses = function(S) {
    let res = '', stack = [];
    for (let i = 0; i < S.length; i++) {
        if(S[i] === ')') {
            stack.pop();
        }
        if(stack.length > 0) {
            res += S[i]
        }
        if(S[i] === '(') {
            stack.push(S[i])
        }
    }
    return res;
};

移掉K位数字

给定一个以字符串表示的非负整数num,移除这个数中的k位数字,使得剩下的数字最小。

输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。输入: num = "10200", k = 1
输出: "200"
解释: 移掉首位的 1 剩下的数字为 200\. 注意输出不能有任何前导零。输入: num = "10", k = 2
输出: "0"
解释: 从原数字移除所有的数字,剩余为空就是0。

来源: leetcode-cn.com/problems/re…

var removeKdigits = function(num, k) {
    let stack = [];
    for (let i = 0; i < num.length; i++) {
        let tmp = num[i];
        while(stack.length > 0 && k > 0 && tmp < stack[stack.length - 1]) {
            stack.pop();
            k--;
        }
        stack.push(tmp);
    }
    while(k > 0) {
        stack.pop();
        k--;
    }
    while(stack.length > 0 && stack[0] === '0') {
        stack.shift()
    }
    return stack.length > 0 ? stack.join('') : '0';
};

比较含退格的字符串

给定 ST 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果。 # 代表退格字符。

输入:S = "ab#c", T = "ad#c"
输出:true
解释:S 和 T 都会变成 “ac”。

输入:S = "ab##", T = "c#d#"
输出:true
解释:S 和 T 都会变成 “”。

输入:S = "a#c", T = "b"
输出:false
解释:S 会变成 “c”,但 T 仍然是 “b”。

来源: leetcode-cn.com/problems/ba…

var backspaceCompare = function(S, T) {
    let stackS = [], stackT = [];
    for (let i = 0 ; i < S.length; i++) {
        if(S[i] === '#') {
            stackS.pop();
        } else {
            stackS.push(S[i]);
        }
    }
    for (let j = 0 ; j < T.length; j++) {
        if(T[j] === '#') {
            stackT.pop();
        } else {
            stackT.push(T[j]);
        }
    }
    return stackS.join('') === stackT.join('');
};

棒球比赛

你现在是棒球比赛记录员。 给定一个字符串列表,每个字符串可以是以下四种类型之一: 

  • 1.整数(一轮的得分):直接表示您在本轮中获得的积分数。 
  • 2. "+"(一轮的得分):表示本轮获得的得分是前两轮有效 回合得分的总和。
  • 3. "D"(一轮的得分):表示本轮获得的得分是前一轮有效 回合得分的两倍。 
  • 4. "C"(一个操作,这不是一个回合的分数):表示您获得的最后一个有效 回合的分数是无效的,应该被移除。 

每一轮的操作都是永久性的,可能会对前一轮和后一轮产生影响。 你需要返回你在所有回合中得分的总和。  

输入: ["5","2","C","D","+"]
输出: 30
解释: 
第1轮:你可以得到5分。总和是:5。
第2轮:你可以得到2分。总和是:7。
操作1:第2轮的数据无效。总和是:5。
第3轮:你可以得到10分(第2轮的数据已被删除)。总数是:15。
第4轮:你可以得到5 + 10 = 15分。总数是:30。

输入: ["5","-2","4","C","D","9","+","+"]
输出: 27
解释: 
第1轮:你可以得到5分。总和是:5。
第2轮:你可以得到-2分。总数是:3。
第3轮:你可以得到4分。总和是:7。
操作1:第3轮的数据无效。总数是:3。
第4轮:你可以得到-4分(第三轮的数据已被删除)。总和是:-1。
第5轮:你可以得到9分。总数是:8。
第6轮:你可以得到-4 + 9 = 5分。总数是13。
第7轮:你可以得到9 + 5 = 14分。总数是27

来源: leetcode-cn.com/problems/ba…

var calPoints = function(ops) {
    let stack = [], sum = 0;
    for (let i = 0; i < ops.length; i++) {
        let tmp, item = ops[i];
        if(item === '+') {
           tmp = stack[stack.length - 1] + stack[stack.length - 2];
           stack.push(tmp);
           sum += tmp; 
        } else if(item === 'D') {
            tmp = stack[stack.length - 1] * 2;
            stack.push(tmp);
            sum += tmp;
        } else if(item === 'C') {
            sum -= stack.pop();
        } else {
            stack.push(Number(item));
            sum += Number(item);
        }
    }
    return sum;
};

简化路径

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。

来源: leetcode-cn.com/problems/si…

//将path以'/'分割成数组,如 /a/./b/../../c/分割成[ '', 'a', '.', 'b', '..', '..', 'c', '' ]。 
//新建一个栈stack为当前的路径,遍历path分割后的数组元素:
//遇到正常的字母时,推入 stack 中
//遇到 .. 时,stack 弹出最近一个路径
//遇到 . 或者为空时,不修改当前 stack。
//最后返回 '/' + stack.join('/') 为新的路径
var simplifyPath = function(path) {
    let stack = [], arr = path.split('/');
    for (let i = 0; i < arr.length; i++) {
        if(arr[i] === '.' || arr[i] === '') {
            continue;
        } else if(arr[i] === '..') {
            stack.pop();
        } else {
            stack.push(arr[i])
        }
    } 
    return '/' + stack.join('/');   
};

去除重复字母

给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。

输入:s = "bcabc"
输出:"abc"

来源: leetcode-cn.com/problems/re…

var removeDuplicateLetters = function(s) {
    let stack = [];
    for (let i = 0; i < s.length; i++) {
        if(stack.indexOf(s[i]) > -1) continue;
        while(stack.length > 0 && stack[stack.length - 1] > s[i] && s.indexOf(stack[stack.length - 1], i) > i) {
            stack.pop()
        }
        stack.push(s[i])
    }
    return stack.join('');
};

逆波兰表达式求值

根据 逆波兰表示法,求表达式的值。有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

输入: ["2", "1", "+", "3", "*"]
输出: 9
解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9

来源: leetcode-cn.com/problems/ev…

var evalRPN = function(tokens) {
    const stack = [];
    for (let index = 0; index < tokens.length; index++) {
        const token = tokens[index];
        if(!Number.isNaN(Number(token))) {
            stack.push(token);
        } else {
            const a = Number(stack.pop());
            const b = Number(stack.pop());
            if(token === '*') {
                stack.push(b * a);
            } else if(token === '/') {
                stack.push(b / a >> 0);
            } else if(token === '+') {
                stack.push(b + a);
            } else if(token === '-') {
                stack.push(b -a);
            }
        }
    }
    return stack.pop();
};

栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。  

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

来源: leetcode-cn.com/problems/zh…

var validateStackSequences = function(pushed, popped) {
    let stack = [];
    let j = 0;
    for (let i = 0; i < pushed.length; i++) {
        stack.push(pushed[i]);
        while(stack.length !== 0 && stack[stack.length - 1] === popped[j]) {
            stack.pop();
            j++;
        }
    }
    return stack.length === 0;
};

检查替换后的词是否有效

输入:"aabcbc"
输出:true
解释:
从有效字符串 "abc" 开始。
然后我们可以在 "a""bc" 之间插入另一个 "abc",产生 "a" + "abc" + "bc",即 "aabcbc"

来源: leetcode-cn.com/problems/ch…

// 当遇到字符a时,直接入栈
// 当遇到字符b时,检查栈顶是否为字符a ,如果是将b入栈,如果不是返回false;
// 当遇到字符c时,检查栈顶是否为字符b,如果是将c入栈,(再将栈顶的cba弹出)如果不是返回false
// 最后判断栈是否为空即可
var isValid = function(S) {
    let stack = [];
    for (let item of S) {
        if(item === 'b' && (stack.length === 0 || stack[stack.length - 1] !== 'a')) {
            return false;
        }
        if(item === 'c' && (stack.length === 0 || stack[stack.length - 1] !== 'b')) {
            return false;
        }
        stack.push(item);
        if(item === 'c') {
            stack.pop();
            stack.pop();
            stack.pop()
        }
    }
    return stack.length === 0;
};

每日温度

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。 例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

来源: leetcode-cn.com/problems/da…

var dailyTemperatures = function(T) {
    let res = new Array(T.length).fill(0);
    let stack = [];
    for (let i = 0; i < T.length; i++) {
        while(stack.length > 0 && T[i] > T[stack[stack.length - 1]]) {
            let idx = stack.pop();
            res[idx] = i - idx;
        }
        stack.push(i)
    }
    return res;
};

柱状图中最大的矩形

给定n个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。

输入: [2,1,5,6,2,3]
输出: 10

来源: leetcode-cn.com/problems/la…

var largestRectangleArea = function(heights) {
    let stack = [], maxArea = 0;
    heights = [0, ...heights, 0];
    for (let i = 0; i < heights.length; i++) {
        while(heights[i] < heights[stack[stack.length - 1]]) {
            let topStackIdx = stack.pop();
            maxArea = Math.max(
                maxArea,
                heights[topStackIdx] * (i - stack[stack.length - 1] - 1)
            )
        }
        stack.push(i)
    }
    return maxArea;
};

最大矩形

给定一个仅包含 0 和 1 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。

输入:
[  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
输出: 6

来源: leetcode-cn.com/problems/ma…

var maximalRectangle = function(matrix) {
    if(!matrix.length || !matrix[0].length) return 0;
    let m = matrix.length, n = matrix[0].length, ans = 0;
    let heghts = new Array(n + 2).fill(0);
    for (let i = 0; i < m; i++) {
        for (let j = 0; j < n; j++) {
            if(matrix[i][j] === '1') heghts[j + 1]++;
            else heghts[j + 1] = 0;
        }
        let stack = [], max = 0;
        for (let j = 0; j < heghts.length; j++) {
            while(stack.length && heghts[j] < heghts[stack[stack.length - 1]]) {
                let top = stack.pop();
                max = Math.max(
                    max,
                    heghts[top] * (j - stack[stack.length - 1] - 1)
                );
            }
            stack.push(j)
        }
        ans = Math.max(ans, max);
    }
    return ans;
};

链表中的下一个更大节点

输入:[2,1,5]
输出:[5,5,0]

来源: leetcode-cn.com/problems/ne…

var nextLargerNodes = function(head) {
    let arr = [], valArr = [], stack = [];
    let i = 0, value;
    while(head) {
        value = head.val;
        valArr[i] = value;
        while(stack.length > 0 && value > valArr[stack[stack.length - 1]]) {
            arr[stack.pop()] = value;
        }
        stack.push(i);
        i++;
        head = head.next;
    }
    let res = new Array(i).fill(0);
    for (let j = 0; j < i; j++) {
        if(arr[j]) {
            res[j] = arr[j]
        }
    }
    return res;
};

不同字符的最小子序列

返回字符串 text 中按字典序排列最小的子序列,该子序列包含 text 中所有不同字符一次。

输入:"cdadabcc"
输出:"adbc"输入:"abcd"
输出:"abcd"

来源: leetcode-cn.com/problems/sm…

var smallestSubsequence = function(text) {
    let len = text.length;
    let stack = [];
    for (let i = 0; i < len; i++) {
        let char = text.charAt(i);
        if(stack.indexOf(char) != -1) {
            continue
        }
        while(stack.length > 0 && char < stack[stack.length - 1] && text.indexOf(stack[stack.length - 1], i) != -1) {
            stack.pop()
        }
        stack.push(char)
    }
    let res = "";
    for (let item of stack) {
        res += item
    }
    return res;
};

队列数据结构

定义

队列是遵循先进先出(FIFO, First In First Out)原则的一组有序的项。队列在尾部添加新元素,并从顶部移除元素。最新添加的元素必须排在队列的末尾.

队列的实现

队列常用方法:

enqueue 向队列尾部添加一个(或多个)新的项
dequeue 移除队列的第一(即排在队列最前面的)项,并返回被移除的元素
head 返回队列第一个元素,队列不做任何变动
tail 返回队列最后一个元素,队列不做任何变动
isEmpty 队列内无元素返回true,否则返回false
size 返回队列内元素个数
clear 清空队列

export default class Queue {
  constructor() {
    this.count = 0;
    this.lowestCount = 0;
    this.items = {};
  }
  enqueue(element) {
    this.items[this.count] = element;
    this.count++;
  }
  dequeue() {
    if (this.isEmpty()) {
      return undefined;
    }
    const result = this.items[this.lowestCount];
    delete this.items[this.lowestCount];
    this.lowestCount++;
    return result;
  }
  peek() {
    if (this.isEmpty()) {
      return undefined;
    }
    return this.items[this.lowestCount];
  }
  isEmpty() {
    return this.size() === 0;
  }
  clear() {
    this.items = {};
    this.count = 0;
    this.lowestCount = 0;
  }
  size() {
    return this.count - this.lowestCount;
  }
  toString() {
    if (this.isEmpty()) {
      return '';
    }
    let objString = `${this.items[this.lowestCount]}`;
    for (let i = this.lowestCount + 1; i < this.count; i++) {
      objString = `${objString},${this.items[i]}`;
    }
    return objString;
  }
}

DFS和BFS与栈和队列的关系

DFS采用递归的形式, 用到了栈结构, 先进先出。BFS选取状态用队列的形式, 先进先出。

队列的应用

根据身高重建队列

假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。 编写一个算法来重建这个队列。  

输入:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]

输出:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]

来源: leetcode-cn.com/problems/qu…

var reconstructQueue = function(people) {
    let ans = [];
    people.sort((a,b) => {
        return a[0] === b[0] ? a[1] - b[1] :  b[0] - a[0];
    });
    for(let i = 0 ; i < people.length; i++) {
        ans.splice(people[i][1],0,people[i]);
    }
    return ans;
};

最近的请求次数

写一个 RecentCounter 类来计算特定时间范围内最近的请求。 请你实现 RecentCounter 类: RecentCounter() 初始化计数器,请求数为 0 。 int ping(int t) 在时间 t 添加一个新请求,其中 t 表示以毫秒为单位的某个时间,并返回过去 3000 毫秒内发生的所有请求数(包括新请求)。确切地说,返回在 [t-3000, t] 内发生的请求数。 保证每次对 ping 的调用都使用比之前更大的 t 值。  

输入:
["RecentCounter", "ping", "ping", "ping", "ping"]
[[], [1], [100], [3001], [3002]]
输出:
[null, 1, 2, 3, 3]

来源: leetcode-cn.com/problems/nu…

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)
 */

栈和队列的实现

用栈实现队列

使用栈实现队列的下列操作
push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。   

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);  
queue.peek();  // 返回 1
queue.pop();   // 返回 1
queue.empty(); // 返回 false

来源: leetcode-cn.com/problems/im…

/**
 * Initialize your data structure here.
 */
var MyQueue = function() {
    this.stack1 = [];
    this.stack2 = [];
};

/**
 * Push element x to the back of queue. 
 * @param {number} x
 * @return {void}
 */
MyQueue.prototype.push = function(x) {
    this.stack1.push(x);
};

/**
 * Removes the element from in front of queue and returns that element.
 * @return {number}
 */
MyQueue.prototype.pop = function() {
    if(this.stack2.length) {
        return this.stack2.pop();
    } else {
        if(this.stack1.length) {
            let len = this.stack1.length;
            for (let i = 0; i < len; i++) {
                this.stack2.push(this.stack1.pop())
            }
            return this.stack2.pop()
        } else {
            return null;
        }
    }
};

/**
 * Get the front element.
 * @return {number}
 */
MyQueue.prototype.peek = function() {
    if(this.stack1.length === 0) {
        return this.stack2[this.stack2.length - 1]
    } else if(this.stack2.length === 0) {
        return this.stack1[0]
    }
};

/**
 * Returns whether the queue is empty.
 * @return {boolean}
 */
MyQueue.prototype.empty = function() {
    if(this.stack1.length === 0 && this.stack2.length === 0) {
        return true;
    } else {
        return false;
    }
};

用队列实现栈

使用队列实现栈的下列操作:
push(x) -- 元素 x 入栈
pop() -- 移除栈顶元素
top() -- 获取栈顶元素
empty() -- 返回栈是否为空 

来源: leetcode-cn.com/problems/im…

/**
 * Initialize your data structure here.
 */
var MyStack = function() {
    this.stack = [];
};

/**
 * Push element x onto stack. 
 * @param {number} x
 * @return {void}
 */
MyStack.prototype.push = function(x) {
    this.stack[this.stack.length] = x;
    return this.stack.length;
};

/**
 * Removes the element on top of the stack and returns that element.
 * @return {number}
 */
MyStack.prototype.pop = function() {
    if(this.empty()) return undefined;
    let value = this.stack[this.stack.length - 1];
    this.stack.length -= 1;
    return value;
};

/**
 * Get the top element.
 * @return {number}
 */
MyStack.prototype.top = function() {
    return this.stack[this.stack.length -1];
};

/**
 * Returns whether the stack is empty.
 * @return {boolean}
 */
MyStack.prototype.empty = function() {
    if(this.stack.length === 0) {
        return true;
    } else {
        return false;
    }
};

最小栈

设计一个支持 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

来源: leetcode-cn.com/problems/mi…

/**
 * initialize your data structure here.
 */
var MinStack = function() {
    this.stack = [];
    this.min_stack = [];
};

/** 
 * @param {number} x
 * @return {void}
 */
MinStack.prototype.push = function(x) {
    this.stack.push(x);
    if(this.min_stack.length === 0 || this.min_stack[this.min_stack.length - 1] >= x) {
        this.min_stack.push(x)
    }
};

/**
 * @return {void}
 */
MinStack.prototype.pop = function() {
    if(this.stack.pop() === this.min_stack[this.min_stack.length - 1]) {
        this.min_stack.pop();
    }
};

/**
 * @return {number}
 */
MinStack.prototype.top = function() {
    return this.stack[this.stack.length - 1]
};

/**
 * @return {number}
 */
MinStack.prototype.getMin = function() {
    return this.min_stack[this.min_stack.length - 1]
};

用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )  。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

输入:
["CQueue","appendTail","deleteHead","deleteHead"]
[[],[3],[],[]]
输出:[null,null,3,-1]

来源: leetcode-cn.com/problems/yo…

var CQueue = function() {
    this.inStack = [];
    this.outStack = [];
};

/** 
 * @param {number} value
 * @return {void}
 */
CQueue.prototype.appendTail = function(value) {
    this.inStack.push(value)
};

/**
 * @return {number}
 */
CQueue.prototype.deleteHead = function() {
    let { inStack, outStack } = this;
    if(outStack.length) {
        return outStack.pop();
    } else {
        while(inStack.length) {
            outStack.push(inStack.pop())
        }
        return outStack.pop() || -1;
    }
};