前言
一、易错选择题
1.字符串截断问题
答案选c
-
方一:
-
a: 00000000 00000000 00000000 11001000
b: 00000000 00000000 00000000 01100100
由于转为char截断后
a:11001000
b: 01100100
由于打印为整数,进行整型提升:
a: 00000000 00000000 00000000 11001000
b: 00000000 00000000 00000000 01100100
a+b:00000000 00000000 00000001 00101100 -
由于c为char型,再次截断:
00101100
然后再整型提升:00000000000000000000000000101100
由此可得:a+b=300;c=44
-
方二:
-
由于unsigned char类型的取值范围只能是0~255。所以300超过了255。
直接计算超出多少,即求出c的值。300-255=45 ,由于是从0开始,因此还减1:45-1=44
2.大端问题
选a
a的地址为:0x00 00 12 34
a在内存中大端存储为:低 00 00 12 34 高
由于char类型,取一字节,为00。
二、
1.猜名次问题
思路:1.考虑到一共五个人,直接模拟推理有些太难,计算机最擅长的遍历此时就会派上用场,将每个人从第1到第5来一遍,则一共会产生5^5种可能性,这个只需要一个5层循环即可搞定。
2.但是这样会导致一些不期望出现的结果出现,因为没有查重,所以会出现两个人抢名次的情况,也就是两个人或者更多的人名次相同的情况,例如两个第二,三个第三这样的,所以即使满足了条件,也要查看一下五个人的名次是否重复。
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
//a:(b==2)+(a==3)=1
//b:(b==2)+(e==4)=1
//c:(c==1)+(d==2)=1
//d:(c==5)+(d==3)=1
//e:(e==4)+(a==1)=1
int a, b, c, d, e;
for (int 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", a, b, c, d, e);
}
}
}
}
}
}
}
}
2.猜凶手
#include<stdio.h>
int main()
{
int killer = 0;
//分别假设凶手是a,b,c,d,看谁是凶手时满足3个人说了真话,一个人说了假话
for (killer = 'a'; killer <= 'd'; killer++)
{
if ((killer != 'a') + (killer == 'c') + (killer == 'd') + (killer != 'd') == 3)
printf("凶手是:%c", killer);
}
return 0;
}
3.杨辉三角
由于此题要打印整个杨辉三角的数据而非取出某一项,所以不可避免的一定是要填出每一项,没有偷懒的余地,那就老老实实的根据规律填空即可。按照题设的场景,能发现数字规律为:d[i][j] = d[i - 1][j] + d[i - 1][j - 1]。所以我们只要按照这个方法填表即可。
方一:
#include<stdio.h>
//1
//1 1
//1 2 1 a[2][1]=a[1][0]+a[1][1]
//1 3 3 1
//1 4 6 4 1
int main()
{
int arr[10][10] = {0};//初始化非常重要
int i;
for ( i = 0; i < 10; i++)
{
int j = 0;
for (j = 0; j <=i; j++)
{
if (j == 0||(i == j))
{
arr[i][j] = 1;
}
if (i >= 2)
{
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
}
}
for (i = 0; i < 10; i++)
{
int j = 0;
{
for (j = 0; j <= i; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
}
方二:
void yangHuiTriangle(int n)
{
int data[30][30] = { 1 }; //第一行直接填好,播下种子
int i, j;
for (i = 1; i < n; i++) //从第二行开始填
{
data[i][0] = 1; //每行的第一列都没有区别,直接给1,保证不会越界。
for (j = 1; j <= i; j++) //从第二列开始填
{
data[i][j] = data[i - 1][j] + data[i - 1][j - 1]; //递推方程
}
}
for (i = 0; i < n; i++) //填完打印
{
for (j = 0; j <= i; j++)
{
printf("%d ", data[i][j]);
}
putchar('\n');
}
}
改进:
由于在填第n行的杨辉三角时,只跟第n-1行的杨辉三角产生联系,不会跟之前的有联系,所以没必要保存每一行的杨辉三角,填一行打一行就行了,这样能让空间复杂度从n^2降低到n。但是在填数据的时候不能对之前的数据覆盖,所以需要从后向前填。而填杨辉三角顺序对结果是没有影响的,所以可以实现。
void yangHuiTriangle(int n)
{
int data[30] = { 1 };
int i, j;
printf("1\n"); //第一行就直接打印了
for (i = 1; i < n; i++) //从第二行开始
{
for (j = i; j > 0; j--) //从后向前填,避免上一行的数据在使用前就被覆盖
{
data[j] += data[j - 1]; //公式同上,由于变成了一维,公式也变简单了。
}
for (j = 0; j <= i; j++) //这一行填完就直接打印了。
{
printf("%d ", data[j]);
}
putchar('\n');
}
}
4.杨氏矩阵
例如:
1 2 3
4 5 6
7 8 9
在此中找7。可以先与每一行最右边的比较,如果比他小,就往那一行左边依次比较。比他大,那就到下一行的最右边比较。依次即可找到。arr[0][2];arr[1][2];arr[2][2];arr[2][1];arr[2][0].
#include <stdio.h>
int findnum(int a[][3], int x, int y, int f) //第一个参数的类型需要调整
{
int i = 0, j = y - 1; //从右上角开始遍历
while (j >= 0 && i < x)
{
if (a[i][j] < f) //比我大就向下
{
i++;
}
else if (a[i][j] > f) //比我小就向左
{
j--;
}
else
{
return 1;
}
}
return 0;
}
int main()
{
int a[][3] = { {1, 3, 5},
{3, 5, 7},
{5, 7, 9} }; //一个示例
if (findnum(a, 3, 3, 2))
{
printf("It has been found!\n");
}
else
{
printf("It hasn't been found!\n");
}
return 0;
}
5.字符串左旋
方法一:
移动字符的方式实现
#include<stdio.h>
#include<string.h>
int main()
{
char a[20] = "abcdef";
int n=strlen(a);
int k;
scanf("%d", &k);
int i = 0;
int time = k % n;//长度为5的情况下,
//旋转6、11、16...次相当于1次,
//7、12、17...次相当于2次,以此类推。
while (time)
{
char temp;
temp = a[0];
for (i = 0; i < n-1; i++) //单次平移,注意这里要长度-1,否则i+1要越界
{
a[i] = a[i + 1];
}
a[i] = temp;
time--;
}
printf("%s", a);
}
方二:利用3次逆序来实现。
abcdef—>cdefab
整体逆序:fedc ba
前部分逆序:cdef ba a[0]–>a[n-k-1]
后部分逆序:cdef ab a[n-k]–>a[n-1]
void reverse_part(char *str, int start, int end) //将字符串从start到end这一段逆序
{
int i, j;
char tmp;
for (i = start, j = end; i < j; i++, j--)
{
tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
}
void leftRound(char * src, int time)
{
int len = strlen(src);
int pos = time % len;
reverse_part(src, 0, pos - 1); //逆序前段
reverse_part(src, pos, len - 1); //逆序后段
reverse_part(src, 0, len - 1); //整体逆序
}
方法三:选择拼接法,一次到位
abcdef—》cdefab
1)ab cdefab cdef
其中转化后的是1)的字串。
void leftRound(char * src, int time)
{
int len = strlen(src);
int pos = time % len; //断开位置的下标
char tmp[256] = { 0 }; //更准确的话可以选择malloc len + 1个字节的空间来做这个tmp
strcpy(tmp, src + pos); //先将后面的全部拷过来
strncat(tmp, src, pos); //然后将前面几个接上
strcpy(src, tmp); //最后拷回去
}
6.字符串旋转结果
本题当然可以将所有旋转后的结果放到一个数组里,然后进行查找,但是这种做法既不好操作,也太费事,但是这题有一个很简单的做法:
其实ABCDE无论怎么旋,旋转后的所有结果,都包含在了ABCDEABCD这个字符串里了。
所以做法很简单,只需要将原字符串再来一遍接在后面,然后找一找待查找的字符串是不是两倍原字符串的子集即可。
int findRound(const char * src, char * find)
{
char tmp[256] = { 0 }; //用一个辅助空间将原字符串做成两倍原字符串
strcpy(tmp, src); //先拷贝一遍
strcat(tmp, src); //再连接一遍
return strstr(tmp, find) != NULL; //看看找不找得到
}