解题思路
这是一个逻辑表达式加括号问题。关键点:
-
预处理:
- 分离数字和运算符
- 数字在偶数位,运算符在奇数位
-
动态规划:
- 表示区间 得到值 的方案数
- 枚举分割点,计算所有可能组合
代码
class Expression {
public:
int countWays(string exp, int len, int ret) {
vector<int> nums((len + 1) / 2);
vector<char> ops(len / 2);
// 分离数字和运算符
for(int i = 0; i < len; i++) {
if(i % 2 == 0) {
nums[i/2] = exp[i] - '0';
} else {
ops[i/2] = exp[i];
}
}
return solve(nums, ops, ret);
}
private:
int cal(int a, int b, char op) {
switch(op) {
case '&': return a & b;
case '|': return a | b;
default: return a ^ b; // '^'
}
}
int solve(vector<int>& nums, vector<char>& ops, int target) {
int n = nums.size();
vector<vector<vector<int>>> dp(n, vector<vector<int>>(n, vector<int>(2, 0)));
// 初始化单个数字
for(int i = 0; i < n; i++) {
dp[i][i][nums[i]] = 1;
}
// 枚举长度和起点
for(int len = 2; len <= n; len++) {
for(int i = 0; i <= n - len; i++) {
int j = i + len - 1;
// 枚举分割点
for(int k = i; k < j; k++) {
// 计算所有可能的值组合
for(int v1 = 0; v1 <= 1; v1++) {
for(int v2 = 0; v2 <= 1; v2++) {
if(dp[i][k][v1] != 0 && dp[k+1][j][v2] != 0) {
int val = cal(v1, v2, ops[k]);
dp[i][j][val] = (dp[i][j][val] +
(long long)dp[i][k][v1] * dp[k+1][j][v2]) % 10007;
}
}
}
}
}
}
return dp[0][n-1][target];
}
};
public class Expression {
private int cal(int a, int b, char op) {
switch(op) {
case '&': return a & b;
case '|': return a | b;
default: return a ^ b; // '^'
}
}
private int solve(int[] nums, char[] ops, int target) {
int n = nums.length;
int[][][] dp = new int[n][n][2];
// 初始化单个数字
for(int i = 0; i < n; i++) {
dp[i][i][nums[i]] = 1;
}
// 枚举长度和起点
for(int len = 2; len <= n; len++) {
for(int i = 0; i <= n - len; i++) {
int j = i + len - 1;
// 枚举分割点
for(int k = i; k < j; k++) {
// 计算所有可能的值组合
for(int v1 = 0; v1 <= 1; v1++) {
for(int v2 = 0; v2 <= 1; v2++) {
if(dp[i][k][v1] != 0 && dp[k+1][j][v2] != 0) {
int val = cal(v1, v2, ops[k]);
dp[i][j][val] = (int)((dp[i][j][val] +
(long)dp[i][k][v1] * dp[k+1][j][v2]) % 10007);
}
}
}
}
}
}
return dp[0][n-1][target];
}
public int countWays(String exp, int len, int ret) {
int[] nums = new int[(len + 1) / 2];
char[] ops = new char[len / 2];
for(int i = 0; i < len; i++) {
if(i % 2 == 0) {
nums[i/2] = exp.charAt(i) - '0';
} else {
ops[i/2] = exp.charAt(i);
}
}
return solve(nums, ops, ret);
}
}
# -*- coding:utf-8 -*-
class Expression:
def cal(self, a, b, op):
if op == '&': return a & b
if op == '|': return a | b
return a ^ b # '^'
def solve(self, nums, ops, target):
n = len(nums)
dp = [[[0] * 2 for _ in xrange(n)] for _ in xrange(n)]
# Initialize single digits
for i in xrange(n):
dp[i][i][nums[i]] = 1
print("Initialize dp[%d][%d][%d] = 1" % (i, i, nums[i]))
# Enumerate length and start point
for l in xrange(2, n + 1):
for i in xrange(n - l + 1):
j = i + l - 1
print("Processing interval [%d, %d]" % (i, j))
# Enumerate split points
for k in xrange(i, j):
# Calculate all possible value combinations
for v1 in xrange(2):
for v2 in xrange(2):
if dp[i][k][v1] != 0 and dp[k+1][j][v2] != 0:
val = self.cal(v1, v2, ops[k])
dp[i][j][val] = (dp[i][j][val] +
dp[i][k][v1] * dp[k+1][j][v2]) % 10007
print("dp[%d][%d][%d] = %d" % (i, j, val, dp[i][j][val]))
print("Final result: %d" % dp[0][n-1][target])
return dp[0][n-1][target]
def countWays(self, exp, length, ret):
# Split numbers and operators
nums = [int(exp[i]) for i in xrange(0, length, 2)]
ops = [exp[i] for i in xrange(1, length, 2)]
print("Numbers: %s" % nums)
print("Operators: %s" % ops)
return self.solve(nums, ops, ret)
算法及复杂度
- 算法:区间动态规划
- 时间复杂度:
- 空间复杂度: