拼多多和字节跳动、美团点评、京东、滴滴、携程、网易互娱2020秋招笔试题复盘

今年是什么情况???这笔试题都是竞赛题难度呀,菜鸡表示很受伤。
多多少少做了一些大厂的笔试题,大佬勿喷,我觉得很多都是劝退笔试。

拼多多笔试题

求方差

给定n个整数,请找出其中3个数,满足这3个数的组合是所有组合中方差最小的。
输入描述:

共两行,第一行一个整数n(2<n<3000)
第二行是n个整数
题目中出现的所有数字的绝对值小于100000

思路:先排个序,之后组成方差的3个数必然是连在一起的,逐个求,记录最小值就好

#include<bits/stdc++.h>
using namespace std;
int a[3001]
int main() {
    int n;
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
}
    sort(a, a + n);
    double val, temp;
    //我之前因为res初始化的比较小,导致了部分样例是没过得
    double res = 10000000;
    for(int i = 0; i < n - 2; i++) {
        val = (a[i] + a[i+1] + a[i+2]) / 3.0;
        temp = ((a[i] - val) * (a[i] - val) + (a[i+1] - val) * (a[i+1] - val) + (a[i+2] - val) * (a[i+2] - val)) / 3.0;
        res = min(res, temp);
}
    printf("%.2lf", res);
    return 0;
}

移动珍珠最小距离

多多鸡有一串长度为L的珍珠项链,上面有N颗珍珠,分布在0到L-1这些位置上。现在多多鸡想把所有的珍珠都移动到一起,并且想让所有的珍珠移动的距离总和尽可能小。
所有的珍珠可以看作在一个环上,珍珠可以向相邻的没有珍珠的位置移动。
请输出最优方案下的所有珍珠移动总和。

输入描述:

共两行,第一行两个整数L、N(2 < N < L 100000)
第二行N个整数,表示每个珍珠所在的位置
题目保证所有珍珠的位置各不相同

分析:
滑动窗口问题,可以先考虑,如果问题不是成环的,而是线性的,该怎么用滑动窗口解决

递增序列总数

给定两个正整数N和S,你需要找出所有的长度为N的正整数数列,满足单调递增以及总和为S的数列有多少个。

输入描述:

共一行,两个整数,N和S( 1 < N ,S < 100000)

输出描述:

共一行,为满足条件的数列个数对1e9+7取模的结果

分析:
…也不会做
我们知道数列 1 到 n 求和为 n * (n + 1) / 2
所以如果出现 n * (n + 1) / 2 > S那么就是无解
结束后群里有大佬给了个解答:
用记忆化搜索求:
假设最小的数为1, 那么给N个数都加上初始值1,子问题成为求长度为N - 1,和为S - N的递增序列的个数。否则,依旧给N个数加上初始值,子问题成为求长度为N,和为S-N 的递增序列个数
f ( N , S) = f( N - 1, S - N) + f(N , S - N)

//
//  test.cpp
//  LeetCode
//
//  Created by huangyi on 2019/7/4.
//  Copyright © 2019 Leetcode. All rights reserved.
//
#include<bits/stdc++.h>
using namespace std;
int n, s;
const int mod = 1e9 + 7;
int cache[501][100001];
int count(int n, int s) {
    if(s <= 0) {
        return 0;
    }
    if(n * (n + 1) / 2 > s) {
        return 0;
    }
    if(n == 1) {
        return 1;
    }
    if(cache[n][s] != -1) {
        return cache[n][s];
    }
    cache[n][s] = count(n, s - n) + count(n - 1, s - n);
    if(cache[n][s] >= mod) {
        cache[n][s] -= mod;
    }
    return cache[n][s];
}
int main()
{
    scanf("%d %d", &n, &s);
    memset(cache, -1, sizeof(cache));
    int res = 0;
    res = count(n, s);
    printf("%d\n", res);
    return 0;
}

多多鸡爬山

多多鸡和同事们跑去大山里露营,总共有N座山,所有的山按编号从小到大分布在一条直线上。每座山的山顶上都有多多鸡的同事。露营需要持续一个月,多多鸡负责露营物资的运送和垃圾的回收,它需要每天开车去每座山的山顶一趟。这边的路可以分为三种,第一种从山底去到山顶的路,第二种从山顶到山底的路,第三种是山顶间的路。每座山都有对应的第一种和第二种路,某些山顶之间有第三种路相连。山顶间的路只有某些山顶之间才有,并且只能从编号小的山开向编号大的山。

多多鸡每天都需要从山底出发,去到所有的山顶。运送物资给同事们。因为山路的特殊性,他可能需要来回山底山顶多次。现在多多鸡想找出一个方案,可以保证每个山顶都去过至少一次的情况下,上山的次数尽可能少。

分析:
… 直接放弃,不会
结束后,某大佬说直接套 最小路径覆盖的板子就可以…
我当时…最小路径覆盖是什么鬼…

字节跳动

起床

当时第一题只过了0.8,最后交卷了也不知道咋回事,哪个地方没过,结束后有人帮我指出来了
题目里面提到了保证至少有一个闹钟可以让牛牛及时到达教室,所以设置初始值的时候就要很当心,别漏了第一个闹钟、

#include<bits/stdc++.h>
using namespace std;
int main() {
    int n,hi[101] = {0}, mi[101] = {0}, x, a, b, t[101] = {0};
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        scanf("%d %d", &hi[i], &mi[i]);
        t[i] = h[i] * 60 + mi[i];
}
    scanf("%d", &x);
    scanf("%d %d", &a, &b);
    int sum = a * 60 + b;
    int temp = sum - x;
    //我当时应该是这里错了
    int max = t[0];
    for(int i = 0; i < n; i++) {
        if(t[i] <= temp && t[i] >= max) {
            max = t[i];
}
}
    int h1 = max / 60;
    int m1 = max % 60;
    printf("%d %d\n", h1, m1);
    return 0;
}

解密

小明和安琪是好朋友,最近,他们的谈话被一家侦察机构监控,所以他们想将他们的谈话内容进行加密处理。于是,他们发明了一种新的加密方式,每条信息都被编译成二进制数B(明文),其长度为N。然后该信息被写下k次,每次向右移动0,1,。。。K-1位。
然后对每一列进行异或操作,并且把最终所得结果记录下来,记为S密文。

输入描述:

第一行两个数N和K
第二行输入一个二进制字符串S,长度为N+K-1
1 <= N <= 1e6
1 <= K <= 1e6

输出描述:

输出明文B

示例:
输入:

6 2
1110001

输出:

101111
#include<bits/stdc++.h>
using namespace std;
int n, k, char s[2000010], ans[1000010];
int main() {
    scanf("%d %d", &n, &k);
    scanf("%s", s);
    ans[0] = s[0];
    int now = s[0] - '0';
    for(int i = 1; i < n; i++) {
        ans[i] = now ^ (s[i] - '0') + '0';
        now = now ^ (ans[i] - '0');
        if(i >= k - 1) {
            now = now ^ (ans[i-k+1] - '0');
} 
    ans[n] = '\0';
    printf("%s\n", ans);
    return 0;
}
}

发奖金

题目要求参考LeetCode135发糖果,基本一致


#include<bits/stdc++.h>
using namespace std;
int main() {
    int n,v;
    vector<int> nums;
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        scanf("%d", &v);
        nums.push_back(v);
    }
    vector<int> price(n, 100);
    for(int i = 1; i < n; i++) {
        if(nums[i] > nums[i-1]) {
            price[i] = price[i-1] + 100;
        }
    }
    for(int i = n - 2; i >= 0; i--) {
        if(nums[i] > nums[i+1]) {
            price[i] = max(price[i], price[i+1] + 100);
        }
    }
    int res = 0;
    for(int i = 0; i < n; i++) {
        res += price[i];
    }
    printf("%d\n", res);
    return 0;
}

跑步

…不会,看不懂题目,不过大佬们说了是个树形dp。
牛客上看到有大佬发代码了,贴出来学习学习,我是看不懂了

作者:Nagichan
链接:https://www.nowcoder.com/discuss/221211
来源:牛客网

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
const int MOD = 1e9 + 7;
int n;
LL ans[3], cnt[N][3], sum[N][3];
vector<int> G[N];
void dfs(int u, int fa) {
    //cout << u << ' ' << fa << endl;
    for(int i = 0; i < 3; i++) {
        cnt[u][i] = sum[u][i] = 0;
    }
    for(auto v : G[u]) {
        if(v == fa)
            continue;
        dfs(v, u);
        for(int x = 0; x < 3; x++) {
            for(int y = 0; y < 3; y++) {
                (ans[(x + y + 1) % 3] +=
                     cnt[v][y] * sum[u][x] % MOD
                     + cnt[u][x] * sum[v][y] % MOD
                     + cnt[u][x] * cnt[v][y] % MOD) %= MOD;
            }
        }
        for(int x = 0; x < 3; x++) {
            (cnt[u][(x + 1) % 3] += cnt[v][x]) %= MOD;
            (sum[u][(x + 1) % 3] += (sum[v][x] + cnt[v][x]) % MOD) %= MOD;
        }
    }
    cnt[u][0]++;
    for(int x = 0; x < 3; x++) {
        ans[x] += sum[u][x];
    }
}
 
int main() {
    scanf("%d", &n);
    for(int i = 0, u, v; i < n - 1; i++) {
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, -1);
    cout << ans[0] << ' ' << ans[1] << ' ' << ans[2] << endl;
    return 0;
}

美团笔试题

美团笔试题题型为:40选择+1问答+2编程

选择题完全随机,啥题型都有,点进去就看到微积分和线性代数等

问答题:
Restful调用和RPC调用什么区别?如何设计一个RPC服务治理系统?Service mesh是为了解决什么问题?

编程题实际上考了两道LeetCode原题:269和763,只不过换了下背景

快递员分界

字符串 S 由大写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。

输入: S = "ABABCBACADEFEGDEHIJHKLIJ"
输出: [9,7,8]
解释:
划分结果为 "ABABCBACA", "DEFEGDE", "HIJHKLIJ"。
每个字母最多出现在一个片段中。

思路:
开一个数组记录某个字母最后一次出现的下标i
从首字符开始遍历字符串,找到首字符最后出现的位置,比较在该区间内字符在字符串中最后出现的位置是否超出区间,如果超出则将区间更新

#include<bits/stdc++.h>
using namespace std;

int main() {
    char a[1001];
    scanf("%s", a);
    int last[30];
    for(int i = 0; i < 26; i++) {
        last[i] = 0;
    }
    vector<int> v;
    for(int i = 0; i < strlen(a); i++) {
        last[a[i] - 'A'] = i;
    }
    for(int i = 0; i < strlen(a); i++) {
        int left = i, index = i, right = last[a[i] - 'A'];
        while(index <= right) {
            right = max(right, last[a[index++] - 'A']);
        }
        v.push_back(right - left + 1);
        i = right;
    }
    for(int i = 0; i < v.size(); i++) {
        if(i != v.size() - 1) {
            printf("%d ", v[i]);
        } else {
            printf("%d\n", v[i]);
        }
    }
    return 0;
}

火星文字典

题目描述:
已知一种新的火星文的单词由英文字母组成,但是此火星文中的字母先后顺序未知。给出一组非空的火星文单词,且此组单词已经按火星文字典序进行好了排序,请推断出此火星文的字母先后顺序。

输入:
一行文本,为一组按火星文字典序排序好的单词(单词两端无引号),单词之间通过空格隔开

输出:
按火星文字母顺序输出出现过的字母,字母之间无其他字符,如果无法确定顺序或者无合理的字母排序可能,请输出“invalid”。

样例输入:
wrt wrf er ett rftt

样例输出:
wertf

思路:
按顺序小的连接边建图,然后拓扑排序

#include<bits/stdc++.h>
using namespace std;

char s[100010], ss[1010][1010];

int G[30][30], indeg[30], have[30];

int main() {
    gets(s);
    for(int i = 0; i < 30; i++) {
        have[i] = 1;
        indeg[i] = 10;
    }
    int cnt = 0, len = 0, up = 0, time = 0;
    for(int i = 0; i <= strlen(s); i++) {
        if(s[i] == ' ' || i == strlen(s)) {
            ss[cnt++][len] = '\0';
            up = max(up, len);
            len = 0;
        } else {
            ss[cnt][len++] = s[i];
            time += have[s[i] - 'a'];
            have[s[i] - 'a'] = 0;
            indeg[s[i] - 'a'] = 0;
        }
    }
    for(int i = 0; i < 30; i++) {
        for(int j = 0; j < 30; j++) {
            G[i][j] = 0;
        }
    }
    for(int j = 0; j < up; j++) {
        int last = 0;
        for(int i = 1; i < cnt; i++) {
            if(j >= strlen(ss[i])) {
                continue;
            }
            bool flag = true;
            for(int k = 0; k < j; k++) 
                if( ss[last][k] != ss[i][k])
                    flag = false;
                if(flag && ss[last][j] != ss[i][j]) {
                    G[ss[last][j] - 'a'][ss[i][j] - 'a'] = 1;
                    indeg[ss[i][j] - 'a']++;      
                }
                last = i;
        }
    }
    string ans = "";
    queue<int> q;
    for(int i = 0; i < 30; i++) {
        if(indeg[i] == 0) {
            q.push(i);
        }
    }
    while(!q.empty()) {
        int u = q.front();
        q.pop();
        ans += (char)u + 'a';
        for(int i = 0; i < 26; i++) {
            if(G[u][i] == 1) {
                indeg[i]--;
                if(indeg[i] == 0) {
                    q.push(i);
                }
            }
        }
    }
    if(ans.length() == time) {
            cout<<ans<<endl;
        } else {
            cout<<"invalid"<<endl;
        }
    return 0;
}

京东笔试题

京东题型是选择+编程,也挺难的(个人觉得)
编程题有两道

合唱队

题目描述:
合唱队的N名学生站成一排且从左到右编号为1到N,其中编号为i的学生身高为H。现在将这些学生分成若干组(同一组的学生编号连续),并让每组学生从左到右按身高从低到高进行排列,使得最后所有学生同样满足从左到右身高从低到高(中间位置可以等高),那么最多可以将这些学生分成多少组?

输入:
第一行包含一个整数N , 1 <= N <= 1e5
第二行包含N的空格隔开的整数Hi 到 HN ,1 <= Hi <= 1e9

输出:
输出能分成的最多组数

样例输入:

4
2 1 3 2

样例输出:

2

分析:
保证区间前半段的最大值小于等于后半段的最小值
可以开两个辅助数组
leftMax[index]用于记录[1, index]的最大值
rightMin[index]用于记录[index, arrSize]的最小值
可以参考下LeetCode768


#include<bits/stdc++.h>
using namespace std;
int a[100001], leftMax[100001], rightMin[100001];
int main() {
    int n;
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    int res = 1;
    leftMax[1] = a[1];
    for(int i = 2; i <= n; i++) {
        leftMax[i] = max(leftMax[i-1], a[i]);
    }
    rightMin[n] = a[n];
    for(int i = n - 1; i >= 1; i--) {
        rightMin[i] = min(rightMin[i+1], a[i]);
    }
    for(int i = 1; i < n; i++) {
        if(leftMax[i] <= rightMin[i+1]) {
            res++;
        }
    }

    printf("%d\n",res);
    return 0;
}

考场安排

输入:
第一行两个整数n和m,表示有n个男生和n个女生,有m个朋友关系
1 <= n <= 500 , 1 <= m <= 100000
接下来m行,每行有两个整数,x和y,表示第x号男生和第y号女生是朋友,男生编号为[1,n],女生编号为[n+1, 2n]

输出:
输出第一行包含一个整数a,表示最少需要搬出教室的人数
输出第二行有a个整数,即a个需要搬出教室的人的编号,要求人数最少,且字典序最小

样例输入:

2 2
1 3
1 4

样例输出:

1
1

分析:二分图最小顶点覆盖问题,匈牙利算法
…考场上交了个匈牙利写的,只过了0.36???

滴滴笔试题

滴滴的笔试题个人觉得也是劝退题,(大佬勿喷)。
题型为20选择+2编程(编程题很难,ACM银牌以上可以尝试下)

算式转移

在这里插入图片描述
分析:
这道题我的理解就是排序,碰到连续加、连续减、连续乘或者连续除的序列就进行排序,注意只能操作相邻的两个数。

移除序列

在这里插入图片描述

上述两题的图片来源网友。

另外提一下,移除序列这道题的出处应该是codefroces Sereja and Two Sequences

CF参考代码

#include<bits/stdc++.h>
using namespace std;
int n, total, cost;
#define INF 0x3f3f3f
int a[50001];
int b[50001];
vector<int> v[50001];
int dp[50001][310];
int main() {
    memset(dp, INF, sizeof(dp));
    scanf("%d %d %d", &n, &total, &cost);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for(int i = 1; i <= n; i++) {
        scanf("%d", &b[i]);
        v[b[i]].push_back(i);
    }
    int tot = total / cost;
    int res = 0;
    dp[0][0] = 0;
    for(int i = 1; i <= n; i++) {
        dp[i][0] = 0;
        for(int j = 1; j <= tot; j++) {
            dp[i][j] = dp[i-1][j];
            int temp = upper_bound(v[a[i]].begin(), v[a[i]].end(), dp[i][j-1]) - v[a[i]].begin();
            if(temp < v[a[i]].size()) {
                dp[i][j] = min(dp[i][j], v[a[i]][temp]);
            }
            if(j > res && j * cost + i + dp[i][j] <= total) {
                res = j;
            }
        }
    }
    printf("%d\n", res);
    return 0;
}

这道题好难理解呀。
看了题解后:考察的应该是dp+二分。需要优化
这道题看完我就想交卷了…打扰了,告辞

携程笔试题

题型为:20选择+3编程

分隔链表

类似LeetCode86:可以参考:
https://blog.csdn.net/hy971216/article/details/82830998

大致意思就是给你一个单链表和一个整数m,要求你把链表里小于等于m的结点放到前面,大于m的结点放到后面

参考代码:

#include<bits/stdc++.h>
using namespace std;
//定义链表结点结构
struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
//分隔链表 
ListNode* partition(ListNode* head, int x) {
        //定义两个哑结点和两个指针
        ListNode dummy1(0),dummy2(0);
        ListNode* p1 = &dummy1;
        ListNode* p2 = &dummy2;
        //定义辅助指针指向表头
        ListNode* p = head;
        while(p) {
            //如果小于等于x,就接到p1后面
            if(p->val <= x) {
                p1->next = p;
                p1 = p1->next;
            } else {
            //反之接到p2后面
                p2->next = p;
                p2 = p2->next;
            }
            p = p->next;
        }
        p2->next = NULL;
        //让p1指向p2
        p1->next = dummy2.next;
        return dummy1.next;
}
//构建单链表
void createList(ListNode* head, int n) {
    cin >> head->val;
    n--;
    for(int i = 0; i < n; i++) {
        //尾插法插入结点
        ListNode* p = new ListNode(0);
        cin >> p->val;
        p->next = nullptr;
        head->next = p;
        head = p;
    }
}
int main() {
    ListNode* head = new ListNode(0);
    head->next = nullptr;
    createList(head, 6);
    ListNode* res = partition(head, 3);
    while(res) {
        cout << res->val;
        cout << " ";
        res = res->next;
    }
    return 0;
}

反转子串

参考代码:

#include<bits/stdc++.h>
using namespace std;

int num[100000];
stack<int> a;
string resolve(string s) {
    string res = "";
    int len = s.size();
    if(len <= 2) {
        return res;
    }
    for(int i = 0; i < len; i++) {
        if(s[i] == '(') {
            a.push(i);
        } else if(s[i] == ')') {
            //这个判断不能漏..不然只能过%71
            if(a.empty()) {
                return "";
            }
            num[i] = a.top();
            num[a.top()] = i;
            a.pop();
        }
    }
    int flag = 1;
    int i = 0;
    while(i < len) {
        if(s[i] == '(' || s[i] == ')') {
            i = num[i];
            flag = -flag;
        } else {
            res += s[i];
        }
        i += flag;
    }
    return res; 
}
int main() {
    string s;
    cin>>s;
    cout<< resolve(s) <<endl;
    return 0;
}

调度队列

参考LeetCode 410分隔数组的最大值;
题目保证了没有负数,如果有负数还要修改下思路
给定一个非负整数数组和一个整数 m,你需要将这个数组分成 m 个非空的连续子数组。设计一个算法使得这 m 个子数组各自和的最大值最小。

这题还是考察二分和贪心的思想,有人用dp做,但是dp的话数据量太大就过不了了

参考代码:

#include<bits/stdc++.h>
using namespace std;
int n, m;
typedef long long ll;
int splitArray(vector<int>& nums, int m) {
    ll left = 0, right = 0;
    int n = nums.size();
    for(int i = 0; i < n; i++) {
        right += nums[i];
        if(left < nums[i]) {
            left = nums[i];
        }
    }
    ll res = right;
    while(left <= right) {
        ll mid = (left + right) >> 1;
        ll sum = 0;
        int cnt = 1;
        for(int i = 0; i < n; i++) {
            if(sum + nums[i] > mid) {
                cnt++;
                sum = nums[i];
            } else {
                sum += nums[i];
            }
        }
        if(cnt <= m) {
            res = min(res, mid);
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    return res;
}
int main() {
    scanf("%d %d", &m, &n);
    vector<int> nums;
    for(int i = 0; i < n; i++) {
        scanf("%d", &x);
        nums.push_back(x);
    }
    int res = splitArray(nums, m);
    printf("%d\n",res);
    return 0;
}

网易互娱

网易互娱我这批的笔试题其实不难,只是我比较菜而已。
第二题因为平时练得太少,都不知道怎么根据结点编号构建二叉树了
第三题运气好过了测试用例,实际提交只能过0…

回文数

第一题就是判断给定整数的二进制形式是不是一个回文数(忽略前导0)
简单的想法就是开一个数组保存这个数的二进制形式,然后判断这个数组是否回文即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main() {
    int t;
    ll x;
    scanf("%d", &t);
    while(t--) {
    bool flag = false; 
    int a[111];
    int index = 0;
        scanf("%lld", &x);
        while(x != 0) {
            a[index++] = x % 2;
            x = x / 2;
        }
        for(int i = 0; i < index; i++) {
            if(a[i] != a[index - i - 1]) {
                flag = true;
                break;
            }
        }
        if(!flag) {
            printf("YES\n");
        } else {
            printf("NO\n");
        }
    }
    return 0;
}

递增二叉树

这题题目也是很好懂得,让你判断一颗二叉树是不是一颗递增二叉树(就是上一层的结点值得和要小于等于下一层的结点值得和)
思路很简单:就是根据结点值和编号构建二叉树,然后层次遍历二叉树,遍历完每一层坐下判断即可。
…但是让我写代码我就哭了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int size = 1001;
//树结点结构
struct node {
    int val;
    node *left, *right;
    node(int v,node *l=NULL,node *r=NULL):val(v),left(l),right(r){}
};
//二叉树层序遍历
bool judge(node *root) {
    if(root == NULL) {
        return false;
    }
    queue<node* > q;
    q.push(root);
    int curSum = 0;
    int preSum = 0;
    while(!q.empty()) {
        curSum = 0;
        int len = q.size();
        for(int i = 0; i < len; i++) {
            node *temp = q.front();
            curSum += temp->val;
            q.pop();
            if(temp->left != NULL) {
                q.push(temp->left);
            }
            if(temp->right != NULL) {
                q.push(temp->right);
            }
            if(curSum < preSum) {
                return false;
            } 
            preSum = curSum;
        }
    }
    return true;
}
int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int n;
        scanf("%d", &n);
        vector<node* > data;
        int *in = new int[n];
        //初始化
        for(int i = 0; i < n; i++) {
            node *temp = new node(-1);
            data.push_back(temp);
            in[i] = 0;
        }
        //构建二叉树
        for(int i = 0; i < n; i++) {
            int v, l, r;
            scanf("%d %d %d", &v, &l, &r);
            in[l] = in[r] = 1;
            data[i]->val = v;
            if(l != -1) {
                data[i]->left = data[l];
            }
            if(r != -1) {
                data[i]->right = data[r];
            }
        }
        int r = 0;
        for(int i = 0; i < n; i++) {
            //找到根节点
            if(in[i] == 0) {
                r = i;
                break;
            }
        }
        if(judge(data[r])) {
            printf("YES\n");
        } else {
            printf("NO\n");
        }
    }
    return 0;
}

喝咖啡

这题主要是考察思维逻辑的严谨性,注意边界问题等


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

int main() {
    int t, k, m;
    cin >> t;
    while(t--) {
        cin >> k >> m;
        vector<int> data;
        data.push_back(1 - k - 1);
        for(int i = 0; i < m; i++) {
            int x;
            cin >> x;
            data.push_back(x);
        }
        data.push_back(30 + k + 1);
        int res = m;
        for(int i = 0; i < data.size() - 1; i++) {
            int diff = data[i + 1] - data[i] - 1;
            if(diff > k) {
                res += (diff - k) / (k + 1);
            }
        }
        cout << res << endl;
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值