校园招聘-2017美团后台开发内推笔试编程题


笔试题型:20道智力题 + 30道选择题 + 2道编程题

考试时间:140min


1. 求K倍数的最长子串

  • 题目描述

    序列中任意个连续的元素组成的子序列称为该序列的子串。

    现给你一个序列P和一个整数K,询问元素和是K的倍数的子串的最大长度。

    比如序列【1,2,3,4,5】,给定的整数K为5,其中满足条件的子串为{5}、{2,3}、{1,2,3,4}、{1,2,3,4,5},那么答案就是5,因为最长的子串为{1,2,3,4,5};如果满足条件的子串不存在,就输出0。

  • 输入

    第一行一个整数N,1<=N<=10^5.

    第二行包含N个整数p(i),p(i)表示序列P第i个元素的值,0<=p(i)<=10^5.

    第三行包含一个整数K,1<=K<=10^5.

  • 输入

    输出一个整数ANS,表示答案。

  • 样例输入

    Input Sample 1
    5
    1 2 3 4 5
    5
    Input Sample 2
    6
    3 1 2 7 7 7
    4
  • 样例输出

    Output Sample 1
    5
    Output Sample 2
    5
  • 时间内存限制

    时间限制:C/C++语言 2000ms;其他语言4000ms
    内存限制:C/C++语言65536K;其他语言589824K

  • 解题思路

    建立N+1个元素的统计数组,该数组第i个元素为对应的输入数组的前i个元素之和对K取余的结果,即:

    sum[0] = 0,
    sum[1] = a[0] % K,
    sum[2] = (a[0] + a[1]) % K,

    sum[N] = (a[0] + a[1] + … +a[N - 1]) % K

    这样,当sum[i] = sum[j]时,(j - i)就表示这时的K倍数的子串长度。

    sum[i]和sum[j]要么都为0,要么都为小于K的一个数,相等时即表示从i到j的子串之和为K的整数倍。

    求余定理:(a - b) % K = (a % K - b % K) % K

  • 代码(C)

#include <stdio.h>
#include <string.h>

int FindLongestSeq(int *str, int N);

int main()
{
    //输入
    int N;
    scanf("%d", &N);
    int array[N];
    memset(array, 0, N);
    int i = 0;
    while (i < N)
    {
        scanf("%d", &array[i]);
        i++;
    }
    int K;
    scanf("%d", &K);

    //建立统计数组
    int sum[N + 1];
    int n = 0;
    for (; n< N + 1; n++)   //不能通过memset()初始化
        sum[n] = 0;         //sum[0] = 0,避免遗漏最长子串为原序列的情况
    int j, k;
    for (j = 0; j < N; j++)
    {
        for (k = j; k >= 0; k--)
        {
            sum[j + 1] = sum[j + 1] + array[k];
        }
        sum[j + 1] = sum[j + 1] % K;
    }

    //函数调用输出
    int ret = FindLongestSeq(sum, N);
    printf("%d\n",ret);
    return 0;
}


int FindLongestSeq(int *sum, int N)
{
    int i = 0, j = N;
    while (j > 0)
    {
        for (i = 0; i < j; i++)
        {
            if (sum[i] == sum[j])     //因为j逐渐减小,相等即达到最长,返回
            {
                return j - i;
            }
        }
        i = 0;
        j--;
    }
    return j - i;                     //不存在,返回0
}


2. 改考卷

  • 题目描述

    在上小学的时候,我们经常碰到这样的事:考完试后老师懒得改试卷,于是让我们同桌互相交换试卷后为对方批改。但是后来老师发现这样做容易出现作弊,于是他想了一个新办法。老师将同学分成了n个组,其中编号为i的组有s(i)个人,然后老师会按某种顺序依次访问这些组。

    对于他访问的第一组,他会将这组内的所有试卷都收走,放置在桌上;
    对于他后续访问的每一个组,首先他会从桌上的试卷最上方拿出该组对应人数数量的试卷,随机分配给该组每个人一张试卷让他们进行批改,而后将这组学生自己考的试卷收走放置在桌面试卷的最下方。当他访问完所有的组后他会将桌面上剩余的所有试卷随机分配给他第一个访问的组的学生进行批改。

    但他发现这种方法也会出现问题:
    [1] 有可能在中途访问到某个组的时候桌面上的试卷不够分配给这组学生每人一张;
    [2] 也有可能最后会有学生分配到改自己的试卷,而且这两种情况是否出现是与他访问每个组的顺序有关的。

    现在他想知道是否存在一种访问顺序能够使以上两种情况都不出现,顺利完成试卷批改呢?

  • 输入

    第一行一个整数n,表示学生组数。2 <= n <= 30

    第二行包含n个整数,s(1),s(2),…,s(n),分别表示每组学生的人数。1 <= s(i) <= 10000

  • 输出

    若存在一种访问顺序能使试卷顺利批改完成,输出 Yes,否则输出 No。

  • 样例输入

    Input Sample 1
    2
    10 20
    Input Sample 2
    4
    2 3 3 1
  • 样例输出

    Output Sample 1
    No
    Output Sample 2
    Yes
  • Hint

    对于第2组样例,我们可以选择先访问人数为3的组,再访问人数为3的组,再访问人数为1的组,最后访问人数为2的组。

  • 时间内存限制

    时间限制:C/C++语言 2000ms;其他语言4000ms
    内存限制:C/C++语言65536K;其他语言589824K

  • 解题思路

    为了避免第一种情况的出现,应该首先访问人数最多的组,保证能有足够多的试卷分给下一个要访问的组。

    为了避免第二种情况的出现,人数最多的组的人数应该不小于其他所有组的人数总和,不然总有数组该组的试卷没有分配到其他组,造成自己改自己试卷的可能。

    数据存储结构呈现队列特性,先放的先拿(FIFO)。

代码(C/C++)

  • C实现
#include <stdio.h>
#include <stdlib.h> //for qsort()

int compare(const void *value1, const void *value2);
void JudgeMethod(int *array, int N);

int main()
{
    int N;
    scanf("%d", &N);        //小组数量
    int array[N];
    int i = 0;
    for (; i < N; i++)
    {
        array[i] = 0;
    }
    int j = 0;
    while (j < N)
    {
        scanf("%d", &array[j]);
        j++;
    }
    JudgeMethod(array, N);
    return 0;
}


//参数1 - 参数2,非降序排序;反之,非升序排序
int compare(const void *value1, const void *value2)
{
    return *(int *)value1 - *(int *)value2;
}

void JudgeMethod(int *array, int N)
{
    qsort(array, N, sizeof(int), compare);          //默认按照非降序排序
    int i;
    int max = array[N - 1];
    for (i = 0; i < N - 1; i++)
    {
        max = max - array[i];
    }
    if (max < 0)
        printf("Yes\n");
    else
        printf("No\n");
}
  • C++实现
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

bool compare(int a, int b) {
    return a > b;
}

void findsolution(vector<int> que, int n) {
    sort(que.begin(), que.end(), compare);
    int val = que[0];
    for (int i = 1; i < que.size(); ++i) {
        val -= que[i];
    }
    if(val > 0)
        cout << "No" << endl;
    else
        cout << "Yes" << endl;
}

int main() {
    vector<int> que;
    int data;
    while(cin >> data)
        que.push_back(data);
    int n = que[0];
    que.erase(que.begin());
    findsolution(que, n);
    return 0;
}



2017.09.01

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值