练习(杨辉三角、字符串旋转)
一、
以下程序执行的结果:
int main()
{//0~255unsigned char a = 200;//00000000000000000000000011001000//11001000 - a 截断unsigned char b = 100;//00000000000000000000000001100100//01100100 - b unsigned char c = 0;c = a + b;//11001000 - a//01100100 - b//提升//00000000000000000000000011001000 - a(无符号类型) //00000000000000000000000001100100 - b//00000000000000000000000100101100 - a+b 300(正数 原码、补码、反码相同)//00101100 - c 44 (c是无符号字符类型,高位默认补0,原码、反码、补码相同)printf("%d %d",a+b,c);//300 44return 0;
}
二、猜名次
题目内容 :
5位运动员参加了代米台跳水比赛,有人让他们预测比赛结果
A选手说 : B第二,我第三;
B选手说:我第二,E第四:
C选手说:我第一,D第二
D选手说 : C最后,我第三
E选手说 : 我第四,A第一;
比赛结束后,每位选手都说对了一半,请编程确定比赛的名次。
思路:a,b,c,d,e都假设一遍(每一个人都假设为第 1 2 3 4 5 名)
至少有一个为真:1+0=1 0+1=1;例如A选手 (b == 2)+(a == 3) == 1
int main()
{int a = 0;int b = 0;int c = 0;int d = 0;int e = 0;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){printf("a=%d b=%d c=%d d=%d e=%d\n",a,b,c,d,e);}}}}}}return 0;
}
如果我们按以上程序打印,会出现许多种可能,其中还会出现重复现象,例如,出现a和e同时是第一名的情况,其中只有一个正确的答案没有重复
由于1*2*3*4*5==120,我们可以利用这条式子来输出正确的答案
int main()
{int a = 0;int b = 0;int c = 0;int d = 0;int e = 0;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;
}
三、猜凶手
题目内容 :
日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。
以輸下为4个嫌疑犯的供词 :
A说:不是我。
B说 : 是C。
C说 : 是D。
D说 : C在胡说
已知3个人说了真话,1个人说的是假话。
现在请根据这些信息,写一个程序来确定到底谁是凶手。
思路:每个人都假设一遍(假设为凶手,看看是否能符合描述)
() + () + () + () == 3 (有三个说的为真,1)
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);//c}}return 0;
}
四、杨辉三角
在屏幕上打印杨辉三角
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
………………
int main()
{int arr[10][10] = {0};printf("请输入杨辉三角的行数:>");int n = 0;scanf("%d",&n);int i = 0;for(i=0;i<n;i++){int j = 0;for(j=0;j<=i;j++)//只需要打印对角线及以下的部分{if(j==0)arr[i][j] = 1;if(i==j)arr[i][j] = 1;if(i>=2 && j>=1)//从第三行开始,每个中间元素等于上一行相邻两个元素之和arr[i][j] = arr[i-1][j-1] + arr[i-1][j];}}for(i=0;i<n;i++){int j = 0;int space = 0;for(space=0;space<(n-i-1)*2;space++){printf(" ");}for(j=0;j<=i;j++){printf("%4d ",arr[i][j]);}printf("\n");}return 0;
}
每行前导空格数采用(n-i-1)*2的计算方式,是为了确保杨辉三角在输出时能居中对齐,形成美观的金字塔形状。
1.居中对齐
杨辉三角的每一行需要逐层缩进,使得所有行的中心线与最后一行的中心对齐。
假设:·总行数为 n,最后一行的元素最多(共n 个元素)。
每个元素占4字符宽度(通过 %4d 格式实现),因此最后一行的总宽度为 4n。
最后一行的中心位置在 2n处(总宽度4n 的一半)。
为了让当前行 i 的中心位置与最后一行的中心对齐,需要动态计算前导空格数。
2.公式推导
当前行 i 的元素数量: i+1个。
当前行的总宽度: 4*(i+1)字符。
当前行的中心位置: 2*(i+1)(当前行总宽度的一半)。
为使当前行中心与最后一行的中心2n对齐:
前导空格数 + 当前行中心位置 = 最后一行中心位置
即:
前导空格数 + (i+1)*2 = 2n
则:
前导空格数 = 2n - 2*(i+1) = (n-i-1)*2
元素之间的空格由 %4d 控制
代码中使用 printf("%4d",arr[i][j])打印每个元素,其中 %4d 表示:。每个数字占用4个字符宽度,右对齐。不足4位的数字:左侧用空格填充,例如数字 1会输出为…1(·表示空格)。·相邻元素:两个 %4d格式符连写时,元素之间的间隔为3个空格(前一个数字的末尾空格和后一个数字的起始空格叠加),例如1 1会输出 ...1...1
前导空格的计算与元素间隔无关
前导空格公式(n-i-1)*2 仅用于整体居中对齐,与元素之间的间隔无关
例如:
当n=5,i=1(第二行):
前导空格数: (5-1-1)*2=6 ,即打印6个空格。
元素间隔:由%4d自动生成3个空格。
6空格 +"…1…1”,即最终输出: .........1...1(视觉上对齐为......1...1)。
五、
根据以下的代码判断:
int main()
{int* p = NULL;int arr[10] = {0};return 0;
}
A.p = arr B.int (*ptr)[10] = &arr C.p = &arr[0]
D.p = &arr 【错误】 - p是int*类型的指针变量,而&arr对应的是一个数组指针int (*)[10]类型
例如我们前面学习的二维数组传参:
void test(int* arr)
{int i = 0;for(i = 0;i < 15; i++){printf("%d ",arr[i]);}
}
int main()
{int arr[3][5] = {{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};test(arr);//arr作为二维数组的数组名,表示的是首元素的地址,是第一行的地址,是一个一维数组的地址,类型是数组指针,而给函数传参时用一个整型指针来接收就不太恰当return 0;
}
//如果就是想要用整型指针来接收,那么应该将二维数组的首元素传进去:
test(&arr[0][0])
六、杨氏矩阵
题目内容:
有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在
以下的矩阵就是一个杨氏矩阵:
x为横坐标,y为纵坐标;这个数组的右上角和左下角(3和7)是特殊的,3是一列的最大数也是一行的最小数,而7与3反过来,以3为例:假如我们要查找的数字是7,此时3<7,去掉一行,此时右上角的数字变成了6,6<7,在去掉一行,此时9>7,去掉一列,8>7,再去掉一列,然后就查找到了7
void find_k(int arr[3][3],int r,int c,int k)
{int x = 0;int y = c - 1;int flag = 0;while(x<=r-1 && y>=0){if(arr[x][y] < k){x++;}else if(arr[x][y] > k){y++;}else{printf("找到了,下标是:(%d,%d)",x,y);flag = 1;break;}}if(flag == 0)printf("找不到\n");
}int main()
{int arr[3][3] = {1,2,3,4,5,6,7,8,9};int k = 0;printf("请输入要查找数:>");scanf("%d",&k);find_k(arr,3,3,k);return 0;
}
方法二:
void find_k(int arr[3][3],int* px,int* py,int k)
{int x = 0;int y = *py - 1;while(x<=*px-1 && y>=0){if(arr[x][y] < k){x++;}else if(arr[x][y] > k){y++;}else{*px = x;*py = y;return 1;}}return 0;
}int main()
{int arr[3][3] = {1,2,3,4,5,6,7,8,9};int k = 0;printf("请输入要查找数:>");scanf("%d",&k);int x = 3;int y = 3;int ret = find_k(arr,&x,&y,k);if(ret == 0)printf("找不到\n");elseprintf("找到了,下标是:(%d,%d)",x,y);return 0;
}
七、字符串左旋
题目内容:
实现一个函数,可以左旋字符串中的k个字符
例如:
ABCD左旋一个字符得到BCDA
ABCD左旋两个字符得到CDAB
思路:创建一个临时变量,每一次实现一个字符的交换
#include <stdio.h>
#include <string.h>
void left_move(int arr[],int k)
{int i = 0;int len = strlen(arr);k %= len;//旋转k位等价于k%len位,例如,字符串长度为5,旋转7位等价于旋转2位for(i = 0;i < k; i++){//旋转一个字符//1char tmp = arr[0];//2int j = 0;for(j = 0;j < len - 1; j++){arr[j] = arr[j+1];}//3arr[len-1] = tmp;}
}
int main()
{int arr[] = "abcdef";int k = 0;printf("左旋字符串的个数:>");scanf("%d",&k);left_move(arr,k);printf("%s\n",arr);return 0;
}
方法二:1 - 逆序前部分
2 - 逆序后部分
3 - 逆序整体
#include <stdio.h>
#include <string.h>
#include <assert.h>
void reverse(char* left,char* right)
{assert(left && right);while(left<right){char tmp = *left;*left = *right;*right = tmp;left++;right--;}
}
void left_move(char arr[],int k)
{int len = strlen(arr);k %= len;//逆序前部分reverse(arr,arr+k-1);//逆序后部分reverse(arr+k,arr+len-1);//整体逆序reverse(arr,arr+len-1);
}
int main()
{int arr[] = "abcdef";int k = 0;printf("左旋字符串个数:>");scanf("%d",&k);left_move(arr,k);printf("%s\n",arr);return 0;
}
八、字符串旋转结果
题目内容:
写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串,
例如:给定S1=AABCD和s2=BCDAA,返回1
给定s1=abcd和S2=ACBD,返回0.
AABCD左旋一个字符得到ABCDA
AABCD左旋两个字符得到BCDAA
AABCD右旋一个字符得到DAABC
左旋转:
#include <string.h>
void reverse(char* left, char* right)
{assert(left && right);while (left < right){char tmp = *left;*left = *right;*right = tmp;left++;right--;}
}
void left_move(char arr[],int k)
{int len = strlen(arr);k %= len;//逆序左reverse(arr, arr + k - 1);//逆序右reverse(arr + k, arr + len - 1);//逆序整体reverse(arr, arr + len - 1);
}
int is_left_move(int arr1[],int arr2[])
{int len1 = strlen(arr1);int len2 = strlen(arr2);if(len1 != len2)return 0;int i = 0;for(i = 0;i < len1; i++){left_move(arr1,1);if(strcmp(arr1,arr2) == 0)return 1;}return 0;
}
int main()
{char arr1[] = "AABCD";char arr2[] = "BCDAA";int ret = is_left_move(arr1,arr2);if(ret == 1)printf("YES\n");elseprintf("NO\n");return 0;
}
通过调试可观察其变化:
右旋转:
#include <string.h>
void reverse(char* left, char* right)
{assert(left && right);while (left < right){char tmp = *left;*left = *right;*right = tmp;left++;right--;}
}
void right_move(char arr[],int k)
{int len = strlen(arr);k %= len;//逆序左reverse(arr, arr+len-1-k);//逆序右reverse(arr+len-k,arr+len-1);//逆序整体reverse(arr, arr + len - 1);
}
int is_right_move(int arr1[],int arr3[])
{int len1 = strlen(arr1);int len3 = strlen(arr3);if(len1 != len3)return 0;int i = 0;for(i = 0;i < len1; i++){left_move(arr1,1);if(strcmp(arr1,arr3) == 0)return 1;}return 0;
}
int main()
{char arr1[] = "AABCD";char arr2[] = "DAABC";int ret = is_right_move(arr1,arr3);if(ret == 1)printf("YES\n");elseprintf("NO\n");return 0;
}
方法二:AABCD -> AABCDAABCD 给要与arr2比较的arr1再叠加整个字符串,看看arr2是否是arr1的子字符串
首先认识一下strcat、strncat、strstr(头文件都是 #include <string.h>)
strcat
int main()
{char arr[20] = "hello ";strcat(arr, "world");//在arr的基础上追加一个"world"字符串printf("%s\n", arr);//打印结果:hello worldreturn 0;
}
strncat - 可以设定要打印一个字符串中的几个字符
int main()
{char arr[20] = "hello ";strncat(arr, "world", 3);printf("%s\n", arr);//打印结果:hello worreturn 0;
}
strstr
int main()
{//是在arr1字符串中查找arr2是否存在//如果存在则返回arr2在arr1中的地址(位置);如果不存在返回NULLchar arr1[] = "abcdefabcdef";char arr2[] = "def";//如果arr1中有两个arr2,只返回第一个开始的地址char* ret = strstr(arr1, arr2);if (ret == NULL)printf("NO\n");elseprintf("%s\n",ret);//打印(%s)结果:defabcdef (从返回的地址开始向后打印)return 0;
}
左右旋转:
//右旋
int is_right_move(int arr1[],int arr3[])
{int len1 = strlen(arr1);int len3 = strlen(arr3);if(len1 != len3)return 0;strncat(arr1,arr1,len1);if(strstr(arr1,arr3) != NULL)return 1;elsereturn 0;
}
//左旋
int is_left_move(int arr1[],int arr2[])
{int len1 = strlen(arr1);int len2 = strlen(arr2);if(len1 != len2)return 0;strncat(arr1,arr1,len1);if(strstr(arr1,arr2) != NULL)return 1;elsereturn 0;
}
int main()
{char arr1[20] = "AABCD";char arr2[] = "BCDAA";char arr3[] = "DAABC";//int ret = is_left_move(arr1,arr2);int ret = is_right_move(arr1,arr3);if(ret == 1)printf("YES\n");elseprintf("NO\n");return 0;
}
九、
以下程序的输出结果是:1 6
int main()
{int aa[2][5] = { 10,9,8,7,6,5,4,3,2,1 };int* ptr1 = (int*)(&aa + 1);//&arr取出整个数组的地址,+1跳过了这个地址,然后强制转化为int*类型int* ptr2 = (int*)(*(aa + 1));//aa是二维数组数组名,即数组名为首行的地址(arr[0]),aa+1跳到第二行地址(arr[1]),然后解引用,强制转化为int*类型printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));//*(ptr1-1) - 减1又回到了数组的最后一个元素的地址上,即1//*(ptr2-1) - 减1回到第一行最后一个元素的地址上,即6return 0;
}