刷题日志:布尔表达式

今天的题核心是区间动态规划,给一个布尔表达式圈括号。

题目如下:

给定一个布尔表达式和一个期望的布尔结果 result,布尔表达式由 0 (false)、1 (true)、& (AND)、 | (OR) 和 ^ (XOR) 符号组成。实现一个函数,算出有几种可使该表达式得出 result 值的括号方法。

【示例】输入:s = "1^0|0|1", result = 0

输出:2

解释: 两种可能的括号方法是

1^(0|(0|1))

1^((0|0)|1)

思考:

我在之前陷入了一个很大的误区,其实动态规划的最优子结构性质并不是必要元素。动态规划的一个很大作用是备忘录方法,在递归过程中减少运算量。对于今天这道题,同样的,结果是多少中方法,而参数给定了,区间加result值,所以有三个参数。

设p[i][j][r]表示从第i个数到第j个数布尔表达式运算为r(0或1)的方法数,思考当前解与前面解的关系。中断点k,由中断点的符号表示出当前解。

由底层区间为2的情况不断向上推出区间为n的情况、

s为输入布尔表达式,r为result

public :
	int solution() {
		int n = (int)s.size();

		vector<int> nums;
		string sign;
		for (int i = 0; i < n; i++) {
			if (!(i % 2)) {
				int num = s[i] - '0';
				nums.push_back(num);
			}
			else
			{
				sign += s[i];
			}
		}
		int  nlen =(int) nums.size();
		//全部初始化为零?
		vector< vector < vector < int > > > dp(nlen,vector < vector < int > >(nlen,vector<int>(2,0)));
		for (int i = 0; i < nlen; i++) {
			if (nums[i] == 1) dp[i][i][1] = 1;
			else dp[i][i][0] = 1;
		}
		//已经记录,有nlen个数
		//如何记录解决方案
		//int cnt = 1, i = 0, k = 0;
		for ( int cnt = 1; cnt <= nlen - 1; cnt++) {
			//按照cnt递增,右端点
			//就是区间为cnt的动态规划解决
			for (int  i = 0; i <= nlen-1-cnt; i++) {
				for ( int k = i; k < i+cnt; k++)  {//中间值
					if (sign[k] == '|') {
						dp[i][i + cnt][1] += dp[i][k][0] * dp[k + 1][i + cnt][1] + dp[i][k][1] * dp[k + 1][i + cnt][0] + dp[i][k][1] * dp[k + 1][i + cnt][1];
						dp[i][i+cnt][0] += dp[i][k][0] * dp[k + 1][i+cnt][0];
					}
					else if (sign[k] == '&') {
						dp[i][i+cnt][1] += dp[i][k][1] * dp[k + 1][i+cnt][1];
						dp[i][i+cnt][0] += dp[i][k][0] * dp[k + 1][i+cnt][0] + dp[i][k][1] * dp[k + 1][i+cnt][0] + dp[i][k][0] * dp[k + 1][i+cnt][1];
					}
					else {
						dp[i][i+cnt][1] += dp[i][k][1] * dp[k + 1][i+cnt][0] + dp[i][k][0] * dp[k + 1][i+cnt][1];
						dp[i][i+cnt][0] += dp[i][k][0] * dp[k + 1][i+cnt][0] + dp[i][k][1] * dp[k + 1][i+cnt][1];
					}
				}
			}
		}
		return dp[0][nlen-1][r];
	}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值