javascript中的栈

1.什么是栈?

栈
栈是一种后进先出,或者说先进后出的结构。
JavaScript中没有栈,但是可以用数组实现栈的所有功能。

2.常用方法

  • push:压入新元素
  • pop:弹出顶部元素,返回弹出的值
  • length:返回栈的长度

3.使用示例

//1.创建一个栈
const stack = [];    //stack为空
//2.往栈内压入元素
stack.push(1);      //stack = [1]
stack.push(2);      //stack = [1,2]
//3.弹出栈顶元素,获取返回值
const item1 = stack.pop();      //stack = [1],item1 = 2
const item2 = stack.pop();      // stack = [],item2 = 1
//4.获取栈顶元素值的
stack.push(666);         //stack = [666]
const top = stack[stack.length - 1];    //数组长度减一就是栈顶下标

4.LeetCode

接下来使用栈这个数组结构来刷LeetCode有关栈的题目,巩固提升对栈的了解。

题号20.有效的括号(简单)

题目要求:在这里插入图片描述解题思路:

  1. 构建栈,遍历字符串s
  2. 遇到左括号就压入栈中,遇到右括号则判断栈顶左括号是否与右括号相匹配,匹配就把栈顶左括号弹出栈,继续遍历字符串s,不匹配则可以直接返回false
  3. 遍历结束后,如果栈内没有剩余左括号,返回true

注意:有效字符串的长度一定为偶数,对于长度为奇数的字符串可以直接返回false
编写代码

var isValid = function(s) { 
    const stack = [];
    if(s.length % 2 == 1) {  
        return false;
    }
    for(let i = 0; i < s.length; i+=1) {  
        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;
}

复杂度分析

  1. 时间复杂度: O(n),其中n是字符串s的长度 (因为只有一个for循环)
  2. 空间复杂度: O(n),栈的长度 (最坏的情况都是左括号)

题号316.去除重复字母(中等)

题目要求:
在这里插入图片描述
解题思路:

  1. 首先要明白什么叫做字典序:
    字典序就是把两个字符串逐个字母比较,比如,abc, adc两个字符串 ,首先a === a,两个字符串第一个字母相同,比较第二个字母, b < d,所以,字符串abc < adc ,以此类推。

  2. 明白了字典序之后,就可以开始做题了,题目要求所有出现的字母都得出现一次,且字典序最小,那我们可以来构造一个单调栈

  3. 每次遍历新的元素,就判断栈中是否已经有该元素了,因为我们是单调栈,如果栈中已经有这个元素了,就丢弃掉,继续遍历。比如4564,丢弃掉后面的4,而不是丢掉前面的4,才能让我们的字典序最小.

  4. 关键点来了:如果栈非空,当前遍历到的元素s[i]栈中还没有,并且s[i]比栈顶stack[stack.length - 1]小。正常来说我们是要把栈顶stack[stack.length - 1]弹出后压入s[i],不过因为我们要让所有不同字母都至少出现一次,所以要确保s[i]之后还有stack[stack.length - 1]对应的元素,如果s[i]后面该元素了,那只能委屈求全,直接压入s[i]了。

编写代码

var removeDuplicateLetters = function(s) {
    const stack = [];//定义一个单调栈
    let i = -1;
    while(++i < s.length) { //遍历字符串
        if(stack.includes(s[i])) continue; //舍弃当前的,继续遍历,保持字典序最小
        //栈非空,栈顶大于s[i],s[i]后面还有栈顶元素才能弹出栈。
        while(stack.length && stack[stack.length -1] > s[i] && s.includes(stack[stack.length - 1], i)) {
          stack.pop();  
        }
        stack.push(s[i]);  //排除上方因素有就可以直接加入栈中了
    }
    return stack.join('');//将栈改造为字符串
};

复杂度分析

  1. 时间复杂度: O(n)
  2. 空间复杂度: O(n)

题号224.基本计算器(困难)

题目要求:
在这里插入图片描述

在这里插入图片描述此题重点在于创建一个栈来维护左括号前的符号,括号内出现正号则sign与左括号前符号相同,出现负号则sign与左括号前符号相反,这样便可以将字符串正常累加。

编写代码

var calculate = function(s) {
    //栈记录了各个括号内元素共同的符号,比如-(1+2),括号看成一个整体,这个整体前是负号
    const ops = [1];
    //
    let sign = 1;
    let ret = 0;
    const n = s.length;
    let i = 0;
    while (i < n) {
        if (s[i] === ' ') {
            i++;
        } else if (s[i] === '+') {
            sign = ops[ops.length - 1];
            i++;
        } else if (s[i] === '-') {
            //每遇到一次减号就让标记取反,可以有效解决负负得正问题
            sign = -ops[ops.length - 1];
            i++;
        } else if (s[i] === '(') {
            //保留左括号此时的sign标志到栈中,遇到右括号再除去
            ops.push(sign);
            i++;
        } else if (s[i] === ')') {
            ops.pop();
            i++;
        } else {
            //如果出现123 + 1 类似这样连续数字的情况,就需要num这个中间数字来维护了
            let num = 0;
            //当i没有超过字符串长度范围,并且s[i]是一个数字
            while (i < n && !(isNaN(Number(s[i]))) && s[i] !== ' ') {
                num = num * 10 + s[i].charCodeAt() - '0'.charCodeAt();
                i++;
            }
            //累加要返回的值
            ret += sign * num;
        }
    }
    return ret;
};

复杂度分析

  • 时间复杂度:O(n),其中 n 为字符串 s的长度
  • 空间复杂度:O(n),空间复杂度主要取决于栈的空间,栈中的元素数量不超过 n。
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript和堆是用来存储变量和数据的两种不同的内存区域。 是一种后进先出(LIFO)的数据结构,用于存储基本类型的变量和引用类型的指针。当我们声明一个变量时,它的值会被直接存储在内存。基本类型的值(如数字、布尔值、字符串等)被直接存储在,而引用类型的变量则存储了指向堆内存实际数据的指针。 堆是一种动态分配的内存区域,用于存储引用类型的数据。当我们创建一个引用类型的变量时,它的值实际上是一个指向堆内存对象的引用。对象本身的数据存储在堆内存,而的变量只是存储了指向堆内存对象的引用。 深拷贝是指创建一个新的对象,将原始对象的所有属性和嵌套对象的属性都复制到新对象。这样,新对象和原始对象是完全独立的,对新对象的修改不会影响原始对象。在JavaScript,可以使用不同的方法实现深拷贝,如使用JSON.parse(JSON.stringify(obj))或自定义递归函数来复制对象的属性和嵌套对象。 浅拷贝是指创建一个新的对象,将原始对象的属性复制到新对象,但嵌套对象的引用仍然指向原始对象的相同嵌套对象。这意味着对新对象的修改可能会影响原始对象。在JavaScript,可以使用Object.assign()或展开运算符(...)来实现浅拷贝。 总结来说,用于存储基本类型的变量和引用类型的指针,而堆用于存储引用类型的数据。深拷贝是创建一个新对象并复制所有属性和嵌套对象的值,而浅拷贝只复制属性,嵌套对象的引用仍然指向原始对象。 #### 引用[.reference_title] - *1* *3* [JavaScript 堆和的区别](https://blog.csdn.net/qq_29850249/article/details/110500006)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [JavaScript内存与堆内存分别是什么?](https://blog.csdn.net/qq_43807473/article/details/123816682)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值