Python笔试题自记——括号匹配问题

校招笔试题中关于括号匹配的问题,一次总结个够!

完成括号匹配

合法的括号匹配序列被定义为:
1. 空串""是合法的括号序列
2. 如果"X"和"Y"是合法的序列,那么"XY"也是一个合法的括号序列
3. 如果"X"是一个合法的序列,那么"[X]"也是一个合法的括号序列
4. 每个合法的括号序列都可以由上面的规则生成
例如"", "[]", "[][][]", "[[][]]", "[[[[]]]]"都是合法的。
牛牛现在给出一个括号序列s,牛牛允许你执行的操作是:在s的开始和结尾处添加一定数量的左括号('[')或者右括号(']')使其变为一个合法的括号匹配序列。牛牛希望你能求出添加最少的括号之后的合法的括号匹配序列是什么。

思路自记

这个思路其实不难,因为括号匹配的对象无非就两类“[”和“]”,那么就可以进行一个从左向右的统计,设定计算初始为count = 0,如果遇到了“[”,就count加1,代表出现了一个朝右的括号,继续往下,如果出现了一个“]”开口向左的括号,就把count抵消掉,最后算下来count是几,就说明有几个朝右的括号没有被抵消掉,需要往后加对应数量的开口向左的括号才行。但这么想,还是有个漏洞,那就是如果先出现一个落了单的开口向“]”的括号,那么后面无论出现什么也都没办法抵消,只能最后再序列前面加上对应的“[”才行,所以,再上面思路的基础上,采用,如果count在计数的过程中,小于0了,就把count给直接置成0,接着,记录下出现这种情况的次数,即需要补充开口朝右“[”括号的个数,最后统计出来需要补充的个数就行了。

PS:题目中要求求出添加最少的括号的要求,但个人感觉这个条件没啥用,因为一个括号就两类,只要出现落单的情况,就必须添加一个对应的括号,和位置没关系。

分析代码

除去思路还有一个让我感觉非常有借鉴意义的是,输入过程的简洁:

import sys
s = sys.stdin.readline().strip()

我自己在写的时候,对这个输入着实费了好多精力,因为题目只要求括号输入,中间没有空格,输入的就是一个字符串,我还得用一个for循环才能将每个括号拆开再逐一存到列表里面,这个输入很简洁一下子就搞定了,直接保存成字符串了!以后可以用于读取一行的操作。

# coding:utf-8

import sys

if __name__ == "__main__":
    # 读取第一行
    s = sys.stdin.readline().strip()
    left = []
    right = []
    count = 0
    for x in s:
        if x == '[':
            count =  count + 1
        elif x == ']':
            count = count - 1
            if count < 0:
                left.append('[')
                count = 0
    right = [']'] * count
    print ''.join(left) + s + ''.join(right)

括号匹配方案

合法的括号匹配序列被定义为:
1. 空串""是合法的括号序列
2. 如果"X"和"Y"是合法的序列,那么"XY"也是一个合法的括号序列
3. 如果"X"是一个合法的序列,那么"(X)"也是一个合法的括号序列
4. 每个合法的括号序列都可以由上面的规则生成
例如"", "()", "()()()", "(()())", "(((())))"都是合法的。 东东现在有一个合法的括号序列s,一次移除操作分为两步:
1. 移除序列s中第一个左括号
2. 移除序列s中任意一个右括号.保证操作之后s还是一个合法的括号序列
东东现在想知道使用上述的移除操作有多少种方案可以把序列s变为空
如果两个方案中有一次移除操作移除的是不同的右括号就认为是不同的方案。
例如: s = "()()()()()",输出1, 因为每次都只能选择被移除的左括号所相邻的右括号.
s = "(((())))",输出24, 第一次有4种情况, 第二次有3种情况, ... ,依次类推, 4 * 3 * 2 * 1 = 24

思路自记

PS:刚看这个题目的时候,感觉懵到没办法拿下,觉得这个没十几行代码是下不来的,但一看大神的解法,瞬间心里就一万头草泥马崩腾撞击!后来自己再咋么咋么味道感觉的确,只要绕过了弯子就好办多了。

理解完题的意思之后,开始思考,现在是拿左括号和右括号来匹配,左括号是从头开始的,右括号是任选,我现在从左往右开始遍历,如果发现的是左括号,那么计数器加count(表示发现了一个左括号),如果发现了一个右括号,这个时候就要想,我是在进行括号的抵消,因为整个括号序列原先是平衡的,那我现在发现的右括号,势必要有对应的左括号来跟他抵消,那也肯定是出现在这个右括号之前的左括号来跟它抵消,不能是后面的,那继续思考,那也就是只要出现在它之前的左括号都可以跟它抵消,也就是跟右括号配对的可以是count个左括号,同样,当把这个右括号抵消掉之后,计数器减一,说明还剩下这么多的左括号继续往下面走,去继续遍历到右括号,与其抵消。那么,最后题目要求是将所有情况算出,计算把刚才的与每个与右括号配对的时候的count值做累乘而已。

PS:这个思路是以右括号为主来思考的,但整个括号序列,左右括号是对称的,所以,结果是相同的。

代码

PS:每次只要遇到一个右括号,就将之前遇到的过的左括号数乘一次,说明,这个右括号可以跟这么多的左括号数可以匹配删除,且不影响括号序列的平衡,同时将count减一,表示从从刚才的左括号里面任减一个,来抵消掉这个右括号的影响。

import sys
s = sys.stdin.readline().strip()
count, x = 0, 1
for i in s:
    if i == '(':
        count += 1
    else:
        x *= count
        count -= 1
print x

括号匹配深度

一个合法的括号匹配序列有以下定义:
1、空串""是一个合法的括号匹配序列
2、如果"X"和"Y"都是合法的括号匹配序列,"XY"也是一个合法的括号匹配序列
3、如果"X"是一个合法的括号匹配序列,那么"(X)"也是一个合法的括号匹配序列
4、每个合法的括号序列都可以由以上规则生成。
例如: "","()","()()","((()))"都是合法的括号序列
对于一个合法的括号序列我们又有以下定义它的深度:
1、空串""的深度是0
2、如果字符串"X"的深度是x,字符串"Y"的深度是y,那么字符串"XY"的深度为max(x,y) 3、如果"X"的深度是x,那么字符串"(X)"的深度是x+1
例如: "()()()"的深度是1,"((()))"的深度是3。牛牛现在给你一个合法的括号序列,需要你计算出其深度。

思路自记

跟第一道很像,求深度,就是把左括号连续出现最长的数。返回即可。

代码

import sys
s = sys.stdin.readline().strip()
max1 = 0
count = 0
for i in s:
    if i == '(':
        count += 1
        max1 = max(max1,count)
    else:
        count -= 1
        if count < 0:
            count = 0

print max1

 

缺失的括号

一个完整的括号字符串定义规则如下:
1、空字符串是完整的。
2、如果s是完整的字符串,那么(s)也是完整的。
3、如果s和t是完整的字符串,将它们连接起来形成的st也是完整的。
例如,"(()())", ""和"(())()"是完整的括号字符串,"())(", "()(" 和 ")"是不完整的括号字符串。
牛牛有一个括号字符串s,现在需要在其中任意位置尽量少地添加括号,将其转化为一个完整的括号字符串。请问牛牛至少需要添加多少个括号。

 

同理,这个思路跟第一个也非常接近

import sys
s = sys.stdin.readline().strip()
count_r = 0
count_l = 0
for i in s:
    if i =='(':
        count_r += 1
    else:
        count_r -= 1
        if count_r < 0:
            count_r = 0
            count_l += 1

print count_r+count_l

 

你可能感兴趣的:(牛客真题刷)