第三周训练题

题解说明

C++和C并无多大区别,在代码中只有输入输出和循环写法的区别。
在C中,输入:scanf("%d",&n); 输出:printf("%d",n);
在C++中,输入和输出写法更加简单,输入:cin>>n; 输出:cout<<n;
在C中循环先声明变量int i,在写循环语句for(i=0;i<10;i++)
在C++中循环变量的声明可以在循环语句内部for(int i=0;i<10;i++)
作此说明是为了方便你们看懂代码,代码不会全部提供,只会提供思路和核心部分语句,看懂之后要自己实现。

7-1 交换最小值和最大值

题目的要求是找到一个数组的最大值和最小值,有两个操作,先将最小值和第一个数交换,再将最大值和最后一个数交换。这道题涉及两个知识点:找最大最小值;两数交换值。

  1. 找最大最小值 ,我相信到了第三周了,找到一个数组中的最大最小值你们应该是会的,大致思路先将最大值和最小值都初始为数组第一个数a[0],再声明两个变量x,y来记录最大值和最小值在数组中的位置,即下标
//既然都将最大值和最小值初始为第一个数,那么最大最小值的初始下标都为0
   int minnum=a[0],maxnum=a[0],x=0,y=0;

接下来就是遍历数组,从第二个数开始遍历,不断比较更新最大值和最小值,以及对应的下标

for(int i=1; i<n; i++)
   {
       //只要当前数比最小值小,就将当前数设为最小值,将下标更新为当前位置
       if(a[i]<minnum)
       {
           minnum=a[i];
           x=i;
       }
       //最大值同理
       if(a[i]>maxnum)
       {
           maxnum=a[i];
           y=i;
       }
   }
  1. 数值交换,交换两个数的值是很基本的操作,设立一个中间变量进行交换,如果看不懂请在草稿本上写一写
//声明中间变量t,交换两个数的值基本操作如下
  int t;
  t=a;
  a=b;
  b=t;

有了基本的交换操作,就可以按题目要求进行两次交换,但是注意特殊情况,该题很人性化,把特殊情况通过样例给出,特殊情况就是最大值刚好就是第一个数

//以下是伪代码,交换部分自己独立完成
   交换(a[0],a[x]);//最小值和第一个数交换
   //特殊情况,也是案例所给的情况
   if(y==0)
       //理解不了的在草稿纸上写一写,该种特殊情况下最大值所在位置就是之前最小值所在位置
       交换(a[x],a[n-1]);
   else
       交换(a[y],a[n-1]);//最大值和最后一个数交换

掌握了上面两个知识点,第一题也就很容易解决。

7-2 组个最小数

该题思路是创建一个数组a[10],元素值初始都为0。下标为0-9,a[5]=3表示有3个5,以此类比。当从0开始遍历数组,只要a[i]>0就输出i,a[i]等于几就输出几个i,所得结果就是题目要求的最小值

   int a[10],n=0;//数组a存放0-9各数字的个数,n为结果数字的位数
   memset(a,0,sizeof(a));//数组的初始化,将数组元素的值全部初始为0,也可以通过for循环实现
   for(int i=0; i<10; i++)
   {
       cin>>a[i];
       n+=a[i];
   }

常识所知数的首位不可能为0,所以对于第一个数要特殊讨论

   for(int i=0; i<n; i++)//结果为n位数,所以循环n次,每次输出一位
   {
       //第一位数特殊讨论,不能为0
       if(i==0)
       {
           for(int j=1; j<10; j++)
           {
               if(a[j]>0)
               {
                   cout<<j;
                   a[j]--;
                   break;//break语句作用是终止当前循环,具体用法请百度
               }
           }
       }
       else
       {
           int t;
           for(int j=0; j<10; j++)
           {
               if(a[j]>0)
               {
                   t=j;
                   break;
               }
           }
           a[t]--;
           cout<<t;
       }
   }

7-3 输出数组元素

这个题实属没啥技巧,数组前后两数依次相减就可以了

  //数组前后两数依次相减语句,当然也可以另开一个数组存储相减的值
   for(int i=0; i<n-1; i++)
       a[i]=a[i+1]-a[i];

需要注意的就是输出的操作

   for(int i=0; i<n-1; i++)
   {
       //k的作用就是计数的作用,当k==3时清为0重新计数
       if(k==0)
           cout<<a[i];
       else
           cout<<" "<<a[i];//该语句只是输出了空格加a[i],和printf(" %d",a[i]);一样效果
       k++;
       if(k==3)
       {
           k=0;
           cout<<""<<endl;//该语句只是起到换行作用,与 printf("\n");一样
       }
   }

7-4 统计字符出现次数

这个题目需要注意的就是怎么输入一整行字符串,字符串就是字符数组char s[n],如果用简单的scanf("%s",s);那么遇到空格就会停止输入。所以输入字符串使用gets(),遇到回车符’\n’才会停止输入。

   char s[87];
   gets(s);

输入整行字符串之后只需要遍历即可,需要知道字符串的长度,这里运用库函数strlen()

  int len=strlen(s);

剩下的只要写个for循环遍历,统计所给字符在字符串中的个数了。

7-5 删除重复字符

这题需要些知识补充,需要知道字符ASCII码范围是0-127,至于原因在专业后续课程计算机组成原理中,不在此详述。我们只需知道一个码值对应一个字符,码值的范围是0-127,码值和字符之间可以通过强制类型转换相互转化。例如:
字符’a’的码值是97,那么(char)97就表示字符‘a’,(int)'a’就表示97。
了解了这个操作,那么这道题的去重和排序就很好解决了,直接上代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=130;
int main()
{
   //创建一个数组a,先将所有元素初始化为0
   int a[maxn],len;
   memset(a,0,sizeof(a));//a[i]=n,表示码值为i的字符在字符串中出现了n次(重点就是了解数组元素值的意义)
   string s;
   getline(cin,s);//输入一整行字符串,在C++中有字符串类型string,在C中的操作上题已有讲述
   len=s.length();//在C++中对字符串类型取长度的操作,在C中的操作上题有提及
   for(int i=0; i<len; i++)
       a[(int)s[i]]++;//这个语句是核心,相信通过上述内容可以理解
   for(int i=0; i<128; i++)//从0开始遍历a数组,这样可以达到按照ASCLL码排序的要求
   {
   //如果a[i]>0,说明字符串中有码值为i的字符,不管a[i]为1还是2还是3,都只输出一次,这样就达到了去重的要求
       if(a[i]>0)
           cout<<(char)i;
   }
   return 0;
}

7-6 冒泡法排序

听你们说冒泡法排序书上是有的,而且交换操作上面也有提及,直接上代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=107;
void myswap(int &x,int &y);//函数的声明,不了解函数的同学请无视这部分
int main()
{
   int n,k,a[maxn];
   cin>>n>>k;
   for(int i=0;i<n;i++)
       cin>>a[i];
   for(int i=0;i<k;i++)//题目要求扫描几遍就循环几遍
   {
       //接下来的操作题目都很明确告诉你了,根据冒泡排序特性想想为什么是j<n-i-1
       for(int j=0;j<n-i-1;j++)
       {
           if(a[j]>a[j+1])
               myswap(a[j],a[j+1]);//还不了解函数的同学,只要知道这个语句起到交换两个数的值作用
       }
   }
   //输出操作,上面有提及,不再赘述
   for(int i=0;i<n;i++)
   {
       if(i==0)
           cout<<a[i];
       else
           cout<<" "<<a[i];
   }
   return 0;
}
//函数的实现,不了解函数的同学请无视这部分
void myswap(int &x,int &y)
{
   int t;
   t=x;
   x=y;
   y=t;
}

7-7 水仙花数判断

看了榜这道题完成情况很好,第三周了,水仙花数这种题也应该会写了:

#include<bits/stdc++.h>
using namespace std;
//函数声明,对函数不了解的同学先无视该部分
int mypow(int x,int y);
int main()
{
   int n,m,res=0;
   cin>>n;
   m=n;
   while(m)
   {
   //mypow(x,3)这个含义就是x的3次方,也可以通过循环来实现此功能
       res+=mypow(m%10,3);
       m/=10;
   }
   if(res==n)
       cout<<"YES"<<endl;
   else
       cout<<"NO"<<endl;
   return 0;
}
//函数实现,对函数不了解的同学先无视该部分
int mypow(int x,int y)
{
   int res=1;
   for(int i=0;i<y;i++)
       res*=x;
   return res;
}

7-8 判断双对称方阵

思路很容易想到,先一个循环判断上下是否对称,再一个循环判断左右是否对称,这里需要声明一个标志变量flag来判断是否对称:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=57;
int main()
{
   
   int t,n,flag,a[maxn][maxn];
   cin>>t;
   while(t--)//t个测试样例的写法
   {
       cin>>n;
       for(int i=0; i<n; i++)
       {
           for(int j=0; j<n; j++)
               cin>>a[i][j];
       }
       flag=0;//flag为标志变量,最终结果为1表示不是双对称,为0表示是双对称
       //先判断是不是上下对称
       //有同学说搞不清二维数组,搞不清你就在草稿纸上按着代码语句模拟一遍
       for(int i=0; i<n/2; i++)
       {
           for(int j=0; j<n; j++)
           {
               if(a[i][j]!=a[n-1-i][j])
               {
                   flag=1;//如果发现不等,那么就不是双对称矩阵
                   break;
               }
           }
       }
       if(flag==0)//如果上下是对称的再判断是否左右对称
       {
           for(int i=0; i<n/2; i++)
           {
               for(int j=0; j<n; j++)
               {
                   if(a[j][i]!=a[j][n-1-i])
                   {
                       flag=1;
                       break;
                   }
               }
           }
       }
       if(flag)
           cout<<"no"<<endl;
       else
           cout<<"yes"<<endl;
   }
   return 0;
}

7-9 蛇形矩阵

如果你写这道题时用的是我们人脑的思维,那么实现起来巨困难,要善于发现规律
在这里插入图片描述
红色的数代表每一行中两个数之间的差值,蓝色的数代表第一列两个数之间的差值。
看到这,相信聪明的你已经发现规律了。代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=107;
int main()
{
   int t,n,a[maxn][maxn];
   cin>>t;
   while(t--)
   {
       cin>>n;
       //可以看到行的差值是从2开始,列的差值是从1开始,聪明的你知道x,y表示啥了吧
       int x=2,y=1,z=n;
       memset(a,0,sizeof(a));
       a[0][0]=1;//第一个数肯定是1
       //如果输入样例为n,那么输出的就是n行,并且每行个数从n开始递减,以此了解变量z的作用
       for(int i=0; i<n; i++)
       {
           int k=x;
           //每一行的第一个数就是第一列,根据列的差值得出每一行第一个数的值
           if(i!=0)
           {
               a[i][0]=a[i-1][0]+y;
               y++;//列的差值要记得累加
           }
           for(int j=1; j<z; j++)
           {
               a[i][j]=a[i][j-1]+k;
               k++;
               //行的差值也要累加,但要注意当你一行结果得出后,开始下一行时,行的差值已经不是下一行开始的差值了
               //比如在本题中,行的差值最后加到5,但第二行开始的差值是3
               //以此你们来分析k和x的关系和各自的作用
           }
           x++;
           z--;
       }
       int m=n;
       //按要求输出格式输出
       for(int i=0;i<n;i++)
       {
           for(int j=0;j<m;j++)
           {
               if(j==0)
                   cout<<a[i][j];
               else
                   cout<<" "<<a[i][j];
           }
           m--;
           cout<<""<<endl;
       }
   }
   return 0;
}

7-10 逐行排序

本质上就是上面冒泡排序的升级版,其实就是输入一行你就将当前行进行排序。冒泡排序每扫描一遍就能确定一个数的位置,那么n个数只要扫描n-1次,因为剩下那个数是不是已经自动确定了位置了。代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=27;
void myswap(int &x,int &y);
int main()
{
   int t,n,a[maxn][maxn];
   cin>>t;
   while(t--)
   {
       cin>>n;
       for(int i=0; i<n; i++)
       {
           for(int j=0; j<n; j++)
               cin>>a[i][j];
           for(int j=0; j<n-1; j++)
           {
               for(int k=0; k<n-j-1; k++)
               {
                   if(a[i][k]>a[i][k+1])
                       myswap(a[i][k],a[i][k+1]);
               }
           }
       }
       for(int i=0; i<n; i++)
       {
           for(int j=0; j<n; j++)
           {
               if(j==0)
                   cout<<a[i][j];
               else
                   cout<<" "<<a[i][j];
           }
           cout<<""<<endl;
       }
   }
   return 0;
}
void myswap(int &x,int &y)
{
   int t;
   t=x;
   x=y;
   y=t;
}

7-11 水仙花求和

不会吧,不会吧,还有人会写水仙花数但不会写这道题吧?
当然如果你们都把代码塞进主函数那肯定是看起来极其难受的,就让你们康康函数封装和模块化的优越性:

#include<bits/stdc++.h>
using namespace std;

//要实现函数的声明
int mypow(int x,int y);
bool judge(int n);

//看看这主函数,是不是很简短
//就光光看这份代码,你只需要知道judge函数干了什么,你不需要去管这个函数内部的具体实现
//让你的代码主函数部分更加清晰易懂,这就是模块化和函数的优势
int main()
{
   int n,res=0;
   cin>>n;
   for(int i=100;i<=n;i++)
   {
       if(judge(i))//judge(i)的功能是判断i是不是水仙花数
           res+=i;
   }
   cout<<res<<endl;
   return 0;
}

//以下都是函数的具体实现
int mypow(int x,int y)
{
   int res=1;
   for(int i=0;i<y;i++)
       res*=x;
   return res;
}
bool judge(int n)
{
   int m,res=0;
   m=n;
   while(m)
   {
       res+=mypow(m%10,3);
       m/=10;
   }
   if(res==n)
       return true;
   else
       return false;
}
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值