算法---栈与队列总结篇

Posted nxf-rabbit75

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法---栈与队列总结篇相关的知识,希望对你有一定的参考价值。

一、括号匹配

Leetcode 20: 有效的括号

题目描述:

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

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。

注意空字符串可被认为是有效字符串。

示例:

示例 1:
输入: "()"
输出: true

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

示例 3:
输入: "(]"
输出: false

示例 4:
输入: "([)]"
输出: false

示例 5:
输入: "{[]}"
输出: true  

【思路】用栈保存括号的左半部分,遇到左半部分就入栈;遇到右半部分就查看栈顶元素是否与该括号为一对,如果是,就将栈顶元素出栈,否则,返回错误,表示该串括号无效。

代码如下:

def isValid(s):
    stack_ = []
    if s == ‘‘:
        return True
    if len(s) == 1:
        return False
    list_s = list(s)
    for i in range(len(list_s)):
        if list_s[i] == ‘(‘ or list_s[i] == ‘[‘ or list_s[i] == ‘{‘:
            stack_.append(s[i])
        else:
            print(‘stack_‘,stack_)
            if len(stack_) > 0:
                if stack_[-1] == None:
                    return False
                if list_s[i] == ‘)‘ and stack_[-1] != ‘(‘:
                    return False
                elif list_s[i] == ‘]‘ and stack_[-1] != ‘[‘:
                    return False
                elif list_s[i] == ‘}‘ and stack_[-1] != ‘{‘:
                    return False
            if list_s[i]  and stack_ == []:
                return False
            stack_ = stack_[:-1]
    return stack_ == []

res = isValid(‘[]]‘)
print(res)

  

Leetcode 32: 最长有效括号

题目描述:给定一个只包含 ‘(‘ 和 ‘)‘ 的字符串,找出最长的包含有效括号的子串的长度。

示例:

示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"

 

思路:

对于是“(”直接压入栈中,如果是“)”,要分情况讨论

(1)如果当前栈为空,说明不存在与当前右括号配对的左括号,直接continue

(2)如果当前栈大小为1

  a)如果栈顶元素是“(”,则找到一个有效的括号序列,弹出栈顶元素,并压入这个序列的长度2

  b)如果栈顶元素为数字,说明不存在与当前右括号配对的左括号,且由于插入了一个右括号,之前得到的括号序列无法更长,需要弹出栈顶元素

(3)如果当前栈的大小大于等于2

  a)栈顶元素如果是“(”,则找到一个为2的有效序列,再检查栈顶元素,如果是数字,说明可以与前面找到的括号序列合并为一个更大的序列,与其相加后入栈,否则直接将2压入栈

  b)栈顶元素如果是数字,由于当前的栈大小大于等于2,则下一个栈的元素一定是“(”,弹出后压入合并后的序列长度,压之前再检查,如果栈顶元素还是为数字,则再合并,再压入。

 

代码如下:

def longestValidParentheses(s):
    stack_ = []
    if s == ‘‘ or len(s) == 1:
        return 0
    max_len = 0
    pre_num = -1
    for i,str in enumerate(s):
        print(i,stack_)
        if str == ‘(‘:
            if not pre_num == -1 and s[i-1] == ‘)‘:#‘)‘+‘(‘
                stack_.append(pre_num)
            else:
                stack_.append(i)
        elif str == ‘)‘:
            if not stack_:#stack_为空   只有一个‘)’
                pre_num = -1
            else:
                temp = stack_.pop()
                max_len = max(max_len,i-temp+1)
                pre_num = temp
    return max_len

res = longestValidParentheses(‘)(()()‘)
print(res)

 

Leetcode 856: 括号的分数

题目描述:

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

()得1分。

AB得A + B分,其中A和B是平衡括号字符串。

(A)得2 * A分,其中A是平衡括号字符串。

 

示例:

示例1:
输入: "()"
输出: 1

示例2:
输入: "(())"
输出: 2

示例3:
输入: "()()"
输出: 2

示例4:
输入: "(()(()))"
输出: 6

提示:S是平衡括号字符串,且只含有(和)。2 <= S.length <= 50

 

 

思路1:递归

对给定的字符串,找出与最左边的括号相匹配的右括号的下标index,如果这两个括号正好占据了字符串一左一右的两侧边界,则最后的分数为这两个括号中间部分的子字符串的分数 * 2。否则最后的分数等于下标index将S分成的左右两个平衡括号字符串分数之和。

思路2:栈

括号匹配的题目一般要用到栈,这个题也是。我们用栈保存两样东西:一是左括号(,二是得分。这样我们在遇到)返回的时候,可以直接判断栈里面是左括号还是得分。

如果是左括号(,那么得分是1,放入栈中。

如果是得分,那么我们需要一直向前求和直到找到左括号为止,然后把这个得分×2,放入栈中。

由于题目给的是符合要求的括号匹配对,那么栈里面最后应该只剩下一个元素了,就是最终得分。

 

思路1代码:

from collections import OrderedDict
class Solution (object):
    # 找第一个左括号的右括号对应的右括号的位置
    def FindFirstRightkh(self,S):
        stack = []
        dict_S = OrderedDict()
        for idx,s in enumerate(list(S)):
            if s == ‘(‘:
                stack.append(idx)
            elif s == ‘)‘ and len(stack) >= 1:
                dict_S[stack[-1]] = idx
                if stack[-1] == 0:
                    return idx
                stack.pop()

    # print(dict_S) #{1: 2, 4: 5, 3: 6, 0: 7}

    def scoreOfParentheses(self, S):
        score = 0
        if S == ‘()‘:
            return 1
        elif S ==‘(())‘:
            return 2
        elif S == ‘()()‘:
            return 2
        idx_Rightkh = self.FindFirstRightkh(S)
        if idx_Rightkh == len(S) - 1:
            score = 2 * self.scoreOfParentheses(S[1:idx_Rightkh])
        else:
            score = self.scoreOfParentheses(S[:idx_Rightkh+1]) + self.scoreOfParentheses(S[idx_Rightkh+1:])
        return score

  

思路2代码:

class Solution1 (object):
    def scoreOfParentheses1(self, S):
        """
        :type S: str
        :rtype: int
        """
        scoreStack = []
        for c in S:
            if c == ‘(‘: #如果是‘(‘,就将-1入栈
                scoreStack.append(-1)
            else:#右括号
                score = 0
                while scoreStack[-1] != -1:#如果是得分,就一直加,直到遇到-1,得到内部的括号之和
                    score += scoreStack.pop()
                scoreStack.pop()#弹出不是-1的
                if score == 0:
                    scoreStack.append(1)
                else: #得分不为0,说明栈顶不为-1,得2倍分
                    scoreStack.append(2 * score)
        totalScore = 0
        while scoreStack != []:
            totalScore += scoreStack.pop()
        return totalScore

s = Solution()
res = s.scoreOfParentheses(S=‘((())(()))‘)
print(res)

  

Leetcode 921: 使括号有效的最少添加

题目描述:给定一个由‘(‘和‘)‘括号组成的字符串S,我们需要添加最少的括号( ‘(‘或是‘)‘,可以在任何位置),以使得到的括号字符串有效

说明:从形式上讲,只有满足下面几点之一,括号字符串才是有效的:

它是一个空字符串,或者它可以被写成AB(A与B连接), 其中A和B都是有效字符串,或者它可以被写作 (A),其中A是有效字符串。

给定一个括号字符串,返回为使结果字符串有效而必须添加的最少括号数。

示例1:
输入:"())"
输出:1

示例2:
输入:"((("
输出:3

示例3:
输入:"()"
输出:0

示例4:
输入:"()))(("
输出:4

提示:
S.length <= 1000
S只包含()字符。

 

思路:

代码如下:

class Solution:
    def minAddToMakeValid(self, S):
        """
        :type S: str
        :rtype: int
        """
        if S == ‘‘:
            return 0
        stack = []
        right_kh_count = 0
        left_kh_count = 0
        for s in S:
            if s == ‘(‘:
                stack.append(s)
            elif s == ‘)‘ and stack != []:
                stack.pop()
            else:
                left_kh_count += 1
        if stack != []:
            right_kh_count = len(stack)
        return left_kh_count + right_kh_count

    def minAddToMakeValid_leetcode(self, S):
        if S == ‘‘:
            return 0
        stack = []
        for s in S:
            if s == ‘)‘ and len(stack) >0 and stack[-1] == ‘(‘:
                stack.pop()
            else:
               stack.append (s)
        return len(stack)

s = Solution()
num = s.minAddToMakeValid_leetcode(S=‘())‘)
print(num)

  

 

 

 

二、下一个更大元素

Leetcode 496:下一个更大元素I

题目描述:给定两个没有重复元素的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个比其大的值。

说明:nums1 中数字 x 的下一个更大元素是指 x 在 nums2 中对应位置的右边的第一个比 x 大的元素。如果不存在,对应位置输出-1。

示例:

示例 1:
输入: nums1 = [4,1,2], nums2 = [1,3,4,2].
输出: [-1,3,-1]
解释:
    对于num1中的数字4,你无法在第二个数组中找到下一个更大的数字,因此输出 -1。
    对于num1中的数字1,第二个数组中数字1右边的下一个较大数字是 3。
    对于num1中的数字2,第二个数组中没有下一个更大的数字,因此输出 -1。

示例 2: 输入: nums1 = [2,4], nums2 = [1,2,3,4]. 输出: [3,-1] 解释: 对于num1中的数字2,第二个数组中的下一个较大数字是3。 对于num1中的数字4,第二个数组中没有下一个更大的数字,因此输出 -1。
注意: nums1和nums2中所有元素是唯一的。 nums1和nums2 的数组大小都不超过1000。

  

 

 

Leetcode 503:下一个更大元素II

 

 

Leetcode 556:下一个更大元素III

 

以上是关于算法---栈与队列总结篇的主要内容,如果未能解决你的问题,请参考以下文章

数据结构与算法知识点总结队列栈与散列表

万字总结图解堆算法链表栈与队列(多图预警)

数据结构算法--栈与队列

栈与队列篇_栈的应用合集

算法 | 第3章 栈与队列相关《程序员面试金典》#yyds干货盘点#

栈与队列小结