1 . 闰年
输出21世纪中截止某个年份以来的所有闰年年份。注意:闰年的判别条件是该年年份能被4整除但不能被100整除、或者能被400整除。
- 注意一点:2000年属于20世纪最后一年,所以21世纪应该是从2001年到2100年(包含)
2 . 找出最小值
输入在一行中首先给出一个正整数n,之后是n个整数,其间以空格分隔。
- 因为给出n个数,直到是n个,所以可以循环输入并比较
- 找出最小,只需要定义一个存最小就好了,每输入一个就与它比较,若小于最小就存入
- 特别注意,定义时一定是将第一个存入的存为最小值的初始值,切忌随便设一个数。
#include<stdio.h>
int main(void){
int n,i,min,m;
scanf("%d",&n);
scanf("%d",&m);
min=m;
for(i=1;i<n;i++){
scanf("%d",&m);
min=m>min?min:m;
}
printf("min = %d",min);
return 0;
}
3 . 最大公约数和最小公倍数
m和n
- 明确m*n=他们最大公约数和最小公倍数相乘
- 最大公约数可以通过辗转相除法计算出来
- 先求出最大公约数再通过公式求出最小公倍数
/*首先明确求解方法,用辗转相除法先求出最大公约数,然后用最大公约数*最小公倍数=m*n求出最小公倍数*/
#include<stdio.h>
int main(void){
int m,i,n;
scanf("%d%d",&m,&n);
i=m*n;//用来最后求最小公倍数的
int r;
while(r=m%n){
m=n;
n=r;
}
printf("%d %d",n,i/n);
return 0;
}
4 . 打印菱形图案
本题要求编写程序,打印一个高度为n的、由“*”组成的正菱形图案
输出样例:
*
* * *
* * * * *
* * * * * * *
* * * * *
* * *
*
- 此题关键:对称!!!
- 怎么个对称,关于中间那一行对称
j<=2*fabs(m-i)
- 关键理解:m是中间那一行的行数,i是遍历每一行时对应的行数,m-i取绝对值就是距离m的距离!!!对称时距离相同哇。
#include<stdio.h>
#include<math.h>
int main(void){
int n,j,i;
scanf("%d",&n);
int m;
m=(n+1)/2;//存放中间的行数
for(i=1;i<=n;i++){//遍历每一行进行打印
for(j=1;j<=2*fabs(m-i);j++){
printf(" ");//打印空格,距离每加一打印两个空格
}
for(j=1;j<=n-2*fabs((m-i));j++){
printf("* ");//打印*
}
printf("\n");
}
return 0;
}
5 . 猴子吃桃问题
一只猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个;第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半加一个。到第N天早上想再吃时,见只剩下一个桃子了。问:第一天共摘了多少个桃子?
输入3,输出10
- 到第n天早上想吃,也就是说第n天没吃,所以一共是吃了n-1天
- 特别注意数学公式x与y的转换,很容易出错
#include<stdio.h>
int main(void){
int n;
int sum=0,i;
int y=1;
scanf("%d",&n);
for(i=1;i<=n-1;i++){
sum=(y+1)*2;
y=sum;
}
printf("%d",sum);
}
6 . 兔子繁衍问题
一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。假如兔子都不死,请问第1个月出生的一对兔子,至少需要繁衍到第几个月时兔子总数才可以达到N对?
输入格式:
输入在一行中给出一个不超过10000的正整数N。
输出格式:
在一行中输出兔子总数达到N最少需要的月数。
输入样例:
30
输出样例:
9
/*首先明确思路:兔子繁衍问题就是那个1,1斐波那契数列,所以求第几个月能到n就是该数列前多少项大于。*/
#include<stdio.h>
int main(void){
int n;
scanf("%d",&n);
int month=3;
int x1,x2,x;
x1=x2=1;
int sum=2;
x=x1+x2;
if(n==1)printf("1");
else if(n==2)printf("3");
else {while(x<n){
x1=x2;
x2=x;
x=x1+x2;
month++;
}
printf("%d",month);}
return 0;
}
也可以用数组,暂时没写出测试点完全通过的代码
7 . 单词首字母大写
本题目要求编写程序,输入一行字符,将每个单词的首字母改为大写后输出。所谓“单词”是指连续不含空格的字符串,各单词之间用空格分隔,空格数可以是多个。
- 这个和书上的统计单词个数很类似
- 两点:首先,在新单词前面要经历过空格,且现在的不是空格
- 实现第一点就是用if,如果为空格时就改变标志的值,在else if加一个条件就是标志值改变,执行了else if就表示现在的不是空格,那么标志的值改回来,这样同一个单词的字母才不会循环执行
- 与书上多了一点限制,因为很有可能输入时该单词首字母就是大写,所以加上判断,当首字母是小写时进行转换。
//思路:如书上输入空格数单词个数一样,将它看作一个整体,判断是一个新单词时就将其输入的字符改写为大写。
#include<stdio.h>
int main(void){
char ch;
int flag=1;
while((ch=getchar())!='\n'){
if(ch==' '){
flag=1;
}
else if(flag){
if(ch>=97&&ch<=122)ch=ch-'a'+'A';
flag=0;
}
putchar(ch);
}
return 0;
}
8 . 恺撒密码加密
输入一个偏移量,若该数>0往右平移,若该数<0往左平移
- 特殊的是<0时往左平移,这个时候要分情况讨论,因为它可能过边界,所以就需要单独讨论
while(a[i]!='\0'){
if(offest<0){
if(a[i]+offest<65||a[i]+offest<97&&a[i]>'a'){
a[i]=a[i]+max+offest;
}
else a[i]=a[i]+offest;
}
i++;
}
特别注意这个代码
a[i]+offest<97&&a[i]>'a'
- 一定不能忘记&&的内容,若是忘记,那么当a[i]是大写时68-1=67,也是小于97的,就会造成错误处理!!!!
如上图,大写S不应该进入if中的,因为少了&&所以当为大写的时候总是满足判断小写的条件,导致S进入加了26再往左移。
- 下面是一个简单向又移动的代码,值得一提的是它在最后到边界时的处理,事实上在之前的循环右移中就可以用这种思路,加个外循环循环平移m次就好
#include<stdio.h>
int main(void){
char a[81];
gets(a);
int i=0;
while(a[i]!='\0'){
if(a[i]>=65&&a[i]<=90||a[i]>=97&&a[i]<=122){
if(a[i]>=65&&a[i]<=90){
a[i]=a[i]-'A'+'a';
if(a[i]=='z')a[i]='a';
else a[i]+=1;
}//大写字母变成小写字母;
else {
a[i]=a[i]-'a'+'A';
if(a[i]=='Z')a[i]='A';
else a[i]+=1;
}//因为前面已经做出判断,所以a【i】不是大写字母就只能是小写字母了
}
i++;
}
puts(a);
return 0;
}
9 . 求最大值及其下标
- 得到了下标还怕不知道对应的最大值吗,怎么可能!!!
- 用条件缩写形式别怕,反正?前是条件,条件当然可以是表达式
int main(void) {
int n;
scanf("%d", &n);
int array[10];
for (int i = 0; i < n; i++) {
scanf("%d", &array[i]);
}
// 假设数组中的第一个元素最大,后续比较过程中进行更新
int maxValIndex = 0;
for (int i = 1; i < n; i++) {
maxValIndex = array[i] > array[maxValIndex] ? i : maxValIndex;
}
printf("%d %d", array[maxValIndex], maxValIndex);
return 0;
}
10 . 将数组中的数逆序存放
本题要求编写程序,将给定的n个整数存入数组中,将数组中的这n个数逆序存放,再按顺序输出数组中的元素。
输入样例:
4
10 8 1 2
输出样例:
2 1 8 10
- 一定要关注它的输入形式,一个数字一个空格,先输入一个字然后通过判断输入字符是否是空格当作输入结束标志,当到最后一个输入的是换行而不是空格。
#include<stdio.h>
int main(void){
int n;
int a[100];
int i=1,j;
scanf("%d",&n);
scanf("%d",&a[0]);
while(getchar()==' '){
scanf("%d",&a[i]);
i++;
}
for(j=i-1;j>0;j--)
printf("%d ",a[j]);
//注意是从最大开始的,所以应该j>=0!
printf("%d",a[j]);
return 0;
}
- 注意输出最后一个不带空格,所以在输出最后一个的时候要单独处理,也就是单独输出,不加空格。
11 . 找出不是两个数组共有的元素
- 可能两个数组中所有的数都不是共有元素,所以在定义存放不是共有元素的数组时,它的大小应该大于两个数组大小之和以防止数组溢出
- 必须两个数组全都遍历,每个数组都要遍历看是否有不是共有元素的存入数组c中
- 在输出不是共有元素的数组c时一定要进行判断,看前面是否输出过相同的数,没有输出过才将它输出,毕竟很可能b数组没有的,a数组有两个,都存入数组c了
#include<stdio.h>
int main(void){
int n1,n2;
int flag;
int i,j;
int c[40];
int a[20],b[20];
scanf("%d",&n1);
for(i=0;i<n1;i++){
scanf("%d",&a[i]);
}
int n=0;
scanf("%d",&n2);
for(i=0;i<n2;i++)scanf("%d",&b[i]);
for(i=0;i<n1;i++){//遍历数组a,找b中没有的
flag=1;
for(j=0;j<n2;j++){
if(a[i]==b[j]){
flag=0;break;
}
}
if(flag)c[n++]=a[i];
}
for(i=0;i<n2;i++){
flag=1;
for(j=0;j<n1;j++){
if(b[i]==a[j]){
flag=0;break;
}
}
if(flag)c[n++]=b[i];
}
printf("%d",c[0]);
for(i=1;i<n;i++){//遍历c数组每一个数
flag=1;
for(j=0;j<i;j++){
if(c[i]==c[j]){//判断前面是否有输出过,避免重复输出哦
flag=0;break;
}
}
if(flag){
printf(" %d",c[i]);
}
}
return 0;
}
12 . 矩阵运算
给定一个n×n的方阵,本题要求计算该矩阵除副对角线、最后一列和最后一行以外的所有元素之和。副对角线为从矩阵的右上角至左下角的连线。
- 找出特点,既然是计算除了它们以外的和,那么就在遍历的时候做出判断就行了
#include<stdio.h>
int main(void){
//副对角线的特点:行列标相加i+j=n-1;所以只需设置一个变量,另一个用减法表示即可
int i;
int n;
int j;
int a[20][20];
int sum=0;
scanf("%d",&n);
for(i=0;i<n;i++){
for(j=0;j<n;j++)scanf("%d",&a[i][j]);
}
//上一次写这个题目的思路是全部相加再减去题目中的除了;
//现在转念一想,可以在遍历时判断是否不属于题目中的不要加的部分,只有不属于时才将其加进去。
for(i=0;i<n;i++){
for(j=0;j<n;j++){
//不是最后一行即i!=n-1;不是最后一行即j!=n-1;不是副对角线就是i!=n-1-j;
if(j!=n-1-i&&i!=n-1&&j!=n-1)sum+=a[i][j];
}
}
printf("%d",sum);
return 0;
}
13 . 方阵循环右移
本题要求编写程序,将给定n×n方阵中的每个元素循环向右移m个位置,即将第0、1、⋯、n−1列变换为第n−m、n−m+1、⋯、n−1、0、1、⋯、n−m−1列。
输入格式:
输入第一行给出两个正整数m和n(1≤n≤6)。接下来一共n行,每行n个整数,表示一个n阶的方阵。
输出格式:
按照输入格式输出移动后的方阵:即输出n行,每行n个整数,每个整数后输出一个空格。
输入样例:
2 3
1 2 3
4 5 6
7 8 9
输出样例:
2 3 1
5 6 4
8 9 7
- 这里特别注意就是在循环右移时的覆盖问题
- 因为怕覆盖,所以先将最后一个数用一个临时变量存放,这样就不用怕覆盖,然后因为空出的是最后一个,所以从后面开始移动而不是从前面开始移动
- 最后再将临时变量存的最后一个数赋给第一个数,以此达到了循环移动一位的作用,所以再以外循环为循环移动 m位
#include<stdio.h>
int main(void){
int n,m,k,temp,i,j;
int a[20][20];
scanf("%d",&m);
scanf("%d",&n);
for(i=0;i<n;i++){
for(j=0;j<n;j++)scanf("%d",&a[i][j]);
}
m%=n;
for(i=0;i<m;i++){
for(j=0;j<n;j++){
temp=a[j][n-1];
//for(k=1;k<n;k++)a[j][k]=a[j][k-1];
//上面这个错了,它从前面开始往后赋值,往后就会覆盖,最后输出的就会没有2 5 8这一行数
//因为我们是将最后一个赋给第一个,相当于先将最后一个位置空出来,所以先从后面往前填才不会出现覆盖的情况。
for(k=n-1;k>0;k--)a[j][k]=a[j][k-1];
a[j][0]=temp;
}
}
for(i=0;i<n;i++){
for(j=0;j<n;j++)printf("%d ",a[i][j]);
printf("\n");
}
return 0;
}
14 . 计算天数
本题要求编写程序计算某年某月某日是该年中的第几天。
输入格式:
输入在一行中按照格式“yyyy/mm/dd”(即“年/月/日”)给出日期。注意:闰年的判别条件是该年年份能被4整除但不能被100整除、或者能被400整除。闰年的2月有29天。
输出格式:
在一行输出日期是该年中的第几天。
输入样例1:
2009/03/02
输出样例1:
61
- 注意这里为了使月份与下标相对应,a[0]存放0来占位,后面月份和下标对应啦,只要不用0就好啦
- 现在在的那个月直接加上该月的天数就好了,不要加一整个月的
#include<stdio.h>
int main(void){
int day,year,month,i;
scanf("%d/%d/%d",&year,&month,&day);
//注意:要使月份与数组对应相同,应将一维数组中的第一个设为0,占位,让后续月份对应数组下标
int a[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31},
{0,31,29,31,30,31,30,31,31,30,31,30,31}};
int leap;
leap=year%4==0&&year%100!=0||year%400==0;
for(i=month-1;i>0;i--){
//day+=a[leap][month]
//粗心:此时已经用i代替month
day+=a[leap][i];
}
printf("%d",day);
return 0;
}
15 . 查找指定字符
本题要求编写程序,从给定字符串中查找某指定的字符。
输入格式:
输入的第一行是一个待查找的字符。第二行是一个以回车结束的非空字符串(不超过80个字符)。
输出格式:
如果找到,在一行内按照格式“index = 下标”输出该字符在字符串中所对应的最大下标(下标从0开始);否则输出"Not Found"。
输入样例1:
m
programming
输出样例1:
index = 7
- 注意因为是要找到最大下标,所以第一次找到后不用打破循环,一直到所有循环完更新
- printf也可以用条件语句输出呢
- 巧妙的一点,给index初始化一个原来没有的值,在条件判断中看该值是否改变就可以知道有没有查到一样的了
#include <stdio.h>
int main () {
int i = 0,index = -1;
char c, str[81];
scanf("%c\n", &c);
gets(str);
// scanf("%[^\n]", str); // 用%s输入字符串,遇到空格会停止,要把空格包括在内可以用"%[^\n]",会读到'\n'为止
while (str[i] != '\0') {
if (str[i] == c) index = i;
i++;
}
printf(index==-1?"Not Found":"index = %d",index);
return 0;
}
16 . 字符串逆序
- 通过指针一头一尾互换位置来达到目的
- 头加尾减,注意尾要减1哦,因为首地址偏移n个元素那么多了一个首地址也就是字符串结束符
void reverse(char* left, char* right)
{
while (left<right)
{
char tmp = 0;
tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char arr[100] = { 0 };
gets(arr);//获取字符串
//将字符串倒置
int len = strlen(arr);//计算字符串长度,以求最后一位的地址
reverse(arr, arr+len-1);//进行倒置
printf("%s\n",arr);
return 0;
}
17 . 选择法排序
- 具体见选择排序专题
- 注意不可以用异或,万一要互换的是两个相同的数那么会将他们异或成0
#include<stdio.h>
int main(void){
int n,i,j,max,temp;
int a[10];
scanf("%d",&n);
for(i=0;i<n;i++)scanf("%d",&a[i]);
for(i=0;i<n-1;i++){
max=i;
for(j=i+1;j<n;j++){
if(a[j]>a[max])max=j;
}//问题:第一个输入的数无论是什么都会变成0
//a[i]^=a[max]^=a[i]^=a[max];
//不要使用异或,异或是可以交换两个值,但是仅限两个不同值,若将两个相同的值进行上述三次异或
//不仅不可以交换两个值,还会将两个值都归0.所以若要将两个值归0,可以将它与他自己或与他相同的值进行异或
temp=a[i];
a[i]=a[max];
a[max]=temp;
}
for(i=0;i<n-1;i++)printf("%d ",a[i]);
printf("%d",a[n-1]);
return 0;
}
18 . 求一批整数中出现最多的个位数字
给定一批整数,分析每个整数的每一位数字,求出现次数最多的个位数字。例如给定3个整数1234、2345、3456,其中出现最多次数的数字是3和4,均出现了3次。
输入格式:
输入在第1行中给出正整数N(≤1000),在第二行中给出N个不超过整型范围的非负整数,数字间以空格分隔。
输出格式:
在一行中按格式“M: n1 n2 ...”输出,其中M是最大次数,n1、n2、……为出现次数最多的个位数字,按从小到大的顺序排列。数字间以空格分隔,但末尾不得有多余空格。
输入样例:
3
1234 2345 3456
输出样例:
3: 3 4
- 很巧妙的一点,数字可以和数组下标相对应,所以直接以该数字为下标加值就可以了
- 将每个数看作一个数组元素存入
- 特别处理,当该数是0的时候,直接将存数字的元素值加一
- 特别注意就是很可能是有一样的出现最大次数,所以最后遍历存出现次数的数组,若为最大次数就输出其下标也就是对应数字
/*关键:每个整数当成一个元素存入数组中,注意存入数组后,该元素也就是
一个整数,可以进行取余等操作,然后进行判断。
巧妙:新建一个数组,数组下标即表示对应数字,当符合时对应元素加一,即代表
该数字出现的次数*/
#include<stdio.h>
int main(void){
int a[1000];
int i;//对应下标数字中数组元素存入的就是该数字出现的次数
int n;
int b[10]={0};
//特别注意:当a为0时,是一个特殊的值,所以要单独拎出来讨论。
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d",&a[i]);
}
for(i=0;i<n;i++){//遍历数组
if(a[i]==0)b[0]++;
while(a[i]!=0){
b[a[i]%10]++;//将数字存入
a[i]/=10;//存入最后一个数字后,数字要更新
}
}
int max=b[0];//因为只要找出最大值,不用进行排序,所以只要遍历找出就好啦
//找出最大值,最后再循环一遍找出与最大值相等的就是对应下标
for(i=1;i<10;i++){
if(b[i]>max){
max=b[i];
}
}
printf("%d:",max);
for(i=0;i<10;i++){
if(b[i]==max)printf(" %d",i);
}
return 0;
}