1. ++操作符判断
int main()
{
int a, b, c;
a = 5;
c = ++a;//a=6 c=6
b = ++c, c++, ++a, a++;
// c=8 a=8 运算后各变量的值
// c=7 c=7 a=7 a=7 运算时的值
b += a++ + c;
// a=9 运算后各变量的值
// a=8 运算时的值
printf("a = %d b = %d c = %d\n:", a, b, c);
return 0;
}
2. 统计二进制中1的个数
思路:让这个数与1按位与。如果最后一位是0,那么按位与的结果就是0,反之是1,结果就是1。
然后把这个数向右移动一位,直到遍历完所有位。
int main()
{
int n = 3;
int count = 0;
int i = 0;
for (i = 0; i < 32; i++)
{
if ((n & 1) == 1)
{
count++;
}
n >>= 1;
}
printf("%d\n", count);
return 0;
}
3. 打印整数二进制的奇数位和偶数位
获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
思路:同上方类似,也是用给定数按位与1就可以得到每一位,只是要注意移动n移动的位数。
自己方法
int main()
{
//偶数位
int n = 2863311530;
int i = 0;
for (i = 0; i < 16; i++)
{
printf("%d ", n & 1);
n >>= 2;
}
printf("\n");
//奇数位
n >>= 1;
for (i = 0; i < 16; i++)
{
printf("%d ", n & 1);
n >>= 2;
}
return 0;
}
老师方法
void Printbit(int num)
{
for (int i = 31; i >= 1; i -= 2)
{
printf("%d ", (num >> i) & 1);
}
printf("\n");
for (int i = 30; i >= 0; i -= 2)//整数的最高位是符号位,而不是奇偶位。所以循环从30开始
{
printf("%d ", (num >> i) & 1);
}
printf("\n");
}
4. 求两个数二进制中不同位的个数
思路:也是通过将最后一位与1按位与,再将这两个数向右移动一位,直到遍历完每一位再比较。
int main()
{
int n = 1;
int m = 2;
int count = 0;
int i = 0;
for (i = 0; i < 32; i++)
{
if ((n & 1) != (m & 1))
count++;
n >>= 1;
m >>= 1;
}
printf("%d\n", count);
return 0;
}
5. 小乐乐上课需要走n阶台阶,因为他腿比较长,所以每次可以选择走一阶或者走两阶,那么他一共有多少种走法?
思路1:
假设n=10,fib(n)表示n个台阶的走法。
如果第一步走1个台阶,那么还剩9个台阶,剩余台阶走法是fib(9)
如果第一步走2个台阶,那么还剩8个台阶,剩余台阶走法是fib(8)
思路2:
假设台阶有5级
n 跳法
1 1
2 2
3 3
4 5
5 8
如果青蛙站在第1级台阶,那么剩下的4级台阶总共有5种跳法
如果青蛙站在第2级台阶,那么剩下的3级台阶总共有3种跳法
所以5级台阶的跳法:3级台阶的跳法+4级台阶跳法(3+5=8)
也就是当n<=2时,有几级台阶就只有几种跳法
当n>2时,跳法总共有:(n-1)+(n-2)
每次求n时,都是青蛙站在第1级,或第2级作为起点(动态规划:用上一步的结果,来计算下一步的结果)
int fib(int n)
{
if (n <= 2)
return n;
else
return fib(n - 1) + fib(n - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int m = fib(n);
printf("%d\n", m);
}
6. 有一个整数序列(可能有重复的整数),现删除指定的某一个整数,输出删除指定数字之后的序列,序列中未被删除数字的前后位置没有发生改变。
输入描述:
第一行输入一个整数(0≤N≤50)。
第二行输入N个整数,输入用空格分隔的N个整数。
第三行输入想要进行删除的一个整数。
输出描述:
输出为一行,删除指定数字之后的序列。
自己方法的思路:遍历数组,如果要删除的数和数组某个数相等则不打印
int main() {
int n = 0;//有几个数
scanf("%d\n", &n);
int i = 0;
int arr[n];//牛客网支持变长数组
//接收n个数字
for (i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int b = 0;//要删除的数
scanf("%d\n", &b);
for (i = 0; i < n; i++) {
if (b == arr[i])
continue;
printf("%d ", arr[i]);
}
return 0;
}
老师方法的思路:用两个下标变量(i和j)进行比较,i是原数组下标,如果i下标的数不等于要删除的数就放到j下标,最后打印遍历打印j下标的元素
int main() {
int n = 0;//有几个数
scanf("%d\n", &n);
int arr[n];//牛客网支持变长数组
//接收n个数字
int i = 0;
for (i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
int del = 0;//要删除的数
scanf("%d\n", &del);
int j = 0;//j作为下标锁定的位置就是用来存放不删除的数据的
for (i = 0; i < n; i++) {
if (arr[i] != del)
{
//j最开始是0,先试用,后++。如果arr[i]不等于要删除的数,就存到arr[j]里面并++
//这一步是将不等于del的元素移到前面
arr[j++] = arr[i];
//等效下方
//arr[j] = arr[i];
//j++;
}
}
for (i = 0; i < j; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
7. 输入n个成绩,换行输出n个成绩中最高分数和最低分数的差。
输入描述:
两行,第一行为n,表示n个成绩,不会大于10000。
第二行为n个成绩(整数表示,范围0~100),以空格隔开。
输出描述:
一行,输出n个成绩中最高分数和最低分数的差。
自己方法的思路:用冒泡排序将数组从小到大排列,比较第一个元素和最后一个元素的差
int main() {
int n = 0;
scanf("%d", &n);
int i = 0;
int arr[n];
for (i = 0; i < n; i++)
{
scanf("%d ", &arr[i]);
}
//冒泡排序
for (i = 0; i < n - 1; i++)
{
int j = 0;
for (j = 0; j < n - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
}
int ret = arr[n - 1] - arr[0];
printf("%d\n", ret);
}
老师方法的思路:
假设第一个元素最大,将数组里面的元素和它逐一比较,比他大就替换;
假设第一个元素最小,将数组里面的元素和它逐一比较,比他小就替换;
优化:
在向数组输入数据时就可以比较
继续优化:
假设最大值是0,最小值是100,在向数组输入数据时直接比较
int main()
{
int n = 0;
scanf("%d", &n);
int i = 0;
int arr[n];
//输入
for (i = 0; i < n; i++)
{
scanf("%d ", &arr[i]);
}
//找出最大值
int max = arr[0];//假设第一个元素最大
for (i = 1; i < n; i++)//不需要从下标为0的第一个元素开始,因为已经假设了一个元素
{
if (arr[i] > max)
max = arr[i];
}
//找出最小值
int min = arr[0];//假设第一个元素最小
for (i = 1; i < n; i++)
{
if (arr[i] < min)
min = arr[i];
}
int ret = max - min;
printf("%d\n", ret);
//优化版本
int max = arr[0];
int min = arr[0];
for (i = 1; i < n; i++)
{
scanf("%d ", &arr[i]);
if (arr[i] > max)
max = arr[i];
if (arr[i] < min)
min = arr[i];
}
//继续优化
int main()
{
int n = 0;
scanf("%d", &n);
int i = 0;
int arr[n];
int min = 100;//同下
int max = 0;//最大值设置0,因为如果设置成100,那么可能数组里没有数比它大
for (i = 0; i < n; i++)
{
scanf("%d ", &arr[i]);
if (arr[i] > max)
max = arr[i];
if (arr[i] < min)
min = arr[i];
}
return 0;
}
8. KiKi想完成字母大小写转换,有一个字符,判断它是否为大写字母,如果是,将它转换成小写字母;反之则转换为大写字母。
输入描述:多组输入,每一行输入一个字母。
输出描述:针对每组输入,输出单独占一行,输出字母的对应形式。
思路:通过scanf读取字符。判断读取到的字符,如果是小写就-32(因为字符保存的是ASCII码值);否则就+32
单次判断
//此方法输出一个字符会有一个*
//因为每输入一个字符就按回车,就会有换行,scanf读了字符但是没有读换行
//所以下次进来不是小写字符,就去到else读取了换行,在+32,所以出错
//scanf读取成功的时候,返回的是读取的数据的个数
//scanf函数在读取失败的时候返回EOF
//这个条件还可以写成(scanf("%c", &ch) != EOF)不等于EOF说明没有失败,所以进入循环
while (scanf("%c", &ch) == 1)
{
if (ch >= 'a' && ch <= 'z')
printf("%c\n", ch - 32);
else
printf("%c\n", ch + 32);
//所以需要下方代码销毁换行
getchar();//处理\n
}
两次判断
方法二:通过两次判断字符,就不需要处理\n
while (scanf("%c", &ch) == 1)
{
if (ch >= 'a' && ch <= 'z')
printf("%c\n", ch - 32);
else if (ch >= 'A' && ch <= 'Z')
printf("%c\n", ch + 32);
}
库函数方法
//方法三:使用库函数
while (scanf("%c", &ch) != EOF)
{
if (islower(ch))
printf("%c\n", toupper(ch));
else if (isupper(ch))
printf("%c\n", tolower(ch));
}
9. KiKi想判断输入的字符是不是字母,请帮他编程实现。
输入描述:多组输入,每一行输入一个字符。
输出描述:针对每组输入,输出单独占一行,判断输入字符是否为字母,输出内容详见输出样例。
思路:直接判断是否是大写字母或是小写字母。
需要单独处理\n版本
while (scanf("%c", &a) != EOF) {
if ((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z')) {
printf("%c is an alphabet.\n", a);
}
else {
printf("%c is not an alphabet.\n", a);
}
getchar();
}
不需要单独处理\n版本
//方法二:
//%c前面加空格,跳过下一个字符之前的所有字符
//这里的空格 " " 表示忽略任意数量的空白字符(包括空格、制表符、换行符等),直到遇到第一个非空白字符为止
while (scanf(" %c", &a) != EOF)
{
if ((a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'))//还可以使用库函数 if (isalpha(a))
{
printf("%c is an alphabet.\n", a);
}
else {
printf("%c is not an alphabet.\n", a);
}
}
10. KiKi参加了语文、数学、外语的考试,请帮他判断三科中的最高分。从键盘任意输入三个整数表示的分数,编程判断其中的最高分。
数据范围:0≤n≤100
输入描述:输入一行包括三个整数表示的分数(0~100),用空格分隔。
输出描述:输出为一行,即三个分数中的最高分。
自己的思路:3个数相互比较,a如果大于b c,那么a最大。其他两个数一样。
int main() {
int a = 0;
int b = 0;
int c = 0;
while (scanf("%d %d %d", &a, &b, &c) != EOF) {
if (a >= b && a >= c) {
printf("%d\n", a);
}
else if (b >= a && b >= c) {
printf("%d\n", b);
}
else if (c >= a && c >= b) {
printf("%d\n", c);
}
}
return 0;
}
老师思路:假设最高是0分,输入的三个数和它比较,比它大就替换它。
//老师方法
int main()
{
int i = 0;
int max = 0;
int score = 0;
for (i = 0; i < 3; i++)
{
scanf("%d ", &score);
if (max < score)
{
max = score;
}
}
printf("%d\n", max);
return 0;
}
11. 变种水仙花数 - Lily Number:把任意的数字,从中间拆分成两个数字,比如1461 可以拆分成(1和461), (14和61), (146和1),
如果所有拆分后的乘积之和等于自身,则是一个Lily Number。
例如:
655 = 6 * 55 + 65 * 5
1461 = 1 * 461 + 14 * 61 + 146 * 1
求出 5位数中的所有 Lily Number。
输入描述:无
输出描述:一行,5位数中的所有 Lily Number,每两个数之间间隔一个空格。
自己的思路:如果是3位数,拆分需要分别除以或模10和100;4位数需要分别除以或模10、100、1000,以此类推到5位数。
int main() {
int i = 0;
for (i = 10000; i <= 99999; i++)
{
int a = (i / 10) * (i % 10);
int b = (i / 100) * (i % 100);
int c = (i / 1000) * (i % 1000);
int d = (i / 10000) * (i % 10000);
int e = a + b + c + d;
if (i == e)
{
printf("%d ", i);
}
}
return 0;
}
老师的思路:通用使用pow库函数来优化重复代码
//老师方法
//假设12345,对它进行拆分
//12345/10000 = 1 2345= 12345%10000
//12345/1000 = 12 345 = 12345%1000
//12345/100 = 123 45 = 12345%100
//12345/10 = 1234 5 = 12345%10
//其中除数(10 100 1000 10000)可以理解为10^1 10^2 10^3 10^4
#include <math.h>//pow库函数需要此头文件
int main()
{
int i = 0;
for (i = 10000; i < 99999; i++)//遍历所有5位数
{
//产生4个数字(10 100 1000 10000)
int sum = 0;
int j = 0;
for (j = 1; j <= 4; j++)
{
int k = (int)pow(10, j);//10为底数,j为指数。此函数产生的结果是double类型,需要类型转换
//然后用i来除以上面这个数,分别得到商和余数。在把商和余数相乘
sum += (i % k) * (i / k);
}
if (sum == i)
printf("%d ", i);
}
return 0;
}