递归与栈刷题

一、化栈为队列

LeetCode03.04题:化栈为队列

 解题思路

设置两个栈s1和s2来模拟一个队列,s2负责入队,s1负责出队;

当s1为空时,如果s2不为空,则将s2中的内容出栈,再入栈到s1;

代码实现

// 实现一个栈
class Stack {
    constructor() {
        this.stack = []
    }
    push(x) {
        this.stack.push(x);
    }
    pop() {
        if(this.empty()) return;
        let top = this.top();
        this.stack.pop()
        return top;
    }
    top() {
        return this.stack[this.size()-1]
    }
    empty() {
        return this.stack.length == 0;
    }
    size() {
        return this.stack.length;
    }
}

// 两个栈实现一个队列
/**
 * Initialize your data structure here.
 */
var MyQueue = function() {
    // 创建两个栈
    this.s1 = new Stack();
    this.s2 = new Stack();
};
// 当s1为空时,将s2内容压入s1中
MyQueue.prototype.transfer = function() {
    if(!this.s1.empty()) return;
    while(!this.s2.empty()) {
        this.s1.push(this.s2.pop())
    }
}

/**
 * Push element x to the back of queue. 
 * @param {number} x
 * @return {void}
 * @description 入队时将数据放入S2中
 */
MyQueue.prototype.push = function(x) {
    this.s2.push(x);
};

/**
 * Removes the element from in front of queue and returns that element.
 * @return {number}
 * @description 出队时判断s1中是否有值,若有,直接将s1栈顶出去;若无,则将s2中的数据全都出栈到s1再将s1栈顶出去。
 */
MyQueue.prototype.pop = function() {
    this.transfer();
    let top = this.s1.top();
    this.s1.pop();
    return top;
};

/**
 * Get the front element.
 * @return {number}
 * @description 队头即s1栈顶,也需要对s1进行判断
 */
MyQueue.prototype.peek = function() {
    this.transfer();
    return this.s1.top();
};

/**
 * Returns whether the queue is empty.
 * @return {boolean}
 * @description s1和s2都为空时队列为空
 */
MyQueue.prototype.empty = function() {
    return this.s1.empty() && this.s2.empty();
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * var obj = new MyQueue()
 * obj.push(x)
 * var param_2 = obj.pop()
 * var param_3 = obj.peek()
 * var param_4 = obj.empty()
 */

二、入栈出栈

LeetCode03.04题:棒球比赛

 解题思路

  • 当遇到数字:进栈;
  • 当遇到加号:取栈顶值top,将栈顶出栈,再取栈顶值与top相加,把top放回栈中,再将相加的值放入栈中;
  • 当遇到D:将栈顶值乘2,并将所得的值放入栈中;
  • 当遇到C:将栈顶值出栈。

最后当栈不为空时,遍历整个栈,将栈顶值出栈并相加,返回相加后的值。

代码实现

// 实现一个栈
class Stack {
    constructor() {
        this.stack = []
    }
    push(x) {
        this.stack.push(x);
    }
    pop() {
        if(this.empty()) return; 
        let top = this.top();
        this.stack.pop()
        return top;
    }
    top() {
        return this.stack[this.size()-1]
    }
    empty() {
        return this.stack.length == 0;
    }
    size() {
        return this.stack.length;
    }
}

/**
 * @param {string[]} ops
 * @return {number}
 */
var calPoints = function(ops) {
    let stack = new Stack();
    let sumScore = 0;
    for(let i = 0; i < ops.length; i++) {
        if(ops[i] == '+') {
            let sum = 0;
            let top1 = 0;
            if(!stack.empty()) {
                top1 = stack.pop();
                sum += top1;
                console.log(stack)
            }
            if(!stack.empty()) {
                sum += stack.top();;
            }
            stack.push(top1);
            stack.push(sum);
        } else if(ops[i] == 'D') {
            let score = 0;
            if(!stack.empty()) {
                score = stack.top();
            }
            stack.push(score * 2);

        } else if(ops[i] == 'C') {
            if(!stack.empty()) {
                stack.pop();
            }
        } else {
            stack.push(ops[i] * 1)
        }
    }
    while(!stack.empty()) {
        sumScore += stack.pop();
    }
    return sumScore;
};

三、入栈出栈

LeetCode844题:比较含退格的字符串

解题思路

设置两个栈,当遇到#则出栈,其他字符入栈;

当两个字符串都入栈后,比较两个栈的长度是否相等,若不相等,则两个字符串不可能相等,返回false;

遍历两个栈,比较两个栈的栈顶,如果栈顶不相等,则两个字符串不可能相等,返回false;直到栈为空时,战斗都相等则返回true。

代码实现 

// 实现一个栈
class Stack {
    constructor() {
        this.stack = []
    }
    push(x) {
        this.stack.push(x);
    }
    pop() {
        if(this.empty()) return; 
        let top = this.top();
        this.stack.pop()
        return top;
    }
    top() {
        return this.stack[this.size()-1]
    }
    empty() {
        return this.stack.length == 0;
    }
    size() {
        return this.stack.length;
    }
}

/**
 * @param {string} s
 * @param {string} t
 * @return {boolean}
 */
var backspaceCompare = function(s, t) {
    let stack1 = new Stack();
    let stack2 = new Stack();
    transfer(stack1, s);
    transfer(stack2, t);
    // 判断两个栈的长度是否相同,若不相同则不可能相等
    if(stack1.size() != stack2.size())return false;
    while(!stack1.empty()) {
        if(stack1.top() != stack2.top()) return false;
        stack1.pop();
        stack2.pop();
    }
    return true;
};
// 遍历判断是否为#,若是则出栈,否则进栈
var transfer = function(stack, str) {
    for(var i = 0; i < str.length; i++) {
        if(str[i] == '#') {
            // !stack.empty() && stack.pop();
            if(!stack.empty()) {
                stack.pop()
            }
        } else {
            stack.push(str[i]);
        }
    }
}

四、验证栈序列

LeetCode946题:验证栈序列

解题思路

pushed中的元素一直入栈,直到有元素和popped中未检测的首个元素相等,出栈,则检测通过,进行下个元素的检测。

当pushed中所有元素都进栈了,然而栈顶不等于监测值时,说明popped的操作序列不对了。

代码实现

class Stack {
    constructor() {
        this.stack = []
    }
    push(x) {
        this.stack.push(x);
    }
    pop() {
        if(this.empty()) return;
        let top = this.top();
        this.stack.pop()
        return top;
    }
    top() {
        return this.stack[this.size()-1]
    }
    empty() {
        return this.stack.length == 0;
    }
    size() {
        return this.stack.length;
    }
}


/**
 * @param {number[]} pushed
 * @param {number[]} popped
 * @return {boolean}
 */
var validateStackSequences = function(pushed, popped) {
    let stack = new Stack();
    // 
    let j = 0;
    // 遍历poped
    for(let i = 0; i < popped.length; i++) {
        // 当pushed中有值,且stack为空或栈顶不等于poped[i]时
        while(j < pushed.length && (stack.empty() || stack.top() != popped[i])) {
            // 将pushed[i]入栈
            stack.push(pushed[j]);
            j++;
        }
        // 当因为j>=pushed.length跳出来时,如果栈顶不等于poped[i],那么可以判断poped的操作序列是不对的
        if(stack.top() != popped[i]) return false;
        stack.pop();
    }
    return true;
};

五、有效的括号

LeetCode946题:有效的括号

 解题思路

当字符为左括号时入栈;

为右括号时检测栈不为空且栈顶为对应的左括号时出栈,否则无效,返回false。

代码实现

class Stack {
    constructor() {
        this.stack = []
    }
    push(x) {
        this.stack.push(x);
    }
    pop() {
        if(this.empty()) return;
        let top = this.top();
        this.stack.pop()
        return top;
    }
    top() {
        return this.stack[this.size()-1]
    }
    empty() {
        return this.stack.length == 0;
    }
    size() {
        return this.stack.length;
    }
}

/**
 * @param {string} s
 * @return {boolean}
 */
var isValid = function(s) {
    let stack = new Stack();
    for(let i = 0; i< s.length; i++) {
        switch(s[i]) {
            case '(': 
            case '[': 
            case '{':   stack.push(s[i]); break;
            case ')':   if(stack.empty() || stack.top() != '(') return false;
                        stack.pop();
                        break;
            case ']':   if(stack.empty() || stack.top() != '[') return false;
                        stack.pop();
                        break;
            case '}':   if(stack.empty() || stack.top() != '{') return false;
                        stack.pop();
                        break;
        }
    }
    return stack.empty();
};

六、删除最外层的括号

LeetCode1021题:删除最外层的括号

 

 解题思路

设置left表示最外层左括号位置;设置cnt,当遇到左括号++,右括号--。

当cnt为0时,证明左右括号对等,则当前所在位置便是最外层右括号的位置,所以使用slice(最外层左括号位置, 最外层右括号位置)提取出删除最外层括号的字符串。

将left指向最外层右括号的后一位,继续检测。

代码实现

/**
 * @param {string} s
 * @return {string}
 */
var removeOuterParentheses = function(s) {
    let left = 0;
    let cnt = 0;
    let str = '';
    for(let i = 0; i < s.length; i++) {
        if(s[i] == '(') {
            cnt ++;
        } else {
            cnt --;
        }
        // 当左右括号配对完,证明第i个字符就是最外层的右括号
        if(cnt != 0) {
            continue;
        }
        // 截取除了最外层左右括号的字符串
        str += s.slice(left + 1, i);
        // 将left移到i右边一位继续检测
        left = i + 1;
    }
    return str;
};

七、移除无效的括号

LeetCode1249题:移除无效的括号

解题思路

1.先从左到右遍历删去无效右括号:

  • 当遇到左括号,ctn+1;
  • 左括号和其他字符都放进str中;
  • 当遇到右括号,判断ctn是否为0,若不为0,则将ctn--,并将当前右括号放进str字符串中,若是0则表示前面字符串中没有与当前右括号匹配的左括号,所以不将当前右括号放进字符串,退出当前循环。

2.再从右到左遍历删去无效左括号:与步骤1中思路一致。

3.由于2中得到的字符串是反转的,所以需要将字符串反转回来。

代码实现

/**
 * @param {string} s
 * @return {string}
 */
var minRemoveToMakeValid = function(s) {
    let ctn = 0; // 判断左右括号是否对等
    let str = ''; 
    let ans = '';
    // 从左到右遍历字符串去除无效右括号
    for(let i = 0; i < s.length; i++) {
        if(s[i] != ')') { //当不为右括号的时候
            ctn += (s[i] == '(');
            str += s[i]; // 将当前字符加入str字符串中
        } else {
            // 当ctn为0时证明前面没有匹配的左括号,所以不做任何操作
            if(ctn == 0) continue;
            // 当ctn不为0时,ctn减1,并将当前右括号加入str字符串中
            ctn --;
            str += s[i];
        }
    }
    // 从右到左遍历字符串去除无效左括号
    ctn = 0;
    for(let i = str.length - 1; i >= 0; i --) {
        if(str[i] != '(') {
            ctn += (str[i] == ')');
            ans += str[i];
        } else {
            if(ctn == 0) continue;
            ctn --;
            ans += str[i];
        }
    }
    // 由于是从右到左遍历,所以需要将字符串反转过来
    ans = ans.split('').reverse().join('');
    console.log(ans)

    return ans;
};

八、二叉树的后序遍历

LeetCode145题:二叉树的后序遍历

后序遍历:左右根

前序遍历:根左右

中序遍历:左根右

解题思路一

采用递归的写法,层层递进,将根节点左边的所有层级处理完,再处理根节点右边的所有层级,最后再处理根节点。

代码实现

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */

var postorder = function(root, ans) {
    if(root == null) return;
    postorder(root.left, ans);
    postorder(root.right, ans);
    ans.push(root.val);
}
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var postorderTraversal = function(root) {
    let ans = [];
    postorder(root, ans);
    return ans;
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值