LeetCode刷题 | Day6 栈与递归

  • JS中Math内置对象:常用属性Math.PI
Math方法作用
Math.random()随机数
Math.ceil() / Math.floor()向上/下取整
Math.abs()绝对值
Math.max() / Math.min()最大/小值
Math.pow()求次方
Math.sqrt()开根号
Math.around()四舍五入
Math.sin()正弦

Math.cos()

余弦

Math.trunc()

向零截断

(正数向下,负数向上)

  • 字符串截断方法

1.array.slice(start,end)

2.array.splice(start,deleteCount,item...)

3.string.split(separator,limit)

682. 棒球比赛

操作数和操作符的题目,很容易想到使用栈的方法。

完全模拟栈的方式写的题解:(在计算“+”有个小细节需要注意,因为是把操作数出栈之后再入栈的,需要注意a,b的顺序,后出先进)

/**
 * @param {string[]} operations
 * @return {number}
 */
var calPoints = function(operations) {
    list = [];
    for (const op of operations) {
        if (op === "C"){
            list.pop();
        } else if ( op === "D"){
            t = list.pop();
            list.push(t);
            list.push(2*t);
        } else if (op === "+") {
            a = list.pop();
            b = list.pop();
            list.push(b, a, a+b);
        } else {

            list.push(parseInt(op)); //注意将字符串转换成int类型
        }
    }
    return list.reduce( (total, val) => total + val ,0);
};

这里是先得出最后记分数组再计算总分,还有个想法就是在记分的同时计算总分。

 150. 逆波兰表达式求值

 逆波兰表达式的计算方法是,运算符写在两个操作数之后,可以通过栈的结构保存操作数,当遇到运算符就出栈两个数,需要注意的是减法和除法的先后顺序。

/**
 * @param {string[]} tokens
 * @return {number}
 */
var evalRPN = function(tokens) {
    var stack=[];
    for (const c of tokens){
        switch(c){
            case '+':
                a = stack.pop();
                b = stack.pop();
                stack.push(b+a);
                break;
            case '-':
                a = stack.pop();
                b = stack.pop();
                stack.push(b-a);
                break;
            case '*':
                a = stack.pop();
                b = stack.pop();
                stack.push(b*a);
                break;
            case '/':
                a = stack.pop();
                b = stack.pop();
                stack.push(Math.trunc(b/a)); //向零截断
                break;
            default:
                stack.push(parseInt(c));
        }    
    }
    return stack.pop()
};

20. 有效的括号

括号匹配,采用辅助栈的解法。js中的Map对象很好地通过键和值的配对达成匹配的目的,可以把一组括号存入Map对象中,由于has(),get()方法传入的参数是键,而括号匹配时遇到右括号开始判断,所以我们把右括号存为键,左括号存为值。

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function(s) {
    var map = new Map();
    map.set(')','(');
    map.set('}','{');
    map.set(']','[');
    var stack = [];

    for (const c of s){
        if (map.has(c)){ //如果是右括号
        //判断栈顶有无匹配的左括号
            if (stack.pop() !== map.get(c)) return false;
        } else {
            stack.push(c);
        }
    }
    // 如果栈非空,说明有括号没有匹配上
    if (stack.length) return false;
    else return true;
};

官解中加入了字符串长度是否是2的整数倍的判断:

const n = s.length;   

if (n % 2 === 1) { return false; }

1019. 链表中的下一个更大节点

这题写两个循环暴力求解也能通过,但是执行用时7%,显然有更优化的方法。

/**
 * Definition for singly-linked list.
 * function ListNode(val, next) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.next = (next===undefined ? null : next)
 * }
 */
/**
 * @param {ListNode} head
 * @return {number[]}
 */
var nextLargerNodes = function(head) {
    if (!head.next){
        return [0];
    }
    cur = head;
    next = head.next;

    var res=[];

    while (next){
        if (next.val > cur.val){
            res.push(next.val);
            cur = next;
            next = next.next;
        } else {
            let larger = 0;
            temp = next;
            // 遍历找到下一个更大的节点
            while (temp.next !== null){
                temp = temp.next;
                if (temp.val > cur.val){
                    larger = temp.val;
                    break;
                }
            }
            res.push(larger);
            cur = next;
            next = next.next;
        }            
    }
    // 最后一个节点必然没有下一个更大的节点了,所以为0
    res.push(0);
    return res;
};

由于需要寻找的是下一个更大的节点,那么在遍历链表的途中,没有找到下一个更大节点的一系列节点必定是一个单调递减的数组。利用这一点可以想到"单调栈"

遍历链表的同时维护一个递减的单调栈,每次进入当前节点后,先把栈中能出栈的出栈(栈顶的值<当前节点的值),再把当前节点放入栈中。

需要注意的是,这里更新结果数组需要知道节点对应的序号,所以额外添加idx记录节点的序号,并且以 [cur.val, idx] 的形式保存栈中内容。

var nextLargerNodes = function(head) {
    const ans = [];
    const stack = [];

    let cur = head;
    let idx = -1;
    while (cur) {
        ++idx;
        ans.push(0);
        // 如果栈不为空且栈顶元素小于当前节点的值,则更新结果数组
        while (stack.length && stack[stack.length - 1][0] < cur.val) {
            ans[stack.pop()[1]] = cur.val;
        }
        // 当前节点和它对应的序号入栈
        stack.push([cur.val, idx]);
        cur = cur.next;
    }
    
    return ans;
};

 394. 字符串解码

 对于嵌套问题,栈的结构是很好的解决方法。

本题对于字符串的处理可能造成一些难度,需要对数字、字母、左右方括号分别进行处理:

var decodeString = function(s) {
    // 用两个栈来存放当前状态,前者是重复次数,后者是累积字符串
    let repetStack=[],resStack=[];
    //拼接字符串
    let resStr = "";
    //表示重复次数
    let repet = 0;
    // 遍历s
    for(let i=0;i<s.length;i++){
        let cur = s.charAt(i);
        if(cur == '['){
            //双双压入栈中,保存当前状态
            repetStack.push(repet);
            resStack.push(resStr);
            //置空,准备下面的累积
            repet = 0;
            resStr = "";
        }else if(cur == ']'){
            // 取出当前重复次数栈中的值,也就是当前字符串的重复次数
            let count = repetStack.pop();
            // 根据重复次数生成重复字符串,赋值给temp,和resStr拼接
            let temp = "";
            for(let i = 0;i<count;i++){
                temp += resStr;
            }
            // 和前面已经求得的字符串进行拼接
            resStr = resStack.pop() + temp;
        }else if(cur>='0' && cur<='9'){
            // repet累积
            repet = repet*10 + (cur-'0');
        }else{
            //字符累积
            resStr += cur;
        }
    }
    return resStr;
};


作者:ityou-o
链接:https://leetcode.cn/problems/decode-string/solution/javascriptban-jie-ti-si-lu-by-ityou-o-mpy0/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值