一、枚举
判断是否可以使用枚举:分析数据量。
若时间限制在1000ms的情况下,大约可以进行10⁷的运算。
复杂度 | 数据量 |
---|---|
O(n!) | 10 |
O(2ⁿ) | 20 |
O(n³) | 200 |
O(n²) | 3000 |
O(nlogn) | 10⁶ |
O(n) | 10⁷ |
O(√10) | 10¹⁴ |
O(logn) | >10²⁰ |
1 abc–清华大学
描述
设a、b、c均是0到9之间的数字,abc、bcc是两个三位数,且有:abc+bcc=532。求满足条件的所有a、b、c的值。
输入描述:
题目没有任何输入。
输出描述:
请输出所有满足题目条件的a、b、c的值。 a、b、c之间用空格隔开。 每个输出占一行。
示例1
输入:
输出:
题解:
分析:
abc和bcc是两个三位数,由乘法分配律可知
abc = a*100 + b*10 + c
bcc = b*100 + c*10 + c = b*100 + 11*c
abc + bcc = a*100 + b*110 + c*12
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
for (int a = 0; a <= 9; ++a) {
for (int b = 0; b <= 9; ++b) {
for (int c = 0; c <= 9; ++c) {
if (a*100 + b*110 + c*12 == 532) {
cout << a << " " << b << " " << c << endl;
}
}
}
}
return 0;
}
2 反序数–清华大学
描述:
设N是一个四位数,它的9倍恰好是其反序数(例如:1234的反序数是4321)
求N的值
输入描述:
程序无任何输入数据。
输出描述:
输出题目要求的四位数,如果结果有多组,则每组结果之间以回车隔开。
示例1
输入:
无
输出:
无
题解:
#include <iostream>
#include <cstdio>
using namespace std;
/*
* 反序数--清华大学
*/
int main() {
int num = 0;
int reverseNum = 0;
for (int a = 0; a <= 9; ++a) {
for (int b = 0; b <= 9; ++b) {
for (int c = 0; c <= 9; ++c) {
for (int d = 0; d <= 9; ++d) {
num = a * 1000 + b * 100 + c * 10 + d;
reverseNum = d * 1000 + c * 100 + b * 10 + a;
//0XXX不是四位数
if (a != 0 && d != 0) {
if (9 * num == reverseNum) {
cout << a << b << c << d << endl;
}
}
}
}
}
}
return 0;
}
#include <iostream>
#include <cstdio>
using namespace std;
/**
* 获取num的反序数
* @param num
* @return
*/
int getReverseNumber(int num) {
int reverseNumber = 0;
while (num != 0) {
reverseNumber *= 10;
reverseNumber += num % 10;
num /= 10;
}
return reverseNumber;
}
/*
* 反序数--清华大学
*/
int main() {
/*
* 1111*9=9999,所以i循环到1111即可
*/
for (int i = 1000; i <= 1111; ++i) {
if (9 * i == getReverseNumber(i)) {
cout << i << endl;
}
}
return 0;
}
3 对称平方数–清华大学
描述
打印所有不超过256,其平方具有对称性质的数。如2,11就是这样的数,因为22=4,1111=121。
输入描述:
无任何输入数据
输出描述:
输出具有题目要求的性质的数。如果输出数据不止一组,各组数据之间以回车隔开。
示例1
输入:
无
输出:
无
题解:
#include <iostream>
#include <cstdio>
using namespace std;
/**
* 获取num的反序数
* @param num
* @return
*/
int getReverseNumber(int num) {
int reverseNumber = 0;
while (num != 0) {
reverseNumber *= 10;
reverseNumber += num % 10;
num /= 10;
}
return reverseNumber;
}
/**
* KY267 对称平方数--清华大学
* @return
*/
int main() {
/*
* 判断某个数num,其完全平方数是否为对称数
* 即 num*num = num*num的反序数
*/
for (int num = 0; num <= 256; ++num) {
if (num * num == getReverseNumber(num * num)) {
cout << num << endl;
}
}
return 0;
}
二、模拟
- 图形排版
- 日期问题
- 其他模拟
1 输出梯形–清华大学
描述:
输入一个高度h,输出一个高为h,上底边为h的梯形。
输入描述:
一个整数h(1<=h<=1000)。
输出描述:
h所对应的梯形。
样例
输入:
4
样例输出:
****
******
********
**********
题解:
此题只需要按几何的方法画出梯形,然后找到行和列之间的关系即可。
#include <iostream>
#include <cstdio>
using namespace std;
/**
* 输出梯形--清华大学
* @return
*/
int main() {
//用户出入h
int h;
while (cin >> h) {
//行
int row = h;
//列
int col = h + 2 * (h - 1);
/*
* 解法1
*/
for (int i = 0; i < row; ++i) {
//打印空格
for (int j = 0; j < col - h - 2 * i; ++j) {
cout << " ";
}
//打印 *
for (int k = 0; k < h + 2 * i; ++k) {
cout << "*";
}
//打印换行
cout << endl;
}
/*
* 解法2
*/
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
if (j < col - h - 2 * i) {
cout << " ";
} else {
cout << "*";
}
}
cout << endl;
}
}
return 0;
}
2 叠筐–杭州电子科技大学
描述:
现在给你两种颜色的箩筐,需要的时候,就把一个个大小差一圈的筐叠上去,使得从上往下看时,边筐花色交错。这个工作现在要让计算机来完成,得看你的了。
输入描述:
输入是一个个的三元组,分别是,外筐尺寸n(n为满足0<n<80的奇整数),中心花色字符,外筐花色字符,后二者都为ASCII可见字符;
输出描述:
输出叠在一起的筐图案,中心花色与外筐花色字符从内层起交错相叠,多筐相叠时,最外筐的角总是被打磨掉。叠筐与叠筐之间应有一行间隔。
示例:
输入:
11 B A
5 @ W
输出:
AAAAAAAAA
ABBBBBBBBBA
ABAAAAAAABA
ABABBBBBABA
ABABAAABABA
ABABABABABA
ABABAAABABA
ABABBBBBABA
ABAAAAAAABA
ABBBBBBBBBA
AAAAAAAAA
@@@
@WWW@
@W@W@
@WWW@
@@@
题解:
这道题属实是有点难,思考了很久没什么思路,最后看了教程才有有点想法。
分析:
1、先将4个角补上,成为一个正方形。
2、从最外圈的正方形向内圈的正方形逐步构造。
3、以正方形的左上角坐标与右下角坐标来表示该圈。
4、为每个圈填充中心字符和外筐字符。
5、确定每个圈的边长,即填充字符的个数
6、构造完成后剔除4个角。
#include <iostream>
#include <cstdio>
using namespace std;
const int MAX_NUM = 80;
/**
* 叠筐--杭州电子科技大学
* @return
*/
int main() {
//二维矩阵存放字符
char matrix[MAX_NUM][MAX_NUM];
//外圈边长
int n;
//中心字符
char centerChar;
//外圈字符
char outsideChar;
//第一个案列
bool firstCase = true;
while (cin >> n >> centerChar >> outsideChar) {
//每个叠筐间输出空行
if (firstCase) {
//第一个叠筐不输出空行
firstCase = false;
} else {
//非第一个叠筐输出空行
cout << endl;
}
//(i, i)表示每个圈最左上角坐标
for (int i = 0; i <= n / 2; ++i) {
//(j, j)表示每个圈最右下角坐标
int j = n - 1 - i;
//当前圈的边长
int length = n - 2 * i;
//当前圈的字符
char currentChar;
if ((n / 2 - i) % 2 == 0) {
//距离为偶数
currentChar = centerChar;
} else {
//距离为奇数
currentChar = outsideChar;
}
/*
* 为当前圈赋值
*/
for (int k = 0; k < length; ++k) {
//上边
matrix[i][i + k] = currentChar;
//下边
matrix[i + k][i] = currentChar;
//左边
matrix[j - k][j] = currentChar;
//右边
matrix[j][j - k] = currentChar;
}
}
/*
* 除去四个角
*/
if (n != 1) {
matrix[0][0] = ' ';
matrix[0][n - 1] = ' ';
matrix[n - 1][0] = ' ';
matrix[n - 1][n - 1] = ' ';
}
/*
* 逐行打印二维数组
*/
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cout << matrix[i][j];
}
cout << endl;
}
}
return 0;
}
3、今年的第几天?–清华大学
描述
输入年、月、日,计算该天是本年的第几天。
输入描述:
包括三个整数年(1<=Y<=3000)、月(1<=M<=12)、日(1<=D<=31)。
输出描述:
输入可能有多组测试数据,对于每一组测试数据, 输出一个整数,代表Input中的年、月、日对应本年的第几天。
示例1
输入:
1990 9 20
2000 5 1
输出:
263
122
题解:
此题较基础,只需把每个月对应的天数加起来即可。但是,日期类问题有一个注意点就是“闰年”,每逢闰年,2月就会有29天。
#include <iostream>
#include <cstdio>
using namespace std;
/*
* 0~12月份对应的天数
*/
int dayTable[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, //平年
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} //闰年
};
/**
* 判断是否为闰年
* @param year
* @return
*/
int isLeapYear(int year) {
//return (year & 3 == 0 && year % 100 != 0) || year % 400 == 0;
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
/**
* 今年的第几天?--清华大学
* https://www.nowcoder.com/practice/ae7e58fe24b14d1386e13e7d70eaf04d?tpId=40
* @return
*/
int main() {
int year;
int month;
int day;
while (cin >> year >> month >> day) {
//记录天数
int dayNumber = 0;
int row = isLeapYear(year);
for (int i = 0; i < month; ++i) {
dayNumber += dayTable[row][i];
}
dayNumber += day;
cout << dayNumber << endl;
}
return 0;
}
4 打印日期–华中科技大学
描述
给出年份m和一年中的第n天,算出第n天是几月几号。
输入描述:
输入包括两个整数y(1<=y<=3000),n(1<=n<=366)。
输出描述:
可能有多组测试数据,对于每组数据, 按 yyyy-mm-dd的格式将输入中对应的日期打印出来。
示例1
输入:
2000 3
2000 31
2000 40
2000 60
2000 61
2001 60
输出:
2000-01-03
2000-01-31
2000-02-09
2000-02-29
2000-03-01
2001-03-01
题解:
注意判断“闰年”,按“yyyy-mm-dd”格式输出日期,格式不对也会判错。
#include <iostream>
#include <cstdio>
using namespace std;
/*
* 空间换时间
* 二维数组保存平年和闰年0~12月份对应的天数
*/
int dayTable[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, //平年
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} //闰年
};
/**
* 判断是否为闰年
* 若是闰年,则返回1,对应dayTable[1][];反之,返回0,对应dayTable[0][]
* @param year
* @return
*/
int isLeapYear(int year) {
//return (year & 3 == 0 && year % 100 != 0) || year % 400 == 0;
return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}
/**
* 打印日期--华中科技大学
* @return
*/
int main() {
int year;
int dayNumber;
while (cin >> year >> dayNumber) {
int month = 0;
int day = 0;
int row = isLeapYear(year);
/*
* 计算月份
* 若dayNumber大于月份的天数,则减去对应天数
* 同时,month++
*/
while (dayNumber > dayTable[row][month]) {
dayNumber -= dayTable[row][month];
month++;
}
day = dayNumber;
/*
* 按格式输出日期
* %2d表示输出宽度为2的整数,超过2位则按实际数据输出,不足2位则右对齐输出
* %02d表示输出宽度为2的整数,超过2位则按实际数据输出,不足2位则前置补0
* %5.2f表示输出宽度为5的浮点数,其中小数点后2位,不足5位则右对齐输出
*/
printf("%04d-%02d-%02d\n", year, month, day);
}
return 0;
}
5 手机键盘–清华大学
描述
按照手机键盘输入字母的方式,计算所花费的时间 如:a,b,c都在“1”键上,输入a只需要按一次,输入c需要连续按三次。 如果连续两个字符不在同一个按键上,则可直接按,如:ad需要按两下,kz需要按6下 如果连续两字符在同一个按键上,则两个按键之间需要等一段时间,如ac,在按了a之后,需要等一会儿才能按c。 现在假设每按一次需要花费一个时间段,等待时间需要花费两个时间段。 现在给出一串字符,需要计算出它所需要花费的时间。
输入描述:
一个长度不大于100的字符串,其中只有手机按键上有的小写字母
输出描述:
输入可能包括多组数据,对于每组数据,输出按出Input所给字符串所需要的时间
示例1
输入:
bob
www
输出:
7
7
题解:
手机按键如下:
因为有些按键上面有三个字母,有些有四个字母,显然很难找到规律。所以,我们采用预处理策略,采取空间换时间的方式,将每个字母需要的按键次数先记录起来。每当遇到一个字母,直接访问数组便可得到该字母的按键次数。
由此,可得
abc def ghi jkl mno pkrs yuv wxyz
123 123 123 123 123 1234 123 1234
定义一维数组,记录按键次数
int keyTable[26] = {1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,4,1,2,3,1,2,3,4};
还有另外一个问题,若两个连续的字符来自同一个按键,按完第一个后中间需要等到一个时间段才能按第二个,那要怎么知道两个字符是否来自同一按键呢?
观察可知,若两个字符来自同一个按键,则字符之间的差值等于两个字符按键次数的差值。
对于与a和c,则有
字符的差值:c-a = 67-65 = 2
字符按键次数的差值:3-1 = 2
对于s和p,则有
字符的差值:s-p = 99-96 = 3
字符按键次数的差值:4-1 = 3
#include <iostream>
#include <cstdio>
using namespace std;
/*
* 字符对应的按键次数
*/
int keyTable[26] = {1, 2, 3, 1, 2, 3, 1, 2, 3,
1, 2, 3, 1, 2, 3, 1, 2, 3,
4, 1, 2, 3, 1, 2, 3, 4};
/**
* 手机按键--清华大学
* @return
*/
int main() {
string str;
while (cin >> str) {
int time = 0;
for (int i = 0; i < str.size(); ++i) {
time += keyTable[str[i] - 'a'];
//连续的字符来自同一个按键
if (i != 0 && (str[i] - str[i - 1] ==
keyTable[str[i] - 'a'] - keyTable[str[i - 1] - 'a'])) {
time += 2;
}
}
cout << time << endl;
}
return 0;
}
三、总结
本章学习收获颇丰,很多的题目都是来自于各大名校的复试题,记录一下笔记,方便自己回顾。
参考教材–《王道计算机考研——机试指南》