算法学习之数论基础(持续更新)

快速幂(包含取模情况下)

解决的问题:

快速得到一个a的b次方,复杂度为log2n

心得:

前提:例如a的6次方,6的二进制’110‘,右边第一位是1次方,第二位是2次方,第三位是4次方,第一位和第二位都是1,所以a的6次方  <=> a的2次方 *  a的4次方

初始化res为1,通过传入的b次方,把b进行二进制操作,查看最后一位是否为1,如果是1则代表需要乘a(a一直在变,a的1、2、3、4次方等等),否则不需要。但是无论需不需要乘,每次b都会右移1位,a也需要进行平方,因为b的二进制右边第一位对应a的1次方,第二位是a的2次方,b移动了,a也要对应相乘

公用代码:

public static void main(String[] args) {
	System.out.println(ksm(5, 2, 9));
}
public static int ksm(int a,int b,int mod) {
	int res=1;
	while(b>0) {
		if((b & 1)==1) {
			res=res*a%mod;
		}
		a=a*a%mod;
		b>>=1;
	}
	return res;
	}

例题(待更新):

矩阵快速幂

解决的问题:

与快速幂相似,也是快速得到一个矩阵的b次方

心得:

与快速幂相似,初始化ans为单位矩阵(类似于快速幂的初始化res为1)判断条件什么的,但是在乘法这一块需要用到矩阵的乘法(twoMatrixPlus方法),当b次方最后一位是1,则ans为ans矩阵与a相乘(类似于快速幂中res为res与a相乘)。但是无论是不是,b一样要右移,a一样还要平方,这个时候平方就是a矩阵与a矩阵相乘

公用代码:

package conbat.动态规划.数论;

import java.util.Arrays;

public class 快速幂与矩阵快速幂 {
	static int[][] res;
	static int[][] temp;
public static void main(String[] args) {
	int[][] jzksm = jzksm(new int[][] { { 2, 3 }, { 2, 4 } }, 2);
	for(int[] sss:jzksm) {
		System.out.println(Arrays.toString(sss));
	}
}

public static int[][] jzksm(int a[][],int n){
	int ans[][]=new int[a.length][a[0].length];
	for(int i=0;i<ans.length;i++)
		for(int j=0;j<ans[0].length;j++) {
			if(i==j)
				ans[i][j]=1;
		}//初始化为单位矩阵
	while(n>0) {
		if((n&1)==1)
			ans=twoMatrixPlus(ans,a);
		a=twoMatrixPlus(a,a);
		n>>=1;
	}
	return ans;
}
public static int[][] twoMatrixPlus(int x [][],int y [][]) {//两个矩阵相乘,具有普适性
	int ans[][]=new int[x.length][y[0].length];
	for(int i=0;i<x.length;i++)
		for(int j=0;j<y[0].length;j++)
			for(int p=0;p<x[0].length;p++)
				ans[i][j]+=x[i][p]*y[p][j];
	return ans;

}
}

例题(待更新):

素数三大筛

解决的问题:

判断n是合数还是质数(素数)

心得:

有三种不同解决方法,简单方法,埃式筛,欧拉筛。

简单方法:int i=2;i*i<=x;i++,如果n/i为0则是合数,一直判断,最后没有就是质数(只看一个数的时候合适,埃式筛欧拉筛是多个数都需要的比较合适)

埃式筛:int i=2;i*i<n;i++,由2开始,一直倍数,倍数后的数就设为true,是素数,最后没有被设为true的就是合数,但是由于有一些数会被重复倍数到,例如8会被2和4进行倍数

欧拉筛:我直接就推荐视频讲解,太牛了家人们这个动画,这个算法主要就是对于埃式筛会重复设置进行了优化(if(i % prime[j] == 0) break;)欧拉筛,几行就行,一次就好_哔哩哔哩_bilibili

公用代码:


import java.beans.Visibility;
import java.util.Arrays;

public class Main {
	public static void main(String[] args) {
		System.out.println(is_easy(17));
		System.out.println(is_comment(17));
		System.out.println(is_good(8));
		System.out.println(is_good(7));
		System.out.println(is_good(9));
		System.out.println(is_good(17));
		System.out.println(is_good(19));
	}
	public static boolean is_easy(int x) {   //复杂度:根号x  合数返回false   质数/素数返回true;
		if(x==0||x==1) {
			return false;
		}
		for(int i=2;i*i<=x;i++) {
			if(x%i==0) {
				return false;
			}
		}
		return true;
	}
	public static boolean is_comment(int x) {//埃式筛 复杂度:nloglogn     得到2-N以内哪个是质数哪个是素数  维护的数组是vis[]  vis[x]=true是合数
		int n=10000005;
		boolean[] vis=new boolean[n];   //默认false =>  质数/素数
		for(int i=2;i*i<n;i++) {
			if(!vis[i]) {
				for(int j=i*2;j<n;j+=i) {
					vis[j]=true;
				}
			}
		}
		return vis[x];
	}


	public static int is_good(int n) {//欧拉筛   复杂度:n
		int cnt = 0;
		int []isPrime = new int[n+1]; // 1 为合数 0为质数
		int []prime = new int[n+1];
		for(int i = 2;i <=n/2;i++){
			if(isPrime[i] == 0){
				prime[++cnt] = i;
			}
			for(int j = 1;j <= cnt && prime[j] * i <= n;j++){
				isPrime[i * prime[j]] = 1;
				if(i % prime[j] == 0) break;
			}
		}
		return isPrime[n];
	}
}

例题(待更新):

扩展欧几里得

解决的问题:

已知整数a,b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y,满足ax + by = gcd(a,b)

心得(待完善):

公用代码:

package conbat.动态规划.数论;

import java.util.Scanner;

public class 拓展欧几里得 {
	//扩展欧几里得算法求x、y
	static int x=-1;
	static int y=-1;
	public static void main(String[] args) {
		//   已知整数a,b,扩展欧几里得算法可以在求得a、b的最大公约数的同时,能找到整数x、y,满足ax + by = gcd(a,b)
		Scanner cin = new Scanner(System.in);
		while(cin.hasNext()) {
			int a = cin.nextInt();
			int b = cin.nextInt();
			int k1 = eeaGcd(a,b);
			System.out.println("最大公因子是:"+k1+",其中x="+x+",y="+y);
		}
		cin.close();
	}
	
	//扩展欧几里得算法
	private static int eeaGcd(int a,int b) {
		//最简单的情形
		if(b==0) {
			x=1;
			y=0;
			return a;//最大公约数
		}else {
			//一般情形
			int r = eeaGcd(b,a%b);
			int t = x;
			x = y;
			y = t-a/b*y;
			return r;			
		}		
	}		
	
}

例题(待更新):

唯一分解定理

解决的问题:

x数可以分解为哪些数相乘

心得:

x/j(2到j*j<=x)可以除几次就输出几次j,不行了就j++,最后数如果不是1则输出最后的数(例如15分为3和5,除完剩5,5不能除3了,因为j最大到3,所以最后还要输出5,例如9可以分为3,除完3还剩3,3再除完3剩1,除不了3了,也正好是1,就不需要输出了)

公用代码:

package conbat.动态规划.数论;

public class 唯一分解定理 {
public static void main(String[] args) {
	idea(4);
}
public static void idea(int x) {
	int i=1;
	while(x>=i*i) {
		i++;
		while(x%i==0) {
			System.out.print(i+" ");
			x/=i;
		}
	}
	if(x!=1) {
		System.out.println(x);
	}
}
}

例题:

最大公约数与最小公倍数

解决的问题:

得到一个数的最大公约数还有最小公倍数方法

心得:

gcd(最大公倍数)a一直%b得到t后,再把a设为原来的b,b设为t,直至b=0,lcm(最小公倍数)a*b/gcd(a,b)

例题(待更新):

公用代码:

package conbat.动态规划.数论;

public class 最大公约数 {
	public static void main(String[] args) {
		int gcd=gcd(15,3);
		int lcm=15*3/gcd;
		System.out.println(gcd);//最大公约数
		System.out.println(lcm);//最小公倍数
	}
	public static int gcd(int a,int b) {
		while(b>0) {
			int t=a%b;
			a=b;
			b=t;
		}
		return a;
	}
}

同余运算(包含乘法逆元)

解决的问题:

题目中数过大,要求取模的情况下

公用方法:

a/b%m   =》(b%p) * (a的逆元%p) %p

(如果b与m互质,则a的逆元为a的p-2次方 b/a%p =》 b*a的逆元%p)  --来自费马小定理

例题(待更新):

龟速乘法(待更新):

米勒罗宾(待更新):

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值