2016网易游戏 游戏研发岗 在线笔试解题报告

原文链接(http://blog.csdn.net/mottolinux/article/details/48502435)

A题 Amusing Digits

问题描述

给定一个数串,从中选出尽可能多的“9706”子串,要求每个digit的相对先后顺序不变且每个digit只能用一次,问最多可以选出多少个9706子串。

样例输入

4 
6097 
97069706 
997776600069 
123901370997606

样例输出

0 
2 
1 
2

解题思路
通过分析,本题满足使用贪心策略。考虑数串9799706,若选择数字9时,跳过第一个9选择第二个9,将会导致第一个数字7无法匹配,因此每次选择数字9时,优先最靠前没使用过的,可以达到最优。同理其他数字也满足该原则。

根据以上分析,容易得到思路:遍历整个数串,选取最靠前的9;若找到9,再选取9以后最靠前的7;依次同理把0和6找到。但很可惜,这样的解法是要TLE的,该方法的复杂度为O((k+1)*n),k为答案,n为(去掉其他无关数字后的)数串长度。构造输入99..977..700..066..6,每个数字都有10000个,这样程序就gg了。

换一种思路,考虑到每次遍历都是要选取最靠前的数字,而下一个候选数字又必须在前一个数字的后面。只考虑数字9和数字7,有效子串的个数实际上取决于有多少个7,每个7的前面都恰好有一个9和它对应。把数字0和6考虑进去同理,所以最终有效子串的个数,取决于有多少个6,每个6的前面都恰有一个0和它对应;这些0中的每一个,前面都恰有一个7和他对应……时间复杂度为O(n)。

#include <iostream>
#include <string>
using namespace std;

int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        string s;
        cin >> s;
        int sz = s.length();
        int c9, c7, c0, c6;
        c9 = c7 = c0 = c6 = 0;
        for (int i = 0; i < sz; i++)
        {
            switch(s[i])
            {
                case '9': c9++; break;
                case '7': if (c7 < c9) c7++; break;
                case '0': if (c0 < c7) c0++; break;
                case '6': if (c6 < c0) c6++; break;
            }
        }
        cout << c6 << endl;
    }
    return 0;
}

B题 Best Compression Algorithms

问题描述

给定一个字符串,仅有圆括号,大写字母和数字组成。字串的数字表示它前面的字母或者括号中的模式的个数,如A2表示AA,(BC)3表示BCBCBC;允许复合,如(A3(BC)2)2表示AAABCBCAAABCBC。求给定字符串展开后的长度(即不包含数字和括号的表示的长度)。

样例输入

4 
(AA)2A 
((A2B)2)2G 
WANGYI 
A2BC4D2

样例输出

5 
13 
6 
9

解题思路
该题的嵌套括号,可以联想到使用栈来保存每一层级的字符个数缓存。考虑变量k为某一层括号中的临时字符个数统计,初始为0,若遇到非括号嵌套的字符直接累加;若遇到左括号,将当前k的值压入栈,对k置0,统计下一层括号中字符个数;若遇到右括号,则将栈顶元素弹出(表示上一层字符个数的缓存),累加到k。

#include <iostream>
#include <stack>
#include <string>

using namespace std;

inline bool isdigit(char c)
{
    return c >= '0' && c <= '9'; 
}

inline bool isalpha(char c)
{
    return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); 
}

int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        long long res = 0;
        string s;
        cin >> s;
        int sz = s.length();
        long long i = 0, k = 0;
        stack<long long> st;
        while (i < sz)
        {
            if (s[i] == '(')
            {
                st.push(k);
                k = 0;
                i++;
            }
            else if (s[i] == ')')
            {
                i++;
                long long count = 0;
                while (i < sz && isdigit(s[i]))
                {
                    count = count * 10 + s[i] - '0';
                    i++;
                }
                long long t = st.top(); st.pop();
                k = k * count + t;
            }
            else if (isalpha(s[i]))
            {
                if (i < sz-1 && isdigit(s[i+1]))
                {
                    i++;
                    long long count = 0;
                    while (i < sz && isdigit(s[i]))
                    {
                        count = count * 10 + s[i] - '0';
                        i++;
                    }
                    k += count;
                }
                else
                {
                    k += 1;
                    i++;
                }
            }
        }
        cout << k << endl;
    }
    return 0;
}

C题 Complicated Expression

问题描述

编写一个简易的Lisp解释器。只包含三种运算符+ - *,操作数均为非负整数组成。 
语法:每个计算表达式必须包含在一对圆括号内,而且由一个运算符和至少一个操作数组成,格式为(运算符 操作数1 操作数2 ...),允许嵌套,即操作数本身也可以是计算表达式。如: 
(+ 9) 表示正整数9; 
(+ 1 2) 代表 1 + 2; 
(+ 1 2 3 4) 代表 1, 2, 3, 4 的连加和。 
(- 9) 表示整数-9; 
(- 5 4) 代表 5 - 4。 
(* 2 3) 代表 2 * 3; 
(* 1 2 3 4) 代表 1 * 2 * 3 * 4。 
(+ (* 2 3) 1) 也是一个合法的表达式,代表了 2 * 3 + 1 
注意,-运算不能有超过2个操作数;*运算不能只有1个操作数。 
运算符、圆括号、操作数之间,在不引起歧义的前提下,允许有任意个空格(包括0个)。 
输入一个表达式,首先判断它是否合法的,若不合法输出invalid expression 否则输出表达式的值。

样例输入

5 
(+ 1 (* 2 3))) 
(2 3) 
(- 3 2 1) 
(+ (+ 1 2) (* 2 3) (- 2 1)) 
(- 2)

样例输出

invalid expression 
invalid expression 
invalid expression 
10 
-2

解题思路
本题可以直接根据Lisp的“代换规则(substitution rule)”为思路,递归求值表达式:将表达式中的运算符、操作数依次压入栈,若遇到操作数为一个子表达式,先递归计算子表达式,返回值再压入栈,最后对栈中的运算符、操作数进行计算。注意判断哪些情况为非法表达式。先考虑整个表达式的括号是否匹配,对后面的操作会方便一些。

#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <stack>

using namespace std;

char s_cstr[1000006];

inline bool isdigit(char c)
{
    return c >= '0' && c <= '9'; 
}

long long eval(string & s, bool & is_invalid)
{
    int sz = s.length();
    stack<long long> st;
    int i = 0;
    int ops = -1;
    if (is_invalid || sz == 0) goto fail_exit;
    while (i < sz)
    {
        if (s[i] == '+' || s[i] == '-' || s[i] == '*')
        {
            if (!st.empty()) goto fail_exit;
            switch(s[i])
            {
                case '+': st.push(0); ops = 0; break;
                case '-': st.push(1); ops = 1; break;
                case '*': st.push(2); ops = 2; break;
            }
            i++;
        }
        else if (isdigit(s[i]))
        {
            if (st.empty()) goto fail_exit;
            long long count = 0;
            do
            {
                count = count * 10 + s[i++] - '0';
            } while (i < sz && isdigit(s[i]));
            st.push(count);
        }
        else if (s[i] == '(')
        {
            string s1;
            i++;
            int m = 0;
            while (i < sz && m >= 0)
            {

                if (s[i] == '(') m++;
                else if (s[i] == ')')
                {
                    if (m > 0) m--;
                    else break;
                }
                s1 += s[i++];
            }
            long long res = eval(s1, is_invalid);
            if (is_invalid) return -1;
            st.push(res);
            i++;
        }
        else i++;
    }

    if (st.size() < 2 || ops == -1)     goto fail_exit;
    else if (ops == 1 && st.size() > 3) goto fail_exit;
    else if (ops == 2 && st.size() < 3) goto fail_exit;

    if (ops == 0)
    {
        long long res = 0;
        while (!st.empty())
        {
            res += st.top();
            st.pop();
        }
        return res;
    }
    if (ops == 1)
    {
        if (st.size() == 2)
        {
            return -st.top();
        }
        else 
        {
            long long i1 = st.top(); st.pop();
            long long i2 = st.top(); st.pop();
            return i2 - i1;
        }
    }
    if (ops == 2)
    {
        long long res = 1;
        while (st.size() > 1)
        {
            res *= st.top();
            st.pop();
        }
        return res;
    }

fail_exit:
    is_invalid = true;
    return -1;      
}

int main()
{
    int T;
    cin >> T;
    fgets(s_cstr, 1000000, stdin);
    while (T--)
    {
        fgets(s_cstr, 1000000, stdin);
        string s(s_cstr, 0, strlen(s_cstr)-1);
        int sz = s.length();
        if (!(s[0] == '(' && s[sz-1] == ')'))
        {
            cout << "invalid expression\n";
            continue;
        }
        stack<int> st;
        bool is_invalid = false;
        for (int i = 0; i < sz; i++)
        {
            if (s[i] == '(') st.push(i);
            else if(s[i] == ')')
            {
                if (st.empty())
                {
                    is_invalid = true;
                    break;
                }
                int j = st.top(); st.pop();
            }
        }
        if (is_invalid || !st.empty())
        {
            cout << "invalid expression\n";
            continue;
        }

        string s1(s, 1, sz-2);
        int res = eval(s1, is_invalid);
        if (is_invalid)
        {
            cout << "invalid expression\n";
            continue;
        }
        else 
        {
            cout << res << endl;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值