NetEase 网易2018年内推笔试编程题
【注:题目可从牛客网获得,网址为:https://www.nowcoder.com】
这一次测试一共有8道题,其中1~5个人认为比较简单,6和7有一点难度,第8题是一个DP(动态规划题目+一点优化)
第 1 题
题目大意:输入一行字符,字符的范围是26个大写字母,小易喜欢的排列是最多只有一对相邻的字符是不一样的,问输入的字符有多少种排列是小易喜欢的。
题目分析:凡是相同的字符都要相邻排列,这是不影响结果的。影响结果的只有不同的字符,要保证最多只有一对相邻字符不同,那么字符种类必然要小于等于2.
题目解析:判断字符串中字符的种类有多少。当字符串长度为0或者字符种类大于2的时候,不存在小易喜欢的排列;字符种类为1时,只有一种排列,字符种类为2时,有两种(AB和BA)。
AC代码如下:
1 #include <cstdio> 2 #include <iostream> 3 4 5 using namespace std; 6 7 int main() { 8 string str; 9 cin >> str; //input the string 10 11 int a[30]; // a[i] stores if the ith block character is in the string(1:in, 0:not in) 12 int num = 0; // record the num of types of character 13 int ans = 0; // anwser 14 15 for (int i = 0; i < 30; i++) a[i] = 0; // initial the array, but it can be omitted 16 17 for (int i = 0; i < str.size(); i++) { 18 int tmpno = str[i] - 'A'; 19 if (a[tmpno] == 0) { 20 num++; 21 a[tmpno] = 1; 22 if (num > 2) { 23 break; 24 } 25 } 26 } 27 28 if (num > 2 || num == 0) { 29 ans = 0; 30 } else if (num == 2) { 31 ans = 2; 32 } else if (num == 1) { 33 ans = 1; 34 } 35 cout << ans << endl; 36 37 }
第 2 题
题目大意:给你一串数字(整形),让你判断用这串数字是否可以构成等差数列。
题目分析:从一个等差数列的特点入手,等差数列要求数列中的每一个数从左到右依次递增或者依次递减相同的增量。也就是说*从左到右数列中的数要么是从大到小,要么是从小到大;*并且前一个数减去后一个数的差值都相等。
题目解析:将数列排序,遍历每两个相邻的数列是否差值相等。
AC代码:
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 5 using namespace std; 6 7 int main() { 8 int num; 9 int a[55]; 10 bool flag = true; 11 12 cin >> num; 13 for (int i = 0; i < num; i++) { 14 scanf("%d", &a[i]); 15 } 16 17 sort(a, a+num); // sort是排序函数,使用的是快速排序算法,包含在头文件<algorithm>中,调用方法:sort(被排序头地址,被排序尾地址,排序规则) 18 19 int d = a[1] - a[0]; 20 21 for (int i = 2; i < num; i++) { 22 if (a[i] - a[i-1] != d) { 23 flag = false; 24 break; 25 } 26 } 27 28 if (flag) { 29 cout << "Possible" << endl; 30 } else { 31 cout << "Impossible" << endl; 32 } 33 34 }
第 3 题
题目大意:给出一个01串(字符串中只有‘1’和‘0’两种字符),相邻字符不一样的01串成为交错串,求输入的01串中最长的交错子串的长度。
题目分析:此题目比较简单在于字符串中只有两种字符(leetcode上有多种字符的题目),所以只要判断当前字符和前一个字符是否相等就可以了。
题目解析:从头遍历一边字符串,设定两个int类行的变量分别存储当前交错串的长度和到目前为止发现的交错串中最长的长度;程序判断当前字符和前一个字符是否相等,如果不相等,当前长度+1;如果相等,说明当前的子串结束,比较当前子串长度和最长的长度,将长度更长的值付给最长,并且将当前字符作为下一个子串的起点,当前字符串长度设置为1。
AC代码:
1 #include <iostream> 2 3 using namespace std; 4 5 int main() { 6 string str; 7 int maxlength = 0, currentlength = 1, strlength; 8 9 cin >> str; 10 11 strlength = str.size(); 12 13 if (strlength == 0) { 14 maxlength = 0; 15 } else if (strlength == 1) { 16 maxlength = 1; 17 } else { 18 for (int i = 0; i < strlength-1; i++) { 19 if (str[i] != str[i+1]) { 20 currentlength++; 21 } else { 22 if (currentlength > maxlength) { 23 maxlength = currentlength; 24 } 25 currentlength = 1; 26 } 27 } 28 } 29 if (currentlength > maxlength) maxlength = currentlength; 30 31 cout << maxlength << endl; 32 33 }
第 4 题
题目大意:给出一个整数序列A,还有一个空序列B,要将A序列中的数字依次放入B序列的末尾同时逆置序列B。求将A序列的数字全部放入B序列是,B序列的样子。
题目分析:拿到这个道题,凭借感觉是可以找规律的。模拟我没有做过,不清楚会不会过的。分析一下,我们将A序列的数字按照位置标号(0~n-1),位置0和1在B序列中的位置一定是挨着的,经过偶数次逆置B序列,1会在0的左边,奇数次逆置,1会在0的右边。所以当第3次操作的时候,0在尾,A位置2的数字会和0挨着,因为只是逆置,所以相邻的数字会是相邻的数字,只是左右位置会变化。那么第4次操作的时候,由于第三次的逆置,1在尾,所以A位置3和1相邻。其实到最后,数列的位置排列(位置号使用在序列A中的位置号),从数列中间分开,会把数列分成两部分,一部分是奇数位置号码,一部分是偶数位置号码。左边的部分是从左向右递减,右边的部分是从左向右递增。
题目解析:判断n的奇偶性,按照以上分析输出数列。
AC代码如下:
#include <cstdio> #include <iostream> using namespace std; int main() { int a[200000]; int n; cin >> n; for ( int i = 1; i <= n; i++ ) { scanf("%d", &a[i]); } if (n%2 == 0) { for (int i = n; i > 0; i -= 2) { cout << a[i] << ' '; } for (int i = 1; i <= n-1; i += 2) { cout << a[i]; if (i < n-1) { cout << ' '; } } cout << endl; } else { for (int i = n; i > 0; i -= 2) { cout << a[i] << ' '; } for (int i = 2; i <= n-1; i += 2) { cout << a[i]; if (i < n-1) { cout << ' '; } } cout << endl; } }
第 5 题
题目分析:这就一道计算题;要注意的是,有可能小易手里的水果大于她能支付房租的天数
AC代码:
#include <cstdio> #include <iostream> using namespace std; int main() { int x, f, d, p; int days = 0; cin >> x >> f >> d >> p; if (f*x <= d) { days += f; d -= (f*x); days += (d/(p+x)); } else { days = d/x; } cout << days << endl; }
第 6 题
题目大意:n个棋子摆放在一张无限大的棋盘上。第i个棋子放在第x[i]行y[i]列。同一个格子允许放置多个棋子。每一次操作小易可以把一个棋子拿起并将其移动到原格子的上、下、左、右的任意一个格子中。小易想知道要让棋盘上出现有一个格子中至少有i(1 ≤ i ≤ n)个棋子所需要的最少操作次数.
题目分析:这道其实是一道枚举题目,但是要想清楚枚举范围。棋子移动的方式有两种,一种是水平,一种是垂直,显而易见的是最后要堆i个棋子的格子必然在这i个棋子位置的中间才可能使得i个棋子一共移动的步数最少。比如说在row=1的这一行,横坐标为x,只有x左右两边的棋子数量相等,这一行的棋子移动到x位置所用的步数最小,否则棋子多的一遍多走的步数>棋子少的一遍棋子少走的步数(画图即可懂)。进一步来讲,如果我想把左右两边的棋子都移动到一个格子里,可以选择最中间的一个棋子所在格子(偶数个棋子有两个中间位置,步数一样)作为最优位置,步数最小。垂直方向同理。因此,对于i个点来说,我们的操作也可以分为两步,第一步是将所有点相同的x位置(这一位置应该是所选的i个点中某一个棋子的x位置),第二步,将所有点移动到相同的y位置(这一位置应该是所选i个点中,某一个点y的位置,因为上一步之改变了棋子x位置,y位置还是原始位置)。因此可以证明,最终的堆i个棋子的点,就在i个棋子的x值和y值的排列组合的位置。因此我们遍历的位置有n*n个坐标。因为要求分别计算出从1~n个棋子的移动最优位置,要一次选取1~n个棋子作为要移动的棋子,所以还是要枚举。
题目解析:设置一个长度大于n的数组a,a[i]存储将i 个棋子放到一个格子的最小操作数;枚举每一个n*n坐标,计算出所有棋子到当前点的曼哈顿距离,然后将这些距离从小到大排序,依次计算前i个距离的和,和a[i]比较,并看情况更新a[i]。
AC代码:
#include <iostream> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; int main() { int n, xMax = 0, yMax = 0; int leastSteps[51], x[51], y[51]; int steps[51]; cin >> n; for (int i = 0; i < n; i++) { scanf("%d", &x[i]); if (x[i] > xMax) xMax = x[i]; } for (int i = 0; i < n; i++) { scanf("%d", &y[i]); if (y[i] > yMax) yMax = y[i]; leastSteps[i] = -1; steps[i] = 0; } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { for ( int k = 0; k < n; k++ ) { steps[k] = abs(x[i] - x[k]) + abs(y[j] - y[k]); } sort(steps, steps+n); int tmp = 0; for (int di = 0; di < n; di++) { tmp += steps[di]; if (leastSteps[di] == -1) { leastSteps[di] = tmp; } else if (leastSteps[di] > tmp) { leastSteps[di] = tmp; } } } } for ( int i = 0; i < n; i++) { cout << leastSteps[i]; if (i < n-1) { cout << " "; } else if (i == n-1) { cout << endl; } } return 0; }
第 7 题
题目大意:给出一个整数序列,求每对相邻排列学生身高差的绝对值最大总和。
题目分析:其实就是用贪心思想进行模拟,每次选择差最大的进行排列。
题目分析:模拟方法有几种,我这里用了我觉得比较好理解的一种。首先排序,然后选择最高的一个,然后选择最小的两个站在两边,然后依次计算两个队列(排序队列和疯狂队列)的两边的差值,选最大进行排序。详细看代码
AC代码:
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; int main() { int a[50]; int n, maxdf = 0, indexl,indexr, stunum; cin >> n; for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } sort(a, a+n); int valuel = a[n-1], valuer = a[n-1]; indexl = 0, indexr = n-2; stunum = n-1; while (stunum) { int valuel_indexl = abs(valuel - a[indexl]); int valuel_indexr = abs(valuel - a[indexr]); int valuer_indexl = abs(valuer - a[indexl]); int valuer_indexr = abs(valuer - a[indexr]); int valuel_potential = max(valuel_indexl, valuel_indexr); int valuer_potential = max(valuer_indexl, valuer_indexr); maxdf += max(valuel_potential,valuer_potential); if (valuel_potential >= valuer_potential) { valuel_indexl > valuel_indexr ? valuel = a[indexl++] : valuel = a[indexr--]; } else { valuer_indexl > valuer_indexr ? valuer = a[indexl++] : valuer = a[indexr--]; } stunum--; } cout << maxdf << endl; }
第 8 题
题目大意:给出n和k,分别为数列长度,和数列中数字的范围(1<=x<=k),当数列中的每一个数字A和它后面的数字B满足这样的关系时:A<=B || A%B != 0, 这是小易最喜欢的数列。问数列有多少种。k的范围时10^5,n <= 10。
题目解析:一看就是好大的数!!!当时拿到这题,吓死宝宝了。对于n个数字的第1个数字,可是1到k个数字的任意一个,对于第2个数字到第n个数字,要看前一个数字是否允许摆放1~k的某一个数字。因此也是dp的思想,用一个数组存储所有子问题的解,dp[n+5][k+5],dp[i][j]表示最后一个数字是j的长度为i的序列的个数。容易得出dp[i][j] = sum( dp[i-1][1~k(可以放在j前面的数字)] )。如果这样做会超时,因为从A和B的关系来看,不能放在A后面的只有A的约数,而A的约数的数量远小于剩下的1~k的数量,所以如果正着求的话时间复杂度是k^3,倒着做,即求不能放在后面的,就好很多。最后d[n][1~k]存储的就是长度为n,最后一个数字1~k的数列个数,都加起来就ans。记得每一步加法都要取模!
AC代码:
#include <cstdio> #include <iostream> using namespace std; const int MOD = 1e9 + 7; int main() { int n, k, ans = 0; cin >> n >> k; int dp[15][100005]; dp[0][1] = 1; for (int i = 1; i <= n; i++) { int sum = 0; for (int j = 1; j <= k; j++) { sum += dp[i-1][j]; sum %= MOD; } for (int j = 1; j <= k; j++) { int invalid = 0, p = 2; while (p*j <= k) { invalid += dp[i-1][p*j]; p++; invalid %= MOD; } dp[i][j] = (sum - invalid + MOD) % MOD; } } for (int i = 1; i <=k; i++) { ans += dp[n][i]; ans %= MOD; } cout << ans << endl; return 0; }
End ~
浙公网安备 33010602011771号