PTA数组写题总结
目录
数组
藏头诗
分析:
假设把藏头诗每一个汉字看成数字
那么题目的要求就是将每一行的第一个数据输出
也就是运用二维数组且赋值给新数组输出解决这道题目
但要注意的就是==一个汉字占三个字节==
一开始存储诗的数组就是每个汉字三个字节
存储到新数组中a[0]a[1]a[2]才算是一个字
新数组赋值那里可以简化循环为
for ( i = 0; i < 4; i++) {
hand[i * 3] = poem[i][0];
hand[i * 3 + 1] = poem[i][1];
hand[i * 3 + 2] = poem[i][2];
}
代码:
#include<stdio.h>
int main(void) {
// 4 句诗,每句 7 个汉字,每个汉字 3 字节
char poem[4][22];
// 藏头诗,4 个汉字,每个汉字 3 字节
char hand[13];
int i;
for (i = 0; i < 4; i++) {
scanf("%s", poem[i]); //poem[i]就是这一行的首地址了,不用&
}
// 第一句的第一个汉字
for ( i = 0; i < 4; i++) {
hand[i * 3] = poem[i][0];
hand[i * 3 + 1] = poem[i][1];
hand[i * 3 + 2] = poem[i][2];
}
hand[12] = '\0';
puts(hand);
return 0;
}
矩阵相乘
分析:
首先就是两个矩阵的输入
然后判断第一个矩阵的列和第二个矩阵的行是否相等
自己去看矩阵相乘怎么算
稍微需要思考的地方就是新数组的赋值需要三个嵌套循环
for(i=0;i<a;i++){
for(j=0;j<n;j++){
for(k=0;k<b;k++){
...
}
}
}
然后是首尾没有多余空格
最后一行不换行需要注意一下
代码:
#include<stdio.h>
int main() {
int i,j,a,b,m,n,k;
scanf("%d %d",&a,&b);
int A[100][100]={0};
for(i=0;i<a;i++){
for(j=0;j<b;j++){
scanf("%d",&A[i][j]);
}
}
scanf("%d %d",&m,&n);
int B[100][100]={0};
for(i=0;i<m;i++){
for(j=0;j<n;j++){
scanf("%d",&B[i][j]);
}
}
if(b!=m){
printf("Error: %d != %d",b,m);
return 0;
}//矩阵规模不匹配
int C[100][100]={0};
for(i=0;i<a;i++){
for(j=0;j<n;j++){
for(k=0;k<b;k++)
C[i][j]+=A[i][k]*B[k][j];
}
} //相乘后的新矩阵
printf("%d %d\n",a,n);
for(i=0;i<a;i++){
for(j=0;j<n;j++){
printf("%d",C[i][j]);
if(j<n-1){
printf(" ");
}
}
//最恶心人的就是最后一行不换行和最后一个不输出空格
if(i<a-1)printf("\n");
}
return 0;
}
个位数统计
这道题有点恶心人
这是错误示范(有个测试点没过)(但我觉得我没错PTA有点大病)
下面这个解法就是桶排序
#include<stdio.h>
int main() {
int i,j,N,a[10];
scanf("%d",&N);
for(i=0;i<10;i++){
a[i]=0;
}
int num=N;
int n;
while(num>0){
n=num%10;
for(i=0;i<10;i++){
if(i==n){
a[i]++;
break;
}
}
num/=10;
}
for(i=0;i<10;i++){
if(a[i]!=0){
printf("%d:%d\n",i,a[i]);
}
}
return 0;
}
下面PTA认为的正解:
主要是读取每一个字符
刚好就是0~9个位数所以可以用
就包括了输入‘0000’这种情况也可以对应输出
(but题目不是说了正整数吗什么垃圾鬼测试点)
数字字符与对应整数转换
‘数字’ - ‘0’ = 数字:‘9’ - ‘0’ = 9
‘0’ + 数字 = ‘数字’:‘0’ + 9 = ‘9’ (势必有一个没有’ ‘)**
注意
(ch=getchar())必须要用括号括起来
!= 的优先级高于=
这个解题思路可以参考一下也不局限于这道题啦
#include<stdio.h>
int main()
{
int arr[10]={0};
char ch = 0; //不要用int,下面用到的是数字字符转换为整数
while((ch=getchar())!='\n') //每一次读取一个数字字符
{
arr[ch-'0']+=1;
}
int i = 0;
for(i=0;i<10;i++)
{
if(arr[i]!=0)
{
printf("%d:%d",i,arr[i]);
printf("\n");
}
}
return 0;
}
刮刮彩票
#include <stdio.h>
int main()
{
int arr[4][4]={0};
int x = 0,y = 0;//x是行,y列
int sum1 = 1+2+3+4+5+6+7+8+9;
for(int i = 1;i<=3;i++)
{
for(int j = 1;j<=3;j++)
{
scanf("%d",&arr[i][j]);
sum1-=arr[i][j];//计算0代表几
if(arr[i][j]==0)//记录0的x,y
{
x = i;
y = j;
}
}
}
arr[x][y]=sum1;//将零换成相应的数字
for(int i = 0;i<3;i++)
{
scanf("%d%d",&x,&y);//刮开的操作
printf("%d\n",arr[x][y]);
}
int operate = 0;//记录选择的方向
scanf("%d",&operate);
int sum[9]={0};//计算对应方向的和
sum[1] = arr[1][1]+arr[1][2]+arr[1][3];
sum[2] = arr[2][1]+arr[2][2]+arr[2][3];
sum[3] = arr[3][1]+arr[3][2]+arr[3][3];
sum[4] = arr[1][1]+arr[2][1]+arr[3][1];
sum[5] = arr[1][2]+arr[2][2]+arr[3][2];
sum[6] = arr[1][3]+arr[2][3]+arr[3][3];
sum[7] = arr[1][1]+arr[2][2]+arr[3][3];
sum[8] = arr[1][3]+arr[2][2]+arr[3][1];
int jb[25]={0};//兑换表格
jb[6]=10000,jb[7]=36,jb[8]=720,jb[9]=360,jb[10]=80;
jb[11]=252,jb[12]=108,jb[13]=72,jb[14]=54,jb[15]=180;
jb[16]=72,jb[17]=180,jb[18]=119,jb[19]=36,jb[20]=306;
jb[21]=1080,jb[22]=144,jb[23]=1800,jb[24]=3600;
printf("%d\n",jb[sum[operate]]);
return 0;
}
(注意数组一开始定义为[3][3]测试点过不了不知道为什么)
可以问下老师
那个找数据为0的方法很值得学习
不要老是想着循环然后类似于桶排序的做法
字母串
Ascii完整码表(256个)_ascii码对照表-CSDN博客)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int n;
scanf("%d",&n);
char arr[2000001]; //创建符合题目上限的数组
while(n)
{
scanf("%s",arr);
int sz = strlen(arr);
getchar(); //吸收回车字符
int i;
int pd = 1;
for(i=0;arr[i+1]!='\0';i++)
{
if('A'<=arr[i]&&arr[i]<='Z') { //输入是大写字母时
if((arr[i+1]==arr[i]+32)||(arr[i+1]==arr[i]+1)) {
continue;
} else{
pd=0;
break;
}
}
if('a'<=arr[i]&&arr[i]<='z') //输入是小写字母时
{
if(arr[i+1]==arr[i]-32||arr[i+1]==arr[i]-1)
{
continue;
} else {
pd=0;
break;
}
}
}
if(pd==0) {
printf("N\n");
} else {
printf("Y\n");
}
n--;
}
return 0;
}
注意这里输出并不规范
but PTA过了
可以把pd定义为数组之后循环输出
规范的输出:
#include <stdio.h>
#include <string.h>
#define N 2000000
char ch[100][N];
int main(){
int x;
scanf("%d",&x);
int i;
for(i=0;i<x;i++) scanf("%s",ch[i]);
int a[100]={0};
int k=0;
while(x--){
for(i=0;i<strlen(ch[k++]);i++){
if('A'<=ch[k][i]&&ch[k][i]<='Z'){
if((ch[k][i]=ch[k][i+1]-32)||(ch[k][i]=ch[k][i+1]-1))
continue;
}else{
a[k]=1;
break;
}
if('a'<=ch[k][i]&&ch[k][i]<='z'){
if((ch[k][i]=ch[k][i+1]+32)||(ch[k][i]=ch[k][i+1]+1))
continue;
}else{
a[k]=1;
break;
}
}
}
for(i=0;i<k;i++) printf("%c\n",a[i]?'N':'Y');
return 0;
}
字符数组
函数
strlen()
统计字符串有效长度 不算'\0'
sizeof
数组长度 int len = sizeof(a)/sizeof(a[0]);
strcmp()
strcmp(str1,str2)
比较第一个不相同字符的ASCII码值
Ascii完整码表(256个)_ascii码对照表-CSDN博客
Dev-c++返回值只有0,1,-1
1.若str1=str2, 返回0
2.若str1>str2, 返回1
3.若str1<str2, 返回-1
输入:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[]="China",str2[]="Chinese";
int n1,n2;
if((n1=strcmp(str1,str2))>0) puts(str1);
else puts(str2);
n2=strcmp(str2,str1);
printf("n1=%d n2=%d",n1,n2);
return 0;
}
输出:
Chinese
n1=-1 n2=1
strcpy()
strcpy(a,b)
将b的内容复制粘贴给a
a的长度>=b , b的‘\0’也会复制过去
输出的是终止符前的字符,但不代表终止符后没有原数组的字符留存
(只是不输出而已)
输入:
#include <stdio.h>
#include <string.h>
int main()
{
char x[7]="abcdef",y[4]="ABC";
strcpy(x,y);
puts(x);
printf("%c\n",x[5]);
strcpy(x,"2010");
puts(x);
printf("%s",x);
return 0;
}
输出:
ABC //不显示ef是因为x[3]是终止符,puts只打印终止符前的字符,但不代表之后数组元素没有值
f
2010
2010
分析:
‘A’ | ‘B’ | ‘C’ | ‘\0’ | ‘e’ | ‘f’ | ‘\0’ |
---|---|---|---|---|---|---|
x[0] | x[1] | x[2] | x[3] | x[4] | x[5] | x[6] |
strcat()
strcat(a,b)
将字符串b连接至a的后部分
字符串a的长度需足够大,a末尾的‘\0’被b[0]覆盖
输入:
#include<stdio.h>
#include<string.h>
int main()
{
char a[20]="ABCabc123";
char b[4]="aznc";
printf("%s",strcat(a,b));
return 0;
}
输出:
ABCabc123aznc
strstr()
使用strstr()函数
strstr()
strstr(a,b)判断b字符串是否为a字符串的子串
b是a子串的话,就返回b在a首次出现的地址,否则返回NULL
注意:在使用strstr()函数时,b的长度一定是要比a小的。不然b咋是a的子串,那该反过来a是b子串了(doge)
例如:
char a[10]=“ABCabc123”;
char b[4]=“abc”;
strstr(a,b)
返回的值为一个字符串即:“abc123”;
#include<stdio.h>
#include<string.h>
int main()
{
char a[11]="ABCabc123";
char b[4]="abc";
printf("%s",strstr(a,b));
return 0;
}
abc123
若b不是a的子串就返回NULL
#include<stdio.h>
#include<string.h>
int main()
{
char a[11]="ABCabc123";
char b[4]="aznc";
printf("%s",strstr(a,b));
return 0;
}
(null)
strlwr()
strlwr(str)
大写字母转小写字母
strupr()
strupr(str)
小写字母转大写字母
字符串逆序
重要的是二分交换
for(i=0;i<len/2;i++)
#include <stdio.h>
#include <string.h>
int main(){
char a[81],t;
gets(a);
int i,len;
len=strlen(a);
for(i=0;i<len/2;i++){
t=a[i];
a[i]=a[len-1-i];
a[len-1-i]=t;
}
printf("%s",a);
return 0;
}
字符串大小写转换
#include <stdio.h>
int main() {
int i, temp;
char a[31];
for (i = 0; i < 31; i++) {
scanf("%c", &a[i]);
if (a[i] == '#') {
temp = i;
break;
}
}
for (i = 0; i < temp; i++) {
if ('A' <= a[i] && a[i] <= 'Z') {
a[i] += 32;
}else if ('a' <= a[i] && a[i] <= 'z') {
a[i] -= 32;
}
}
for (i = 0; i < temp; i++) {
printf("%c", a[i]);
}
return 0;
}
注意
这段循环不要两个if,必须else if
如果两个if,
在第一个条件转换完大写字母为小写后,
第二个条件会再次将小写字母转换为大写,
这就导致了最终输出的结果全为大写。
for (i = 0; i < temp; i++) {
if ('A' <= a[i] && a[i] <= 'Z') {
a[i] += 32;
}else if ('a' <= a[i] && a[i] <= 'z') {
a[i] -= 32;
}
}
6翻了
#include <stdio.h>
#include <string.h>
int main() {
int i,j,temp,num=0;
char a[1001];
gets(a);
int len=strlen(a);
for(i=0;i<len;i++){
if(a[i]=='6'){
num++;
}else{ //扫描不为6为其他字符
if(num<=3){
for(j=0;j<num;j++){
printf("6");
}
}else if(num>3&&num<=9){
printf("9");
}else{
printf("27");
}
num=0; //注意初始化
printf("%c",a[i]); //打印其他字符
/*这个是首先从6起统计6出现次数
然后直接判断接下来的字符是否是数字
不是则在不是6处这里停下
然后看已统计的6的个数
满足对应条件则对应打印
接着打印停下来的字符包括后面的字符串
就不会出现空格之类的
如果用for循环打印a[i]则会有些元素没有值了
也不好写代码
*/
}
}
/*下面这个if是当最后一个字符为6时
因为不满足a[i]!=6
不会进入到上面的else if语句打印对应数字
于是加上确保打印对应数字
*/
if(num>0){
if(num<=3){
for(j=0;j<num;j++){
printf("6");
}
}else if(num>3&&num<=9){
printf("9");
}else{
printf("27");
}
}
return 0;
}
分析
这个是首先从6起统计6出现次数
然后直接判断接下来的字符是否是
不是则在不是6处这里停下
然后看已统计的6的个数
满足对应条件则对应打印
接着打印停下来的字符包括后面的字符串
就不会出现空格之类的
如果用for循环打印a[i]则会有些元素没有值了
也不好写代码
A-B
解法一:将符合字符存入新数组
#include <stdio.h>
#include <string.h>
int main() {
int i,j,temp,z=0,num=0;
char A[10001];
char B[10001];
char C[10001];
gets(A);
gets(B);
int len1=strlen(A);
int len2=strlen(B);
for(i=0;i<len1;i++){
temp=1; //注意每次i循环temp都要初始化
for(j=0;j<len2;j++){
if(A[i]==B[j]){
temp=0;
break;
}//从A的第一个元素,遍历B的每一个元素
//temp!=0说明B的所有字符与A[i]都不相同
}
if(temp){ //temp!=0
C[z]=A[i];
z++;
}
}
C[z]='\0';//注意自行加上
for(i=0;C[i]!='\0';i++) printf("%c",C[i]);
return 0;
}
主要思想:
最重要的就是将符合的值重新赋给一个新的数组然后输出
别老是在原数组里绕来绕去
注意每一次i循环temp都需要重新初始化
for(i=0;i<len1;i++){
temp=1;
for(j=0;j<len2;j++){
...
}
}
解法二:遍历一遍B就输出
#include <stdio.h>
#include <string.h>
#define N 10001
int main(){
char A[N]={0},B[N]={0};
fgets(A,sizeof(A)/sizeof(A[0]),stdin);
fgets(B,sizeof(B)/sizeof(B[0]),stdin);
int i,j,pd=0;
int lenA=strlen(A);
int lenB=strlen(B);
for(i=0;i<lenA;i++){
pd=0; //注意每一个字符检查后要更新pd的值
for(j=0;j<lenB;j++){
if(A[i]==B[j]){
pd=1;
break;
}
}
if(!pd) printf("%c",A[i]); //检查完一个字符就输出
}
return 0;
}
删除重复字符
#include <stdio.h>
int main() {
int ascii[128]={0};
char s[81];
gets(s);
int i;
for(i=0;s[i]!='\0';i++){
ascii[(int)s[i]]=1;//强制类型转换
}
for(i=0;i<128;i++){
if(ascii[i]==1){
printf("%c",i);//从小到大打印
}
}
return 0;
}
类似于桶排序
但因为是ASCII所以可以不用具体数字
注意不要用
while((ch=getchar())!='\0'){
ascii[ch-'0']=1;
}
输入字符不全为数字*
别用 ch-'0'
但是可以用
while((ch=getchar())!='\n')
ASCII[(int)ch]=1;
吃火锅
#include <stdio.h>
#include <string.h>
int main() {
char a[100][81];
char d[15]="chi1 huo3 guo1";
gets(a[0]);
int i=0,j=0,count=0;
while(strcmp(a[i],".")!=0){ //'.'为输入结束符
i++;
gets(a[i]);
}
printf("%d\n",i); //信息总条数
while(i--){
if(strstr(a[j],d)!=NULL){
count++;
if(count==1){
printf("%d ",j+1); //第一条出现的行数
}
}
j++;
}
if(count!=0){
printf("%d",count); //总共出现的次数
}else{
printf("-_-#");
}
return 0;
}
注意比较字符串最终是否读到终止值
即题目中的“.”
用的是strcmp(a[i],".")!=0
而不是a[i]!="."
敲笨钟
代码:
#include<stdio.h>
#include<string.h>
int main()
{
int n;
scanf("%d\n",&n);
while(n--){
int flag1=0,flag2=0,t; //flag1储存是否上下句是否押韵,flag2用于找最后3个字
char str[200];
gets(str);
//判断上下句是否都押韵
for(int i=0;i<strlen(str);i++){
if(str[i]==','&&str[i-3]=='o'&&str[i-2]=='n'&&str[i-1]=='g')
flag1++;
if(str[i]=='.'&&str[i-3]=='o'&&str[i-2]=='n'&&str[i-1]=='g')
flag1++;
}
if(flag1==2){
for(int i=strlen(str)-1;i>=0;i--){
//找到倒数第3个字并将位置赋值给t
if(str[i]==' ')
flag2++;
if(flag2==3){
t=i;
break;
}
}
//前面正常输出,最后3个字替换为“敲笨钟”
for(int i=0;i<=t;i++){
printf("%c",str[i]);
if(i==t)
printf("qiao ben zhong.\n");
}
}else
printf("Skipped\n"); //如果不押韵,直接输出Skipped
}
return 0;
}
实验题
古风排版
#include <stdio.h>
#include <string.h>
int main() {
int n=0;
scanf("%d",&n); //相当于行数(每一列字符数)
char ch[1001]={0};
getchar(); //读取换行符
gets(ch); //读取字符串
int len=strlen(ch);
int col=len/n; //计算出列数
if(len%n!=0){
col+=1;
} //最后一列可能不足n个的情况
int i=0,j=0;
int index=0;
char arr[100][100]={0};
for(j=col-1;j>=0;j--){ //逆序存放,先从最后一列开始存放
for(i=0;i<n;i++){
if(ch[index]!='\0'){
arr[i][j]=ch[index];
index++;
}else{
arr[i][j]=' '; //整个句子输入完毕换行符变为' ',古风排版后是空格
}
}
}
for(i=0;i<n;i++){
for(j=0;j<col;j++){
printf("%c",arr[i][j]);
}
printf("\n");
}
return 0;
}
思路:
就是将字符数组转化为二维数组输出
绕弯的一点是反过来
像是循环一般习惯了先行后列,且是从左到右
但这题是先列后行,从右到左
所以:
for(j=col-1;j>=0;j--){
for(i=0;i<n;i++){
...
}
}
稍微转一下思路就好
凯撒密码
最最最主要的就是
//unsigned起着至关重要的作用,
//限制char的范围在0 ~ 255而不是-128 ~ 127,
//若不限制则报错,原因是ASCII码的范围超过char的范围而不能正确返回
//unsigned起着至关重要的作用,
//限制char的范围在0 ~ 255而不是-128 ~ 127,
//若不限制则报错,原因是ASCII码的范围超过char的范围而不能正确返回
#include <stdio.h>
#include <math.h>
int main()
{
unsigned char a[80];
int x = 0;
int y;
int offset;
while( (a[x] = getchar()) != '\n' )
{
x++;
}
scanf("%d", &offset);
int i,j,k;
if( offset > 0 ) //右移
{
y = offset % 26; //若offset>26,只需要移动offset-26位
for( i = 0; i < x; i++ )
{
if( a[i] >= 'A' && a[i] <= 'Z' )
{
a[i] += y;
if( a[i] > 'Z' ) //右移移除了字母表26位,挪正回来
{
a[i] -= 26;
}
}
else if( a[i] >= 'a' && a[i] <= 'z' )
{
a[i] += y;
if( a[i] > 'z' )
{
a[i] -= 26;
}
}
printf("%c", a[i]);
}
}
else if( offset < 0 ) //左移
{
offset = fabs(offset);
y = offset % 26;
for( j = 0; j < x; j++ )
{
if( a[j] >= 'A' && a[j] <= 'Z' )
{
a[j] -= y;
if( a[j] < 'A' )
{
a[j] += 26;
}
}
else if( a[j] >= 'a' && a[j] <= 'z' )
{
a[j] -= y;
if( a[j] < 'a' )
{
a[j] += 26;
}
}
printf("%c", a[j]);
}
}
else //offset=0即不移动的情况
{
for( k = 0; k < x; k++ )
{
printf("%c", a[k]);
}
}
return 0;
}
练习1
字符串循环左移
主要思想就是将需要后移的字符存到数组1
剩下的存到数组2
最后输出21
代码:
#include <stdio.h>
#include <string.h>
int main(){
char ch[101];
int n;
gets(ch);
scanf("%d",&n);
char ch1[101];
char ch2[101];
int len=strlen(ch);
int N=n%len;
int i;
for(i=0;i<N;i++){
ch1[i]=ch[i];
}
ch1[N]='\0';
int j=0;
for(i=N;i<len;i++){
ch2[j]=ch[i];
j++;
}
ch2[j]='\0';
for (i = 0;ch2[i] != '\0'; i++)
putchar(ch2[i]);
for (i = 0;ch1[i] != '\0'; i++)
putchar(ch1[i]);
return 0;
}
注意:
‘\0’不能忘记
要记得在新的字符数组后手动添加null终止符
不然存在缓冲区溢出风险
ch1[N]='\0';
ch2[j]='\0';
以防N大于数组长度复制时越界,则略掉数组长度的倍数
int N=n%len;