基础向算法题练习记录

基础向算法题练习记录

最大回文乘积

回文数就是从前往后读和从后往前读都一样的数。由两个2位数相乘得到的最大的回文数是 9009=91×99。
求由两个3位数相乘得到的最大的回文数。

暴力枚举把得到的答案拆解对调和原数比对加入循环找出其中最大的,分层写代码可读性好

#include <iostream>
using namespace std;
int func(int x){
	int t=0;
	int raw=x;
	while(x){  //把数字分解
		t=t*10+x%10;
		x/=10;
	}
	return t==raw;
}
int main() {
	int ans=0;
	for(int i=100;i<1000;i++){
		for(int j=i;j<1000;j++){//三位数,两个数
			int t=i*j;
			if(func(t)){
				ans=max(ans,t);
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

平方的和与和的平方之差

前十个自然数的平方的和是
12+22+…+102=385
前十个自然数的和的平方是
(1+2+…+10)2=552=3025
因此,前十个数的平方的和与和的平方之差是3025−385=2640。
求前一百个数的平方的和与和的平方之差。

较为简单枚举解决

#include <iostream>
using namespace std;
int main() {
	int sum=0,psum=0;
	for(int i=1;i<=100;i++){
		sum+=i;
		psum+=i*i;
	}
	cout<<sum*sum-psum<<endl;
	return 0;
}

连续数字最大乘积

在如下的1000位数中,连续四个数字的最大乘积是 9×9×8×9=5832。
73167176531330624919225119674426574742355349194934 96983520312774506326239578318016984801869478851843 85861560789112949495459501737958331952853208805511 12540698747158523863050715693290963295227443043557 66896648950445244523161731856403098711121722383113 62229893423380308135336276614282806444486645238749 30358907296290491560440772390713810515859307960866 70172427121883998797908792274921901699720888093776 65727333001053367881220235421809751254540594752243 52584907711670556013604839586446706324415722155397 53697817977846174064955149290862569321978468622482 83972241375657056057490261407972968652414535100474 82166370484403199890008895243450658541227588666881 16427171479924442928230863465674813919123162824586 17866458359124566529476545682848912883142607690042 24219022671055626321111109370544217506941658960408 07198403850962455444362981230987879927244284909188 84580156166097919133875499200524063689912560717606 05886116467109405077541002256983155200055935729725 71636269561882670428252483600823257530420752963450
求这个1000位数中连续十三个数字的最大乘积。

大整数加法了,数据十分的巨大。因为在有0时会影响答案的计算,所以需要特殊考虑。


#include<iostream>
using namespace std;
char num[1005];
long long ans,zero_cnt,now=1;
int main(){
	cin>>num;
	for(int i=0;i<1000;i++){
		if(i<13){
			now*=num[i]-'0';
		}else{
			if(num[i]=='0'){
				zero_cnt++;
			}else{
				now*=num[i]-'0';
			}
			if(num[i-13]=='0'){
				zero_cnt--;
			}else{
				now/=num[i-13]-'0';
			}
		}
		if(zero_cnt==0){
			ans=max(ans,now);
		}
	}
	cout<<ans<<endl;
	return 0;
}

方阵中的最大乘积

在如下的20×20方阵中,有四个呈对角线排列的数被标记为红色。
08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08 49 49 99 40 17 81 18 57 60 87 17 40 98 43 69 48 04 56 62 00 81 49 31 73 55 79 14 29 93 71 40 67 53 88 30 03 49 13 36 65 52 70 95 23 04 60 11 42 69 24 68 56 01 32 56 71 37 02 36 91 22 31 16 71 51 67 63 89 41 92 36 54 22 40 40 28 66 33 13 80 24 47 32 60 99 03 45 02 44 75 33 53 78 36 84 20 35 17 12 50 32 98 81 28 64 23 67 10 26 38 40 67 59 54 70 66 18 38 64 70 67 26 20 68 02 62 12 20 95 63 94 39 63 08 40 91 66 49 94 21 24 55 58 05 66 73 99 26 97 17 78 78 96 83 14 88 34 89 63 72 21 36 23 09 75 00 76 44 20 45 35 14 00 61 33 97 34 31 33 95 78 17 53 28 22 75 31 67 15 94 03 80 04 62 16 14 09 53 56 92 16 39 05 42 96 35 31 47 55 58 88 24 00 17 54 24 36 29 85 57 86 56 00 48 35 71 89 07 05 44 44 37 44 60 21 58 51 54 17 58 19 80 81 68 05 94 47 69 28 73 92 13 86 52 17 77 04 89 55 40 04 52 08 83 97 35 99 16 07 97 57 32 16 26 26 79 33 27 98 66 88 36 68 87 57 62 20 72 03 46 33 67 46 55 12 32 63 93 53 69 04 42 16 73 38 25 39 11 24 94 72 18 08 46 29 32 40 62 76 36 20 69 36 41 72 30 23 88 34 62 99 69 82 67 59 85 74 04 36 16 20 73 35 29 78 31 90 01 74 31 49 71 48 86 81 16 23 57 05 54 01 70 54 71 83 51 54 69 16 92 33 48 61 43 52 01 89 19 67 48
这四个数的乘积是26×63×78×14=1788696。
在这个20×20方阵中,四个呈一直线(竖直、水平或对角线)相邻的数的乘积最大是多少?
方向数组问题,选择4个相邻方向,防止边界越界(补几圈0)

#include<iostream>
using namespace std;
int dirx[4]={0,1,1,1};   //方向选择了右,右下,下,左下
int diry[4]={1,1,0,-1};
int num[40][40],ans;
int main(){
	for(int i=5;i<25;i++){    //因为有补0所以从1开始,长是4
		for(int j=5;j<25;j++){
			cin>>num[i][j];
		}
	}
	for(int i=5;i<25;i++){
		for(int j=5;j<25;j++){
			for(int k=0;k<4;k++){
				int t=num[i][j];     
				for(int l=1;l<4;l++){   //k,l是长度
					int x=i+dirx[k]*l;   
					int y=j+diry[k]*l;
					t*=num[x][y];
				}
				ans=max(ans,t);
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

大和

大整数加法。

大整数加法从后往前诸位加法进位

#include<iostream>
#include<cstring>
using namespace std;
int num1[105],num2[105],sum[105];
char s1[105],s2[105];
int main(){
	cin>>s1>>s2;
	num1[0]=strlen(s1);
	num2[0]=strlen(s2);
	for(int i=0,j=num1[0];i<num1[0];i++,j--){
		num1[j]=s1[i]-'0';
	}
	for(int i=0,j=num2[0];i<num2[0];i++,j--){
		num2[j]=s2[i]-'0';
	}
	sum[0]=max(num1[0],num2[0]);
	for(int i=1;i<=sum[0];i++){
		sum[i]=num1[i]+num2[i];
	}
	for(int i=1;i<=sum[0];i++){
		if(sum[i]>9){
			sum[i+1]+=sum[i]/10;
			sum[i]%=10;
			if(i==sum[0]){
				sum[0]++;
			}
		} 
	} 
	for(int i=sum[0];i>0;i--){
		cout<<sum[i];
	}
	cout<<endl;
	return 0;
}

最长考拉兹序列

考虑如下定义在正整数集上的迭代规则:
n→n/2 (若n为偶数)n→3n+1 (若n为奇数)
从13开始,可以迭代生成如下的序列:
13→40→20→10→5→16→8→4→2→1
可以看出这个序列(从13开始到1结束)共有10项。尽管还未被证明,但普遍认为,从任何数开始最终都能回到1(这被称为“考拉兹猜想”)。
在小于一百万的数中,从哪个数开始迭代生成的序列最长?
注: 在迭代过程中允许出现超过一百万的项。
有提示要考虑越界问题,对比斐波那契数列的递归和递推写法,递归+记忆化的速度约等于递推速度,记忆数组更大可以更快提升运行速度
不用记忆数组也可以,不过太大了写题通不过编译

#include<iostream>
using namespace std;
int num[10000000]; //记忆数组 
int func(long long n){
	if(n==1)return 1;
	if(n<10000000&&num[n])return num[n];
	int t;
	if(n%2==0){
		t=func(n/2)+1;
	}else{
		t=func(3*n+1)+1	
	}
	if(n<10000000){
		num[n]=t;
	}
	return t;
} 
int main(){
	int ans=1;
	for(int i=2;i<=1000000;i++){
		if(func(ans)<func(i)){
			ans=i;
		}
	}
	return 0;
}

网格路径

从一个2×2网格的左上角出发,若只允许向右或向下移动,则恰好有6条抵达右下角的路径。
在这里插入图片描述
对于20×20网格,这样的路径有多少条?
路径规划问题,后续有动态规划。单论这一题是正方形的有数学办法。
小技巧:从1,1开始存而不是从0,0开始.根据题意补0。

//通过遍历找出
#include<iostream>
using namespace std;
int main(){        
	long long dp[25][25]={10};
	for(int i=1;i<=21;i++){       //左到右(因为从一开始所以为21)
		for(int j=1;j<=21;j++){   //上到下
			if(i==1&&j==1){
				dp[i][j]=1;
			}else{
				dp[i][j]=dp[i-1][j]+dp[i][j-1]
			}
		}
	}

	cout<<dp[21][21]<<endl;
	return 0;
}
//数学方法,因为是正方形走到从左上角右下角的所有方法步数都一样
#include<iostream>
using namespace std;
int main(){        
	long long ans=1;
	for(int i=40,j=1;i>20;i--,j++){
		ans*=i;
		ans/+j;
	}
	cout<<dp[21][21]<<endl;
	return 0;
}

最大路径和

从如下的数字三角形的顶端出发,不断移动到下一行与其相邻的元素,所能得到的最大路径和是23。
3
7 4
2 4 6
8 5 9 3
如上图,最大路径和为3+7+4+9=23。
从如下的数字三角形顶端出发到达底部,求所能得到的最大路径和。
75
95 64
17 47 82
18 35 87 10
20 04 82 47 65
19 01 23 75 03 34
88 02 77 73 07 63 67
99 65 04 28 06 16 70 92
41 41 26 56 83 40 80 70 33
41 48 72 33 47 32 37 16 94 29
53 71 44 65 25 43 91 52 97 51 14
70 11 33 28 77 73 17 78 39 68 17 57
91 71 52 38 17 14 91 43 58 50 27 29 48
63 66 04 68 89 53 67 30 73 16 69 87 40 31
04 62 98 27 23 09 70 98 73 93 38 53 60 04 23
注意: 在这个问题中,由于只有16384条路径,通过穷举所有的路径来解决问题是可行的。但是当数字三角形将拥有一百行,就不再能够通过暴力破解来解决,而需要一个更加聪明的办法!;o)
本题数字三角形,数塔问题。在题中已经给出了行数的规定不需考虑太多但是按照提示还是一步到位的好
其实图是个等腰三角形但是可以按照直角三角形看,粘贴过来也变直角了这样看只能从左上和正上方过来,成了有规律的递推问题。加0补成正方形,因为从上往下算需要遍历最后一排比出最大值(不想遍历就在循环的时候顺便带上),不如倒过来从下往上。这样答案只有一个就方便一些。
Dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+num[i][j](核心规律)

//从上向下版
#include<iostream>
using namespace std;
int num[20][20],ans[20][20],n;
int main(){        
	n=15;  //行数
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cin>>num[i][j];
		}
	}
	int fin=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			ans[i][j]=max(ans[i-1][j-1],ans[i-1][j])+num[i][j];
			fin=max(fin,ans[i][j]);    //循环时就把较大的比较出来不用另写比较
		}
	}
	cout<<fin<<endl;
	return 0;
}
//从下向上版:
#include<iostream>
using namespace std;
int num[20][20],ans[20][20],n;
int main(){        
	n=15;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cin>>num[i][j];
		}
	}
	for(int i=n;i>0;i--){
		for(int j=1;j<=i;j++){
			ans[i][j]=max(ans[i+1][j],ans[i+1][j+1])+num[i][j];		//有一点改变
		}
	}
	cout<<ans[1][1]<<endl; //输出塔尖
	return 0;
}

1000位斐波那契数

斐波那契数列是按如下递归定义的数列:
F1=1 F2=1Fn=Fn−1+Fn−2
因此斐波那契数列的前12项分别是:
F1=1F2=1F3=2F4=3F5=5F6=8F7=13F8=21F9=34F10=55F11=89F12=144
第一个包含三位数字的是第12项F12。
在斐波那契数列中,第一个包含1000位数字的是第几项?

保留两个数循环相加没必要保存前面所有的数

#include<iostream>
using namespace std;
int func(int *n1,int *n2){   //大整数加法 
	n2[0]=n1[0];
	for(int i;i<=n2[0];i++){
		n2[i]+=n1[i];
		if(n2[i]>9){
			n2[i+1]+=n2[i]/10;
			n2[i]%=10;
			if(i==n2[0]){
				n2[0]++;
			}
		}
	}
	return n2[0]>=1000;
}
int main(){        //循环加法 
	int num[2][1100]={{1,1},{1,1}};
	int a=0,b=1;
	for(int i=3;1;i++){
		if(func(num[a],num[b])==1){
			cout<<i<<endl;
			break;
		}
		swap(a,b);
	}
	
	return 0;
}

小菜鸡打算持续更新记录一下。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值