招商银行信用卡中心2019秋招IT笔试(AI、开发、测试开发方向)第三批

员工考勤记录

题目

给定一个字符串来代表一个员工的考勤纪录,这个纪录仅包含以下两个字符:

'A' : Absent,缺勤
'P' : Present,到场

如果一个员工的考勤纪录中不超过两个'A'(缺勤),那么这个员工会被奖赏。

如果你作为一个员工,想在连续N天的考勤周期中获得奖赏,请问有多少种考勤的组合能够满足要求

输入描述:

考勤周期的天数N(正整数)

输出描述:

N天里能获得奖赏的考勤组合数

样例:

3
>--------------------------------------------------<
7

解析

C n 2 + C n 1 + C n 0 C_n^2+C_n^1+C_n^0 Cn2+Cn1+Cn0

#include 

int main()
{
    for (int n; std::cin >> n; std::cout << n * (n - 1) / 2 + n + 1 << std::endl) {}
    return 0;
}

解码方法

题目

一条包含字母 A-Z 的消息通过以下方式进行了编码:

'A' -> 1
'B' -> 2
...
'Z' -> 26

给定一个只包含数字的非空字符串,请计算解码方法的总数。

输入描述:

一串编码过的数字,比如12

输出描述:

解码方法的总数

样例:

12
>--------------------------------------------------<
2

解析

基本动态规划,注意数字为0, 0[0-9], 2[7-9], [3-9][0-9]是不合法的。

#include 

int main()
{
    for (std::string str; std::cin >> str; ) {
        int dp[2];
        if (str.size() >= 1)
            dp[0] = str.front() != '0';
        if (str.size() >= 2)
            dp[1] = (str.front() != '0' && (str[0] == '1' || (str[0] == '2' && str[1] <= '6'))) + (str[1] != '0' ? dp[0] : 0);
        for (unsigned i = 2; i < str.size(); ++i)
            dp[i & 1] = (str[i] != '0' ? dp[(i - 1) & 1] : 0) +
                    (str[i - 1] != '0' && (str[i - 1] == '1' || (str[i - 1] == '2' && str[i] <= '6')) ? dp[(i - 2) & 1] : 0);
        std::cout << dp[(str.size() - 1) & 1] << std::endl;
    }
    return 0;
}

漂流船问题

题目

公司组织团建活动,到某漂流圣地漂流,现有如下情况:
员工各自体重不一,第 i 个人的体重为 people[i],每艘漂流船可以承载的最大重量为 limit
每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit
为节省开支,麻烦帮忙计算出载到每一个人所需的最小船只数(保证每个人都能被船载)。

输入描述:

第一行输入参与漂流的人员对应的体重数组

第二行输入漂流船承载的最大重量

输出描述:

所需最小船只数

样例:

1 2
3
>--------------------------------------------------<
1

解析

贪心,尽可能让每条船满负荷。

#include 

int main()
{
    std::string arrString;
    std::getline(std::cin, arrString);
    std::stringstream sin(arrString);
    std::multiset<int> arr;
    for (int x; sin >> x; arr.emplace(x)) {}
    int limit, ans = 0;
    std::cin >> limit;
    for (auto it = std::begin(arr); it != std::end(arr); ) {
        auto pos = arr.find(limit - *it);
        if (pos != std::end(arr) && it != pos) {
            arr.erase(pos);
            it = arr.erase(it);
            ++ans;
        } else {
            ++it;
        }
    }
    for (auto it = std::begin(arr); it != std::end(arr); ) {
        auto pos = arr.upper_bound(limit - *it);
        if (pos != std::begin(arr) && pos != ++std::begin(arr) && *std::prev(pos) < limit - *it) {
            arr.erase(--pos);
            it = arr.erase(it);
            ++ans;
        } else {
            it = arr.erase(it);
            ++ans;
        }
    }
    std::cout << ans << std::endl;
    return 0;
}

挑选代表

题目

我们有很多区域,每个区域都是从ab的闭区间,现在我们要从每个区间中挑选至少2个数,那么最少挑选多少个?

输入描述:

第一行是NN<10000),表示有N个区间,之间可以重复

然后每一行是ai,bi,持续N行,表示现在区间。均小于100000

输出描述:

输出一个数,代表最少选取数量。

样例:

4
4 7
2 4
0 2
3 6
>--------------------------------------------------<
4

解析

这个题是典型的区间选点的变形。原题是POJ - 1716。

区间选点问题的链接:POJ - 1328,要求每个区间至少一个点。

而这个题要求每个区间至少两个点。

一样的啊,贪心,按右端点排序(左端点一样可以),如果每个区间至少一个点,那么这个点一定是在右端点,这样子可以让后续的区间更容易覆盖到这个点,从而减少选点的数量;同理,如果每个区间至少两个点,那个这个两个点一定也在右端点和右端点前一个点,原因是一样的。

这个题还可以扩展成每个区间至少三个点,四个点…

终极扩展是POJ - 1201。每个区间至少c[i]个点。一样可以贪心搞,只不过要用树状数组维护一下而已。

不过这类题还可以用差分约束系统来搞,这里就不细说了。有兴趣自己可以学一下。

#include 

int main()
{
    for (int n; std::cin >> n; ) {
        typedef std::pair<int, int> Line;
        std::vector<Line> lines;
        for (int i = 0, x, y; i < n; std::cin >> x >> y, lines.emplace_back(x, y), ++i) {}
        std::sort(std::begin(lines), std::end(lines), [] (const Line & A, const Line & B) {
            return A.second < B.second;
        });
        std::vector<int> points {lines[0].second - 1, lines[0].second};
        for (int i = 1; i < n; ++i) {
            if (lines[i].first <= points[points.size() - 2]) {
                nullptr;
            } else if (lines[i].first <= points.back()) {
                if (lines[i].second != points.back()) points.emplace_back(lines[i].second);
            } else {
                points.emplace_back(lines[i].second - 1);
                points.emplace_back(lines[i].second);
            }
        }
        std::cout << points.size() << std::endl;
    }
    return 0;
}

目的地最短步数

题目

考虑你从家出发步行去往一处目的地,该目的地恰好离你整数单位步长(大于等于1)。你只能朝向该目的地或者背向该目的地行走,而你行走的必须为单位步长的整数倍,且要求你第N次行走必须走N步。

请就给出目的地离你距离,判断你是否可以在有限步内到达该目的地。如果可以到达的话,请计算到达目的地的最短总步数(不能到达则输出-1)。

输入描述:

1个整数:目的地离你距离T

输出描述:

1个整数:最短总步数(进行了多少次行走)

样例:

2
>--------------------------------------------------<
3

解析

暴力 B F S BFS BFS,注意,这个题不可能出现-1这种情况(左边走一次,右边走一次,始终可以前进一);

还要注意,这个题不能保存走过的点,因为第一次走过的点,再次走也许就是最短路径。

#include 

int main()
{
    for (int n; std::cin >> n; ) {
        std::queue< std::pair<int, int> > que;
        int ans = -1;

        que.emplace(0, 0);

        while (true) {
            std::pair<int, int> now = que.front();
            que.pop();

            if (now.first == n) {
                ans = now.second;
                break;
            }
            que.emplace(now.first + now.second + 1, now.second + 1);
            que.emplace(now.first - now.second - 1, now.second + 1);
        }
        std::cout << ans << std::endl;
    }
    return 0;
}

你可能感兴趣的:(算法,笔试面试题)