题目一:1-100各类数之和
(1)求1+2+3+…+100的和
简单的一个for循环的练习,从1遍历到100,每次递增1.
#include<iostream>
using namespace std;
int main(){
int sum=0; //定义一个变量存储总和
for(int i=1;i<=100;i++){ //for循环遍历
sum+=i; //每次累加,更新sum值
}
cout<<"1+2+3+...+100和为"<<sum;
}
(2)求1+3+5+…+99的奇数和
循环的练习,从1遍历到100,每次递增2,保证都是奇数。
#include<iostream>
using namespace std;
//for循环
void fun_for(){
int sum=0;
for(int i=1;i<=100;i+=2){
sum+=i;
}
cout<<"1+3+5+7..+99和为"<<sum<<endl;
}
//while循环
void fun_while(){
int sum=0,n=1;
while(n<=99){
sum+=n;
n+=2;
}
cout<<"1+3+5+7..+99和为"<<sum<<endl;
}
int main(){
fun_for();
fun_while();
return 0;
}
(3)求1+1/2+1/3+…+1/100的和
可以观察到,分子都是1,分母是从1逐一递增到100.
我们可以把分母这个变量,拿去遍历再求和。
#include<iostream>
using namespace std;
int main(){
float sum=0;
for(int i=1;i<=100;i+=1){
sum+=1.0/i; //1.0是为了转换数据类型,因为i还是整型
}
cout<<"1+1/2+1/3+...+1/100和为"<<sum;
//printf("%.2f\n",sum); 保留两位小数
}
若结尾保留两位小数,则要
.2f
,如代码中注释的部分。
我们也可写成递归的形式,递归的出口是n==1
,返回一个double类型的总和。
#include<iostream>
using namespace std;
double sum(int n){ //递归的求和函数,返回值是double类型,函数名是sum,传入参数是整型的n
if(n==1){
return 1.0; //返回double值
}
return 1.0/n+sum(n-1); //若n不等于1,则一直return这段语句
}
int main(){
int n=100;
double result = sum(n); //调用函数sum,传入参数n,把函数sum返回的值 赋值给变量result
printf("1+1/2+1/3+...+1/100和为%.2f",result);
return 0;
}
若需要自定义n,可以使用
cin>>n
,自己输入n的值,结尾改成printf("1+1/2+1/3+...+1/%d和为%.2f",n,result);
n是分母,只能输入正数。
(4)求-1+1/2-1/3+1/4…-1/99+1/100的和
仔细观察可以看出,与上一题不同之处在于符号的正负,奇数位为负,偶数位为正.
我们此时需要写一个if语句
来判断奇数偶数。
#include<iostream>
using namespace std;
int main(){
float sum=0;
for(int i=1;i<=100;i++){
if(i%2==0) //若i是偶数
sum+=1.0/i; //则sum加上1.0/i
else
sum-=1.0/i;
}
cout<<"-1+1/2-1/3+...+1/100和为"<<sum;
//printf("%.2f\n",sum);
}
题目二:斐波那契数列(Fibonacci Sequence)又称黄金分割数列
Q:设一对大兔子每月生一对小兔子,每对新生兔在出生一个月后又下崽,假若兔子都不死亡。问:一对兔子一年能繁殖成多少对兔子?
经典的递归问题
当n=1或者2时,第n项的值为1;
当n>2时候,这个数列的第n项的值就是它前面两项之和。
///第n个fibonacci数可递归如下:
int fibonacci(int n){
if(n==1||n==2)
return 1;
else
return fibonacci(n-1)+fibonacci(n-2);
}
回到这道题。
#include<iostream>
using namespace std;
int fib(int n){
if(n==1||n==2)
return 1;
else
return fib(n-1)+fib(n-2);
}
int main(){
int n; //天数
cout<<"请输入天数:";
cin>>n;
cout<<"第"<<n<<"天共有兔子"<<fib(n)<<"对";
return 0;
}
如果不使用递归呢?
我们可以设置三个变量作为前天、昨天、今天的兔子数量,每过一天就及时更新这些数据。
#include<iostream>
using namespace std;
//f当天兔子对数
//f1昨天兔子对数
//f2前天兔子对数
int main(){
int f1=1,f2=1,f; //第1.2天都只有一只兔子
for(int i=3;i<=10;i++){ //从第三天开始,到第十天
f=f1+f2; //每过一天,今天的兔子=昨天+前天
printf("%d天共有兔子%d对\n",i,f);
f2=f1; //更新前天的数据
f1=f; //更新昨天的数据
}
return 0;
}
题目三:判断素数
素数一般指质数。质数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
暴力法
根据素数的定义,不能被2~n-1之内的数整除的整数n就被称为素数。所以我们从2跑到n-1,每次取模判断即可,这是最直观的一种方法。
bool isPrime_1(int num)
{
for(int i=2;i<=num-1;i++)
if(num%i==0) //若被整除,则说明不是素数,返回0
return 0;
return 1;
}
开根号法
对于每个数n,其实并不需要从2判断到n-1,我们知道,一个数若可以进行因数分解,那么分解时得到的两个数一定是一个小于等于sqrt(n),一个大于等于sqrt(n),据此,上述代码中并不需要遍历到n-1,==遍历到sqrt(n)==即可,因为若sqrt(n)左侧找不到约数,那么右侧也一定找不到约数!所以从2跑到sqrt(n)就可以了。
bool isPrime_2(int num)
{
double tmp=num-1;
for(int i=2;i<=sqrt(tmp);i++)
if(num%i==0)
return 0;
return 1;
}
在 头文件中声明的 sqrt() 函数的参数和返回值都是浮点数类型
Q:遍历101-200的素数。
#include <iostream>
#include <cmath>
using namespace std;
bool isPrime(int num) {
if (num <= 1) {
return false;
}
for (int i = 2; i <= sqrt(num); i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
int main() {
int count = 0;
cout << "素数列表:\n";
for (int i = 101; i <= 200; i++) {
if (isPrime(i)) {
cout << i << " ";
count++;
}
}
cout << "\n101到200之间的素数个数为:" << count << endl;
return 0;
}
题目四:打印九九乘法表
我们可以知道,乘法表的格式是列数 * 行数 = 结果值
。那么这里面就有三个变量,分别是列数、行数、结果值。
我们假设行数是i
,列数是j
,那么结果值可以为i*j
,(这里就直接写表达式,不再定义变量)
对于行数i,遍历从1到9,那列数j呢,也是直接遍历从1到9吗?
nonono,你可以试试,打印出来会是一个9*9的长方形乘法表,不是三角形的。我们可以发现,九九乘法表的每一行的列数是<=行数的,那么由此我们也找到了列数的限制范围。
#include<iostream>
using namespace std;
//简单版
int main(){
for(int i=1;i<=9;i++){
for(int j=1;j<=i;j++)
printf("%d*%d=%-5d",j,i,i*j);
cout<<endl;
}
return 0;
}
#include<iostream>
using namespace std;
const int WIDTH=5; //宏定义,所有的WIDTH的值均为5
int main(){
//打印列头
cout<<setw(WIDTH)<<'*' ; //setw()字段宽度限制
for(int i=1;i<=9;i++)
cout<<setw(WIDTH)<<i;
cout<<endl;
for(int i=1;i<10*WIDTH;i++){
cout<<'-';
}
cout<<endl;
for(int i=1;i<=9;i++){
cout<<setw(WIDTH)<<i; //最左边的表格列
for(int j=1;j<=i;j++)
cout<<setw(WIDTH)<<i*j;
for(int j=i;j<=9;j++)
cout<<setw(WIDTH)<<' ';
cout<<endl;
}
return 0;
}
setw(int n)是c++中在输出操作中使用的字段宽度设置,设置输出的域宽,n表示字段宽度。
题目五:猴子爬杆
(1)猴子每天爬3米,再向下退1米,到第十天后刚好到达杆顶,问杆子高度。
爬十天,前九天每天爬2米,最后一天爬3米
#include<iostream>
using namespace std;
int main(){
int day=1,high=0;
while(day<10){
high=high+2;
day++;
}
high=high+3;
cout<<high;
return 0;
}
(2)杆子20米,猴子每天爬3米,下退1米,问猴子第几天爬到顶
最后一天爬的总高度>20米,其实就是求当达到这个条件的时候的天数。
#include<iostream>
using namespace std;
int main(){
int day=1,high=0;
while((high+3)<20){
high=high+2;
day++;
}
cout<<day;
return 0;
}
题目六:猴子吃桃
Q:猴子每天吃掉一半的桃,再贪吃一个,到第10天就剩1个桃子,问最初有多少桃子?
已知最后一天的天数和桃子个数,往前推就可推出总数。
#include<iostream>
using namespace std;
int main(){
int day=9,x=1;
while(day>0){
x=(x+1)*2;
day--;
}
cout<<x;
return 0;
}
题目七:水仙花数
Q:遍历从100到1000的水仙花数
水仙花数:个位3+十位3+百位3=数值
第一步:分解一个三位数的个位,十位,百位;
第二步:判断是否满足水仙花数的条件;
第三步:通过循环遍历所有的三位数;
#include<iostream>
using namespace std;
int main(){
int ge,shi,bai;
for(int n=100;n<=1000;n++){
ge=n%10;
shi=n%100/10;
bai=n/100;
if(ge*ge*ge+shi*shi*shi+bai*bai*bai==n)
cout<<n<<"是水仙花数"<<endl;
}
return 0;
}
题目八:菱形打印
Q:输入一个正整数m,打印出高度有2*m-1的菱形
可在草稿纸上罗列出m=1,2,3,4时候的菱形,寻找m与空格和*
的关系,寻找行数与空格和*
的关系,先用数学公式表示,再翻译为代码。
#include<iostream>
using namespace std;
int main(){
int m;
cin>>m;
for(int i=1;i<=m;i++){ //行数
for(int j=1;j<=m-i;j++) //空格
cout<<" ";
for(int k=1;k<=2*i-1;k++) //*
cout<<"*";
cout<<endl;
}
for(int i=2;i<=m;i++){ //这里的行数没有计算长的那一行,所以是m-1行
for(int j=1;j<i;j++)
cout<<" ";
for(int k=1;k<=2*m+1-2*i;k++)
cout<<"*";
cout<<endl;
}
}
题目九:判断位数并倒叙输出
Q:输入一个整数,倒序输出每个位数的数值。如输入456
,输出6 5 4
.
#include<iostream>
#include<cmath> //注意导入库函数
using namespace std;
int main(){
int m,i=1;
printf("请输入一个整数:");
scanf("%d",&m);
printf("%3d",abs(m)%10); //输出个位数的数值
while((m=abs(m)/10)>0){ //abs求绝对值
printf("%3d",m%10);
i++; //i统计循环次数,位数为循环次数+1
}
printf("输入的是%d位数\n",i);
return 0;
}
判断位数,并倒叙输出
m=123 m%10=3
m=m/10=12 m%10=2
m=m/10=1 m%10=1
abs (n)函数定义在 或 <math.h> 头文件中,返回参数n的绝对值
题目十:最大公约数与最小公倍数
Q:先输入大数字a,再输入小数字b,求这两个数字的最大公约数和最小公倍数。
最大公约数算法如下:
穷举法
从较小的数开始,遍历到1,一次一次查询是否能被两个数字所整除。由于是从大开始遍历到小,所以首先得到的结果就是最大公约数。
void fun1(){
int a,b;
cin>>a>>b;
for(int i=b;i>0;i--){
if(a%i==0&&b%i==0){
cout<<a<<"和"<<b<<"的最大公约数是"<<i<<endl;
break;
}
}
}
欧几里德算法(辗转相除法)
gcd(a,b)=gcd(b,a%b)
a%b为0时,两数最大公约数为b
long gcd(int a,int b){
if(a%b==0)
return b; //b为最大公约数
return gcd(b,a%b);
}
最大公约数x最小公倍数=axb
cout<<"最大公约数是"<<m<<endl; cout<<"最小公倍数是"<<(a*b)/n<<endl;
题目十一:字符串倒序
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
int main(void){
char str[]="student";
char ch;
int len=strlen(str); //strlen(),获取字符串长度
for(int i=0;i<len/2;i++){ //对半分开,首尾交换字符,下面三行代码类似冒泡排序里的交换数值
ch=str[i];
str[i]=str[len-i-1];
str[len-i-1]=ch;
}
puts(str); //puts(),用于输出一个字符串并换行
return 0;
}
题目十二:杨辉三角
第一步:定义一个二维数组,赋初值为1
第二步:从第2行 第2列开始,当前数=上一行的数=上一行前面的数
第三步:只输出左下角部分数据
第四步:每行加上数量不等的数,使其居中
#include<iostream>
using namespace std;
int main(){
int data[9][9];
for(int i=0;i<9;i++){
for(int j=0;j<9;j++){
data[i][j]=1;
}
}
for(int i=1;i<9;i++){
for(int j=1;j<9;j++){
data[i][j]=data[i-1][j]+data[i-1][j-1]; //当前数=上一行的数=上一行前面的数
}
}
for(int i=0;i<9;i++){
for(int k=0;k<26-6*i/2;k++) //i/2:居中只需左边加空格; *6:输出时%6d; 用26剪:不大不小刚刚好
printf(" ");
for(int j=0;j<i;j++) //输出左下角的数据
printf("%6d",data[i][j]);
printf("\n");
}
return 0;
}
题目十三:完数
Q:输入一个正整数,判断是否为完数
如果一个数等于它的因子之和 ,则这个数为完数
例如:6的因子是1,2,3,且123=6,故6为完数
#include<iostream>
using namespace std;
int main(){
int m,s=0; //s为m的因子的总和值
printf("请输入一个正整数:");
scanf("%d",&m);
for(int i=1;i<m;i++){
if(m%i==0) //如果i是因子,则加到s值中
s+=i;
}
if(m==s)
printf("%d是一个完数\n",m);
else
printf("%d不是一个完数\n",m);
}
题目十四:求阶乘
Q:求出1-10的阶乘,最后累加求和
#include<iostream>
using namespace std;
int main(){
unsigned s=0; //使用unsigned类型可以确保结果不会出现负数;s是阶乘和
for(int n=1;n<=10;n++){
unsigned jie=1; //每个数字的阶乘值
int i=1;
for(;i<=n;i++)
jie*=i;
printf("%d!=%u\n",i-1,jie); //上一行的for循环结束后,i被++了,比n大了一
s+=jie;
}
printf("1!+2!+...+10!=%u\n",s); //注意是%u噢,对应的unsighed
return 0;
}
递归:
#include<iostream>
using namespace std;
int fac(int n){
int f=0;
if(n<0)
cout<<"n<0,error!";
else if(n==0||n==1)
f=1;
else f=n*fac(n-1);
return f;
}
int main(){
int n,y; //n为被阶乘的数字,y为n的阶乘值
cin>>n;
y=fac(n);
cout<<n<<"!="<<y;
return 0;
}
题目十五:求字符串符号长度函数
Q:手写strlen()函数,求字符串符号长度函数
以查询到字符为'\0'
的情况为终止条件,此时字符串的字母已经遍历完
#include<iostream>
using namespace std;
int strlen(const char *p){ //函数类型int,函数名strlen,输入的参数是char型的常量指针p
int count=0;
while(*p!='\0'){ //字符串最后的字符是'\0'
count++;
p++;
}
return count;
}
int main(){
char str[]="hello";
printf("%d\n",strlen(str));
return 0;
}
常量指针:指针本身是可变的,但指针所指向的值是不可变的。声明方式为
const int *ptr;
,意味着不能通过该指针修改所指向的值,但可以改变指针指向的位置。
指针常量:指针本身是不可变的,但指针所指向的值是可变的。声明方式为int *const ptr;
,意味着指针本身不能指向其他位置,但可以通过该指针修改所指向的值。
题目十六:冒泡排序
经典题目,必会!
#include<iostream>
using namespace std;
void bubble(int[],int); //函数声明,int[] 表示一个整型数组,等效于int*
int main(){
int array[]={55,2,6,4,32,12,9,73,26,37};
int len=sizeof(array)/sizeof(int); //数组长度=数组的总字节数/数据类型的字节数
for(int i=0;i<len;i++)
cout<<array[i]<<","; //输出原先的数组
cout<<"\n\n";
bubble(array,len);
}
void bubble(int a[],int size){ //传入两个参数,数组和数组长度
for(int pass=1;pass<size;pass++){ //外层循环控制遍历数组的次数,每次遍历都会将当前最大(或最小)的元素移动到正确位置,只需size-1次
for(int i=0;i<size-pass;i++) //内层循环用于实际比较相邻元素并进行交换操作
if(a[i]>a[i+1]){
int temp=a[i];
a[i]=a[i+1];
a[i+1]=temp;
}
for(int i=0;i<size;i++) //打印每一次排序后的数组
cout<<a[i]<<",";
cout<<endl;
}
}
sizeof(x), 计算出x在内存中所占字节数.
题目十七:数列求和
Q:a[n]=1/(n+1)+2/(n+1)+……+n/(n+1),求前n项和S[n]
#include<iostream>
using namespace std;
int main(){
cout<<"请输入一个正整数";
int n;
scanf("%d",&n);
if(n<=0){
cout<<"输入的值不合法";
return 0;
}
float a=0,s=0;
for(int j=1;j<=n;j++){
for(int i=1;i<=j;i++){
a+=i/(j+1.0);
}
printf("a[%d]=%-8.4f",j,a);
s+=a;
}
printf("\ns[%d]=%.4f\n",n,s);
return 0;
}
%-8.4f
:用来输出浮点数,具体含义如下:
-
:表示左对齐。
8
:表示输出的总宽度为 8 个字符,包括小数点和小数部分。
.4
:表示保留 4 位小数。
f
:表示输出的是浮点数。
题目十八:输入日期第几天
Q:输入日期是第几天,判断一个日期是当年的第几天,判断月份的天数、判断闰年、判断每个月的天数
#include<iostream>
using namespace std;
int main(){
int sum=0;
int day,month,year;
printf("请输入日期(以空格区分)(例如:2024 1 1)\n");
scanf("%d%d%d",&year,&month,&day);
if(day>31){
cout<<"输入错误";
return 0;
}
switch(month-1) {
case 11:sum+=30;
case 10:sum+=31;
case 9:sum+=30;
case 8:sum+=31;
case 7:sum+=31;
case 6:sum+=30;
case 5:sum+=31;
case 4:sum+=30;
case 3:sum+=31;
case 2:
if((year%100!=0&&year%4==0)||year%400==0){
sum+=28;
}
else
sum+=29;
case 1:sum+=30;break;
case 0:break;
default:
cout<<"输入错误";
return 0;
}
printf("当前日期是今年的第%d天",sum+day);
return 0;
}
此代码还可完善,缺少部分的错误输入警告
题目十九:输出1234组成不重复的三位数
Q:有1,2,3,4个数字能组成多少个没有重复数字的三位数?输出这些三位数
#include<iostream>
using namespace std;
int main(){
for(int i=1;i<=4;i++){ //百位
for(int j=1;j<=4;j++){ //十位
for(int k=1;k<=4;k++){ //个位
if(i!=j&&j!=k&&i!=k) //没有重复
printf("%6d",i*100+j*10+k);
}
}
}
printf("\n");
return 0;
}
题目二十:数组对角线之和
Q:求下列数组的对角线之和
j=0 | j=1 | j=2 | |
---|---|---|---|
i=0 | 1 | 2 | 3 |
i=1 | 4 | 5 | 6 |
i=2 | 7 | 8 | 9 |
L1=1+5+9=arr[0][0]arr[1][1]+arr[2][2] i==j
L2=3+5+7=arr[0][2]arr[1][1]+arr[2][0] i+j=2
对角线之和=L1+L2-arr[1][1]
#include<iostream>
using namespace std;
#define LEN 3 //定义一个符号常量,代理程序中的字面常量
int main(){
int L1,L2,s;
L1=L2=s=0;
int arr[][LEN]={{1,2,3},{4,5,6},{7,8,9}};
for(int i=0;i<LEN;i++){
L1+=arr[i][i]; //主对角线
L2+=arr[i][LEN-1-i]; //次对角线
}
s=L1+L2-arr[(LEN-1)/2][(LEN-1)/2];
printf("对角线之和为:%d\n",s);
return 0;
}
题目二十一:数组中的最值与均值
#include<iostream>
using namespace std;
int main(){
int data[]={21,32,56,79,98,64,31,51,84,67};
int max,min,sum=0;
float avg;
max=min=data[0];
for(int i=1;i<10;i++){
if(max<data[i])
max=data[i];
if(min>data[i])
min=data[i];
sum+=data[i];
}
avg=sum/10.0;
cout<<"最大值是"<<max<<endl
<<"最小值是"<<min<<endl
<<"平均值是"<<avg<<endl;
return 0;
}
参考资料
1.b站up主 慕码人CPL
2. 大一自己的学习资料