笔试强训错题总结
文章目录
选择题
- 以下程序的运行结果是()
#include <stdio.h>
int main(void) {
printf("%s , %5.3s\n", "computer", "computer");
return 0;
}
A.computer , puter
B.computer , com
C.computer , computer
D.computer , compu.ter
- 在头文件及上下文均正常的情况下,下列代码的运行结果是()
int a[] = {1, 2, 3, 4};
int *b = a;
*b += 2;
*(b + 2) = 2;
b++;
printf("%d,%d\n", *b, *(b + 2));
A. 1,3 B. 1,2 C. 2,4 D. 3,2
- 在32位cpu上选择缺省对齐的情况下,有如下结构体定义:
struct A
{
unsigned a : 19;
unsigned b : 11;
unsigned c : 4;
unsigned d : 29;
char index;
};
则sizeof(struct A)的值为()
A. 9 B. 12 C. 16 D. 20
- 假设在一个 32 位 little endian 的机器上运行下面的程序,结果是多少?
#include <stdio.h>
int main()
{
long long a = 1, b = 2, c = 3;
printf("%d %d %d\n", a, b, c);
return 0;
}
A. 1,2,3 B. 1,0,2 C. 1,3,2 D. 3,2,1
- 求函数返回值,输入x=9999
int func(int x)
{
int count=0;
while (x)
{
count++;
x=x&(x-1);//与运算
}
return count;
}
A. 8 B. 9 C. 10 D. 12
- 二维数组X按行顺序存储,其中每个元素占1个存储单元。若X[ 4 ] [ 4 ]的存储地址为Oxf8b82140,X[9] [9]的存储地址为Oxf8b8221c,则X[7] [7]的存储地址为()。
A. Oxf8b821c4 B. Oxf8b821a6 C. Oxf8b82198 D. Oxf8b821c
- 下列程序的打印结果是()//day5
char p1[15] = "abcd", *p2 = "ABCD", str[50] = "xyz";
strcpy(str + 2, strcat(p1 + 2, p2 + 1));
printf("%s", str);
A. xyabcAB B. abcABz C. ABabcz D. xycdBCD
- 有一个如下的结构体: 请问在64位编译器下用sizeof(struct A)计算出的大小是多少()
struct A
{
long a1;
short a2;
int a3;
int *a4;
};
A. 24 B. 28 C. 16 D. 18
- 执行下面语句后的输出为
int I=1;
if(I<=0)
printf("****\n") ;
else
printf("%%%%\n");
A. %% B. * * * * C. 有语法错,不能正确执行 D. %%%%
- C++ 中,有如下类模板定义: 已知 b1, b2 是 BigNumber 的两个对象,则下列表达式中错误的是()
template<class T> class BigNumber
{
long n;
public:
BigNumber(T i) :n(i) {}
BigNumber operator+(BigNumber b)
{
return BigNumber(n + b.n);
}
}
A. 3+3 B. b1+3 C. b1+b2 D. 3+b1
- 以下代码共调用多少次拷贝构造函数:
Widget f(Widget u)
{
Widget v(u);
Widget w=v;
return w;
}
int main()
{
Widget x;
Widget y=f(f(x));
}
A. 1 B. 3 C. 5 D. 7
- 下面有关c++静态数据成员,说法正确的是()
A. 不能在类内初始化 B. 不能被类的对象调用 C. 不能受private修饰符的作用 D. 可以直接用类名调用
- 在C++中,为了让某个类只能通过new来创建(即如果直接创建对象,编译器将报错),应该()
A. 将构造函数设为私有 B. 将析构函数设为私有 C. 将构造函数和析构函数均设为私有 D. 没有办法能做到
- 拷贝构造函数的特点是()
A. 该函数名同类名,也是一种构造函数,该函数返回自身引用
B. 该函数只有一个参数,是对某个对象的引用
C. 每个类都必须有一个拷贝初始化构造函数,如果类中没有说明拷贝构造函数,则编译器系统会自动生成一个缺省拷贝构造函数,作为该类的保护成员
D. 拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象
- 以下程序输出是____。
#include <iostream>
using namespace std;
int main(void)
{
const int a = 10;
int * p = (int *)(&a);
*p = 20;
cout<<"a = "<<a<<", *p = "<<*p<<endl
return 0;
}
A. 编译阶段报错运行阶段报错
B. a = 10, *p = 10
C. a = 20, *p = 20
D. a = 10, *p = 20
E. a = 20, *p = 10
- 假定有类AB,有相应的构造函数定义,能正确执行 语句,请问执行完此语句后共调用该类的构造函数次数为___ //day11
AB a(4),b(5),c[3],*p[2]={&a,&b}
A. 5 B. 4 C. 3 D. 9
- 下列关于赋值运算符“=”重载的叙述中,正确的是
A. 赋值运算符只能作为类的成员函数重载
B. 默认的赋值运算符实现了“深层复制”功能
C. 重载的赋值运算符函数有两个本类对象作为形参
D. 如果己经定义了复制拷贝构造函数,就不能重载赋值运算
- 若PAT是一个类,则程序运行时,语句“PAT(*ad)[3];”调用PAT的构造函数的次数是()
A. 2 B. 3 C. 0 D. 1
- 下面对析构函数的正确描述是()
A. 系统不能提供默认的析构函数
B. 析构函数必须由用户定义
C. 析构函数没有参数
D. 析构函数可以设置默认参数
编程题
连续最大和
题目描述:一个数组有 N 个元素,求连续子数组的最大和。
例如:[-1,2,1],和最大的连续子数组为[2,1],其和为 3 输入描述:输入为两行。 第一行一个整数n(1 <= n <= 100000),表示一共有n个元素 第二行为n个数,即每个元素,每个整数都在32位int范围内。以空格分隔。 输出描述:所有连续子数组中和最大的值。
解法
我原本就是暴力破解,搞一个双重循环,从第一个位置开始往后加,然后将结果与max进行判断,再从第二个位置往后加,再将结果与max判断,最后得到最大值。但是这样的解法是一个O(N^2)效率极差,所以这里就不放代码了。
优化解法
这题可以使用动态规划的思想,将复杂度优化到O(N);动态规划最关键的是状态方程:
求最大子数组连续和的状态方程是GetMax=(dp[i-1]+arr[i],arr[i])
如果i位置前的数组元素和是一个正数,那么对于i位置来说,最大和肯定是arr[i]
加上之前的元素和,但是如果之前的元素和是一个负数,那么对于i位置来说,它的最大和就是它自己本身,因此我们可以得到如下代码:
#include<iostream>
#include<vector>
using namespace std;
int GetMax(int a,int b)
{
return a>b?a:b;
}
int main() {
int n = 0;
cin >> n;
vector<int> v;
v.resize(n);
for (int i = 0; i < n; i++) {
cin >> v[i];
}
int sum = v[0];
int maxsum = v[0];
for (int i = 1; i < n; i++) {
sum=GetMax(sum+v[i],v[i]);
if(sum>=maxsum)
maxsum=sum;
}
cout << maxsum << endl;
return 0;
}
不要二
二货小易有一个W*H的网格盒子,网格的行编号为0H-1,网格的列编号为0W-1。每个格子至多可以放一块蛋糕,任意两块蛋糕的欧几里得距离不能等于2。
对于两个格子坐标(x1,y1),(x2,y2)的欧几里得距离为: ( (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) ) 的算术平方根
小易想知道最多可以放多少块蛋糕在网格盒子里。
#include<iostream>
#include<string>
using namespace std;
int main()
{
int w, h;
int count = 0;
cin >> w >> h;
vector<vector<int>> vv;//需要定义一个w行,h列的二维数组
vv.resize(w);
for (auto& e : vv)
e.resize(h,1);//将每一行的元素扩容为h个,并初始化为1
//遍历判断,当x1,y1位置放了蛋糕以后,(x1+2,y1)或者(x1,y1+2)的位置不能放蛋糕,最后统计非0元素的个数即可
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
if (vv[i][j] == 1)
{
count++;
if (i + 2 < w)
vv[i + 2][j] = 0;
if (j + 2 < h)
vv[i][j + 2] = 0;
}
}
}
cout << count << endl;
return 0;
}
最近公共祖先
将一棵无穷大满二叉树的结点按根结点一层一层地从左往右编号,根结点编号为1。现给定a,b为两个结点。设计一个算法,返回a、b最近的公共祖先的编号。注意其祖先也可能是结点本身。
测试样例:
2,3
返回:1
解题思路
其实这道题的思路很简单,因为编号是层序从小到大编号的,所以子节点的值一定大于父节点的值,让大的节点去找它的父节点,将这个父节点再与小的节点作比较看是否相等,如果不相等就再让大的节点去找父节点,知道相等为止
所以可以得到这样的代码:
class LCA {
public:
int getLCA(int a, int b) {
// write code here
while(a!=b)
{
if(a>b)
{
a=a/2;
}
else
{
b=b/2;
}
}
return a;
}
};
最大连续的bit数
求一个int类型数字对应的二进制数字中1的最大连续数,例如3的二进制为00000011,最大连续2个1
数据范围:数据组数:1≤t≤5 1\le t\le 5\ 1≤t≤5 ,1≤n≤500000 1\le n\le 500000\ 1≤n≤500000
进阶:时间复杂度:O(logn) O(logn)\ O(logn) ,空间复杂度:O(1) O(1)\ O(1)
解题思路
判断一个数的比特位中有多少个1,只要不断左移再让每一个比特位按位与上1即可,这里不建议使用右移,因为右移补的是符号位,也就是说如果是一个负数,那么就会不断在高位补1,永远无法结束
#include <iostream>
using namespace std;
int main() {
int num=0;
while(cin>>num)
{
int count=0,maxcount=0;
for(int i=0;i<32;i++)
{
if(num&(1<<i))
{
count++;
maxcount=maxcount>count?maxcount:count;
}
else{
count=0;
}
}
cout<<maxcount<<endl;
}
}
幸运的袋子
一个袋子里面有n个球,每个球上面都有一个号码(拥有相同号码的球是无区别的)。如果一个袋子是幸运的当且仅当所有球的号码的和大于所有球的号码的积。
例如:如果袋子里面的球的号码是{1, 1, 2, 3},这个袋子就是幸运的,因为1 + 1 + 2 + 3 > 1 * 1 * 2 * 3
你可以适当从袋子里移除一些球(可以移除0个,但是别移除完),要使移除后的袋子是幸运的。现在让你编程计算一下你可以获得的多少种不同的幸运的袋子。
输入描述:
第一行输入一个正整数n(n ≤ 1000)
第二行为n个数正整数xi(xi ≤ 1000)
输出描述:
输出可以产生的幸运的袋子数
解题思路
这个题目要采用回溯的办法来解决:
1.首先要清楚,如果一些数的和大于它们的乘积那就说明这些数里面至少包括一个1
2.先对这些数据进行排序,这样可以减少重复次数,排序也为后面的去重打下了一定的基础
3.首先以最小的数打头,开始往后一旦到某个数不再幸运,那么就说明比这个数大的数放进来也不会是幸运的,那么此时就打断回溯
4.回溯以后进行去重,如果有两个一样的数,就不能再将这个数作为开头了,否则会将两个重复的结果作为两次输出,而且因为前面排序的原因,不用担心会有131和113这样随机的相同序列产生。
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int getLuckPacket(vector<int>& x, int n, int pos, int sum, int mul)
{
int count = 0;
for (int i = pos; i < n; i++)
{
//第一个数直接加上去就行
sum += x[i];
mul *= x[i];
if (sum > mul)
count += 1 + getLuckPacket(x, n, i + 1, sum, mul);
else if (x[i] == 1)//如果不幸运就看第一个数是不是1,是1的话后面还可能会是幸运的,否则后面的数再加进来也不会幸运,直接打断回溯
count += getLuckPacket(x, n, i + 1, sum, mul);
else
break;
//回溯就要将之前那个数的影响去掉
sum -= x[i];
mul /= x[i];
//去重
while (i < n - 1 && x[i] == x[i + 1])
i++;
}
return count;
}
int main()
{
int n = 0;
while (cin >> n)
{
vector<int> v(n);
for (int i = 0; i < n; i++)
cin >> v[i];
//排序
sort(v.begin(), v.end());
cout << getLuckPacket(v, n, 0,0, 1)<<endl;
}
return 0;
}
手套
在地下室里放着n种颜色的手套,手套分左右手,但是每种颜色的左右手手套个数不一定相同。A先生现在要出门,所以他要去地下室选手套。但是昏暗的灯光让他无法分辨手套的颜色,只能分辨出左右手。所以他会多拿一些手套,然后选出一双颜色相同的左右手手套。现在的问题是,他至少要拿多少只手套(左手加右手),才能保证一定能选出一双颜色相同的手套。
给定颜色种数n(1≤n≤13),同时给定两个长度为n的数组left,right,分别代表每种颜色左右手手套的数量。数据保证左右的手套总数均不超过26,且一定存在至少一种合法方案。
测试样例:
4,[0,7,1,6],[1,5,0,6]
返回:10(解释:可以左手手套取2只,右手手套取8只)
解题思路
解决本题的关键在于如何拿一次就可以将所有的颜色都覆盖到,假设有这样一个手套数组[4,2,3,7,5]要想将其中每种颜色都包含进去的话,至少要拿19只手套,即总和sum减去最小值min再加1只手套。此外如果遇到某种颜色左手有,右手没有,或者右手有,左手没有,那么就要将该种颜色的手套也添加进去
class Gloves {
public:
int findMinimum(int n, vector<int> left, vector<int> right)
{
// write code here
int left_sum=0,left_min=INT_MAX;
int right_sum=0,right_min=INT_MAX;
int sum=0;
for(int i=0;i<n;i++)
{
if(left[i]*right[i]==0)
sum+=left[i]+right[i];
else
{
left_sum+=left[i];
left_min=left_min<left[i]?left_min:left[i];
right_sum+=right[i];
right_min=right_min<right[i]?right_min:right[i];
}
}
return sum+min(left_sum-left_min+1,right_sum-right_min+1)+1;
//为零的累加和加上左右手中的最小值再+1
}
};