[英雄星球六月集训LeetCode解题日报] 第14日 栈

一、 剑指 Offer 31. 栈的压入、弹出序列

链接: 剑指 Offer 31. 栈的压入、弹出序列

1. 题目描述

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

2. 思路分析

  • 用栈模拟入队,遇到出队数字时尝试出队。
  • 如果最后能出完就是正确。

3. 代码实现

class Solution:
    def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        stack = []
        i = 0
        for p in pushed:
            stack.append(p)
            while stack and stack[-1] == popped[i]:
                stack.pop()
                i += 1
        
        return not stack

二、 946. 验证栈序列

链接: 946. 验证栈序列

1. 题目描述

给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false 。

2. 思路分析

同上题。

3. 代码实现

class Solution:
    def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        stack = []
        i = 0
        for p in pushed:
            stack.append(p)
            while stack and stack[-1] == popped[i]:
                stack.pop()
                i += 1        
        return not stack

三、 856. 括号的分数

链接: 856. 括号的分数

1. 题目描述

给定一个平衡括号字符串 S,按下述规则计算该字符串的分数:

  • () 得 1 分。
  • AB 得 A + B 分,其中 A 和 B 是平衡括号字符串。
  • (A) 得 2 * A 分,其中 A 是平衡括号字符串。

2. 思路分析

好像之前群友出过一道类似的题,用括号处理内部字符串重复次数。
这种题可以用栈维护每个“级别”的子问题,当前级别括回时,转移回上一级别,并出栈。
这题:

  • 遇到’(',栈升高,为空(0)等待。
  • 遇到’)',当前栈顶关闭,加回上一层,注意转移关系是要乘2 (条件3) 再加;关闭时判断自己是否空(0),来进行+1 (条件1) 或者*2 (条件2) 操作。
  • 为了回到上一层 这个动作方便处理,我们一开始就设置一个栈底,最后结果返回栈底即可。

3. 代码实现

class Solution:
    def scoreOfParentheses(self, s: str) -> int:
        stack = [0]
        for c in s:
            if c == '(':
                stack.append(0)
            else:
                if stack[-1] == 0:
                    stack[-1] = 1
                else:
                    stack[-1] *= 2
                stack[-2] += stack[-1]
                stack.pop()   
        return stack[0]

四、 1190. 反转每对括号间的子串

链接: 1190. 反转每对括号间的子串

1. 题目描述

给出一个字符串 s(仅含有小写英文字母和括号)。

请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。

注意,您的结果中 不应 包含任何括号。
在这里插入图片描述

2. 思路分析

与上题类似,但是每层维护的是本层字符串,且关闭操作是翻转,因此最坏复杂度可能到O(n2)

  • 遇到’(‘,栈升高,为空(’')等待。
  • 遇到’)',当前栈顶关闭,追加回上一层,这里关闭操作是翻转。
  • 遇到字母直接追加到栈顶字符串。
  • 为了回到上一层 这个动作方便处理,我们一开始就设置一个栈底,最后结果返回栈底即可。

3. 代码实现

class Solution:
    def reverseParentheses(self, s: str) -> str:
        stack = ['']

        for c in s:
            if c == '(':
                stack.append('')
            elif c != ')':
                stack[-1] += c
            else:
                tmp = stack.pop()
                stack[-1] += tmp[::-1]
        return stack[0]

五、 群友作业

1. 题目描述

在这里插入图片描述

2. 思路分析

类似,但是每层维护当前层字符串,大致逻辑:遇到’)‘时关闭当前层,去后边找到第一个数字,重复后加回上一层;
由于’)‘后必跟因此实际上是遇到’>'再关闭

  • 遇到’(‘,栈升高,为空(’')等待。
  • 遇到’)',当前栈顶关闭,追加回上一层,这里关闭操作是重复n次。
  • 遇到字母直接追加到栈顶字符串。
  • 为了回到上一层 这个动作方便处理,我们一开始就设置一个栈底,最后结果返回栈底即可。
    在这里插入图片描述

3. 代码实现

python

import collections
import heapq
import math
from bisect import bisect, bisect_left
from collections import Counter, deque
from functools import cache
from typing import List, Optional

class Solution:
    def calc(self, s) -> str:
        stack = ['']
        num = ''
        for c in s:
            if c == '(':
                stack.append('')
            elif c.isalpha():
                stack[-1] += c
            elif c == ')':
                pass
            elif c.isdigit():
                num += c
            elif c == '<':
                num = ''
            elif c == '>':
                v = stack.pop()*int(num)
                stack[-1] += v

        return stack[0]


if __name__ == '__main__':
    ss = ["abc(d)<2>e", "a(b(c)<3>d)<2>e", "a(b(c)<3>d)<2>e"]
    for s in ss:
        print(Solution().calc(s))

当初写的是cpp,硬是麻烦。

/*
* File: hdu.cpp
* Author: LIU
*/
#include <cstring>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <map>
#include <set>
#include <functional>
#include <queue>
#include <vector>
#include <iostream>
#include <cmath>
using namespace std;

int main()
{
#ifdef DEBUG
    freopen("ojin.txt", "r", stdin);
// freopen("ojout.txt", "w", stdout);
#endif


    char no_use[10005]="";
    char record[] = "a(b(c)<3>d)<2>e";
    int len = strlen(record);
    char  stack[200][10005];
    int top = 0;
    memset(stack,0,sizeof(stack));
    for (int i = 0;i < len;++i)
    {
        char c = record[i];
        char* stack_top = stack[top];
        int len_top = strlen(stack_top);
        if ('a'<=c&&c<='z')
        {
            stack_top[len_top] = c; // c写追加好恶心,yue
        }
        if (c == '(')
        {
            ++top;
        }
        if (c == ')')
        {
            int repeat = 0;
            sscanf(record+i,")<%d%s",&repeat,no_use);
            i = strstr(record+i,">")-record;
            while(--repeat > 0)
            {
                memcpy(stack_top+strlen(stack_top), stack_top, len_top);
            }
            strcpy(stack[--top]+strlen(stack[top]),stack_top);
        }
    }
    printf("%s\n",stack[0]);
//    for(int i = 0; i <= top; ++i)
//    {
//        printf("%s\n",stack[i]);
//    }

    return 0;
}

六、参考链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值