day01
1. %m.ns 打印输出
以下程序的运行结果是()_表示空格
#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
【答案解析】B
==%m.ns打印输出,其中m表示的是输出字符串的宽度,而n表示从左起截取目标字符串n个字符,并且是右对齐,如果左边不够补空格==
若字符串长度>n>m
例如:%3.5s,"computer" 输出的就是"com"
若n>字符串长度
例如:%.15s,"computer" 输出的就是"computer"
那么该题%5.3s的输出结过应该为"__com"
2. 赋值表达式的返回值
下列main()函数执行后的结果为()
int func() { int i, j, k = 0; for (i = 0, j = -1; j = 0; i++, j++) { k++; } return k; } int main() { cout << (func()); return 0; }
A -1
B 0
C 1
D 2
【答案解析】B
该题目其实考察的是进入for循环的次数,而for循环的判断部分是 j = 0 ,是一个赋值语句,而赋值语句的返回值就是赋值符号右边的值,也就是0,不会进入循环
3. 贪心算法
【答案解析】
队伍的水平值等于该队伍队员中第二高水平值,为了所有队伍的水平值总和最大的解法,也就是说每个队伍的第二个值是尽可能大的值。所以实际值把最大值放到最右边,最小是放到最左边。
【解题思路】:
本题的主要思路是贪心算法,贪心算法其实很简单,就是每次选值时都选当前能看到的局部最优解,所以这里的贪心就是保证每组的第二个值取到能选择的最大值就可以,我们每次尽量取最大,但是最大的数不可能是中位数,所以退而求其次,取每组中第二大的
例如 现在排序后 有 1 2 5 5 8 9 ,那么分组为1 8 9 和 2 5 5
关系arr[arr.length-2*(i+1)
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
// IO型OJ可能会有多组测试用例,所以这里要持续接收输入多组测试用例。
int n;
while (cin >> n)
{
long long sum = 0;
vector<int> a;
a.resize(3 * n);
for (int i = 0; i < (3 * n); i++)
{
cin >> a[i];
}
std::sort(a.begin(), a.end());
for (int i = 0; i < n; i++) {
sum += a[a.size() - (2 * (i + 1))];
}
cout << sum << endl;
}
}
day02
4. 指针内容的改变
下面叙述错误的是()
char acX[]="abc"; char acY[]={ 'a','b','c'}; char *szX="abc"; char *szY="abc";
A acX与acY的内容可以修改
B szX与szY指向同一个地址
C acX占用的内存空间比acY占用的大
D szX的内容修改后,szY的内容也会被更改
【答案解析】D
针对于D选项,szX的内容改变是指的指针指向的改变,而常量字符串"abc"并未改变,所以选D
而A选项,两个字符数组开辟在栈区,所以都是可改变的对象
5. 根据递增递减分段
【答案解析】
解题思路:
- 本题依次比较整个数组
- a[i+1]>a[i] ,则进入非递减序列判断,直到遍历到下一个值不大于等于为止count++,然后进行下一位置的判断
- a[i+1]<a[i],则进入非递增序列判断,直到遍历到下一个值不小于等于为止count++,然后进行下一位置的判断
a[i+1] == a[i]
不进行操作,++i进行下一位置遍历,因为相等既可以属于非递增序列,也可以属于非递减 序列。
本题注意点:本题开始比较a[i+1]与a[i]进行比较,为了避免越界,数组定义为n+1个,同时给a[n] = 0
;a[n] =0
带来的影响,我们分为三种情况讨论:- 若到a[n-1] 的最后一组是非递减序列,当
i==n-1
,a[i] >a[i+1],因为前面的数都是大于0的,这个输入条件已经说明了(去看看题目输入条件描述),里面的循环结束,i++,count++,i==n,外面的循环结束。- 若到a[n-1] 的最后一组是非递增序列,当
i==n-1
,a[i] >a[i+1],因为前面的数都是大于0的,这个输入条件已经说明了(去看看题目输入条件描述),循环再走一次,i++,i== n
,里面的循环结束,i++,count++,i==n+1
,外面的循环结束。- 第三种情况 1 2 1 2 1最后一个数是单独的情况,后面补个0,序列变成1 2 1 2 1 0,当走完全面的序列
i==n-1
时,a[i] > a[i+1],进入判断出一个非递增序列,count++,i++,循环结束。- 也就是说数组最后一个位置多增加一个0,不会影响第1、2情况的判断,主要是帮助第3情况的正确判断。
#include<iostream>
#include<vector>
using namespace std;
// 本题牛客测试用例不全,至少应该增加以下两组测试用例
// 输入:
// 4
// 1 3 2 3
// 输出:2
// 输入:
// 6
// 3 2 1 1 2 3
// 输出:2
#include <iostream>
using namespace std;
int main()
{
int n = 0;
cin>>n;
int arr[n+1];
for(int i=0;i<n;i++)
{
cin>>arr[i];
}
arr[n] = 0;
int i = 0;
int count = 0;
while(i<n)
{
if(arr[i]<arr[i+1])
{
while(i<n && arr[i]<=arr[i+1])
{
++i;
}
count++;
++i;
}
else if(arr[i] == arr[i+1])
{
++i;
}
else
{
while(i<n && arr[i]>=arr[i+1])
{
++i;
}
count++;
++i;
}
}
cout << count << endl;
return 0;
}
6. string类和reverse库函数
【答案解析】
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main()
{
string s1;
getline(cin, s1);
auto start = s1.begin();
auto end = start;
for (int i = 0; i < s1.size(); i++)
{
if (*(end + i) == ' ')
{
reverse(start, end + i);
start = end + i + 1;
}
}
reverse(start, s1.end());
reverse(s1.begin(), s1.end());
cout << s1.c_str() << endl;
return 0;
}
【解题思路1】:
先将整个字符串逆置过来,再遍历字符串,找出每个单词,对单词逆置。这里我们使用了stl算法中的reverse,所以这里使用迭代器遍历string
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string s;
// 注意这里要使用getline,cin>>s遇到空格就接收结束了
getline(cin, s);
// 翻转整个句子
reverse(s.begin(), s.end());
// 翻转单词
auto start = s.begin();
while (start != s.end())
{
auto end = start;
while (end != s.end() && *end != ' ')
end++;
reverse(start, end);
if (end != s.end())
start = end + 1;
else
start = end;
}
cout << s << endl;
return 0;
}
【解题思路2】:
第二思路是一个比较讨巧的思路,直接利用cin>>s接收输入,遇到空格就结束了,自然就分割开了每个单词,其次将每次接收到的单词拼接到之前串的前面就逆置过来了
#include <iostream>
#include <string>
using namespace std;
// cin读取string时自动会被空格分隔开,用另一个字符串存储进行逆序输出
int main()
{
string s1, s2;
cin >> s2;
while (cin >> s1)
s2 = s1 + " " + s2;
cout << s2 << endl;
return 0;
}
day03
7. 大小端与栈性质的运用
假设在一个 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
【答案解析】B
day04
8. 进制的输入输出形式
有以下程序
#include<iostream> #include<cstdio> using namespace std; int main() { int m = 0123, n = 123; printf("%o %o\n", m, n); return 0; }
程序运行后的输出结果是()
A 0123 0173
B 0123 173
C 123 173
D 173 173
【答案解析】C
首先我们需要了解的就是进制的输出形式和表示方法
==表达方式==
二进制:101010b (结尾带b)
八进制:0123 (开头带0)
十进制:123
十六进制:0x123 或者 123h (开头带0x)或者(末尾带h)
==输出方式==
%d:十进制方式输出
%o:八进制方式输出
%x:十六进制方式输出
9. 通过表达式计算对应值
10. 进制转换
【答案解析】:
【解题思路】:
本题思路很简单,首先想清楚原理:N进制数,每个进制位的值分别是X0 N ^ 0,X1 N ^ 1, X2* N ^ 2.....,X0,X1,X2就是这些进制位的值,就是就是进行取模余数就是当前低进制的位的值是多少,通过除掉进制数,进入下一个进制位的计算。
#include <iostream>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
string s, table = "0123456789ABCDEF";
int m, n;
cin >> m >> n;
bool flag = false;
// 如果是负数,则转成正数,并标记一下
if (m < 0)
{
m = 0 - m;
flag = true;
}
// 按进制换算成对应的字符添加到s
while (m)
{
s += table[m % n];
m /= n;
}
if (flag)
s += '-';
reverse(s.begin(), s.end());
cout << s << endl;
return 0;
}
day05
11. strcat函数的使用
下列程序的打印结果是()
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
【答案解析】D
==strcat的函数作用:strcat(p,q) 将q中字符串的内容 拼接在p字符串之后,最终返回p== 注意:p空间一定要容纳的下q拼接过来的字符
12. 动态规划
状态方程式: max( dp[ i ] ) = getMax( max( dp[ i -1 ] ) + arr[ i ] ,arr[ i ] )
dp[i] 就是以数组下标为 i 的数做为结尾的最大子序列和,注意是以 i 为结尾,比如说现在有一个数组
{6,-3,-2,7,-15,1,2,2},dp[2]就是以-2为结尾的,那么显然dp[2]的最大值就是1(6,-3,-2),dp[3]要以7结
尾那么以7结尾的子序列最大和就是8(6,-3,-2,7)。现在我们开始细细品一下上面这个递推式,求dp[i]
的时候是不是有两种可能,要么就是像上面的dp[3]一样,dp[2]求出来是1了,再加上自己array[3]是最大
的,那么还有一种可能就是说如果dp[2]我求出来是-100,那如果我也是dp[2]+array[3]的话是-93, 这时候
dp[2]反而是累赘,最大就是自己(因为前面定义了必须以i为结尾,也就说必须以7结尾)
#include <iostream>
#include<vector>
using namespace std;
int GetMax(int a, int b) //得到两个数的最大值
{
return (a) > (b) ? (a) : (b);
}
int main()
{
int size;
cin >> size;
vector<int> nums(size);
for (size_t i = 0; i < size; ++i)
cin >> nums[i];
int Sum = nums[0]; //临时最大值
int MAX = nums[0]; //比较之后的最大值
for (int i = 1; i < size; i++)
{
Sum = GetMax(Sum + nums[i], nums[i]); //状态方程
if (Sum >= MAX)
MAX = Sum;
}
cout << MAX << endl;
return 0;
}
day06
13. printf函数中格式化串的性质
执行下面语句后的输出为
int I=1; if(I<=0) printf("****\n") ; else printf("%%%%\n");
A %%
B **
C 有语法错,不能正确执行
D %%%%
【答案解析】A
printf(格式化串,参数1,参数2...)
==格式化串的作用:printf中第一个参数之后的参数要按照什么格式打印==
例如: %d --->按照整型打印 %f --->按照float类型打印...
==格式串是存在一定规定的,%符号之后若是跟上特定的字符才会表示一定的格式化串==
例如:%Q --->无效的格式 ----> 编译器会忽略%
printf("%Q); --->直接输出Q
那么本题的printf("%%%%\n"); 在打印浮点数的过程中有时候会存在打印%符号的情况,而%%就会转换成打印%
结果就是两个%
14. 贪心
【答案解析】
仔细读理解了上面的题目解读,本题就非常简单了,使用vector>定义一个二维数组,resize开
空间并初始化,每个位置初始化为1,表示当蛋糕,a[i][j]位置放蛋糕,则可以标记处a[i][j+2]和a[i+1][j]位置
不能放蛋糕,遍历一遍二维数组,标记处不能放蛋糕的位置,统计也就统计出了当蛋糕的位置数。
// 直接暴力计算,默认所有蛋糕的位置标记成1,不能放的地方标记成0
// 1 1 0 0 1 1
// 1 1 0 0 1 1
// 0 0 1 1 0 0
// 0 0 1 1 0 0
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int w, h, res = 0;
cin >> w >> h;
vector<vector<int>> a;
a.resize(w);
for (auto& e : a)
e.resize(h, 1);
for (int i = 0; i < w; i++)
{
for (int j = 0; j < h; j++)
{
if (a[i][j] == 1)
{
res++;
// 标记不能放蛋糕的位置
if ((i + 2) < w)
a[i + 2][j] = 0;
if ((j + 2) < h)
a[i][j + 2] = 0;
}
}
}
cout << res;
return 0;
}
day07
15. 默认值从右往左依次给出
在 C++ 语言中,对函数参数默认值描述正确的是()
A 函数带默认值的参数只能有一个
B 一个函数的参数若有多个,则参数默认值的设定可以不连续
C 函数参数必须设定默认值
D 在设定了参数的默认值后,该参数后面定义的所有参数都必须设定默认值
【答案解析】D
16. 缺省(默认)访问权限
下面关于类定义的说法中,正确的是:
A 类定义中包括数据成员和函数成员的声明
B 类成员的缺省访问权限是保护的
C 数据成员必须被声明为私有的
D 成员函数只能在类体外进行定义
【答案解析】A
针对B选项,==缺省访问权限其实就是默认访问权限,C++中class类的默认访问权限是private,而struct类的默认访问权限是public==
17. 必须通过初始化列表初始化的条件
有一个类A,其数据成员如下:
class A { //... private: int a; public: const int b; float*& c; static const char* d; static double* e; };
则构造函数中,成员变量一定要通过初始化列表来初始化的是:__。
A a b c
B b c
C b c d e
D b c d
E b
F c
【答案解析】B
首先,我们需要明确概念:==对于初始化来说,只有初始化列表位置才是真正的初始化,构造函数体中只是赋值==,而初始化列表只能对类中非静态的成员变量来进行初始化 (那么本题中可选的只有a,b,c 三个元素可进行初始化列表初始化)
- [ ] 必须要在初始化列表初始化的情况:
- const 修饰的成员变量 - 引用类型的成员变量 - 类类型的对象,该类没有默认的构造函数
其中前两种情况是因为const和引用必须要在初始化的时候赋初值,而对于第三种情况,对于有默认构造函数的类,,编译器会自动调用默认构造函数,但是没有默认构造函数则需要用户自己调用
18. operator +=
C++ 中,有如下类模板定义:
template<class T> class BigNumber { long n; public: BigNumber(T i) :n(i) { } BigNumber operator+(BigNumber b) { return BigNumber(n + b.n); } };
已知 b1, b2 是 BigNumber 的两个对象,则下列表达式中错误的是()
A 3 + 3
B b1 + 3
C b1 + b2
D 3 + b1
【答案解析】D
==如果将运算符重载成类的成员函数,形参个数会比该运算符所需的参数个数少1
因为:成员函数具有隐藏的this指针==
那么该题目中实现的operator+= 是对两个BigNumber的对象进行相加
A选项:3+3 二者都是int类型 不需要用到运算符重载
B选项:因为类中存在单参的构造函数,该构造函数具有类型转换的功能
b1+3 编译器在调用单参构造函数时,会将3转换成BigNumber类型的对象
C选项:两个BigNumber类型的对象相加
D选项:int + BigNumber类型的对象 因为隐含this指针的缘故,无法实现
19. 类模板的实例化过程
类模板的使用实际上是类模板实例化成一个具体的__。
A 类
B 函数
C 模板类
D 对象
【答案解析】A
20. 括号匹配问题
【答案解析】
用栈结构实现,栈中存放左括号,当遇到右括号之后,检查栈中是否有左括号,如果有则出栈,如果没有,则说明不匹配。
#include <string>
#include <iostream>
#include <stack>
using namespace std;
class Parenthesis {
public:
bool chkParenthesis(string A, int n) {
// write code here
stack<char> sc;
for (auto ele : A) {
switch (ele) {
case '(':
sc.push(ele);
break;
case ')':
{
if (sc.empty() || sc.top() != '(')
return false;
else
sc.pop();
}
break;
default:
return false;
}
}
return true;
}
};