2020华为笔试编程题

第一题

给定两个字符集合,一个为全量字符集,一个为已占用字符集。已占用的字符集中的字符不能再使用,要求输出剩余可用字符集。
输入描述:输入为一个字符串,字符串中包含了全量字符集和已占用字符集,两个字符集使用@连接,前面为全量,后面为已占用。
已占用字符集中的字符一定是全量字符集中的字符。
字符集中的字符跟字符之间用英文逗号分隔。
字符集中的字符表示为字符加数字,字符跟数字使用英文冒号分隔,比如a:1,表示1个a字符。字符只考虑英文字母,区分大小写,数字只考虑正整形,数量不超过100,如果一个字符都没被占用,@标识仍然存在,例如a:3,b:5,c:2@
示例1:
输入
a:3,b:5,c:2@a:1,b:2
输出
a:2,b:3,c:2
注意:输出的字符顺序要跟输入一致!如果某个字符已全被占用,不需要再输出!
示例2:
输入
a:3,b:5,c:2@a:3,b:2
输出
b:3,c:2

分析

用映射来模拟即可。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;

char ss[100010];
map<char,int> mp;
char ans[60];

int main()
{
    cin>>ss;
    int len = strlen(ss);
    mp.clear();
    int sum = 0;
    int i;
    for (i=0 ; i<len ; i++){
        if ( (ss[i]>='a' && ss[i]<='z')||(ss[i]>='A' && ss[i]<='Z') ){
            char now = ss[i];
            i += 2;
            int data = 0;
            while (ss[i]>='0' && ss[i]<='9'){
                data = 10*data + ss[i]-'0';
                i++;
            }
            mp[now] = data;
            ans[sum] = now;
            sum++;
        }

        if (ss[i]=='@') break;
    }

    for (int j=i+1 ; j<len ; j++){
        if ( (ss[j]>='a' && ss[j]<='z')||(ss[j]>='A' && ss[j]<='Z') ){
            char now = ss[j];
            j += 2;
            int data = 0;
            while (ss[j]>='0' && ss[j]<='9'){
                data = 10*data + ss[j]-'0';
                j++;
            }
            mp[now] -= data;

        }
    }

    for (int k=0 ; k<sum ; k++){
        if (mp[ans[k]]){
            printf("%c:%d",ans[k],mp[ans[k]]);
            if (k < sum-1) printf(",");
        }

    }
    printf("\n");
    return 0;
}

第二题没看懂题目,时间不太够。。。

第三题

常用的逻辑计算有And(表示为&),Or(表示为|),Not(表示为!)。
它们的优先级关系是Not > And > Or
例如: A|B&C = A|(B&C)
A&B|C&D = (A&B)|(C&D)
!A&B|C = ((!A)&B)|C

输入描述:测试用例中间无空格,表达式只包含 0 , 1 , ( , ) , & , !, | , 保证输入为合法输入,长度不超过128字符,括号可以重复嵌套,例如((!0&1))|0 = 1。
输出描述:输出逻辑运算后的最终结果,0或者1

分析

显然这题直接输出0或者1可以至少通过50%的测试样例,如果时间不够的话就应该想到这种保底的做法,正确做法和实现一个四则运算计算器的做法差不多,先把字符串转为逆波兰式,然后计算逆波兰式,用栈搞来搞去。字符按顺序入栈,1.遇到数字,不进栈,直接放入逆波兰式中;2.遇到计算符,把它与栈顶字符进行优先级比较,如果栈顶的字符优先级大或者相同,则栈顶字符放入逆波兰式中,出栈一次,继续判断优先级直到当前计算符优先级比栈顶大,那么当前计算符入栈;3.遇到左括号,直接入栈,遇到右括号,开始出栈并且栈顶元素放入逆波兰式中,此操作可以保证括号内的运算顺序优先于括号外,直到左括号出栈则停止。
最后,把栈中元素全部取出按顺序放入逆波兰式中,由于入栈时保证了优先级是从小到大的,所以出栈以后逆波兰式肯定是按优先级从大到小计算。
计算逆波兰式,从前往后计算即可,遇到数字就入栈,遇到与和或操作则出栈两次,把两个数与(或),把结果入栈,遇到非操作,出栈,取非,结果入栈。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<stack>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long LL;

char ss[130],ss2[130];

int Precedence(char op)//运算符优先级判断
{
	switch(op)
	{
	case '|':
		return 1;
	case '&':
		return 2;
	case '!':
		return 3;
	case '(':
	case '\0':
	default:
		return 0; //定义在栈中的左括号和栈底字符的优先级为0
	}
}

void tonibolan(char *s1,char *s2)
{
    stack<char> s;
    s.push('\0');
    int i=0,j=0;
    char ch=s1[i];
    while (ch != '\0'){
        if (ch == '('){
                s.push('(');
                ch = s1[++i];

        }
        else if (ch == ')'){
            while (s.top() != '('){
                    s2[j++] = s.top();
                    s.pop();
            }
            s.pop();
            ch = s1[++i];
        }
        else if (ch=='!' || ch=='&' || ch=='|'){
            char w=s.top();
            while (Precedence(w) >= Precedence(ch)){
                s2[j++] = w;
                s.pop();
                w = s.top();
            }
            s.push(ch);
            ch = s1[++i];

        }
        else {
            if (ch=='0' || ch=='1'){
                s2[j++] = ch;
                ch = s1[++i];
            }
            s2[j++] = ' ';
        }
    }
    ch =  s.top();
    s.pop();
    while (ch != '\0'){
        s2[j++] = ch;
        ch = s.top();
        s.pop();
    }
    s2[j++] = '\0';
    cout<<s2<<endl;
}

int nibolan(char *s)
{
    stack<int> sd;
    int i=0,num1,num2,n1,n2,n3;
    while (s[i] != '\0'){
        num1 = 0;
        num2 = 1;
        if (s[i]=='0' || s[i]=='1'){
            num1 = s[i]-'0';
            i++;
            sd.push(num1);
        }
        else if (s[i]==' ')
            i++;
        else if (s[i]=='!'){
            n1 = sd.top();
            sd.pop();
            n2 = !n1;
            sd.push(n2);
            i++;
        }
        else if (s[i]=='&'){
            n1 = sd.top();
            sd.pop();
            n2 = sd.top();
            sd.pop();
            n3 = n1&n2;
            sd.push(n3);
            i++;
        }
        else if (s[i]=='|'){
            n1 = sd.top();
            sd.pop();
            n2 = sd.top();
            sd.pop();
            n3 = n1|n2;
            sd.push(n3);
            i++;
        }
    }
    return sd.top();
}

int main()
{
    cin>>ss;
    tonibolan(ss,ss2);
    cout<<nibolan(ss2)<<endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值