第三周训练题题解
题解说明
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 交换最小值和最大值
题目的要求是找到一个数组的最大值和最小值,有两个操作,先将最小值和第一个数交换,再将最大值和最后一个数交换。这道题涉及两个知识点:找最大最小值;两数交换值。
- 找最大最小值 ,我相信到了第三周了,找到一个数组中的最大最小值你们应该是会的,大致思路先将最大值和最小值都初始为数组第一个数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;
}
}
- 数值交换,交换两个数的值是很基本的操作,设立一个中间变量进行交换,如果看不懂请在草稿本上写一写
//声明中间变量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;
}