1.猜凶手
某地发生了一起谋杀案,警察通过排查确定杀人凶手必为四个嫌疑犯的一个,以下是4个嫌犯的供词。已知(请编写代码找出凶手)
A说:不是我。 |
---|
B说:是C。 |
C说:是D。 |
D说:C再胡说。 |
程序分析:这是一道实际问题,其实本身并不复杂,只需要分别假定A、B、C、D四人分别是凶 手,假定谁是凶手时满足题意,就能确定凶手。写成代码形式可以把这些条件相加(条件为真为1,假则为0),当结果等于3时,就可以得到正确答案。
程序源代码:
#include<stdio.h>
int main()
{
char killer = 0;
for (killer = 'A'; killer <= 'D'; killer++)
{
if ((killer != 'A') + (killer == 'C') + (killer == 'D') + (killer != 'D') == 3)
{
printf("凶手是:%c\n", killer);
}
}
return 0;
}
2.猜名次
5位运动员参加了10米台跳水比赛,有人让他们预测比赛结果 A选手说:B第二,我第三; B选手说:我第二,E第四; C选手说: 我第一,D第二; D选手说:C最后,我第三; E选手说:我第四,A第一; 比赛结束后,每位选手都说对了一半,请编程确定比赛的名次
程序分析:通过前面一题的经验,我们可以采用条件相加等于一个特定值来进行判断满足条件的名次,这里,我们通过穷举法进行分析。
程序源代码:
#include <stdio.h>
int main() {
int a, b, c, d, e;
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) &&
((b == 2) + (e == 4) == 1) &&
((c == 1) + (d == 2) == 1) &&
((c == 5) + (d == 3) == 1) &&
((e == 4) + (a == 1) == 1))
{
if(a * b * c * d * e == 120 )
printf("A:%d, B:%d,C:%d, D:%d, E:%d\n", a, b, c, d, e);
}
}
}
}
}
}
return 0;
}
3.杨氏矩阵
有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。
要求:时间复杂度小于O(N)
程序分析:对于在一个题目中这种数组中查找某个数字,我们可以采取遍历整个数组的方法找到该数字,但是时间复杂度上就不满足,因此我们要选择一种更优的查找算法。在本代码中,我们选取右上角的数字为标准,因为数组不论是从上到下还是从左到右都是递增的。如果要查找的数字大于右上角的数字,则第一排的数字不可能存在我们要找的数字,因此可以直接划去第一排;如果要查找的数字小于右上角的数字,则该列的数字不可能存在我们要找的数字,因此可以直接划去该列。
int find_num(int arr[3][3], int* row, int* col, int k)
{
int x = 0;
int y = *col - 1;
while (x < *row && y>=0)
{
if (arr[x][y] < k)
{
x++;
}
else if (arr[x][y] > k)
{
y--;
}
else
{
*row = x;
*col = y;
return 1;
}
}
return 0;
}
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
//查找数字7
int k = 7;
int x = 3;
int y = 3;
int ret = find_num(arr, &x, &y, k);
if (ret == 1)
{
printf("找到了,在arr[%d][%d]",x ,y );
}
else
{
printf("找不到\n");
}
return 0;
}
4.旋转字符串
左旋字符串,实例:A B C D E F,逆序一次后变成B C D E F A
程序分析:
要左旋一次字符串,就是要把最左边的字符放在最右边,然后后边的字符串都往前挪动一个长度。因此我们想到用指针的方式来进行作答,先把最左边的字符存储起来,后面的字符利用循环的方式依次前移,最后把存储起来的字符放在最后即可
程序源代码:
#include<stdio.h>
#include<string.h>
void left_rotate(char* str, int k)
{
int i = 0;
int len = (int)strlen(str);
for (i = 0; i < k; i++)
{
//把左侧数字存储起来
char tmp = *str;
int j = 0;
for (j = 0; j < len - 1; j++)
{
//把n-1个字符前移
*(str + j) = *(str + j + 1);
}
//把tmp的值放在最后
*(str + len - 1) = tmp;
}
}
int main()
{
char str[10] = "ABCDEF";
int k = 2;
left_rotate(str, k);
printf("%s", str);
return 0;
}
我们也可以使用三步翻转法来解决该问题,大家可以参考一下下面的代码:
#include<stdio.h>
void reverse_string(char* left, char* right)
{
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void left_rotate(char* str, int k)
{
int len = strlen(str);
reverse_string(str, str + k - 1);//左
reverse_string(str + k, str + len - 1);//右
reverse_string(str, str + len - 1);//整体
}
int main()
{
char str[10] = "ABCDEF";
int k = 4;
left_rotate(str, k);
printf("%s\n", str);
return 0;
}
5.逆序字符串
将一句话的单词进行倒置,标点不倒置,比如I like beijing.经过函数后变为:beijing. like I
程序分析:在这里介绍一种经典的翻转字符串的方法:三步翻转法。首先我们把整个字符串进行翻转,就以I like beijing.为例,翻转后变成.gnijieb ekil I,然后紧接着再把各个单词进行翻转,就变成beijing. like I正好满足题意。
程序源代码:
//三步翻转法
#include<stdio.h>
#include<stdlib.h>
void reverse_string(char* left, char* right)
{
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char arr[100] = { 0 };
gets(arr);
int len =(int) strlen(arr);
//字符串整体反转
reverse_string(arr, arr + len - 1);
//单个单词反转
char* start = arr;
while (*start)
{
char* end = start;
while (*end != ' ' && *end!= '\0')
{
end++;
}
reverse_string(start, end - 1);
if (*end == ' ')
start = end + 1;
else
start = end;
}
printf("%s", arr);
return 0;
}
6.公务员面试
公务员面试现场打分,有7位考官,从键盘上输入若干组成绩,每组7个分数(百分制),去掉一个最高分和一个最低分,输出每组的平均成绩。输入描述:一行,输入7个参数(0~100),代表7个成绩,用空格分隔。
程序分析:其实大体的思路比较清晰,就是利用scanf依次读取7个数据,找出七个数据中的最大值和最小值,打印输出除去最大最小值后,其他数据的平均值。下面是最普通的代码实例。
程序源代码:
#include<stdio.h>
int cmp(const void* a,const void* b)
{
return (*(int*)a - *(int*)b);//升序
}
int main()
{
int sum = 0;
int score[7] = { 0 };
int i = 0;
for (i = 0; i < 7; i++)
{
scanf("%d", &score[i]);
sum += score[i];
}
qsort(score, 7, sizeof(int), cmp);
int min = score[0];
int max = score[6];
printf("%.2f", (sum - min - max) / 5.0);
return 0;
}
其实上面的实现方法比较复杂,使用了快速排序函数qsort先排序后找出最大最小值,其实我们可以在读取数据时就顺便把最大最小值找出,这样极大简化了程序的复杂程度。请看下面源代码:
#include<stdio.h>
int main()
{
int score = 0;
int sum = 0;
int max = 0;
int min = 100;//我们把min的初始值置成100,以确保最小值能够正常更新
int i = 0;
for (i = 0; i < 7; i++)
{
scanf("%d", &score);
sum += score;
if (score > max)
{
max = score;
}
if (score < min)
{
min = score;
}
}
printf("%.2f", (sum - min - max) / 5.0);
return 0;
}
7.获得月份的天数
KIKI想获得某年某月有多少天,请帮助他编程实现,输入年份和月份,计算这一年这个月有多少天。输入描述:多组输入,一行有两个整数,分别表示年份和月份,用空格分隔
程序分析:首先,看见多组输入,我们设计成while循环,以end of file作为结束条件,实现多组输入。然后,我们要考虑特殊情况,平年的二月是28天,闰年的二月是29天,所以我们要判断一下平年还是闰年。因为每年都是十二个月,除二月有特殊情况外其他的每年都一样,我们决定采用数组下标访问的方式来进行。
#include<stdio.h>
#define EOF (-1)
int main()
{
int year = 0;
int month = 0;
int days[13] = { 0,31,28,31,30,31,30,31,31,30,30,31 };
while (scanf("%d %d", &year, &month) != EOF)
{
int day = days[month];
if (year == 2)
{
//判断是否是闰年
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
{
day += 1;
}
}
printf("%d\n", day);
}
return 0;
}
8、有序序列插入一个数,使其仍为一个有序数组
有一个有序数字序列,从小到大排序,将一个新输入的数插入到序列中,保证插入新数后,序列仍然是升序输入描述:第一行输入一个整数(0<=N<=50)。第二行输入N个升序排列的整数,输入用空格分隔的N个整数第三行输入想要进行插入的一个整数。
程序分析:我们看见题目最先想到的是把数字直接插入进去,进行冒泡排序即可再次得到一个有序数组,但是冒泡排序使用了两次for循环,时间复杂度为o(n^2),比较复杂。
通过列举一个简单的示例,我们发现要把一个数字插入,只要后面的数字依次往后后退一个位置,再把这个数字插入进去,问题就得到了解决。
程序源代码:
#include<stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int arr[51] = { 0 };
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
int m = 0;//要插入的数字
scanf("%d", &m);
for (i = n - 1; i>=0 ; i--)
{
if (m < arr[i])
{
arr[i + 1] = arr[i];
}
else
{
arr[i+1] = m;
break;
}
}
if (i < 0)
{
arr[0] = m;
}
for(i = 0; i < n + 1; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
9.找出缺失的数字(多种方法实现)
数组num包含从0到n的所有整数,但其中缺了一个,请编写代码找出那个缺失的整数,你有办法在O(n)内完成吗,编写C语言代码解决,使用按位异或的知识
程序分析:法一、看见题目,我们首先想到可以用遍历数组的方式来找出缺失的值,先使用qsort函数进行排序,如果碰到一个数字的值不等于下一个数字的值-1,那么我们就找到了缺失的数字。法二、采用相减的方法可快速求出结果(0+1+2+3+...+n)-(a[0]+a[1]+[2]+...+a[n-1])。法三、qsot排序,数组中值是几就在第几个位置上写下这个值。法四、采用按位异或的方法:a^a=0,a^0=a.这里具体只实现第四种方法。
程序源代码:
#include<stdio.h>
int find_missing(int arr[], int sz)
{
int missing = 0;
int i = 0;
//对0~n的数字进行抑或
for (i = 0; i <= sz; i++)
{
missing ^= i;
}
//与数组中的数字进行抑或
for (i = 0; i < sz; i++)
{
missing ^= arr[i];
}
return missing;
}
int main()
{
int arr[] = { 0,1,2,3,5,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
printf("%d\n",find_missing(arr,sz));
return 0;
}
10.把字符串中空格替换成“%20”
写一个C语言程序,题目:请实现一个函数,把字符串中的每个空格替换成"%20"。例如输We are happy.”,则输出“We%20are%20happy”,要求时间复杂度O(N)以内
程序分析:我们的思路就是先遍历数组,找出数组中空格的个数,如果直接把空格替换成“%20”的话,%20会占用三个位置,会造成字符串后面的内容被覆盖,因此我们需要重新创建一个新的数组,新数组的大小就是:strlen(原数组)+blankspace*2+1,最后加的这个1用来存放'\0',作为字符串结束的标志。
程序源代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void replace(char* str)
{
//遍历字符串,数出空格个数
int count = 0;
int len = strlen(str);
int i = 0;
for (i = 0; i < len; i++)
{
if (str[i] == ' ')
{
count++;
}
}
//重新创建一个数组
char* newstr = malloc(sizeof(char) * (len + count * 2 + 1));
int newbegain = 0;
//开始遍历数组,复制非空格内容到新的字符串
for (i = 0; i < len; i++)
{
if (str[i] == ' ')
{
newstr[newbegain++] = '%';
newstr[newbegain++] = '2';
newstr[newbegain++] = '0';
}
else
{
newstr[newbegain++] = str[i];
}
}
newstr[newbegain] = '\0';
strcpy(str, newstr);
free(newstr);
newstr = NULL;
}
int main()
{
char str[] = "we are heppy";
replace(str);
printf("%s\n", str);
return 0;
}