表达式得到期望结果的组合种数

https://www.nowcoder.com/practice/9690bd908d5b4f9b91640fa835ef6f4ftpId=101&tqId=33115&tPage=1&rp=1&ru=/ta/programmer-code-interview-guide&qru=/ta/programmer-code-interview-guide/question-ranking

 

题目描述

给定一个只由0(假)、1(真)、&(逻辑与)、|(逻辑或)和^(异或)五种字符组成的字符串express,再给定一个布尔值desires。求出express能有多少种组合方式,可以达到desired的结果。并输出你所求出的总方案数对10^9+7取模后的值。

输入描述:

输出两行,第一行包含一个只有0、1、&、|和^组成的字符串。其长度小于500,第二行只有一个布尔值,代表desired。

输出描述:

输出一个整数,表示取模后的答案。

示例1

输入

1^0|0|1
false

输出

2

说明

1^((0|0)|1)和1^(0|(0|1))可以得到false

示例2

输入

1
false

输出

0

备注:

时间复杂度O(n^3),空间复杂度O(n^2)。
//方法一:暴力枚举 O(n!) O(n)
//运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。
//case通过率为15.00%
#include
using namespace std;
const int number=1000000007;
bool isValid(const string& exp) {
	if ((exp.size() & 1) == 0) {
		return false;
	}
	for (int i = 0; i < exp.size(); i += 2) {
		if (exp[i] != '1' && exp[i] != '0') {
			return false;
		}
	}
	for (int i = 1; i < exp.size(); i += 2) {
		if (exp[i] != '&' && exp[i] != '|' && exp[i] != '^') {
			return false;
		}
	}
	return true;
}

long long p(const string& exp, const string& desired, int left, int right) {
	if (left == right) {
		if (exp[left] == '1') {
			return desired=="true" ? 1 : 0;
		}
		else {  //exp[left]=='0'
			return desired=="true" ? 0 : 1;
		}
	}
	long long res = 0;
	if (desired=="true") { //desired==true
		for (int i = left + 1; i < right; i += 2) {
			if (exp[i] == '&') {
				res += p(exp, "true", left, i - 1)*p(exp, "true", i + 1, right);
                res%=number;
			}
			else if (exp[i] == '|') {
				res += p(exp, "true", left, i - 1)*p(exp, "true", i + 1, right);
				res += p(exp, "true", left, i - 1)*p(exp, "false", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "true", i + 1, right);
                res%=number;
			}
			else { //exp[i]=='^'
				res += p(exp, "true", left, i - 1)*p(exp, "false", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "true", i + 1, right);
                res%=number;
			}
		}
	}
	else {       //desired==false
		for (int i = left + 1; i < right; i += 2) {
			if (exp[i] == '&') {
				res += p(exp, "true", left, i - 1)*p(exp, "false", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "true", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "false", i + 1, right);
                res%=number;
			}
			else if (exp[i] == '|') {
				res += p(exp, "false", left, i - 1)*p(exp, "false", i + 1, right);
                res%=number;
			}
			else { //exp[i]=='^'
				res += p(exp, "true", left, i - 1)*p(exp, "true", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "false", i + 1, right);
                res%=number;
			}
		}
	}
	return res;
}

int main() {
	string exp,desired;
	cin >> exp >> desired;
    int n=exp.size();
	if (!isValid(exp)) {
		cout << 0 << endl;
	}
	else {
		cout << p(exp, desired, 0, n - 1)%number << endl;
	}
	system("pause");
	return 0;
}
//方法二:记忆化搜索,减支   通过
#include
using namespace std;

const int number=1000000007;
vector> memoT;
vector> memoF;

bool isValid(const string& exp) {
	if ((exp.size() & 1) == 0) {
		return false;
	}
	for (int i = 0; i < exp.size(); i += 2) {
		if (exp[i] != '1' && exp[i] != '0') {
			return false;
		}
	}
	for (int i = 1; i < exp.size(); i += 2) {
		if (exp[i] != '&' && exp[i] != '|' && exp[i] != '^') {
			return false;
		}
	}
	return true;
}

long long p(const string& exp, const string& desired, int left, int right) {
	if (left == right) {
		if (exp[left] == '1') {
			return desired=="true" ? 1 : 0;
		}
		else {  //exp[left]=='0'
			return desired=="true" ? 0 : 1;
		}
	}
	long long res = 0;
	if (desired=="true") { //desired==true
        if(memoT[left][right]!=-1){
            return memoT[left][right];
        }
		for (int i = left + 1; i < right; i += 2) {
			if (exp[i] == '&') {
				res += p(exp, "true", left, i - 1)*p(exp, "true", i + 1, right);
                res%=number;
			}
			else if (exp[i] == '|') {
				res += p(exp, "true", left, i - 1)*p(exp, "true", i + 1, right);
				res += p(exp, "true", left, i - 1)*p(exp, "false", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "true", i + 1, right);
                res%=number;
			}
			else { //exp[i]=='^'
				res += p(exp, "true", left, i - 1)*p(exp, "false", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "true", i + 1, right);
                res%=number;
			}
		}
        memoT[left][right]=res;
	}
	else {       //desired==false
        if(memoF[left][right]!=-1){
            return memoF[left][right];
        }
		for (int i = left + 1; i < right; i += 2) {
			if (exp[i] == '&') {
				res += p(exp, "true", left, i - 1)*p(exp, "false", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "true", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "false", i + 1, right);
                res%=number;
			}
			else if (exp[i] == '|') {
				res += p(exp, "false", left, i - 1)*p(exp, "false", i + 1, right);
                res%=number;
			}
			else { //exp[i]=='^'
				res += p(exp, "true", left, i - 1)*p(exp, "true", i + 1, right);
				res += p(exp, "false", left, i - 1)*p(exp, "false", i + 1, right);
                res%=number;
			}
		}
        
        memoF[left][right]=res; 
	}
    
	return res;
}

int main() {
	string exp,desired;
	cin >> exp >> desired;
    int n=exp.size();
    memoT=vector>(n,vector(n,-1));
    memoF=vector>(n,vector(n,-1));
	if (!isValid(exp)) {
		cout << 0 << endl;
	}
	else {
		cout << p(exp, desired, 0, n - 1)%number << endl;
	}
	system("pause");
	return 0;
}
//方法三:dp O(n^3) O(n^2)
#include
using namespace std;
const int number = 1000000007;
bool isValid(const string& exp) {
	if ((exp.size() & 1) == 0) {  //必须为奇数
		return false;
	}
	for (int i = 0; i < exp.size(); i += 2) {
		if (exp[i] != '1' && exp[i] != '0') {
			return false;
		}
	}
	for (int i = 1; i < exp.size(); i += 2) {
		if (exp[i] != '&' && exp[i] != '|' && exp[i] != '^') {
			return false;
		}
	}
	return true;
}

int main() {
	string exp,desired;
	cin >> exp >> desired;
	if (!isValid(exp)) {
		cout << 0 << endl;
		return 0;
	}

	int n = exp.size();
	vector> dpT(n, vector(n, 0));
	vector> dpF(n, vector(n, 0));
	for (int i = 0; i < n; i += 2) {
		dpT[i][i] = (exp[i] == '1') ? 1 : 0;
		dpF[i][i] = (exp[i] == '0') ? 1 : 0;
	}

	for (int i = 2; i < n; i += 2) {
		for (int j = i - 2; j >= 0; j -= 2) {
			for (int k = j; k < i; k += 2) {
				if (exp[k + 1] == '&') {
					dpT[j][i] += dpT[j][k] * dpT[k + 2][i];
					dpF[j][i] += dpT[j][k] * dpF[k + 2][i] + dpF[j][k] * dpT[k + 2][i] + dpF[j][k] * dpF[k + 2][i];
					dpT[j][i] %= number;
					dpF[j][i] %= number;
				}
				else if (exp[k + 1] == '|') {
					dpT[j][i] += dpT[j][k] * dpT[k + 2][i] + dpT[j][k] * dpF[k + 2][i] + dpF[j][k] * dpT[k + 2][i];
					dpF[j][i] += dpF[j][k] * dpF[k + 2][i];
					dpT[j][i] %= number;
					dpF[j][i] %= number;
				}
				else {
					dpT[j][i] += dpT[j][k] * dpF[k + 2][i] + dpF[j][k] * dpT[k + 2][i];
					dpF[j][i] += dpT[j][k] * dpT[k + 2][i] + dpF[j][k] * dpF[k + 2][i];
					dpT[j][i] %= number;
					dpF[j][i] %= number;
				}
			}
		}
	}

	if (desired=="true") {
		cout << dpT[0][n - 1] << endl;
	}
	else {
		cout << dpF[0][n - 1] << endl;
	}
	system("pause");
	return 0;
}

注:本体输入对于C++有陷阱,C++读入bool值是0和非0,而不是true和false(用true和false输入后,bool变量输出都是0)。

你可能感兴趣的:(面试指南,dp,牛客)