本文作者:大家好,我是原始豌豆,欢迎来到牛客网刷题解析第四期,感谢你阅读本文欢迎评论,收藏,点赞哦。
内容专栏:这里是《牛客网在线编程》专栏,笔者用重金(时间和精力)打造,每道题目提供多种解法,从基础到拓展,希望可以帮到读者们。
写作不易:本文对每道题目提供了多种解法并加上了详细的注释,意在帮助读者锻炼思维灵活性,提高分析、解决问题的能力)。
开端
本次更新,全篇共一万多字,详细解析了每道题目,对其中一些题目采用了多种解法,并详细讲解了其中蕴含的算法思想和数学公式,在这篇文章中,我将分享刷题过程中的一些感悟、技巧和策略。同时,我也会分享一些个人的学习心得和经验,希望能帮助到同样热爱编程的你。
提升算法能力的秘密武器,让我们一起踏上这段奇妙的C语言刷题之旅吧!!!!
题目目录
牛客网语法篇基础语法50~80题(C语言实现)
本次更新在牛客网基础语法50~80题之间的题目进行了筛选,挑选了一些有价值的题目作为讲解题目
题目网址链接请点这✌️
标注“ * ”符号的题目为重点题目(“ * ” 数越多,难度越高)
本页目录跳转请点下方
BC52 判断整数奇偶性
BC55 判断闰年
BC56 判断字母
BC59 小乐乐找最大数 *
BC61 牛牛的二三七整除 *
BC63 网购
BC64 牛牛的快递 *
BC66 牛牛的通勤
BC67 牛牛的金币 *
BC71 三角形判断
BC72 牛牛的计划*
BC73 计算一元二次方程 **
BC76 [NOIP2008]ISBN号码 **
BC79 小乐乐求和
B80 奇偶统计
//解法一 传统解法 利用奇数模2不等于0,偶数模2等于0的性质
int main() {
int num;
while (scanf("%d", &num) !=EOF) { // 循环从键盘输入中获取值并赋给num
if ((num & 1) == 1)
printf("Odd\n"); // 奇数打印Odd
else
printf("Even\n"); // 偶数打印Even
}
return 0;
}
//解法二 利用位运算符&进行判断
//将该数与1进行按位与(&)运算,如果结果为1,那么这个数是奇数,如果结果为0,那么这个数是偶数。
//这是因为,对于任何整数n,n&1的结果只有两种可能:0或1,分别对应偶数和奇数。
#include
int main() {
int num = 0;
while ( scanf("%d", &num) != EOF) {
// 你要判断的数
if (num & 1)
printf("Odd\n");
else
printf("Even\n");
}
}
//解法三 利用异或运算^进行判断
//具体来说,如果一个数与1进行异或(^)运算,如果这个数是偶数;那么结果等于这个数本身+1,如果这个数为奇数,那么结果等于这个数本身-1
#include
int main() {
int num = 0;
while (scanf("%d", &num) != EOF) {
// 你要判断的数
if ((1 ^ num ) == num - 1)
printf("Odd\n");
else
printf("Even\n");
}
}
/*
1、非整百年份:能被4整除且不能被100整除的年份是闰年。(如2004,2020是闰年)
2、整百年份:能被400整除的年份是闰年。(如2000,1600是闰年)
*/
#include
int main() {
int year = 0;
scanf("%d", &year);
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))//注意两个条件是逻辑或关系
printf("yes\n");
else
printf("no\n");
return 0;
}
//解法一 传统解法
#include
int main() {
char a;
scanf("%c", &a);
//不能直接写成if(a>='A'&&a<='z'),因为'A'到'z'之间还有一些特殊字符
if ((a >= 'A' && a <= 'Z') || (a >= 'a' &&a <= 'z'))
printf("YES");
else
printf("NO");
return 0;
}
//解法二 调用库函数
#include
#include // isalpha函数的头文件
int main() {
printf("%s", isalpha(getchar()) ? "YES" : "NO");
//直接运用判断是否是字母的函数,并利用三目运算符判断并输出
return 0;
}
//int isalpha(int c);函数,其中,c 是要检查的字符。如果 c 是一个字母,函数返回非零值;否则,返回0。
//解法一
#include
int main() {
int a,b,c,d,max=0;
for(int i=0;i<4;i++)
{
scanf("%d",&a);
max=a>max?a:max; //三目运算符判断a是否大于max,是则更新max,不是则继续循环判断
}
printf("%d",max);
return 0;
}
//解法二 作者原创
#include
int main() {
int num = 0, max = 0;///定义两个整数变量num和max,分别用于存储当前读取的数字和最大数字
char ch;
while ((ch = getchar()) != '\n') {
if (ch >= '0' && ch <= '9') { // 检查当前字符是否为数字(0-9)
num = num * 10 + (ch - '0');
//这步是关键,如果只是ch-'0',将ch转换成整型数据,那么只能判断一组数并且每个数都是一位数中的最大值,
//加上num*10,num初始为0,则可以对任意的几位数都进行比较。通过num不断*10,恢复数字所对应的权值,这也是在不知道元素个数
//的情况下,或不创建数组情况下,判断数字最大或最小值的新方法。
if (num > max) //检查当前数字是否大于max。
max = num; // 如果是,更新max的值。
} else // 如果当前字符不是数字
num = 0; // 遇到空格代表当前数字已处理完,重置num,开始处理下一个数字
}
printf("%d\n", max);
return 0;
}
//解法三,针对本题4个数比较而言,完全可以三目运算符嵌套使用,实现最精简写法
#include
int main() {
int a, b, c, d;
scanf("%d %d %d %d", &a, &b, &c, &d);
printf("%d", ((a > b ? a : b) > ( c > d ? c : d )) ? (a > b ? a : b) :( c > d ? c : d));
return 0;
}
// 解法一
#include // 引入标准输入输出库,用于使用printf和scanf等函数。
int main() { // 主函数,程序的入口点。
int num = 0; // 定义一个整数变量num,用于存储用户输入的数字。初始值设为0。
scanf("%d", &num); // 使用scanf函数从标准输入读取一个整数,并存储在num变量中。
// 检查num是否为偶数(能被2整除)
if (num % 2 == 0)
printf("2 "); // 如果num是偶数,输出“2 ”。
// 检查num是否为3的倍数(能被3整除)
if (num % 3 == 0)
printf("3 "); // 如果num是3的倍数,输出“3 ”。
// 检查num是否为7的倍数(能被7整除)
if (num % 7 == 0)
printf("7 "); // 如果num是7的倍数,输出“7 ”。
// 如果num不能被2、3、7中的任何一个整除
if (num % 2 != 0 && num % 3 != 0 && num % 7 != 0)
printf("n"); // 输出“n”。
return 0; // 主函数返回0,表示程序正常结束。
}
//解法二 数组
#include // 引入标准输入输出库,这样就可以使用printf、scanf等函数。
int main() // 主函数,程序的入口点。
{
int num; // 定义一个整数变量num,用于存储用户输入的数字。
char arr[3] = {2, 3, 7}; // 定义一个字符数组arr,并初始化为{2, 3, 7}。这个数组将用于存储可以整除的数字。
int i = 0; // 初始化i为0,用于后面循环的计数。
int j = 0; // 初始化j为0,用于标记是否找到可以整除的数字。
scanf("%d", &num); // 使用scanf函数从标准输入读取一个整数,并存储在num变量中。
for(i=0; i < 3; i++) // 开始一个for循环,从i=0开始,直到i<3结束。
{
if(num % arr[i] == 0) // 如果num能被arr[i]整除(即余数为0)。
{
printf("%d ", arr[i]); // 输出arr[i],即可以整除的数字。
j = 1; // 设置j为1,表示找到了可以整除的数字。
}
}
if(j == 0) // 如果j仍然是0,表示没有找到可以整除的数字。
putchar('n'); // 输出字符'n'。
return 0; // 主函数返回0,表示程序正常结束。
}
#include // 引入标准输入输出库
int main() { // 主函数
double price = 0.0; // 定义一个双精度浮点数变量,用于存储商品的价格
int month = 0; // 定义一个整数变量,用于存储月份
int day = 0; // 定义一个整数变量,用于存储日期
int flag = 0; // 定义一个整数变量,用于存储一个标志位,有优惠券用1表示,无优惠券用0表示
scanf("%lf %d %d %d", &price, &month, &day,
&flag); // 从标准输入读取价格、月份、日期和标志位
// 如果输入的日期是11月11日
if (month == 11 && day == 11)
price = price * 0.7 - 50.0 * flag; // 调整价格:原价的70%减去50*flag
// 如果输入的日期是12月12日
else if (month == 12 && day == 12)
price = price * 0.8 - 50 * flag; // 调整价格:原价的80%减去50*flag
// 如果调整后的价格小于0,输出0.00;否则输出调整后的价格,保留两位小数
if (price < 0)
printf("0.00\n");
else
printf("%.2lf\n", price);
return 0;
}
#include
#include // 引入数学库,用于使用数学函数如ceil。
int main() {
float a; // 定义三个浮点数变量a、b和c,但b和c在代码中并未使用。
char b; // 定义一个字符变量d,用于存储用户输入的字符。
scanf("%f %c", &a, &b); // 使用scanf函数从标准输入读取一个浮点数和一个字符,并分别存储在变量a和d中。
// 心得:%c前一定要加空格,这样可以在输入时跳过空格字符。
int money = a - 1 > 0 ? 20 + ceil(a-1) : 20; // 定义一个整数变量money。
// 如果a-1大于0,money的值为20加上a-1向上取整的结果;否则money的值为20。
//判断是否超重,a-1表示超重的公斤数,向上取整表示超重部分不足1kg 部分按 1kg计算。
if(b=='y') // 如果输入的字符b等于'y'。
printf("%d", money+5); // 输出money+5的值。
else // 如果输入的字符d不等于'y'。
printf("%d", money); // 输出money的值。
return 0;
}
#include
int main() {
int m, walk;
float taxi;
scanf("%d", &m);
walk = m;//走路时间就是距离的米数
taxi = 10 + m / 10.0;//打车时间就是等车的时间10S加上坐车的时间
printf("%c", walk < taxi ? 'w' : 'v');// 这里使用三元运算符来判断:如果walk小于taxi,则输出'w',否则输出'v'。
return 0;
}
#include
int main() {
int x, y, x1, y1; // 定义四个整数变量x, y, x1, y1,用于存储用户输入的坐标。
char ch; // 定义一个字符变量ch,用于存储方向字符。
scanf("%d%d%d%d", &x, &y, &x1, &y1);
// 判断x和x1的关系
if (x == x1) { // 如果x和x1相等 判断y和y1的关系来确定方向
if (y1 > y) // 如果y1大于y
ch = 'u'; // 设置ch为'u'(代表向上)
else if (y1 < y) // 如果y1小于y
ch = 'd'; // 设置ch为'd'(代表向下)
} else if (y == y1) { // 如果y和y1相等 判断x和x1的关系来确定方向
if (x1 > x) // 如果x1大于x
ch = 'r'; // 设置ch为'r'(代表向右)
else if (x1 < x) // 如果x1小于x
ch = 'l'; // 设置ch为'l'(代表向左)
}
printf("%c", ch); // 使用printf函数输出字符ch。
return 0;
}
#include
int main() {
int a, b, c;
while (scanf("%d%d%d", &a, &b, &c) != EOF) {
if (a + b > c && a + c > b && b + c > a)//首先检查这三个数是否满足三角形的基本条件:任意两边之和大于第三边。
{
if (a==b||b==c||a==c)//检查是否至少有两边的长度相等
{
if (a == b && b == c || a == b && a == c || b == c && a == c)//检查是否所有边都相等,如果是,则输出“等边三角形”。
printf("Equilateral triangle!\n");
else// 如果不是所有边都相等,但至少有两边相等,则输出“等腰三角形”。
printf("Isosceles triangle!\n");
}
else//如果既不是等边三角形也不是等腰三角形,则输出“普通三角形”。
printf("Ordinary triangle!\n");
}
else//如果输入的三个数不满足三角形的基本条件,则输出“不是三角形”
printf("Not a triangle!\n");
}
return 0;
}
//解法一 分支判断年月日
#include
int main() {
int y, m, d, y1, m1, d1;//定义六个整数变量,y,m,d表示开始学习日期的年、月、日。y1,m1,d1表示判断学习日期的年、月、日。
scanf("%d %d %d\n%d %d %d", &y, &m, &d, &y1, &m1, &d1);
if (y < y1) printf("yes");//如果年份1小于年份2,则输出“yes”
else if (y == y1 && m < m1) printf("yes");//如果年份相等,月份1小于月份2,则输出“yes”。
else if (y == y1 && m == m1 && d <= d1)printf("yes");// 如果年份和月份都相等,日期1小于等于日期2,则输出“yes”。
else printf("no");
return 0;
}
//解法二 完全可以一行解决,此中有真意。
#include
int main() {
int y, m, d, y1, m1, d1;
scanf("%d%d%d%d%d%d", &y, &m, &d, &y1, &m1, &d1);
printf("%s", ((y1 * 365 + m1 * 31 + d1) >= (y * 365 + m * 31 + d)) ? "yes" : "no");
return 0;
}
// 该题目难点在于求虚数根
//其次就是某些数据会出现-0.0的结果
//在C语言中,浮点数-0.0是合法的,表示一个负的零。这是因为浮点数在计算机中的表示方法决定的。
//浮点数使用IEEE 754标准进行表示,这个标准定义了浮点数的格式,包括符号位、指数和尾数。当一个数的符号位为1时,这个数就被表示为负数。
//因此,即使浮点数的尾数是0,但由于它的符号位为1,所以这个数仍然会被表示为负数。
//至于0本身,在数学上通常被认为是正数和负数的中性元素,即0既不是正数也不是负数。但在计算机中表示浮点数时,0被分为正0和负0,分别表示+0.0和-0.0。
//因此,在C语言中,-0.0是一个合法的表示,表示一个负的零。而0本身也可以被表示为+0.0或-0.0,这取决于它是在正数环境中还是负数环境中。
#include
#include
int main() {
double a, b, c, x1, x2,
delta; //定义变量a,b,c,delta 分别代表二次项系数,一次项系数,常数项和根的判别式Δ
while (scanf("%lf%lf%lf", &a, &b, &c) != EOF) {
if (a != 0) {
delta = pow(b, 2) - 4 * a * c;
if (delta > 0) {
x1 = (-b - sqrt(delta)) / (2 * a);
x2 = (-b + sqrt(delta)) / ( 2 * a);
printf("x1=%.2lf;x2=%.2f\n", x1, x2);
} else if (delta == 0) {
x1 = x2 = ( -b / (2 * a))+0 ; //会出现-0的情况,浮点数不能准确表示0 //解决方法-0+0=0;
//测试用例 4 0 0
printf("x1=x2=%.2lf\n", x1);
} else {
x1 = -b / (2 * a);//实部
x2 = sqrt(-delta) / (2 * a);//虚部
if (x2 < 0)//虚部如果出现负数,直接取反,因为符号是由打印处控制的(这里不要取绝对值会丢失精度)
x2 = -x2;//测试用例-1 5 -10
printf("x1=%.2lf-%.2lfi;x2=%.2lf+%.2lfi\n", x1, x2, x1, x2);
}
} else
printf("Not quadratic equation\n");
}
return 0;
}
//这个题还是有一点难度的,整体思路如下,将输入的字符串存到字符数组里,循环判断每个字符是否是数字字符,
//是就将它转换为数字,然后乘以count,count从零开始,每乘一次就自增一下。最后将每次dight的结果累加起来
//累加的和sum%11的结果就是识别码,然后通过分支语句判断识别码是否正确,作为修改的参照
#include
int main() {
char ch[14] = {'\0'};//创建字符数组用来存放字符串
scanf("%s",
ch);//输入13位的字符串,数组最后一位用来存放'\0',保证最后输出时依旧可以以%s打印
int count = 1, sum = 0, digit = 0;
char c = 0;
for (int j = 0; j < 11; j++) {//字符串的前11位才会出现数字字符,所以j<11
if (ch[j] >= '0' && ch[j] <= '9') {//判断是不是数字字符
digit = (ch[j] - '0') * count; //将数字字符转换成整数然后乘count
count++;//count每次乘完,就会++
sum += digit;//累加
}
}
sum %= 11;//累加的和sum%11的结果就是识别码
if (ch[12] - '0' == sum) //判断sum是否等于第12位的识别码
printf("Right");
else if (ch[12] == 'X' && sum == 10)//判断第12位是否等于X并且sum==10?
printf("Right");
else {
ch[12] = sum == 10 ? 'X' : sum + '0';//算出来的sum是否是10,是就将'X'变为识别码,不是就将sum转换为换为字符再作为识别码
printf("%s", ch);
}
return 0;
}
//说一下解法二的思路,将整个ISBN编码,以‘-’划分为四部分,分别计算每部分的累乘1 2 3···的和,
//将三部分的值加起来,%11得到正确的识别码,再将正确的识别码与输入的识别码用三目操作符作比较并考虑是否修改输入的识别码的值。
//解法二 14行代码,恐怖如斯
#include
int fin(int number, int dis) {
if (number == 0)
return 0;
return number % 10 * dis + fin(number / 10, dis - 1);//递归调用。它首先获取数字的最后一位,然后乘以dis,然后加上数字缩小10倍与dis-1这两个参数继续递归。
}
int main() {
int a, b, c;
char x, x1;
scanf("%d-%d-%d-%c", &a, &b, &c, &x);
x1 = (((a * 1 + fin(b, 4) + fin(c, 9)) % 11) == 10) ? 'X' : ((a * 1 + fin(b,4) + fin(c, 9)) % 11) + '0';
(x == x1) ? printf("Right") : printf("%d-%d-%d-%c", a, b, c, x1);
return 0;
}
//运用了一些面向对象的思想
#include
//定义四个函数,分别用于加法、减法、乘法和除法:
double Add(double x, double y) {
return x + y;
}
double Sub(double x, double y) {
return x - y;
}
double Mul(double x, double y) {
return x * y;
}
float Div(float x, float y) {
return x / y;
}
int main() {
double num1 = 0.0, num2 = 0.0, ret = 0.0;
char oper;
//使用switch语句根据运算符执行相应的数学运算:
scanf("%lf%c%lf", &num1, &oper, &num2);
switch (oper) {
case '+':
ret = Add(num1, num2);
break;
case '-':
ret = Sub(num1, num2);
break;
case '*':
ret = Mul(num1, num2);
break;
case '/':
if (num2 == 0)
printf("Wrong!Division by zero!");
else {
ret = Div(num1, num2);
}
break;
default:
printf("Invalid operation!");
break;
}
//使用另一个条件语句检查运算符是否为加、减、乘或除(且除数不为0),如果是,则输出运算的结果。
if (oper == '+' || oper == '-' || oper == '*' ||(oper=='/'&&num2!=0))
printf("%.4lf%c%.4lf=%.4lf", num1, oper, num2, ret);
return 0;
}
//解法一 递归写法
#include
long digui(long n) {
if (n == 1) //n 等于1,则函数返回 n。
return n;
else
return n + digui(n - 1);//函数返回 n 加上 digui(n - 1) 的值。
}
int main() {
long n = 0;
scanf("%ld", &n);
printf("%ld", digui(n));
}
//解法二 //等差数列求和公式 时间复杂度O(1)
#include
int main() {
long long n = 0;
scanf("%lld", &n);
long long sum = 0;
sum = (1 + n) * n / 2;//(首项加尾项)乘项数再除以2
printf("%lld\n", sum);
return 0;
}
//解法一 传统解法
#include
int main() {
int a = 0, b = 0, n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
if (i % 2 == 0)
a++;//统计奇数位数
else
b++;//统计偶数个数
}
printf("%d %d", b, a);
return 0;
}
//解法二 数学解法 通过规律发现如果n是偶数,那么1~n之间就有n/2个奇数,n/2个偶数
#include
int main() {
int n = 0;
//输入
scanf("%d", &n);
if (0 == n % 2) {
printf("%d %d", n / 2, n / 2);
}
else {//如果n是奇数,那么1~n之间就有n/2+1个奇数,n/2个偶数
printf("%d %d", n / 2 + 1, n / 2);
}
return 0;
}
总结:
本次筛选过的题目比往期明显增加了一些难度,刷题需要持之以恒的努力和耐心,只有不断地练习和总结,才能提高自己的编程能力和解决问题的能力。同时,也需要注重方法,选择合适的题目、理解题目、优化算法、测试和调试、总结和反思都是非常重要的步骤。
同时掌握一定的数学思维更有利于解题,数学培养了抽象思维的能力,从而更好地进行编程。比如在73题中,求解一元二次方程虚数根的方法,就需要一定的数学基础,67题中金币的位置判断本质上就是圆的标准方程,79题中求累加和,其实可以采用高斯算法前n项和的公式,直接使时间复杂度变成O(1),大大提高了效率。