牛客网上 共有真题六套,其中每套题有15分题一道,20分题目3道,25分题目1道,共计100分。考试时要求考生在180分钟内完成。我之前只学过Java和C#,没有学过C语言,粗浅学习了一下C语言基本语法,想借刷题这个机会好好体会一下面向过程的设计语言的精髓。这里计划: 1.先说题目思路,2.再贴上自己的垃圾代码,做一番自我批评,3.然后贴上我认为的经典代码,分析一番以便学习。通过这样的三个步骤希望提高自己的水平,也为后面开始做20分题做准备。
解题思路
1.将输入数字按照字符形式输入(绝对常考考点)
15分题总会出一些“大数据“给我们来做,这个时候一般的处理方法就是把长长的数字看成一个个字符来读取到字符串中:
char A[10],B[10];//10的10次方是1+十个零,小于1+十个零就是十个九
scanf("%s %s",A,B);//这里因为A和B都是字符数组所以不用加&符号,但是一般变量要加
2.将读取的DA和DB和字符串中比较得到PA和PB
就是一个简单的for循环就可以搞定,唯一要注意的点是DA和DB是数字,A和B里面是字符,字符‘1’变成数字1需要经过转换,这也是一个容易遗漏的知识点:
1='1'-'0';//其他数字同理
3.输出PA+PB
贴上第一次做的代码
#include
int splid(int A,int *LA,int NA);
int main() {
int a, b, da, db, na=1, nb=1;
int pa=0, pb=0;
int la[1000], lb[1000];
scanf("%d %d %d %d", &a, &da, &b, &db);
na=splid(a, la, na);
nb=splid(b, lb, nb);
for (int i = 0; i < na; i++) {
if (la[i] == da) {
pa = pa * 10 + da;
}
}
for (int i = 0; i < nb; i++) {
if (lb[i] == db) {
pb = pb * 10 + db;
}
}
printf("%d\n", pa + pb);
return 0;
}
//拆分a,b
int splid(int A,int *LA,int NA) {
NA = 1;
int i = 0;
while (A / 10 >= 1) {
NA++;
LA[i] = A % 10;
A /= 10;
i++;
}
LA[i] = A % 10;
return NA;
}
虽然三十来行,但是很明显可以更短,输入时当时并不会直接把数字变成字符串,导致多出一个splid函数,复杂!
看到其他同学就很厉害了:灵活、轻巧,但是太集成化,赋值与使用直接二合一,不知道有没有隐患,看了多遍,对我小白来说真的很精彩
#include
#include
int main()
{
long long A,DA,B,DB;
while(scanf("%lld %lld %lld %lld",&A,&DA,&B,&DB)!=EOF)
{
long long PA=0,PB=0;
while(A)
{
if(A%10==DA)
PA=PA*10+DA;
A=A/10;
}
while(B)
{
if(B%10==DB)
PB=PB*10+DB;
B=B/10;
}
printf("%lld\n",PA+PB);
}
return 0;
}
解题思路
很明显此题和1006题有很大相似,都是要对各位数字做事情:
一、读取数字为字符串数组
二、每个非零(!= 0)字符进行判断
这里注意非零字符又是新学到的一点,如果用while( XX != 0){ }这样的结构,循环可以及时停止。后面接上switch case或者双重for循环都可以达到扫描每个数字的数量的作用
三、输出
输出时候判断一下该位数字的个数是不是0;如果不是0则输出。
写的太丑,贴出代码需要勇气,可见结构异常臃肿,重复相当多,这个也是第一次做的,垃圾代码
#include
void print(int a, int n,int large);
int main() {
char input[1000];
int i = 0;
int num[10] = { 0 };
int large = 9;
scanf("%s", input);
while (input[i])
{
switch (input[i])
{
case '0':
num[0]++; break;
case '1':
num[1]++; break;
case '2':
num[2]++; break;
case '3':
num[3]++; break;
case '4':
num[4]++; break;
case '5':
num[5]++; break;
case '6':
num[6]++; break;
case '7':
num[7]++; break;
case '8':
num[8]++; break;
case '9':
num[9]++; break;
default:
break;
}
i++;
}
for (int j = 9; j > 0; j--) {
if (num[j] != 0) {
large = j;
break;
}
}
print(num[0],0,large);
print(num[1],1,large);
print(num[2],2, large);
print(num[3],3, large);
print(num[4],4, large);
print(num[5],5, large);
print(num[6],6, large);
print(num[7],7, large);
print(num[8],8, large);
print(num[9],9, large);
return 0;
}
void print(int a,int n, int large) {
if (a != 0&& n!=large) {
printf("%d:%d\n", n, a );
}
else if(a != 0 && n == large)
printf("%d:%d", n, a);
}
这里继续贴上我认为的经典代码,也很简练,c++写的不过差别不大,也就是读取输入不一样。
#include
#include
using namespace std;
int times[10];
string n;
int main() {
cin >> n;
for (int i = 0; i < n.length(); i++) //不用判断直接给数组++,思路精巧!!
times[n[i]-'0']++;
for (int i = 0; i < 10; i++)//输出思路也值得学习
if(times[i])
printf("%d:%d\n", i, times[i]);
return 0;
}
这里他所使用的计数方法简直让我这个小白茅塞顿开,五星好评!!
输入例子:
123 4577973
输出例子:
12:42:59
题目分析:
题目说的天花乱坠,其实就是两个数相减、除以100、再转化成时间的60进制的这么一个过程
一、两数相减除以100得到时间间隔Span
简单的运算,需要注意要对span这个结果进行四舍五入,刚学到一个四舍五入的办法很好:
int s = int(span + 0.5);//即加0.5再取整
二、转化成60进制
一般的做法就是按照 H-> M-> S的顺序来进行就可以了,注意输出如果小于10要表示为比如3就是03。
自己第一次的代码:
#include
int main() {
int big = 0, little = 0;
int hour, minute, second,span;
double span0;
scanf("%d %d", &little, &big);
span = (big - little) / 100;
span0 = (big - little) / 100.0;
if (span0 > span + 0.4)
span++;
hour = span / 3600;
minute = (span - hour * 3600) / 60;
second = (span - hour * 3600 - minute * 60);
if (hour < 10)
printf("0%d:", hour);
else
printf("%d:",hour);
if (minute < 10)
printf("0%d:", minute);
else
printf("%d:", minute);
if (second < 10)
printf("0%d\n", second);
else
printf("%d\n", second);
return 0;
}
1.这里用的输出00:00:00格式用的是笨办法;
2.四舍五入用的也是笨办法;
3.反正看起来惨不忍睹
放上别人的好代码(还是C++):
#include
using namespace std;
int main() {
int c1, c2;
cin >> c1 >> c2;
double t = 1.0*(c2 - c1) / 100;
int h = t / 3600;
int m = t / 60 - h * 60;
int s = int(t + 0.5) % 60; //保证四舍五入,浮点数+0.5再取整
printf("%02d:%02d:%02d", h, m, s);//输出格式,我曾经试了一次printf("%2d:%2d:%2d",h,m,s),失败就放弃了这个方法,现在看来真是学的太粗糙
return 0;
}
题目分析
这道题目数据稍稍有点多,考点还是大数据运算后的单个数字处理,因此还是使用char字符串来读取数据
一、读取身份证号(18位)
二、按权值求和再取模(取余数)
三、验证余数与最后一位是否匹配,不匹配则输出
因为都匹配需要输出all passed,所以这里可以引入一个判断标志,有不匹配就变false,最后是true就输出all passed
#include
#include
int main() {
int gra[] = { 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 };//权重
char M[] = { '1','0','X','9','8','7','6','5','4','3','2' };//尾号
bool isNamal=true;//判别标志位
int n = 2, graSum[100] = { 0 }, arv[100] = { 0 };//总数,权和,取模
scanf("%d", &n);//曾经第一个错误:忘记&
char id[100][18] = { '0' };//第二个错误,想成了17位
for (int i = 0; i < n; i++) {
scanf("%s", id[i]);
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < 17; j++) {
if (id[i][j] == 'X') {
id[i][j] = '0' + 10;
}
graSum[i] += gra[j] * (id[i][j]-'0');//注意-'0'
}
arv[i] = graSum[i] % 11;
if (M[arv[i]] != id[i][17]) {//第三个错误,第二个错误改为18以后忘记把这个改成17
isNamal = false;
for (int j = 0; j < 18; j++) {
if (id[i][j] == '0'+10) {
id[i][j] = 'X';
}
printf("%c", id[i][j]);//第四个错误,输出要一个一个输,所以是%c而不是%s
}
printf("\n");
}
}
if (isNamal == true) {
printf("All passed");
}
return 0;
}
别人的经典代码:
#include
int main()
{
int N;
int weight[] = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
char ZtoM[] = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
char ID[19];
scanf("%d", &N);
int d, sum, count = 0; /* index, weighted sum and count for legal IDs */
for(int i = 0; i < N; i++)
{
scanf("%s", ID);
for(d = 0, sum = 0; d < 17 && ID[d] >= '0' && ID[d] <= '9'; d++)
sum += (ID[d] - '0') * weight[d];
if(d == 17 && ID[17] == ZtoM[sum % 11]) /* legal ID */
count++;
else /* illegal ID */
puts(ID);
}
if(count == N)
puts("All passed");
return 0;
}
需要注意的是,我在输入身份证的时候将’X’转换成了’0’+10(也就是’:’),但是看别的程序并没有增加这一步,但是他们的编译也得到了通过,稍有不解。