昨天做了下头条的后端开发工程师的编程题,这编码量大啊,两个小时,三个编程题,一个改错题,一个设计题,说实话,很考技术含量,而且编程题中有两个还特别考细心编码,如果两个小时能做三个题,确实非常不错了,写下解题报告吧,根据自己截的图和别人截的图把题还原下,并给出自己的解法,自己不确定是不是最优的,如果有不同意见可以一起讨论.
 
 

第一题:推箱子

题目:

给你一个矩阵,里面有‘#’,表示障碍,‘.’表示空地,‘S’表示人开始的位置,‘E’表示箱子的预期位置,‘0’表示箱子的初始位置,你的任务是把箱子从‘0’推到‘E’.

注意不能将箱子推到‘#’上,也不能将箱子推出边界;

现在给你游戏的初始样子,你需要输出最少几步能够完成游戏,如果不能完成,则输出-1.

输入描述:

第一行为2个数字, n,m n,m,表示游戏盘面大小有 n n行mm列( 5<n,m<50 5);后面为 n n行字符串,每行字符串有mm字符,表示游戏盘面.

输出描述:

一个数字,表示最少几步能完成游戏,如果不能,输出-1.

样例输入:

3 6 3\ 6
.S#..E .S\#..E
.#.0.. .\#.0..
...... ......

样例输出:

11 11

解析:

首先可以看出是一个 bfs bfs问题,推箱子的时候首先人要站到箱子紧挨的四个方向的格子中,才能把箱子推向某一个方向,因此,两个 bfs bfs,第一个 bfs bfs搜索箱子的位置,第二个 bfs bfs搜索人的位置到箱子紧挨的四个方向的格子要走的步数,大致方向就是这样,下面说下细节.

  • 到终点时,箱子可以从四个方向推到终点,因此要维护一个最小值,当然了,箱子可能并不一定可以从四个方向推到终点,这个你自己去判一下就好了;
  • 我用了优先队列做优化,原因是人到箱子的四个方向的步数大小不一,因此我们优先选择总步数最小的扩展;
  • 在第二个 bfs bfs中,要把箱子当成障碍物;
  • 走过的地方不能再走,但是这里位置的唯一性要由人的位置和箱子的位置共同确定,因此要开一个4维数组,不过我们通过 hash hash可以降到2维;
  • 我们把方向按:上 - 0,右 - 1, 下 - 2,左 - 3编号,为的就是在编码的时候可以方便统一地求人要走的那个位置和箱子即将推到的那个位置.

代码:

#include <bits/stdc++.h>using namespace std;const int dirx[] = {-1, 0, 1, 0};
const int diry[] = {0, 1, 0, -1};int n, m;struct Point {int x, y;Point() {}Point(int x, int y) : x(x), y(y) {}bool operator == (const Point &other) const {return x == other.x && y == other.y;}
};struct Node {Point peo, box;int step;Node() {}Node(Point peo, Point box, int step = 0) :peo(peo), box(box), step(step) {}bool operator < (const Node &other) const {return step > other.step;}
};struct Peo {Point point;int step;Peo() {}Peo(Point point, int step = 0) :point(point), step(step) {}
};bool check(int x, int y)
{return x >= 0 && x < n && y >= 0 && y < m;
}int bfs(Point src, Point des, Point box, vector<string> &mp)
{queue<Peo> que;vector<vector<bool> > used(n, vector<bool>(m, false));que.push(src);used[src.x][src.y] = true;int ret = -1;while (!que.empty()) {auto now = que.front();que.pop();if (now.point == des) {ret = now.step;break;}for (int k = 0; k < 4; k++) {int tx = now.point.x + dirx[k];int ty = now.point.y + diry[k];if (check(tx, ty) && mp[tx][ty] == '.' && !(Point(tx, ty) == box) && !used[tx][ty])que.emplace(Point(tx, ty), now.step + 1), used[tx][ty] = true;}}return ret;
}int main()
{// freopen("in", "r", stdin);while (cin >> n >> m) {string str;vector<string> mp;Point initS, initE, initZ;for (int i = 0; i < n; i++) {cin >> str;mp.push_back(str);for (int j = 0; j < str.size(); j++) {if (str[j] == 'S') {initS = Point(i, j);mp[i][j] = '.';break;}}for (int j = 0; j < str.size(); j++) {if (str[j] == 'E') {initE = Point(i, j);mp[i][j] = '.';break;}}for (int j = 0; j < str.size(); j++) {if (str[j] == '0') {initZ = Point(i, j);mp[i][j] = '.';break;}}}vector<vector<bool> > used(n * m + 1000, vector<bool>(n * m + 1000, false));priority_queue<Node> que;que.emplace(initS, initZ);used[initS.x * n + initS.y][initZ.x * n + initZ.y] = true;int ans = 0x3f3f3f3f;int cnt = 0;for (int k = 0; k < 4; k++)if (check(initE.x + dirx[k], initE.y + diry[k]) && mp[initE.x + dirx[k]][initE.y + diry[k]] == '.')++cnt;while (!que.empty()) {auto now = que.top();que.pop();if (now.box == initE) {cnt--;ans = min(now.step, ans);if (cnt == 0)break;elsecontinue;}for (int k = 0; k < 4; k++) {int tmpSx = now.box.x + dirx[k];int tmpSy = now.box.y + diry[k];int tmpZx = now.box.x + dirx[(k + 2) % 4];int tmpZy = now.box.y + diry[(k + 2) % 4];if (!check(tmpSx, tmpSy) || !check(tmpZx, tmpZy))continue;if (mp[tmpSx][tmpSy] != '.')continue;if (mp[tmpZx][tmpZy] != '.')continue;if (used[now.box.x * m + now.box.y][tmpZx * m + tmpZy])continue;int step = bfs(now.peo, Point(tmpSx, tmpSy), now.box, mp);if (step == -1)continue;que.emplace(now.box, Point(tmpZx, tmpZy), step + now.step + 1);used[now.box.x * m + now.box.y][tmpZx * m + tmpZy] = true;}}cout << (ans == 0x3f3f3f3f ? -1 : ans) << endl;}return 0;
}

第二题:房间

题目:

有 n n个房间,现在ii号房间里的人需要被重新分配,分配的规则是这样的:先让 i i号房间的人全部出来,接下来按照i+1,i+2,i+3,...i+1,i+2,i+3,...的顺序依次往这些房间里放一个人, n n号房间的下一个房间是1号房间,直到所有人被重新分配。

现在告诉你分配完后每个房间的人数以及最后一个人被分配的房间号xx,你需要求出分配前每个房间的人数,数据保证一定有解,若有多解输出任意一个解。

输入描述:

第一行两个整数 n,x(2<=n<=105,1<=x<=n) n,x(2,代表房间数量以及最后一个人被分配到的房间号;
第二行 n n个整数ai(0<=ai<=109)a_i(0,代表每个房间分配后的人数。

样例输入:

3 1 3\ 1
6 5 1 6\ 5\ 1

样例输出:

4 4 4 4\ 4\ 4

解析:

首先,如果所有房间都有人,这个问题很好考虑,找最小值,例如最小值是3,长度为4,那么就循环了3圈,然后从最后一个分配到的房间向前数,数到最小值数了多少下。例如样例中,第三个房间的人肯定是被请出去的,那么第三个房间的原本人数就是 1×3+1=4 1\times 3+1=4,第一个房间的原本人数就是 6−1−1=4 6-1-1=4,第二个房间原本的人数是 5−1 5 - 1,那么我们就得到了一个一般的解法:先找最小值,然后所有房间的人数先减去最小值,再从最小值这个地方先后到最后一个分配的房间要再减一,最后最小值这个地方的人数就是最小值乘长度加上最后一个人分配的地方向前到这最小值这个地方的距离减一.

但是现在存在有的房间可能没人,这就意味着最小值可能有很多个,那么就要分两种情况了,一、最后一个分配的房间里的人数就是最小值,这种情况这个房间里的人就是先前被请出去了,也就是循环了 theMin theMin圈,很好计算;二、最后一个分配的房间里的人数不是最小值,那么先前被请出去的房间就是从最后一个分配的房间向前数第一个遇到的最小值的房间,自己画一个图就理解了.

代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;int main()
{int n, k;while (~scanf("%d%d", &n, &k)) {vector<LL> arr;LL theMin = 0x3f3f3f3f3f;for (int i = 0; i < n; i++) {LL x;scanf("%lld", &x);arr.push_back(x);theMin = min(theMin, x);}if (arr[k - 1] == theMin) {for (vector<LL>::size_type i = 0; i < arr.size(); i++) {if (i == k - 1)printf("%lld", 1LL * theMin * n);elseprintf("%lld", arr[i] - theMin);putchar(i == arr.size() - 1 ? '\n' : ' ');}} else {int i, d;for (i = k - 1, d = 0; theMin != arr[(i + n) % n]; i--, d++)arr[(i + n) % n] = arr[(i + n) % n] - theMin - 1;arr[(i + n) % n] = 1LL * theMin * n + d;if ((i + n) % n != k) {for (--i; (i + n) % n != k; i--)arr[(i + n) % n] = arr[(i + n) % n] - theMin;arr[(i + n) % n] = arr[(i + n) % n] - theMin;}for (vector<LL>::size_type i = 0; i < arr.size(); i++)printf("%lld%c", arr[i], i == arr.size() - 1 ? '\n' : ' ');}}return 0;
}

附加题:二阶魔方

题目:

二阶魔方又叫小魔方,是2*2*2的立方体结构,每一面都有4个块,共有24个块,每次操作可以将一面逆时针或者顺时针旋转 90。 90^。,如将上面逆时针旋转 90。 90^。操作如下:

Zero在小魔上做了一些改动,用数字替换每个块上面的颜色,称之为数字魔方。魔方上每一面的优美度就是这个面上4个数字的乘积,而魔方的总优美度就是6个面优美度的总和。

现在Nero有一个数字魔方,他想知道这个魔方在操作步超过5次的前提下能达到的最大优美度是多少。

魔方展开后每一块的序号如下图:

输入描述:

输入一行包含24个数字,按序号顺序给出魔方每一块上面的数字。所有数字的范围为 [−100,100] [-100,100]。

输出描述:

输出一行包括一个数字,表示最大优美度。

样例输入:

2 −3 −2 3 7 −6 −6 −7 9 −5 −9 −3 −2 1 4 −9 −1 −10 −5 −5 −10 −4 8 2 2\ -3\ -2\ 3\ 7\ -6\ -6\ -7\ 9\ -5\ -9\ -3\ -2\ 1\ 4\ -9\ -1\ -10\ -5\ -5\ -10\ -4\ 8\ 2

样例输出:

8281 8281

解析:

模拟题,最主要的是写出6个移动位置的置换群,仔细点写,我一开始写错好几次,太多了,本来想用代码来写,但是想了下,还不如手写呢,最后我是通过下面这个debug函数才找出来我哪个地方写错了,如果这个函数输出的全是1,那么数字上就没错,但是不保证你的置换方式有没有错.

void debug()
{for (int i = 0; i < 6; i++) {int a[24];memset(a, 0, sizeof(a));cout << i << ":" << endl;for (int j = 0; j < 24; j++)a[mp[i][j]]++;for (int j = 0; j < 24; j++)printf("%d ", a[j]);puts("");}
}

还要注意一点,这里顺时针逆时针只要考虑一个就好了,因为顺时针移动三次可以得到逆时针!

时间复杂度 O(125) O(12^5)可以接受,不过这个题如果说在15步内那就不是这么简单的了,首先,15步去暴搜是不行的,太多了,那么怎么办呢,这个时候我们就要考虑魔方的“上帝之数”了,二阶魔方在任意状态11步内是可以还原的,那么也就是说,15步可以从任意一个状态到另一个任意的状态了,那么这个问题就变成了,24个数字分成6组,求这6个组的乘积最大和了,但是要注意一点,有些数字是永远不可能出现在同一面的,这个要考虑到,比如一条棱上的两个数字。

这样子考虑不用去模拟魔方转动了,但是好像这个问题变难了,贪心是肯定搞不了的,我也不知道做了.

代码:

#include <bits/stdc++.h>using namespace std;typedef long long LL;const int mp[6][24] = {
//  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 21, 20, 10, 11, 12, 13, 18, 16, 19, 17, 15, 14, 22, 23},{1, 3, 0, 2, 23, 22, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 9, 8},{0, 21, 2, 23, 4, 5, 6, 1, 9, 15, 10, 11, 12, 3, 8, 14, 16, 7, 18, 13, 20, 17, 22, 19},{20, 1, 22, 3, 10, 4, 0, 7, 8, 9, 11, 5, 2, 13, 14, 15, 6, 17, 12, 19, 16, 21, 18, 23},{0, 1, 11, 5, 4, 16, 12, 6, 2, 9, 10, 17, 13, 7, 3, 15, 14, 8, 18, 19, 20, 21, 22, 23},{10, 4, 2, 3, 18, 5, 6, 7, 8, 0, 19, 11, 12, 13, 14, 1, 16, 17, 15, 9, 21, 23, 20, 22}
};const int face[6][4] = {{0, 1, 2, 3},{4, 5, 10, 11},{6, 7, 12, 13},{8, 9, 14, 15},{16, 17, 18, 19},{20, 21, 22, 23}
};LL ans;void flip(vector<int> &a, int index)
{vector<int> b(a);for (vector<int>::size_type i = 0; i < a.size(); i++)b[i] = a[mp[index][i]];a = b;
}LL getSum(vector<int> &arr)
{LL ret = 0;for (int i = 0; i < 6; i++) {LL s = 1;for (int j = 0; j < 4; j++)s *= arr[face[i][j]];ret += s;}return ret;
}void dfs(int dep, vector<int> arr)
{ans = max(ans, getSum(arr));if (dep == 5) {return ;}for (int i = 0; i < 6; i++) {vector<int> a(arr);flip(a, i);dfs(dep + 1, a);flip(a, i);flip(a, i);dfs(dep + 1, a);}
}void debug()
{for (int i = 0; i < 6; i++) {int a[24];memset(a, 0, sizeof(a));cout << i << ":" << endl;for (int j = 0; j < 24; j++)a[mp[i][j]]++;for (int j = 0; j < 24; j++)printf("%d ", a[j]);puts("");}
}int main()
{// debug();// freopen("in1", "r", stdin);while (true) {bool isBreak = true;vector<int> arr(24);for (int i = 0; i < 24; i++)if (cin >> arr[i])isBreak = false;elsebreak;if (isBreak)break;ans = -0x3f3f3f3f3f;dfs(0, arr);cout << ans << endl;}return 0;
}

今日头条2018校园招聘后端开发工程师(第三批)编程题 - 题解相关推荐

  1. 今日头条2018校园招聘后端开发工程师(第四批)编程题 - 题解

    做过第三批的题目,今日头条2018校园招聘后端开发工程师(第三批)编程题 - 题解和第二批的题目,今日头条2018校园招聘后端开发工程师(第二批)编程题 - 题解. 这一场题目还是挺好玩的,也挺有技巧 ...

  2. 今日头条2018校园招聘后端开发工程师(第二批)编程题 - 题解

    以前做过第三批的题目,今日头条2018校园招聘后端开发工程师(第三批)编程题 - 题解.这一场的题目偏技巧和算法,而第三批的题偏编码.这一场涉及的算法有二分查找.区间动态规划. 原题链接:点这儿. 第 ...

  3. 今日头条2018校园招聘后端开发工程师(第二批)编程题 (Java版)

    本人技术小白一枚,文章只是记录个人的解题思路和过程 牛客网地址:原题链接 第一题:用户喜好 题目 为了不断优化推荐效果,今日头条每天要存储和处理海量数据.假设有这样一种场景:我们对用户按照它们的注册时 ...

  4. 今日头条2018校园招聘后端开发工程师 (第二批) 编程题 - 字母交换

    题目描述: [编码题]字符串S由小写字母构成,长度为n.定义一种操作,每次都可以挑选字符串中任意的两个相邻字母进行交换.询问在至多交换m次之后,字符串中最多有多少个连续的位置上的字母相同? 输入描述: ...

  5. 手串(暴力) - 今日头条2018校园招聘后端方向(9.10)

    时间限制:1秒 空间限制:65536K 题目描述 作为一个手串艺人,有金主向你订购了一条包含n个杂色串珠的手串--每个串珠要么无色,要么涂了若干种颜色.为了使手串的色彩看起来不那么单调,金主要求,手串 ...

  6. 七牛2018春季校园招聘后端开发工程师笔试经验

    笔试公司:上海七牛信息技术有限公司 笔试岗位:后端开发工程师 笔试时间:2018年4月14日14:00-15:30 笔试形式:牛客网在线做题 笔试回忆: 笔试共分为不定项选择和问答两部分,不定项选择1 ...

  7. 今日头条2018校园招聘第一题 ---POJ 2479

    第一次参加公司的招聘笔试,虽然只是抱着试试水的心态去参加的,可惜的是第一题就做错了..... 第一题,其实只是一个求最大子段和的变式题,不过笔试的时候也不知道怎么了,就是不知道思路,最后还写了一个错的 ...

  8. 今日头条2018校园招聘第一次笔试第二题“字符串拼接”题解(一维动态规划及递归解法)

    3.24晚的笔试,结束后题目看不到了,有人截图了,来源:https://www.jianshu.com/p/00d3fd1d9e23 最新更新:在leetcode 上有一道类似的题,区别在于第一种操作 ...

  9. 【求职】 网易 2018 校园招聘 Java 开发工程师(BJ)笔试卷

    文章目录 一.单选题 二.编程题 一.单选题 1.以下哪些方法或场景不会导致 java 线程阻塞?( ) A. 调用wait() 方法 B. 系统IO 阻塞 C. 调用notify()方法 D. 调用 ...

最新文章

  1. 肝了三天,万字长文教你玩转 tcpdump,从此抓包不用愁
  2. 【错误记录】Visual Studio 中配置 NDK 头文件路径
  3. AVL树(一)之 C语言的实现
  4. 关于WebApi 跨域问题的解决的方式
  5. 《延世大学韩国语教程2》第十九课 生病(下)
  6. “云”起风涌,邮件服务器助航企业云端升级
  7. java案例代码2-素数判断测试
  8. declspec(dllexport)和declspec(dllexport)的实际应用
  9. 【2022年】帝豪gs/帝豪gl 车机安装第三方软件教程
  10. 计算机硬盘中没有设控制器,电脑设置硬盘为兼容模式
  11. 2021系统架构设计师考试知识点
  12. 【图片、字符画互转】字符画实现(JAVA)
  13. Linux修改IP地址
  14. 会打飞机吗?原来用 Python 实现打飞机更爽
  15. electron????开发跨平台桌面应用程序???
  16. 在 js 中应用 订阅发布模式(subscrib/public)
  17. kali配置静态IP地址
  18. 计算机不联网会有ip地址吗,IP地址到底有什么用,为什么每次上网IP会不同?
  19. JSD-2204-酷莎商城(后端)-Day17,18
  20. 语言哲学与计算机语言,20世纪语言哲学和心智哲学的发展走向——以塞尔为例...

热门文章

  1. 个人开发者如何进行广告变现
  2. ora-01017: 用户名/口令无效; 登录被拒绝
  3. 2022年安全员-A证考试试题及答案
  4. 中国生态系统服务空间/食物生产、土壤保持、水源涵养、防风固沙、生物多样性、碳固定
  5. html5 css3画八卦图,用纯CSS3绘制乾坤八卦图
  6. SAP 教程之 SAP 中的 IDOC
  7. H5+ Webview窗口对象
  8. 一个超方便的国内版Chatgpt,基于gpt-3.5-turbo
  9. 盘点三款好用的计时器
  10. php反调试,反调试原理