复试机试算法总结#5:数学问题

1.进制转换

对于不大的输入,可以借助向量,模一次存一次整除一次,倒序输出即可;而对于过长位数的输入,则应使用字符串来模拟数字的模运算和整除运算

1.1 十进制->二进制->十进制 (十进制数的位数<=1000)

十进制->二进制时要用到字符串除法;二进制->十进制时要用到字符串乘法+字符串加法

https://www.nowcoder.com/practice/fd972d5d5cf04dd4bb4e5f027d4fc11e?tpId=40&tqId=21357&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking

#include<iostream>
#include<cstdio>
#include<string>
#include<vector>

using namespace std;

string strDivide(string str,int x)//字符串除法 
{
	int remainder=0;//保存余数 
	for(int i=0;i<str.size();++i)//从高位到低位 
	{
		int current=remainder*10+str[i]-'0';//上一次保留的余数x10与本次第一位的数一起处理 
		str[i]=current/x+'0';
		remainder=current%x;//不能整除则保留余数 
	}
	int pos=0;//标记非前导0的位数 
	while(str[pos]=='0')
		pos++;
	return str.substr(pos);//删除前导0 
}

string strMultiple(string str,int x)//字符串乘法 
{
	int carry=0;//保存进位
	for(int i=str.size()-1;i>=0;--i) 
	{
		int current=x*(str[i]-'0')+carry;
		str[i]=current%10+'0';
		carry=current/10;
	}
	if(carry!=0)//若仍有进位,则在结果前面补1 
		str="1"+str;
	return str;
}

string strAdd(string str,int x)//字符串加法 
{
	int carry=x;//保存进位,这一步与字符串乘法不同 
	for(int i=str.size()-1;i>=0;--i) 
	{
		int current=(str[i]-'0')+carry;//这一步与字符串乘法不同 
		str[i]=current%10+'0';
		carry=current/10;
	}
	if(carry!=0)//若仍有进位,则在结果前面补1 
		str="1"+str;
	return str;
}

int main()
{
	string str;
	while(cin>>str)
	{
		vector<int> binary;
		//十进制->二进制 
		while(str.size()!=0)//类似与整数的直接进制转换 
		{
			int last=str[str.size()-1]-'0';//取最低位的值
			binary.push_back(last%2);//取模 
			str=strDivide(str,2);//整除运算 
		}//获得二进制串(反序的 
		
		//二进制->十进制 
		string answer="0"; 
		for(int i=0;i<binary.size();++i)
		{
			answer=strMultiple(answer,2);
			answer=strAdd(answer,binary[i]);
		}
		cout<<answer<<endl;
	}
	
	return 0;
} 

1.2 M进制的数输出为N进制的数

中间转换为十进制作为过渡,涉及到字符与数字之间的转换,超过十进制就要带上字母

https://www.nowcoder.com/practice/ae4b3c4a968745618d65b866002bbd32?tpId=40&tqId=30990&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking

#include<iostream>
#include<cstdio>
#include<string>
#include<vector>

using namespace std;

char int2char(int x)//数字->字符 
{
	if(x<10)
		return x+'0';
	else//大于9的数字转换为a,b,c...... 
		return x-10+'a';
}

int char2int(char c)//字符->数字 
{
	if(c>='0'&&c<='9')
		return c-'0';
	else//a,b,c...转换为10,11,12...... 
		return c-'A'+10;
}

int main()
{
	int m,n;
	string x;
	while(cin>>m>>n) 
	{
		cin>>x;
		//M进制转化为十进制 
		long long number=0;
		for(int i=0;i<x.size();++i)
		{
			number*=m;
			number+=char2int(x[i]);
		}
		//十进制转化为N进制 
		vector<char> answer;
		while(number!=0)
		{
			answer.push_back(int2char(number%n));
			number/=n;
		}
		//倒序输出 
		for(int i=answer.size()-1;i>=0;--i)
		{
			cout<<answer[i];
		}
		cout<<endl;
	}	
	return 0;
} 

2. 最大公约数与最小公倍数

2.1 最大公约数GCD

原理:欧几里得算法(辗转相除):a,b的公约数g可整除“a除以b后的余数r”,则问题转换为球b,(a mod b)的最大公约数,不断重复直至问题变为球某个非零数与0的最大公约数,该非零数即为答案

int GCD(int a,int b)
{
	if(n==0)
		return a;
	else
		return GCD(b,a%n);
} 

2.2 最小公倍数LCM

a,b两个数的最小公倍数是两者的乘积÷两者的最大公约数

3. 质数(素数)

质数是只能被1和自己整除的数。

3.1 一般方法

找素数只需遍历到sqrt(n),适合判定某数是否是素数的情况

bool Judge(int x)
{
	if(x<2) 
		return false;
	int bound=sqrt(x);//判断上界 
	for(int i=2;i<=bound;++i)
	{
		if(x%i==0)
			return false;
	}
	return true;
}

3.2 素数筛法

找到一个素数后就把它的倍数也标记为素数。适合找出某个大范围内的所有素数的情况

vector<int> prime;
bool isPrime[MAXN];

void Initial()//把非质数标记出来,剩下的就是质数 
{
	//初始化 
	for(int i=0;i<MAXN;++i)
		isPrime[i]=true;
	isPrime[0]=false;
	isPrime[1]=false;
	//遍历 
	for(int i=2;i<MAXN;++i)
	{
		if(!isPrime[i])//跳过非质数
			continue; 
		prime.push_back(i);
		for(int j=i*i;j<MAXN;j+=i)//质数的背书为非质数 
			isPrime[i]=false
	}
	return; 
}

4. 分解质因数

每一个数字都可以写成多个质数相乘的形式,而其中各种质数就是这个数字的质因数。只需遍历到N的开方,而非1e9是因为n最多只有一个>sqrt(n)的因子;若有两个,乘积就大于n了

https://www.nowcoder.com/practice/20426b85f7fc4ba8b0844cc04807fbd9?tpId=40&tqId=21338&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking

//用素数筛法,确定0到MAXN内的所有素数
//输入n,依次测试能否整除n,能则计数
//不断将n除以该素数,直至不能整除,统计其幂指数
//遍历所有的素数后,若n=1,则分解完成;否则n存在一个大于MAXN的因子,这个因子必为素因子 
#include<iostream>
#include<cstdio>
#include<vector>

using namespace std;

const int MAXN=100001;//使用素数筛法只需找到N的开方即可
vector<int> prime;
bool isPrime[MAXN];

void Initial()//素数筛法 
{
	for(int i=0;i<MAXN;++i)
		isPrime[i]=true;
	isPrime[0]=false;
	isPrime[1]=false;
	
	for(int i=2;i<MAXN;++i)
	{
		if(!isPrime[i])
			continue;
		prime.push_back(i);
		for(int j=i*i;j<MAXN;j+=i)
			isPrime[j]=false;
	}
}

int main()
{
	Initial();
	int n;
	while(cin>>n)
	{
		int answer=0;
		for(int i=0;i<prime.size()&&prime[i]<n;++i)
		{
			int factor=prime[i];
			while(n%factor==0)//不断试除 
			{
				n/=factor;
				answer++;
			}
		}
		if(n>1)//还剩一个质因数 
			answer++;
		cout<<answer<<endl;
	}
	return 0;
}

5. 快速幂

求某个数的高次幂时,不用一次一次地乘这个数,而可以使用若干个中间结果的平方,以此减少乘的次数

例题:求A^B的最后三位数

输入:每行输入都是A和B,输入0  0时结束输入,且1<=A,B<=10000

输出:A^B结果后三位形成的整数

#include<iostream>
#include<cstdio>

using namespace std;

int FastMi(int a,int b,int mod)
{
	int answer=1;
	while(b!=0)//不断将b转换为二进制数,其中1代表乘一次a,0代表不乘 
	{
		if(b%2==1)//若当前位为1 
		{
			answer*=a;
			answer%=mod;
		}
		b/=2;
		a*=a;//二进制的下一位对应的乘a次数增加,所以这里a自乘 
		a%=mod;//保存后几位 
	}
	return answer;
}

int main()
{
	int a,b;
	while(cin>>a>>b)
	{
		if(a==0&&b==0)
			break;
		cout<<FastMi(a,b,1000)<<endl;//保存后三位,所以mod取1000 
	} 	
	return 0;
} 

6. 矩阵与矩阵快速幂

6.1 矩阵乘法

按照线性代数正常运算

struct Matrix
{
	int matrix[MAXN][MAXN];
	int row,col;//行,列
	Matrix(int r,int c):row(r),col(c) {} 
}; 

Matirx Multiply(Matrix x,Matrix y)
{
	Matrix answer(x.row,y.col);
	for(int i=0;i<answer.row;++i)//前两层循环用于遍历 
	{
		for(int j=0;j<answer.col;++j)
		{
			answer.matrix[i][j]=0;
			for(int k=0;k<x.col;++k)//计算 
				answer.matrix[i][j]+=x.matrix[i][k]*y.matrix[k][j];
		}
	}
	return answer; 
}

6.2 矩阵快速幂

矩阵乘法+快速幂

https://www.nowcoder.com/practice/31e539ab08f949a8bece2a7503e9319a?tpId=40&tqId=21523&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking

#include<iostream>
#include<cstdio>

using namespace std;

struct Matrix
{
	int matrix[10][10];
	int row,col;//行,列
	Matrix(int r,int c):row(r),col(c) {} 
}; 

Matrix Multiply(Matrix x,Matrix y)
{
	Matrix answer(x.row,y.col);
	for(int i=0;i<answer.row;++i)//前两层循环用于遍历 
	{
		for(int j=0;j<answer.col;++j)
		{
			answer.matrix[i][j]=0;
			for(int k=0;k<x.col;++k)//计算 
				answer.matrix[i][j]+=x.matrix[i][k]*y.matrix[k][j];
		}
	}
	return answer; 
}

void PrintMatrix(Matrix x)
{
	for(int i=0;i<x.row;++i)
	{
		for(int j=0;j<x.col;++j)
		{
			if(j!=0)
				cout<<" ";
			cout<<x.matrix[i][j];
		}
		cout<<endl;
	}
	return ;
}

Matrix FastMi(Matrix x,int k)//x矩阵的k次幂
{
	Matrix answer(x.row,x.col);
	for(int i=0;i<answer.row;++i)//矩阵的快速幂需要初始化为单位矩阵 
	{
		for(int j=0;j<answer.col;++j)
		{
			if(i==j)
				answer.matrix[i][j]=1;
			else
				answer.matrix[i][j]=0;
		}
	}
	while(k!=0)//类似正常的快速幂 
	{
		if(k%2==1)
			answer=Multiply(answer,x);
		k/=2;
		x=Multiply(x,x);
	}
	return answer;
} 

int main()
{
	int n,k;
	while(cin>>n>>k)
	{
		Matrix x(n,n);
		for(int i=0;i<n;++i)//输入矩阵 
		{
			for(int j=0;j<n;++j)
			{
				cin>>x.matrix[i][j];
			}
		}
		
		Matrix answer=FastMi(x,k);
		PrintMatrix(answer); 
	}	
	return 0;
}

7. 高精度整数

使用Java中的BigInteger类,或使用C++高精度整数模板

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值