蓝桥杯常用算法模板个人总结

蓝桥杯尤其喜欢考察 全排列和组合。DFS、BFS、自定义比较器排序、简单递推。偶尔考考二分、数论。

蓝桥杯常用算法模板

    • 不带重复元素的全排列
    • 带重复元素的全排列
    • 不带重复元素的子集
      • 迭代写法
    • 带重复元素的子集
    • 快速幂
    • 矩阵快速幂
    • 二分搜索
    • lower_bound
    • 判断是否是闰年
    • 判断是否素数
    • 素数打表——倍筛法
    • 最大公约数gcd
    • 最小公倍数
    • 判断括号是否合法
    • 前缀和
    • 区间树
    • 并查集

不带重复元素的全排列

package 常用算法模板;
/**
* @author JohnnyLin
* @version Creation Time:2020年10月15日 下午10:53:40
*/
public class 全排列_不带重复元素的_抓 {
	
	static int[]a= {1,2,3,4,5};
	static boolean vis[]=new boolean[a.length];
	static int ans;
	public static void dfs(int m,String s) {
		if(m==a.length) {
			//s记录一个排列方案
			System.out.println(s);
			//ans记录排列方案数目 
			ans++;
			return;
		}
		for(int i=0;i<a.length;i++) {
			if(!vis[i]) {
				vis[i]=true;
				dfs(m+1,s+a[i]+" ");
				vis[i]=false;
				
			}
		}
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		dfs(0,"");
		//A(5,5)=120
		System.out.println(ans);

	}

}

另一种写法

import java.util.Scanner;

public class Main{
    static int N = 10, n ;
    static boolean st[] = new boolean[N];
    static int[] f = new int[N];
    
    public static void dfs(int u){
        if( u == n){
            for(int i = 0; i < n; i ++)
                System.out.print(f[i]+" ");
            System.out.println();
            return;
        }
        for(int i = 1; i <= n; i++)
            if(!st[i]){
                st[i] = true;
                f[u] = i;
                dfs( u + 1);
                st[i] = false;
                
            }
    }
    
    public static void main(String args[]){
        Scanner reader = new Scanner(System.in);
        n = reader.nextInt();
        dfs(0);
    }
}

带重复元素的全排列

package 常用算法模板;

import java.util.Arrays;

/**
* @author JohnnyLin
* @version Creation Time:2020年10月15日 下午11:00:44
*/
public class 全排列_带重复元素的_抓 {
	static int a[]= {2,1,2,3,3};
	static boolean vis[]=new boolean[a.length];
	static int ans;
	static void dfs(int m,String s) {
		if(m==a.length) {
			//记录每一个排列方案
			System.out.println(s);
			//记录方案数目
			ans++;
		}
		for(int i=0;i<a.length;i++) {
			if(!vis[i]) {
				if(i>0&&a[i-1]==a[i]&&!vis[i-1]) continue;
				vis[i]=true;
				dfs(m+1,s+a[i]+" ");
				vis[i]=false;
			}
		}
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Arrays.sort(a); 
		dfs(0, "");
		System.out.println(ans);

	}

}

import java.util.Scanner;
import java.util.Arrays;
/*
带重复元素的全排列
*/
public class Main{
    //1 2 2 3 3
    
    static int a[]= {2,1,2};
    static int n = a.length;
    static boolean st[] = new boolean[n];
    static int [] f=  new int[n];
    
    public static void dfs(int u){
        if( u == n){
            for(int i = 0; i < n; i ++)
                System.out.print(f[i]+" ");
            System.out.println();
            return;
        }
        for(int i = 0; i < n; i ++){
            if( !st[i]){
                //当前元素与前一个元素相同 且 前一个元素没有用过 
                if( i > 0 && a[i] == a[i - 1] && !st[i - 1]) continue;
                st[i] = true;
                f[u] = a[i];
                dfs( u + 1);
                st[i] = false;
            }

        }
            
    }
    public static void main(String args[]){
        //Scanner reader = new Scanner(System.in);
        //n = reader.nextInt();
        Arrays.sort(a, 0, n);
        dfs(0);
    }
}

LeetCode传送门

LeetCode全排列、全排列II

不带重复元素的子集

package 常用算法模板;

import java.util.ArrayList;
import java.util.List;

/**
* @author JohnnyLin
* @version Creation Time:2020年10月15日 下午11:53:16
*/
public class 子集_不带重复元素的 {
	static int []a= {1,2,3};
	public static void dfs(int m,List<Integer> sub,List<List<Integer>> res) {
		
		res.add(new ArrayList<>(sub));
		for(int i=m;i<a.length;i++) {
			sub.add(a[i]);
			dfs(i+1,sub,res);
			sub.remove(sub.size()-1);
		}
		
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<List<Integer>> res=new ArrayList<>();
		List<Integer> sub=new ArrayList<>();
		dfs(0, sub, res);
		//每一种子集
		for(List<Integer> list:res){
			System.out.println(list.toString());
		}
		//子集方案数
		System.out.println(res.size());
		

	}

}

迭代写法

import java.util.*;
/*
不带重复元素的子集
*/
public class Main{
    
    static int a[]= {1,2,3,4,5};
    static int n = a.length;
    public static void main(String args[]){
        
       
        int n = a.length;
        Set<List<Integer>> ans = new HashSet<>();
        for(int i = 0; i <= n; i ++){ //枚举长度 [0,n]
           
            for(int j = 0; j <= n - i; j ++){//枚举左端点[0,n - i]
                int k = j + i;//右端点 [i, n]
                List<Integer> sub =  new ArrayList<>();
                //枚举左右区间断点 [j, k)
                for(int m = j; m < k; m ++) sub.add(a[m]);
                ans.add(sub);
            }
        }
        for(List list : ans)
            System.out.println(list);
        
    }
}

带重复元素的子集

package 常用算法模板;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
* @author JohnnyLin
* @version Creation Time:2020年10月15日 下午11:53:16
*/
public class 子集_带重复元素的 {
	static int []a= {2,1,2};
	public static void dfs(int m,List<Integer> sub,List<List<Integer>> res) {
		
		res.add(new ArrayList<>(sub));
		for(int i=m;i<a.length;i++) {
			if(i>m&&a[i-1]==a[i]) continue;
			sub.add(a[i]);
			dfs(i+1,sub,res);
			sub.remove(sub.size()-1);
		}
		
		
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<List<Integer>> res=new ArrayList<>();
		List<Integer> sub=new ArrayList<>();
		Arrays.sort(a);
		dfs(0, sub, res);
		//每一种子集
		for(List<Integer> list:res){
			System.out.println(list.toString());
		}
		//子集方案数
		System.out.println(res.size());
		

	}

}

LeetCode传送门:
LeetCode子集、子集II的三种解法

快速幂

static int mod=100000007;
	/**
	 * 计算a的n次方(要求n>=0)
	 * @param a
	 * @param n
	 * @return
	 */
	public static long quickPow(long a,int n) {
		
		long ans=1;
		while(n>0) {
			if((n&1)==1)
				ans=ans*a%mod;
			a=a*a%mod;
			n>>=1;
			
		}
		return ans;
		
	}

矩阵快速幂

//一般矩阵运算结果都会比较大 会有取模要求
	static final long mod=10000;
	/**
	 * 矩阵乘法
	 * @param a
	 * @param b
	 * @return 返回矩阵a与矩阵相乘的结果
	 */
	public static long [][] matrixMutiply(long [][]a,long b[][]) {
		int n=a.length;
		int m=b[0].length;
		int q=a[0].length;
		if(q!=b.length)
			throw new IllegalArgumentException();
		long c[][]=new long[n][m];
		for(int i=0;i<n;i++) {
			for(int j=0;j<m;j++) {
				for(int k=0;k<q;k++) {
					//若有取模要求: c[i][j]=(c[i][j]%mod+a[i][k]*b[k][j]%mod)%mod;
					c[i][j]+=a[i][k]*b[k][j];
				}
			}
		}
		return c;
		
	}
	/**
	 * 矩阵快速幂
	 * @param a
	 * @param n
	 * @return 返回n个矩阵a相乘的结果
	 */
	public static long [][] matrix_Pow(long [][]a, int n) {
		int  m=a.length;
		long [][]ans=new long[m][m];
		//注意:这里是单位矩阵
		for(int i=0;i<m;i++)
			ans[i][i]=1;
		while(n>0) {
			if((n&1)==1)
				ans=matrixMutiply(ans, a);
			a=matrixMutiply(a, a);
			n>>=1;
		}
		return ans;
	}

二分搜索

二分查找符合条件的最大值:经典问题是蓝桥杯2017第八届java B组分巧克力

public static int binarySerachTarget(int []a,int low,int high,int target) {
		int ans=1;
		while(low<=high) {
			int mid=(low+high)>>1;
			if(check(mid)) {
				low=mid+1;
				ans=mid;
			}else high=mid-1;
		}
		
		//ans即为答案
		return ans;
	}
	//根据题目写check函数
private static boolean check(int  mid) {
	return false;
}

lower_bound

/**
	 * @param a
	 * @param l
	 * @param r
	 * @param target
	 * @return
	 * 返回第一个大于等于target的元素下标
	 */
	public static int lowe_bound(int []a,int l,int r,int target) {
		while(l<=r) {
			int mid=(l+r)>>1;//或l+(r-l);
			if(a[mid]>=target)
				r=mid-1;
			else 
				l=mid+1;
		}
		return l;
	}

判断是否是闰年

	public static boolean isLeapYear(int y) {
		//能被400整除 H或能被4整除但是不能被100整除
		return (y%4==0&&y%100!=0)||(y%400==0);
	}

判断是否素数

	public static boolean isPrime(int n) {
		if(n==1)return false;
		for(int i=2;i*i<=n;i++) {
			if(n%i==0)return false;
		}
		return true;
	}

素数打表——倍筛法

static final int N=100000005;
	static int []st=new int[N];
	//埃氏筛法:一个质数的倍数一定是合数,筛掉合数剩下的自然就是素数
	//得到n以内的素数
	public static void  selcetPrime(int n) {
		
		for(int i=2;i<=n;i++) {
			if(st[i]==0) {//是素数 一开始是2 2是素数 就筛出所有的2的倍数
				for(int j=2*i;j<=n;j+=i) {//筛去i的倍数
					st[j]=1;
				}
			}
		}

		int res=0;
		//统计素数个数  1不是素数  从2开始统计
		for(int i=2;i<=n;i++) {
			if(st[i]==0) {
				res++;
				System.out.println(i);
			}
		}
		//合数个数:因为统计是 从2开始 因此要加上1这个合数
		System.out.println(n-res+1);
		///素数个数:res
		System.out.println(res);
	}

最大公约数gcd

	/**
	 * @param a
	 * @param b
	 * @return 返回a、b的最大公约数
	 */
	public static int  gcd(int a,int b) {
		return (b==0)?a:gcd(b,a%b );
	}

最小公倍数

	public static int  gcd(int a,int b) {
		return (b==0)?a:gcd(b,a%b );
	}
	/**
	 * @param a
	 * @param b
	 * @return 返回a、b的最小公倍数
	 */
	public static int lcm(int a,int b) {
		//最小倍数*最大公约数即为最小公倍数
		return a*b/gcd(a, b);
	}

判断括号是否合法

public static boolean isValid(String exp) {
		if(exp==null||exp.equals("")) return true;
		char e[]=exp.toCharArray();
		Stack<Character> stack=new Stack<>();
		for(int i=0;i<e.length;i++) {
			if(e[i]=='<'||e[i]=='{'||e[i]=='('||e[i]=='[')//左括号则入栈
				stack.push(e[i]);
			else {
				//取出栈顶左括号与现有右括号匹配
				//取前要判断栈非空
				if(!stack.isEmpty()) {
					Character c=stack.peek();
					stack.pop();
					if(c=='<'&&e[i]=='>')continue;
					if(c=='{'&&e[i]=='}')continue;
					if(c=='('&&e[i]==')')continue;
					if(c=='['&&e[i]==']')continue;
				}
				return false;
				
			}
			
		}
		//若左右括号匹配 则栈为空返回真值
		return stack.empty();
	}

前缀和

static  int a[]= {1,5,36,7,0,52,67,5};
	//1 6 42 49 49 101 168 173
	static int []preSum;
	public static void prefixSum() {
		int len=a.length;
		preSum=new int[len];
		preSum[0]=a[0];
		for(int i=1;i<len;i++) {
			preSum[i]=preSum[i-1]+a[i];
		}
			
	}
	
preSum[j]-preSum[i]查询(i,j]区间的区间和

区间树

使用前缀和可以O(1)操作查询区间和,O(n)操作更新。对于在计算过程中需要更新原数据的这种区间求和,可以使用区间树实现O(logn)更新,O(logn)查询。

package 常用算法模板;

import java.util.Scanner;

/**
* @author JohnnyLin
* @version Creation Time:2020年10月16日 下午3:48:00
*/
class SegTree{
	//左右子树
	SegTree lson,rson;
	//区间范围
	int l,r;
	int sum;
	public SegTree(int l,int r) {
		this.l=l;
		this.r=r;
	}
}
public class 线段树区间求和 {
	static int [] a={1,5,36,7,0,52,67,5};
	static int [] b=new int[a.length];;
	static int [] ans;
	static SegTree root;
	/**
	 * @param l
	 * @param r
	 * @return 根据给定区间建立[l,r]范围的线段树
	 */
	public static SegTree buildsegTree(int l,int r) {
		SegTree segTree=new SegTree(l, r);
		if(l==r) {
			segTree.sum=a[l];
			return segTree;
		}
		int mid=(l+r)>>1;
		SegTree lson=buildsegTree(l, mid);
		SegTree rson=buildsegTree(mid+1, r);
		segTree.lson=lson;
		segTree.rson=rson;
		segTree.sum=lson.sum+rson.sum;
		return segTree;
	}
	/**
	 * @param tree
	 * @param x
	 * @param y
	 * @return 返回[x,y]区间和
	 */
	public static int query(SegTree tree,int x,int y) {
		int l=tree.l;
		int r=tree.r;
		if(x<=l&&y>=r) return tree.sum;
		int mid=(l+r)>>1;
		int ans=0;
		if(x<=mid) ans+=query(tree.lson, x, y);
		if(y>mid) ans+=query(tree.rson, x, y);
		return ans;
	}
	/**
	 * @param tree
	 * @param p	下标
	 * @param i 值
	 * 	修改了原数据需要,需要更新线段树 
	 * 	时间复杂度:log(n)
	 */
	public static void  update(SegTree tree,int p,int i) {
		
		if(tree==null)//叶子结点的下一层了
			return;
		//更新节点的sum
		tree.sum+=i;
		int l=tree.l;
		int r=tree.r;
		int mid=(l+r)>>1;
		if(p<=mid) update(tree.lson, p, i);
		else update(tree.rson, p, i);
	}

	public static void main(String[] args) {
		Scanner reader=new Scanner(System.in);
		
		//建立与原数组长度相对的区间树
		root=buildsegTree(0, a.length-1);
		//1 6 42 49 49 101 168 173
		//[i,j] {1,5,36,7,0,52,67,5}
		System.out.println(query(root,3,6));//126
		System.out.println(query(root,0,0));//0
		System.out.println(query(root,0,2));//6
		
		//修改a数值元素值
		a[4]=11;
		update(root, 4, 11);
		System.out.println(query(root,3,6));//6
	}

}

并查集

你可能感兴趣的:(#,备战蓝桥杯,算法,蓝桥杯常用算法模板)