目录
1. 猜名次
5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果:
A选手说:B第二,我第三;
B选手说:我第二,E第四;
C选手说:我第一,D第二;
D选手说:C最后,我第三;
E选手说:我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次
解析:
(1)5位选手,5个名次,也就是有5 * 5 = 25(种)可能
(2)25种可能中,有1种可能是满足ABCDE选手所说的,且只是说对一半的情况,所以才有如下代码:
(b == 2) +(a == 3) == 1 ,(b == )和(a == 3)满足一个即可,也就是一个为1,另一个一定要为0才是满足题意,每人说对一半。
#include <stdio.h>
int predict(int a, int b, int c, int d, int e) {
int arr[] = { a,b,c,d,e };
int i = 0;
int value = 1;
for (i; i < 5;i++) {
value *= arr[i];
}
if (value == 120)
return 1;
return 0;
}
int main() {
int a = 1, b = 1, c = 1, d = 1, e = 1;
for (a = 1;a <= 5;a++) {
for (b = 1;b <= 5;b++) {
for (c = 1;c <= 5;c++) {
for (d = 1;d <= 5;d++) {
for (e = 1;e <= 5;e++) {
if ((b == 2) + (a == 3) == 1) {
if ((b == 2) + (e == 4) == 1) {
if ((c == 1) + (d == 2) == 1) {
if ((c == 5) + (d == 3) == 1) {
if ((e == 4) + (a == 1) == 1) {
if (predict(a, b, c, d, e))
{
printf("a = %d,b = %d,c = %d,d = %d,e = %d", a, b, c, d, e);
}
}
}
}
}
}
}
}
}
}
}
}
2. 猜凶手
日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。
以下为4个嫌疑犯的供词:
A说:不是我。
B说:是C。
C说:是D。
D说:C在胡说
已知3个人说了真话,1个人说的是假话。
解析:
(1)循环四位嫌疑人,有四种可能
(2)因为三人说真话,一人说假话,所以有了如下代码:
(ch != 'A') + (ch == 'C') + (ch == 'D') + (ch != 'D') == 3,四种可能中,有一种可能会满足三人说真话,一人说假话的情况。
#include<stdio.h>
int main() {
//ch变量表示凶手
char ch = 'A';
for (ch;ch <= 'D';ch++) {
//当某个嫌疑人满足4个证词中的3个就是凶手
if ((ch != 'A') + (ch == 'C') + (ch == 'D') + (ch != 'D') == 3) {
printf("真相只有一个,凶手就是:%c凶手", ch);
}
}
return 0;
}
3. 杨辉三角
在屏幕上打印杨辉三角。
1
1 1
1 2 1
1 3 3 1
……
解析:
#define NUM 9
#include<stdio.h>
int main() {
int arr[NUM][NUM] = { 0 };
//为两行杨辉三角赋值
arr[0][0] = arr[1][0] = arr[1][1] = 1;
int i = 0;
int j = 2;
//为没行的第一个数和最后一个数赋值,值为1
for (i = 2;i < NUM;i++,j++) {
arr[i][0] = 1;
arr[i][j] = 1;
}
//赋值
for (i = 2;i < NUM;i++) {
for (j = 1;j < i + 1;j++) {
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
}
//打印
for (i = 0;i < NUM;i++) {
for (j = 0;j < i + 1;j++) {
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
4. 调整奇数偶数顺序
输入一个整数数组,实现一个函数,
来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分,
所有偶数位于数组的后半部分。
解析:
(1)用oddCount和evenCount两个变量分别记录数组中奇数和偶数的个数
(2)用两个数组去分别临时存储偶数的值和奇数的值
(3)先将奇数数组的元素从开头赋值给原数组,然后偶数组赋值从奇数后一位给原数组赋值
//给原数组的后部赋值偶数
for (i = oddCount + 1,n = 0;i <= eventCount +oddCount + 1;i++,n++) {
arr[i] = arrEvent[n];
}
#define NUM 10
#include<stdio.h>
#include<string.h>
int oddCount = -1;//奇数计数器
int eventCount = -1;//偶数计数器
int arrOdd[NUM] = { 0 };//临时存储奇数数据的数组
int arrEvent[NUM] = { 0 };//临时存储偶数数据的数组
void changeOddAndEvent(int arr[]) {
int n = 0;//n代表了偶数数组的下标
int j = 0;//j代表了奇数数组的下标
int i = 0;//i代表原来数组的下标
//重点在于判断条件
for (n = 0,j = 0,i = 0;i < NUM;) {
if (arr[i] % 2 == 0) {
arrEvent[n] = arr[i];
eventCount++;
n++;
i++;
}
else {
arrOdd[j] = arr[i];
oddCount++;
j++;
i++;
}
}
//给原数组的前部赋值奇数
for (i = 0;i <= oddCount;i++) {
arr[i] = arrOdd[i];
}
//给原数组的后部赋值偶数
for (i = oddCount + 1,n = 0;i <= eventCount +oddCount + 1;i++,n++) {
arr[i] = arrEvent[n];
}
}
int main() {
int arr[NUM] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
/*printf("请输入十个整数:\n");
for (i = 0;i < NUM;i++) {
scanf("%d", &arr[i]);
}*/
changeOddAndEvent(arr);
for (i = 0;i < NUM;i++) {
printf("%d ", arr[i]);
}
return 0;
}
5. strcpy实现
模拟实现库函数strcpy
解析:
(1)得想知道目标字符串和资源字符串有多长
(2)if (destCount < resourceCount) {
printf("目标数组的存储空间小于资源数组的存储空间");
return NULL;
}如果目标数组的长度小于资源数组,那就复制不了
(3)最后挨个将资源数组的元素复制给目标数组
#include<stdio.h>
#include<stdlib.h>
char* myStrcpy(char dest[], char resource[]) {
char *destP = dest,*resourceP = resource;
int destCount = 0, resourceCount = 0;
while (*destP != '\0') {
destCount++;
destP++;
}
while (*resourceP != '\0') {
resourceCount++;
resourceP++;
}
if (destCount < resourceCount) {
printf("目标数组的存储空间小于资源数组的存储空间");
return NULL;
}
resourceP = resource;
destP = dest;
while (*resourceP != '\0') {
*destP = *resourceP;
resourceP++;
destP++;
}
*destP = '\0';
return dest;
}
int main() {
char ch1[] = "abcd";
char ch2[] = "asdasdasd";
printf("ch2:%s\n", ch2);
char* s = myStrcpy(ch2, ch1);
printf("ch2:%s\n", ch2);
printf("s:%s", s);
return 0;
}
6. strlen实现
模拟实现库函数strlen
解析:
(1)将字符数组的首元素地址赋值给字符指针destP
(2)然后用destP挨个遍历,用destCount去计数
//模拟实现库函数strlen
#include<stdio.h>
int myStrlen(char dest[]) {
char* destP = dest;
int destCount = 0;
while (*destP != '\0') {
destCount++;
destP++;
}
return destCount;
}
int main() {
char c[] = "adscas";
printf("%d", myStrlen(c));
return 0;
}
7. 喝汽水问题
喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以喝多少瓶汽水(编程实现)。
解析:注释中有解释
第一种
int main() {
int money = 0;
scanf("%d", &money);
int emptyCount = money;//记录空瓶子数
int totalCount = money;//记录总瓶数
while (emptyCount >= 2) {
totalCount += emptyCount / 2;
//例如空瓶子剩下5个,那么剩下的空瓶子数应该是5个瓶子(5以内)的最大偶数 + 剩下的1个没用来兑换的瓶子
emptyCount = emptyCount / 2 + emptyCount % 2;
}
printf("一共能喝%d瓶水", totalCount);
return 0;
}
第二种
/*
我们可以发现,10块钱能喝19瓶水、20块钱能喝39瓶水,有个规律是
m块钱,能喝2m-1瓶水。但是要注意一点,一定要排除1块钱的情况
1块钱的情况也好处理,1块钱就只能喝一瓶水
*/
int main() {
int money = 0;
scanf("%d", &money);
int totalCount = money;
if (money > 1)
totalCount = 2 * money - 1;
printf("一共能喝%d瓶水", totalCount);
}
8. 是否会死循环,为什么,画图解释!
解析:
9. 使用指针打印数组内容
写一个函数打印arr数组的内容,不使用数组下标,使用指针。arr是一个整形一维数组。
//写一个函数打印arr数组的内容,不使用数组下标,使用指针。arr是一个整形一维数组。
#include<stdio.h>
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* p = arr;
int i = 0;
for (i = 0;i < 10;i++) {
printf("%d ", * p);
p++;
}
return 0;
}
10. 逆序字符串内容
写一个函数,可以逆序一个字符串的内容
解析:
#include<stdio.h>
#include<string.h>
void reverse(char dest[],int length) {
char* left = dest;
char* right = dest + length - 1;
char tmp;
while (left <= right) {
tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
11. 打印菱形
解析:
//用C语言在屏幕上输出以下图案:
#include<stdio.h>
int main() {
int line = 0;//输入你想打印的上部分行数
scanf("%d", &line);
int i = 0;
int j = 0;
//打印上部分
for (i = 0;i < line;i++) {
//打印空格
for (j = 0;j < line - i - 1;j++)
printf(" ");
//打印星星
for (j = 0;j < 2*(i+1) - 1;j++)
printf("*");
printf("\n");
}
//打印下部分
for (i = 0;i < line - 1;i++) {
//打印空格
for (j = 0;j < i + 1;j++)
printf(" ");
//打印星星
for (j = 0;j < 2*(line - i) - 3;j++)
printf("*");
printf("\n");
}
return 0;
}
12. 求自幂数
求出0~100000之间的所有“自幂数”并输出。
“自幂数”是指一个n位数,其各位数字的n次方之和确好等于该数本身,如:153=1 ^ 3+5 ^ 3+3 ^ 3,则153是一个“自幂数”。
解析:
12345 % 10 = 5, 12345 / 10 = 1234
1234 % 10 = 4, 1234 / 10 = 123
123 % 10 = 3, 123 / 10 = 12
12 % 10 = 2, 12 / 10 = 1
#include<stdio.h>
#include<math.h>
int main() {
int i = 0;
int tmp = 0;
int sum = 0;
int count = 1;//计算该数的位数
for (i = 0;i <= 10000;i++) {
tmp = i;
//1.知道这个数字为几位数
while (tmp /= 10) {
count++;
}
//2.计算是不是自幂数
tmp = i;
while (tmp) {
sum += pow(tmp % 10, count);
tmp /= 10;
}
if (sum == i)
printf("%d\n", i);
sum = 0;
count = 1;
}
return 0;
}
13. 计算求和
求Sn = a + aa + aaa + aaaa + aaaaa的前5项之和,其中a是一个数字,
例如:2 + 22 + 222 + 2222 + 22222
解析:见如下注释
#include<stdio.h>
//num1:求哪个数字;num2:求多少项
int calculateSum(int num1,int num2) {
//给了第一项的值给sum,例如2这个数,求5项
//这里就是把第一项2先给了sum
//这里就是把第一项2先给了tmp,方便计算后面项的值
int tmp = num1;
int sum = num1;
//循环次数就只剩下5-1 = 4次
while (num2 > 1) {
//第二项的值等于前一项的值乘以10,例如求第二项的值2*10 + 2 = 22,第三项的值22*10 + 2 = 222 ……
tmp = tmp * 10 + num1;
sum += tmp;
num2--;
}
return sum;
}
int main() {
int x = 0, y = 0;
scanf("%d %d", &x, &y);
int sum = calculateSum(x, y);
printf("%d", sum);
}
14. 获取月份天数
解析:
用数组存储12个月的天数,在用函数is_leap_year来判断某年是否为闰年,是闰年2月份的天数要加1。
#include <stdio.h>
int is_leap_year(int y)
{
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))
return 1;
else
return 0;
}
int main()
{
int y = 0;
int m = 0;
//31 28 31 30 31 30 31 31 30 31 30 31
//31 29 31 30 31 30 31 31 30 31 30 31
int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
//0 1 2
while (scanf("%d %d", &y, &m) == 2)
{
int d = days[m];
if (is_leap_year(y) && (m == 2))
d++;
printf("%d\n", d);
}
return 0;
}
15. 变种水仙花
计算10000到99999的数,例如1461 可以拆分成(1和461)、(14和61)、(146和1),如果所有拆分后的乘积之和等于自身。
#include<stdio.h>
#include<math.h>
int main() {
int i = 0;
for (i = 10000;i < 99999;i++) {
int sum = 0;
int j = 0;
for (j = 1;j <= 4;j++) {
sum += (i /(int) pow(10, j)) * (i %(int) pow(10, j));
}
if (sum = i)
printf("%d ", i);
}
return 0;
}
16. 交换两个变量
不允许创建临时变量,交换两个整数的内容
#include<stdio.h>
//第一种方法:用异或解决问题
/*
关于异或有两个重要的点:
(1)x ^ 0 = x
(2)x ^ x = 0
*/
int main() {
int a = 0, b = 0;
scanf("%d %d", &a, &b);
//规律如下:
b = a ^ b;
a = a ^ b;//等同于 a = a ^ a ^ b = 0 ^ b = b
b = a ^ b;//等同于 b = a ^ b ^ b = a ^ 0 = a
printf("a:%d,b:%d", a, b);
return 0;
}
第二种方法:用加减法解决问题
int main() {
int a = 0, b = 0;
scanf("%d %d", &a, &b);
a = a + b;
b = a - b;// b = a + b - b = a
a = a - b;// a = a + b - b = a + b - a = b(此时的b里面的值变成了a)
printf("a:%d,b:%d", a, b);
return 0;
}
17. 统计二进制中1的数量
写一个函数返回参数二进制中 1 的个数。
比如: 15 0000 1111 4 个 1
解析:见如下注释
#include<stdio.h>
int calculateBin(int n) {
int count = 0;
while (n > 0) {
/*
按位与是都为1结果才为1,所以此题的思路就是,从最右边一位去和
a = 0000 0000 0000 0000 0000 0000 0000 0001比较,记录最右边的数是不是1
b = 0000 0000 0000 0000 0000 0000 0000 1111 a & b = 1
结果为1后,让count++,然后将b数据右移,看下一位是不是1
*/
if (n & 1 == 1)
count++;
n >>= 1;
}
return count;
}
int main() {
int n = 0;
scanf("%d", &n);
int count = calculateBin(n);
printf("%d", count);
return 0;
}
18. 打印二进制的奇位数和偶位数
获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
解析:解题逻辑就是使用按位&与,逻辑与17题相似
//获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
#include<stdio.h>
int main() {
int n = 0;
scanf("%d", &n);
//将输入的数据先存到tmp中,防止后序代码改变了n里面的值,用tmp代替n进行数据操作
int tmp = n;
printf("原数据为:");
while (tmp > 0) {
printf("%d", tmp & 1);
tmp >>= 1;
}
printf("\n");
tmp = n;
printf("奇数的二进制序列为:");
while (tmp > 0) {
if(tmp & 1)
printf("%d", tmp & 1);
tmp >>= 1;
}
printf("\n");
tmp = n;
printf("偶数的二进制序列为:");
while (tmp > 0) {
if (!(tmp & 1))
printf("%d", tmp & 1);
tmp >>= 1;
}
return 0;
}
19. 求两个数二进制中不同位的个数
编程实现:两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?
解析:见如下注释
#include<stdio.h>
int main() {
int x = 0, y = 0;
scanf("%d %d", &x, &y);
int i = 0;
int count = 0;//count用来记录有多少个bit位不一样
int tmp = x ^ y;//利用异或的特点,相同为0,不同为1
while (tmp > 0) {
//遍历出tmp里面有多少个1,就知道x和y有多少个比特位不相同了
if (tmp & 1)
count++;
tmp >>= 1;
}
printf("有%d个比特位不同", count);
return 0;
}
20. 计算斐波那契数
递归和非递归分别实现求第n个斐波那契数
例如:
输入:5 输出:5
输入:10, 输出:55
输入:2, 输出:1
解析:见如下注释
#include<stdio.h>
//第一种:使用递归
int fun1(int n) {
if (n == 1 || n == 2)
return 1;
return fun1(n - 1) + fun1(n - 2);
}
//第二种:非递归
int fun2(int n) {
int i = 0;
int one = 1, tow = 1;//one:为前一个数,tow:为前两个数
int num = 0;//表示当前数
if (n == 1 || n == 2)
return 1;
for (i = 3;i <= n;i++) {
//前一个数加前两个数等于当前位置的数
num = one + tow;
//tow的位置前进一
tow = one;
//one的位置前进一
one = num;
}
return num;
}
int main() {
int n = 0;
scanf("%d", &n);
int num = fun2(n);
printf("%d", num);
return 0;
}
21. 递归实现n的k次方
编写一个函数实现n的k次方,使用递归实现。
解析:见如下注释
//编写一个函数实现n的k次方,使用递归实现。
#include<stdio.h>
//obj:是指底数;num:是指指数
//例如:2^3
//(1)2 * 2 * 2 = 2 * (2) 指数为3 num = 3
//(2)2 * 2 = 2 * (3) 指数为2 num = 2
//(3)2 指数为1 num = 1
//由此可知num 即是递归结束条件,也是让问题变小的的关键
int myPow(int obj, int num) {
if (num == 1)
return obj;
return myPow(obj, num - 1) * obj;
}
int main() {
int x = 2;
int n = 5;
int num = myPow(x, n);
printf("%d", num);
return 0;
}
22. 计算一个数的每位之和(递归实现)
写一个递归函数DigitSum(n),输入一个非负整数,返回组成它的数字之和
例如,调用DigitSum(1729),则应该返回1 + 7 + 2 + 9,它的和是19
输入:1729,输出:19
解析:见如下注释
#include<stdio.h>
int DigitSum(int n) {
if (n / 10 == 0)
return n;
return n % 10 + DigitSum(n / 10);
}
int main() {
int n = 0;
scanf("%d", & n);
int sum = DigitSum(n);
printf("%d", sum);
return 0;
}
23. 字符串逆序
编写一个函数 reverse_string(char* string)(递归实现)
实现:将参数字符串中的字符反向排列,不是逆序打印。
要求:不能使用C函数库中的字符串操作函数。
比如 :
char arr[] = "abcdef";逆序之后数组的内容变成:fedcba
解析:见如下注释
void reverse_string(char string[]) {
int length = 0;//用来记录数组长度
char* tmp = string;
while (*tmp != '\0') {
length++;
tmp++;
}
//1.先将第一位保存起来
char c = string[0];//c是中间变量,用来临时存储第一位的字符
//2.将最后一位取出来放在第一位
string[0] = string[length - 1];
//3.将最后一位先赋值为'\0'
string[length - 1] = '\0';//为了方便后续去读取字符串的长度
//4.如果字符串里面的字符大于等于2时,进入递归,所以该条件也是递归终止条件
if (length - 2 >= 2)
reverse_string(string + 1);
//5.将中间变量的值赋值给最后一位,也就是第一位和最后一位进行的交换
string[length - 1] = c;
}
int main() {
char arr[] = "abcdef";
reverse_string(arr);
printf("%s", arr);
return 0;
}
24. strlen(递归实现)
递归和非递归分别实现strlen
解析:见如下注释
//第一种:非递归,用循环
int myStrlen1(char dest[]) {
int length = 0;
while (*dest != '\0') {
length++;
dest++;
}
return length;
}
//第二种:递归方法
int myStrlen2(char* dest) {
if (*(dest + 1) == '\0')
return 1;
return myStrlen2(dest+1) + 1;
}
int main() {
char arr[] = "abcdef";
int length = myStrlen2(arr);
printf("%d", length);
return 0;
}
25. 求阶乘
递归和非递归分别实现求n的阶乘(不考虑溢出的问题)
解析:见如下注释
#include<stdio.h>
//第一种方法:递归方式
int factorialOne(int n) {
if (n == 1)
return 1;
return factorialOne(n - 1) * n;
}
//第二种方法:非递归
int factorialTow(int n) {
int i = 0;
int num = 1;
for (i = 1;i <= n;i++) {
num *= i;
}
return num;
}
int main() {
int n = 0;
scanf("%d", &n);
int num = factorialOne(n);
int num2 = factorialTow(n);
printf("num:%d,num2:%d", num, num2);
return 0;
}
26. 打印一个数的每一位
递归方式实现打印一个整数的每一位
解析:见如下注释
//第一种:倒着打印
#include<stdio.h>
#include<math.h>
void printfNum(int n) {
int num1 = 0;
//1.第一步取出个位数,并且打印出来
num1 = n % 10;
printf("%d\n", num1);
//2.第二步让数据的往右走,也就是十位变个位
if (n / 10)
printfNum(n / 10);
}
//第二种:正着打印
//n:表示传入的原数据,count:表示有几位数
void printfNum2(int n) {
//如果n>=10,就进入递归,这就满足了从前往后打印
if (n / 10)
printfNum2(n / 10);//将一个数缩小十倍
printf("%d", n % 10);
}
int main() {
int n = 123;
printfNum2(n);
//printf("%d", count);
//printfNum(n);
return 0;
}