华为笔试题

1、全量字符集与已占用字符集 

输入描述:
输入一个字符串,字符串中包含了全量字符集和已占用字符集,两个字符集用@相连。@前的字符集合为全量字符集,@后的字符集为已占用字符集合。已占用字符集中的字符一定是全量字符集中的字符。字符集中的字符跟字符之间使用英文逗号分隔。字符集中的字符表示为字符加数字,字符跟数字使用英文冒号分隔,比如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

说明:全量字符集为3个a,5个b,2个c。已占用字符集为1个a,2个b。由于已占用字符集不能再使用,因此,剩余可用字符为2个a,3个b,2个c。因此输出a:2,b:3,c:2。注意,输出的字符顺序要跟输入一致。不能输出b:3,a:2,c:2。如果某个字符已全被占用,不需要输出。例如a:3,b:5,c:2@a:3,b:2,输出为b:3,c:2。

 用正则表达式分割。

#include 
using namespace std;

int main()
{
    string str;
    getline(cin, str);
    int i = 0, n = str.size();
    while(i < n && str[i] != '@') i++;
    string all = str.substr(0, i);
    i++;
    string used;
    if(i < n) used = str.substr(i);
    regex re(R"(([a-zA-Z]):(\d+))");
    vector hash(256, 0);
    int cnt = 0;
    vector input;
    for(sregex_token_iterator it(all.begin(), all.end(), re), end; it != end; it++)
    {
        string sub = *it;
        smatch m;
        if(regex_match(sub, m, re))
        {
            string character = m[1];
            int val = stoi(m[2]);
            hash[character[0]] = val;
            if(val > 0) cnt++;
            input.emplace_back(character[0]);
        }
    }
    for(sregex_token_iterator it(used.begin(), used.end(), re), end; it != end; it++)
    {
        string sub = *it;
        smatch m;
        if(regex_match(sub, m, re))
        {
            string ch = m[1];
            int val = stoi(m[2]);
            hash[ch[0]] -= val;
            if(hash[ch[0]] == 0) cnt--;
        }
    }
    for (int j = 0; j < input.size(); ++j)
    {
        if(hash[input[j]] > 0)
        {
            printf("%c:%d", input[j], hash[input[j]]);
            cnt--;
            if(cnt > 0) printf(";");
        }
    }
    return 0;
}

 

 2、逻辑计算

题目描述:

常用的逻辑计算有And(表示为&);Or(表示为|);Not(表示为!)。其中,他们的优先级关系是Not(!)>And(&)>Or(|)。

输入描述:

1、测试用例中间无空格,无需考虑空格。

2、测试用例表达式只会出现如下字符:“0”,“1”,“(”,“)”,“&”,“|”,“!”。

3、测试用例所给的输入都是合法输入,无需要考虑非法输入。

4、测试用例长度不会超过128个字符。

5、括号可以重复嵌套。

例如:

1 | ( 1 & 0 )                       返回值:1

1 & 0 | 0 & 1                     返回值:0

! 0 & 1 | 0                          返回值:1

( ( ! 0 & 1 ) ) | 0                 返回值:1

输出描述:

输出逻辑运算后的最终结果:0或者1

示例1:
输入:! ( 1 & 0 ) | 0 & 1

输出:1

示例2:
输入:! ( 1 & 0 ) & 0 | 0

输出:0
 

中缀转后缀,再用后缀表达式求值。

(1) 中缀转后缀的步骤:使用栈存储运算符,预定义运算符的优先级。然后,遍历中缀表达式:

(a) 如果是左括号,压栈;

(b) 如果是右括号,直到栈顶是左括号为止,持续出栈,附到后缀表达式后面。之后,将左括号出栈。

(c) 如果是运算符,从栈顶将所有优先级大于等于当前的运算符持续出栈,直到栈顶运算符优先级小于当前运算符为止。之后,将当前运算符压栈。

(d) 如果是操作数,直接附到后缀表达式的后面。

最后,直到栈为空为止,持续出栈,附到后缀表达式后面。

(2) 使用后缀表达式求值相比之下就很简单,使用栈存储操作数,当遍历到运算符时,取出栈顶的1个或者2个元素进行运算,将结果压栈。最后,栈中剩下的那一个值就是运算结果。

#include 
using namespace std;

//中缀转后缀
void convert(string& in, string& post)
{
    vector hash(256, 0);
    hash['&'] = 1;
    hash['!'] = 2;
    stack op;
    for(char c : in)
    {
        if(c == '(') op.push('(');
        else if(c == ')')
        {
            while(!op.empty() && op.top() != '(')
            {
                post += op.top();
                op.pop();
            }
            op.pop();
        }
        else if(c == '&' || c == '|' || c == '!')
        {
            while(!op.empty() && hash[op.top()] >= hash[c])
            {
                post += op.top();
                op.pop();
            }
            op.push(c);
        }
        else if(isdigit(c)) post += c;
    }
    while(!op.empty())
    {
        post += op.top();
        op.pop();
    }
}

//使用后缀表达式计算
char calc(string& post)
{
    stack st;
    for(char c : post)
    {
        if(c == '0') st.push(false);
        else if(c == '1') st.push(true);
        else if(c == '!')
        {
            bool top = st.top();
            st.pop();
            st.push(!top);
        }
        else if(c == '&')
        {
            bool a = st.top();
            st.pop();
            bool b = st.top();
            st.pop();
            st.push(a & b);
        }
        else if(c == '|')
        {
            bool a = st.top();
            st.pop();
            bool b = st.top();
            st.pop();
            st.push(a | b);
        }
    }
    return st.top() ? '1' : '0';
}

int main()
{
    string str;
    while(getline(cin, str))
    {
        string post;
        convert(str, post);
        printf("%c\n", calc(post));
    }
    return 0;
}

 

3. 四则运算

https://www.nowcoder.com/practice/9999764a61484d819056f807d2a91f1e?tpId=37&&tqId=21273&rp=1&ru=/ta/huawei&qru=/ta/huawei/question-ranking

同样是中缀转后缀的做法,但是要注意'-'的处理,如果是做负号用,需要变成减法的形式。

对于比较弱的数据,'-'作负号用时只出现在首位或者'('的后面,所以只需要判断下'-'是否是在首位,或者'('的后面,如果是就变成"0-"即可。

        //先把括号换掉
        for(char& c : str)
        {
            if(c == '[' || c == '{') c = '(';
            else if(c == ']' || c == '}') c = ')';
        }
        //处理负号
        string tmp;
        int i = 0, n = str.size();
        while(i < n)
        {
            if(str[i] == '-')
            {
                if(i == 0 || str[i-1] == '(')
                {
                    tmp += "0-";
                    i++;
                }
                else tmp += str[i++];
            }
            else tmp += str[i++];
        }

对于比较强的数据,如2*-(2*3+(6+3)*5)这种,就要严谨的判断负号作用的起点和终点,然后变成"(0-...)"的形式:

(1) 首先判断是否是负号:当'-'前面为空,或者前面的字符不是数字,就是负号

(2) 然后判断负号作用的起点和终点:如果'-'后面的字符是数字,那么'-'的作用范围就是后面的连续数字字符串。否则,'-'的后面是'(',那么要一直往后统计左括号和右括号的个数,直到二者匹配,说明括号匹配结束,找到了'-'的作用范围。

        //先把括号换掉
        for(char& c : str)
        {
            if(c == '[' || c == '{') c = '(';
            else if(c == ']' || c == '}') c = ')';
        }
        //处理负号
        string tmp;
        int i = 0, j = 0, n = str.size();
        while(i < n)
        {
            if(str[i] == '-')
            {
                //‘-’的前面不是')',并且'-'的前面也不是数字,那么'-'是负号,要变成 (0-...)
                if(tmp.empty() || (tmp.back() != ')' && !isdigit(tmp.back())))
                {
                    if(i + 1 < n && isdigit(str[i+1]))
                    {
                        j = i + 2;
                        while(j < n && isdigit(str[j])) j++;
                        //[i+1...j-1]
                        tmp += "(0-" + str.substr(i+1, j - i - 1) + ")";
                        i = j;
                    }
                    else if(i + 1 < n && str[i+1] == '(')
                    {
                        int leftcnt = 1;
                        j = i + 2;
                        while(j < n)
                        {
                            if(str[j] == ')')
                            {
                                if(--leftcnt == 0) break;
                            }
                            else if(str[j] == '(') leftcnt++;
                            j++;
                        }
                        //[i+1...j]
                        tmp += "(0-" + str.substr(i+1, j - i);
                        i = j;
                    }
                    else i++;
                }
                else tmp += str[i++];
            }
            else tmp += str[i++];
        }

总体代码:数据较弱,不需要复杂的判断'-'的方法。

#include 
using namespace std;

int priority[128] = {0};

vector inToPost(const string& in)
{
    stack op;
    vector ans;
    int i = 0, j = 0, n = in.size();
    while(i < n)
    {
        if(in[i] == '(')
        {
            op.push(in[i++]);
        }
        else if(in[i] == ')')
        {
            while(!op.empty() && op.top() != '(')
            {
                ans.emplace_back(string(1, op.top()));
                op.pop();
            }
            op.pop();
            i++;
        }
        else if(isdigit(in[i]))
        {
            j = i + 1;
            while(j < n && isdigit(in[j])) j++;
            ans.emplace_back(in.substr(i, j - i));
            i = j;
        }
        else
        {
            while(!op.empty() && op.top() != '(' && priority[op.top()] >= priority[in[i]])
            {
                ans.emplace_back(string(1, op.top()));
                op.pop();
            }
            op.push(in[i++]);
        }
    }
    while(!op.empty())
    {
        ans.emplace_back(string(1, op.top()));
        op.pop();
    }
    return ans;
}

int calc(const vector& postorder)
{
    stack st;
    for(const auto& s : postorder)
    {
        if(isdigit(s[0])) st.push(stoi(s));
        else
        {
            int b = st.top();
            st.pop();
            int a = st.top();
            st.pop();
            if(s == "+") st.push(a+b);
            else if(s == "*") st.push(a*b);
            else if(s == "/") st.push(a/b);
            else st.push(a - b);
        }
    }
    return st.top();
}

int main(){
    priority['*'] = priority['/'] = 1;
    string str;
    while(getline(cin, str))
    {
        if(str.empty()) break;
        //先把括号换掉
        for(char& c : str)
        {
            if(c == '[' || c == '{') c = '(';
            else if(c == ']' || c == '}') c = ')';
        }
        //处理负号
        string tmp;
        int i = 0, n = str.size();
        while(i < n)
        {
            if(str[i] == '-')
            {
                if(i == 0 || str[i-1] == '(')
                {
                    tmp += "0-";
                    i++;
                }
                else tmp += str[i++];
            }
            else tmp += str[i++];
        }
        printf("%d\n", calc(inToPost(tmp)));
    }
    return 0;
}

 

你可能感兴趣的:(华为笔试题)