0
点赞
收藏
分享

微信扫一扫

蓝桥杯dfs(二)

文章目录

正则问题

题目描述
考虑一种简单的正则表达式:

只由 x ( ) | 组成的正则表达式。

小明想求出这个正则表达式能接受的最长字符串的长度。

例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是: xxxxxx,长度是 6。

输入描述
一个由 x()| 组成的正则表达式。输入长度不超过 100,保证合法。

输出描述
这个正则表达式能接受的最长字符串的长度。

样例输入
((xx|xxx)x|(x|xx))xx

样例输出
6

样例解释


正则表达式,又称规则表达式,通常被用来检索、替换符合某个模式(规则)的文本。

比如题目中由“ x ( ) | ”组成的正则表达式,括号“()”的优先级最高,或操作“|”次之。括号里面是一个整体,或的两边保留最长的一个。

((xx|xxx)x|(x|xx))xx 是怎么执行的,为什么是 6 呢?

先执行括号,再执行或,步骤是:

先看第一个括号,发现里面还有嵌套括号,找到最内部的括号,括号内是一个或操作。((xx|xxx)x|(x|xx))xx,得:(xxxx|(x|xx))xx
继续执行最内部括号。(xxxx|(x|xx))xx,得:(xxxx|xx)xx
继续执行最后括号。(xxxx|xx)xx,得:xxxxxx,结束,得长度为 6 的字符串。

分析

  • 可能是习惯反射吧,一看到有括号的问题我就会想到括号匹配这道题,会想用栈的结构去解决问题。事实证明,这样真可以。
  • 我们这题肯定会用到dfs,因为括号不止一个,通过递归解决每一个小括号,这样就好办了。
  • 首先,由于我们需要遍历每一个字符,所以定义一个pos变量,进行位置的记录,为避免递归这个小朋友迷失方向,我们把pos设为一个全局变量,这样时刻就不会走到奇怪的位置了。
  • 这里因为存在或|,所以必定有前后的比较,所以用两个变量ans,tmp的比较来判断究竟哪边X比较多。
  • 首先无论遍历到哪个字符,位置都要进行移动,即pos+=1
  • 进栈可能暂时还想不到干嘛,但出栈的时候,我们需要获取最大值,所以res和ans进行比较,我们以ans为最终结果,就return ans
  • 对于或符的处理,我们是这样做的,首先比较ans和tmp谁大取谁,tmp一定要清零,因为或后面的字符需要用tmp来统计。即或前用ans记录,或后用tmp记录
  • 对于x的记录,使用tmp进行记录。
  • 结束的时候我们就返回ans和tmp的最大值,相当于或前或者或后的值。
  • 这里我们应该知道,在进栈的时候,应该做一件事情,就是tmp要改写值,因为tmp的值要给ans作为或前值的记录,所以这里必须要加,且需要在入栈加(因为一开始就需要统计了),这就是为什么我要在出栈设置返回值的缘故。
  • 总体程序就是:我用tmp进行统计,将或前给ans,将或后给自己,再比较最大值即可。

代码

s = input()
pos = 0

def dfs(s):
  
  global pos
  n = len(s)
  ans = 0
  tmp = 0 # 记录另外一边(与res比较)
  while pos < n:
    if s[pos] == '(': # 进栈
      pos+=1
      tmp += dfs(s)
    elif s[pos] == ')': # 出栈
      pos+=1
      ans = max(ans,tmp)
      return ans
    elif s[pos] == '|': # 处理或符之前的值
      pos+=1
      ans = max(ans,tmp)
      tmp = 0
    else: # 记录x
      pos+=1
      tmp+=1
  ans = max(ans,tmp)
  return ans

print(dfs(s))

通过截图

在这里插入图片描述

寒假作业

题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

现在小学的数学题目也不是那么好玩的。 看看这个寒假作业:

   □ + □ = □
   □ - □ = □
   □ × □ = □
   □ ÷ □ = □

每个方块代表 1~13 中的某一个数字,但不能重复。

比如:

 6  + 7 = 13
 9  - 8 = 1
 3  * 4 = 12
 10 / 2 = 5

以及:

 7  + 6 = 13
 9  - 8 = 1
 3  * 4 = 12
 10 / 2 = 5

就算两种解法。(加法,乘法交换律后算不同的方案)

你一共找到了多少种方案?

运行限制
最大运行时间:1s
最大运行内存: 128M

分析

  • 一看就知道是全排列问题,枚举13!是会超时的,所以不提倡(由于是填空所以超时不可怕,可怕的是在比赛中跑不出来)
  • 而且我们知道肯定如果加减乘除有一个运算不行,后面就不用看了。这不就是剪枝吗?
  • 所以,这题我们使用回溯算法来做。
  • 全排列数组设为nums,一开始用0初始化
  • 标记数组设为vis,一开始也用0初始化,表示尚未标记
  • 我们设几个计算函数为布尔类型(当然也可以直接写),这个有点简单,不刻意进行说明。
  • 由于我们可能不知道我们取了几个数,所以这里用num进行全排列数组长度的记录,在我以前写全排列的时候,当时使用path数组记录可能的全排列,所以那时候,直接len就可以得到path取了几个,现在我们不用path,所以要另外取变量记录。
  • 终止条件为什么是num==13呢?因为循环在终止条件下面,如果是num==12的话,这时候nums[12]尚未构建好,所以一定要下一个数。
    其他就是模板问题了。

代码

res = 0
nums = [0 for i in range(14)]
vis = [0 for i in range(14)] # 标记数组


def check3(): # 检查前3个
  return nums[1]+nums[2] == nums[3]

def check6(): 
  return nums[4]-nums[5] == nums[6]

def check9():
  return nums[7]*nums[8] == nums[9]

def check12(): # 本来是nums[10]/nums[11] == nums[12],这样转化避免出现小数
  return nums[11]*nums[12] == nums[10]

def dfs(num): # 参数num用来计数
  global res
  if num == 13: # 终止条件
    if check12():
      res+=1
    return

  # 剪枝
  if num == 4 and not check3():
    return
  if num == 7 and not check6():
    return
  if num == 10 and not check9():
    return

  for i in range(1,14): # 从1到13取:
    if not vis[i]: # 没被标记
      nums[num] = i
      vis[i] = 1 # 标记
      dfs(num+1)
      vis[i] = 0 # 回溯
dfs(1)
print(res)

通过截图

答案为:64
在这里插入图片描述
如有错误,敬请指正,欢迎交流,谢谢♪(・ω・)ノ

举报

相关推荐

0 条评论