算法常用模板

从最常考的全排列开始吧~

全排列模板1,最常用的写法


 
 
  1. public class 全排列_模板1 {
  2. public static void main(String[] args) {
  3. dfs( 0);
  4. System.out.println(ans); //9的全排有362880种
  5. }
  6. static int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9};
  7. static int n= 9,ans= 0;
  8. static void dfs(int m) {
  9. if(m>=n) {
  10. System.out.println( "一些核心的操作 比如ans:"+ans);
  11. ans++;
  12. for( int i= 0;i<n;i++)
  13. System.out.print(a[i]+ " ");
  14. System.out.println();
  15. return;
  16. }
  17. for( int i=m;i<n;i++) {
  18. swap(i,m);
  19. dfs(m+ 1);
  20. swap(i,m); //回溯
  21. }
  22. }
  23. static void swap(int i,int j) {
  24. int t = a[i];
  25. a[i] = a[j];
  26. a[j] = t;
  27. }
  28. }

 

全排列模板2,使用标记数组的写法


 
 
  1. public class 全排列_模板2 {
  2. public static void main(String[] args) {
  3. vis = new boolean[n];
  4. b = new int[n];
  5. dfs( 0);
  6. System.out.println(ans); //9的全排有362880种
  7. }
  8. static int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9};
  9. static int[] b;
  10. static boolean[] vis;
  11. static int n= 9,ans= 0;
  12. static void dfs(int m) {
  13. if(m>=n) {
  14. System.out.println( "一些核心的操作 比如ans:"+ans);
  15. ans++;
  16. for( int i= 0;i<n;i++)
  17. System.out.print(b[i]+ " ");
  18. System.out.println();
  19. return;
  20. }
  21. for( int i= 0;i<n;i++)
  22. if(!vis[i]) {
  23. vis[i] = true;
  24. b[m] = a[i];
  25. dfs(m+ 1);
  26. b[m] = 0; //其实这个也可以不用回溯,它会被覆盖
  27. vis[i] = false; //回溯
  28. }
  29. }
  30. }

 

下面是需要排重的全排_模板

在上面模板上使用了哈希表查重,把一些数组并接成字符串


 
 
  1. import java.util.HashSet;
  2. public class 全排列_模板3 {
  3. public static void main(String[] args) {
  4. dfs( 0);
  5. System.out.println(ans); //9的全排有362880种
  6. System.out.println(set.size()); //1680
  7. }
  8. static int[] a = new int[] { 1, 1, 1, 2, 2, 2, 3, 3, 3};
  9. static int n= 9,ans= 0;
  10. static HashSet<String> set = new HashSet<>();
  11. static void dfs(int m) {
  12. if(m>=n) {
  13. System.out.println( "一些核心的操作 比如ans:"+ans);
  14. ans++;
  15. String s= "";
  16. for( int i= 0;i<n;i++) {
  17. s+=a[i];
  18. System.out.print(a[i]+ " ");
  19. }
  20. System.out.println();
  21. set.add(s);
  22. return;
  23. }
  24. for( int i=m;i<n;i++) {
  25. swap(i,m);
  26. dfs(m+ 1);
  27. swap(i,m); //回溯
  28. }
  29. }
  30. static void swap(int i,int j) {
  31. int t = a[i];
  32. a[i] = a[j];
  33. a[j] = t;
  34. }
  35. }

 

使用哈希表查重后是无序的,那么遇到需要打印字典序的有重复元素的全排呢

leetcode 46. 全排列

leetcode 47. 全排列 II

子集的写法也和全排很相似

leetcode 78. 子集(Subsets) beat 100%

leetcode 90. 子集 II(Subsets II) beat 98.57%

 

 

 

判断闰年


 
 
  1. static boolean is(int x) {
  2. return x% 400== 0 || (x% 4== 0 && x% 100!= 0);
  3. }

 

 

筛素数O({\color{DarkBlue} n^{\tfrac{3}{2}}})


 
 
  1. static boolean is(int n) {
  2. if(n== 1)
  3. return false;
  4. for( int i= 2;i*i<=Math.sqrt(n);i++)
  5. if(n%i== 0)
  6. return false;
  7. return true;
  8. }

 

倍筛法_素数O(nlogn)


 
 
  1. public class 倍筛模板 {
  2. public static void main(String[] args) {
  3. boolean[] is = new boolean[ 1000005];
  4. is[ 1] = true; //true表示不是素数
  5. for( int i= 2;i< 1000005;i++)
  6. if(!is[ 2])
  7. for( int j= 2*i;j< 1000005;j+=i)
  8. is[j] = true;
  9. System.out.println(is[ 2004]);
  10. }
  11. }

 

01背包


 
 
  1. public class _01背包 {
  2. public static void main(String[] args) {
  3. Scanner in = new Scanner(System.in);
  4. int m = in.nextInt(); //大小
  5. int n = in.nextInt(); //物品数
  6. int[] dp = new int[m+ 5]; //开背包质量的大小
  7. for( int i= 1;i<=n;i++) {
  8. int v = in.nextInt(); //物品体积
  9. int w = in.nextInt(); //物品价值
  10. for( int j=m;j>=v;j--)
  11. dp[j] = Math.max(dp[j], dp[j-v]+w);
  12. }
  13. System.out.println(dp[m]);
  14. }
  15. }

 

完全背包


 
 
  1. import java.util.Scanner;
  2. public class _完全背包 {
  3. public static void main(String[] args) {
  4. Scanner in = new Scanner(System.in);
  5. int m = in.nextInt(); //大小
  6. int n = in.nextInt(); //物品数
  7. int[] dp = new int[m+ 5]; //开背包质量的大小
  8. for( int i= 1;i<=n;i++) {
  9. int v = in.nextInt(); //物品体积
  10. int w = in.nextInt(); //物品价值
  11. for( int j=v;j<=m;j++)
  12. dp[j] = Math.max(dp[j], dp[j-v]+w);
  13. }
  14. System.out.println(dp[m]);
  15. }
  16. }

 

 

最小公倍数gcd


 
 
  1. static int gcd(int a,int b) {
  2. return b== 0?a:gcd(b,a%b);
  3. }

最大公约数lcm


 
 
  1. static int lcm(int a,int b) {
  2. return a*b/gcd(a,b);
  3. }

多个数共同的gcd和lcm模板


 
 
  1. static int gcd(int[] a) {
  2. int n = a.length;
  3. int g = a[ 0];
  4. for( int i= 1;i<n;i++)
  5. g = gcd(g,a[i]);
  6. return g;
  7. }
  8. static int lcm(int[] a) {
  9. int n = a.length;
  10. int l = a[ 0];
  11. for( int i= 1;i<n;i++)
  12. l = lcm(l,a[i]);
  13. return l;
  14. }

二分答案_模板

蓝桥杯 2017年第八届真题 分巧克力 经典的二分答案 输入挂


 
 
  1. static void f(int[] a) {
  2. int n = a.length;
  3. int l= 0,r=n- 1,ans= 0; //一般上界需要自己构造
  4. while(l<=r) {
  5. int mid = l + (r-l)/ 2;
  6. if(ok(a[mid])) {
  7. r = mid- 1;
  8. ans = mid;
  9. } else
  10. l = mid+ 1;
  11. }
  12. System.out.println(ans);
  13. }
  14. static boolean ok(int x) {
  15. return false; //按照题意写
  16. }

二分lower_bound的实现(找到第一个大于等于给定值key的那个数)如[1,2,2,3]查找2,会返回第一个2的下标


 
 
  1. public static int lowerBound(int []nums,int l,int r,int target){
  2. while(l<=r){ //r=n-1
  3. int m = (l+r)/ 2;
  4. if(nums[m]>=target) r= m- 1;
  5. else l = m + 1;
  6. }
  7. return l;
  8. }

upper_bound的实现(要求在按照非递减顺序排好序的数组中找到第一个大于给定值key的那个数)(不常用)


 
 
  1. public static int upperBound(int []nums ,int l,int r, int target){
  2. while(l<r){ //其中 r = nums.length
  3. int m = (l+r)/ 2;
  4. if(nums[m]<=target) l = m+ 1;
  5. else r = m;
  6. }
  7. return l;
  8. }

 

各种排序实现

  • 冒泡排序(学会手写)
  • 选择排序(没什么应用)
  • 插入排序(对近乎有序的数组复杂度提升到O(n))
  • 计数排序(给定区间排序)
  • 归并排序(求逆序数)
  • 快速排序(找第K大数)
  • 堆排序(优先队列API)
  • 希尔排序(插入排序的升级版)

 

大数类BigInteger和BigDecimal及方法API

考场上查API

 

 

进制问题,如有价值1,2,4,8等价值的硬币,如何用最小的硬币数凑出100元


 
 
  1. static int f(int n,int k) { //调用API转成k进制,缺点题目有上界为8
  2. int ans= 0;
  3. String s = Integer.toString(n, k);
  4. System. out.println(s);
  5. for( int i= 0;i<s.length();i++)
  6. ans+=s.charAt(i)- '0';
  7. return ans;
  8. }

头条面试题:找钱问题,共1024,64,16,4,1几种面值 


 
 
  1. static void solve(){
  2. Scanner cin = new Scanner(System. in);
  3. int N = 1024-cin.nextInt(), ans = 0;
  4. for( int i= 0; i< 4; i++){
  5. ans += N/arr[i];
  6. N %= arr[i];
  7. }
  8. System. out.println(ans);
  9. }

堆的应用,给定一个只包括 '('')''{''}''['']' 的字符串,判断字符串是否有效

leetcode 20. 有效的括号(Valid Parentheses)


 
 
  1. public boolean isValid(String s) {
  2. if(s== null||s.equals( ""))
  3. return true;
  4. char[] ch = s.toCharArray();
  5. Stack<Character> stack = new Stack<>();
  6. for( int i= 0;i<ch.length;i++)
  7. {
  8. if(ch[i]== '(' || ch[i]== '[' || ch[i]== '{')
  9. stack.push(ch[i]);
  10. else if(ch[i]== ')' || ch[i]== ']' || ch[i]== '}')
  11. {
  12. if(!stack.isEmpty())
  13. {
  14. char p = stack.pop();
  15. if(p== '(' && ch[i]== ')')
  16. continue;
  17. if(p== '[' && ch[i]== ']')
  18. continue;
  19. if(p== '{' && ch[i]== '}')
  20. continue;
  21. }
  22. return false;
  23. }
  24. }
  25. return stack.empty();
  26. }

 

快速幂及矩阵快速幂模板

矩阵幂_快速幂_矩阵乘法_模板


 
 
  1. static long mpow(long a,long n) { //快速幂,mod一般题目给1e9+7
  2. if(n== 0 || a== 1)
  3. return 1;
  4. long ans= 1;
  5. while(n!= 0) {
  6. if(n% 2== 1)
  7. ans = a*ans%mod;
  8. a=a*a%mod;
  9. n>>= 1;
  10. }
  11. return ans;
  12. }

 矩阵乘法模板


 
 
  1. //这里是矩阵的乘法模板,默认方阵
  2. static int[][] mul( int[][] a, int[][] b){
  3. int n = a.length;
  4. int[][] ans = new int[n][n];
  5. for( int i= 0;i<n;i++)
  6. for( int j= 0;j<n;j++)
  7. for( int k= 0;k<n;k++)
  8. ans[i][j] =(ans[i][j] + a[i][k]*b[k][j])%MOD; //ans[i][j] += a[i][k]*a[k][j];
  9. return ans;
  10. }

 矩阵快速幂模板


 
 
  1. //矩阵快速幂_模板
  2. static int[][] mpow( int[][] a, int n){
  3. int N = a.length;
  4. int[][] ans = new int[N][N];
  5. for( int i= 0;i<N;i++)
  6. ans[i][i] = 1; //初始化为单位矩阵W
  7. while(n> 0) { //写 n!=0也行,会快些么,反正位运算是会快的.这个不清楚
  8. if((n& 1)== 1)
  9. ans = mul(ans,a);
  10. a = mul(a,a);
  11. n>>= 1;
  12. }
  13. return ans;
  14. }

 

阶乘逆元求组合数C(n,m)模板_O(nlogn)


 
 
  1. public static void main(String[] args) {
  2. Scanner in = new Scanner(System.in);
  3. n = in.nextInt();
  4. f = new long[n+ 5];
  5. inv = new long[n+ 5];
  6. f[ 0]= 1;
  7. for( int i= 1;i<n+ 5;i++) {
  8. f[i]=f[i- 1]*i%mod;
  9. inv[i] = mpow(f[i],mod- 2);
  10. }
  11. }
  12. static int n;
  13. static long mod = 1000000009;
  14. static long[] f;
  15. static long[] inv;
  16. static long C(int n,int m) {
  17. return f[n]*inv[m]%mod*inv[n-m]%mod;
  18. }
  19. static long mpow(long a,long n) { //快速幂
  20. if(n== 0 || a== 1)
  21. return 1;
  22. long ans= 1;
  23. while(n!= 0) {
  24. if(n% 2== 1)
  25. ans = a*ans%mod;
  26. a=a*a%mod;
  27. n>>= 1;
  28. }
  29. return ans;
  30. }

 

 

欧拉函数模板        定义:小于n的正整数中与n互质的数的数目(φ(1)=1)


 
 
  1. static int Euler(int n) { //O(n) 有时候需要long
  2. int ans=n;
  3. for( int i= 2;i<=n;i++)
  4. if(n%i== 0) {
  5. ans=ans/i*(i- 1);
  6. while(n%i== 0)
  7. n/=i;
  8. }
  9. return ans;
  10. }

 
 
  1. static int Euler(int n) { //O(sqrt(n))
  2. int ans=n;
  3. for( int i= 2;i*i<=n;i++)
  4. if(n%i== 0) {
  5. ans=ans/i*(i- 1); n*(1-(1/p))转化为n/p*(p-1)
  6. while(n%i== 0)
  7. n/=i;
  8. }
  9. if(n> 1) //优化 O(sqrt(n)) 不过要在出口 if(n>1)ans/n*(n-1) O(n)不用
  10. ans=ans/n*(n- 1);
  11. return ans;
  12. }

 

前缀和模板


 
 
  1. import java.util.Scanner;
  2. public class 前缀和模板 {
  3. public static void main(String[] args) {
  4. Scanner in = new Scanner(System.in);
  5. int n = in.nextInt();
  6. int[] sum = new int[n+ 1];
  7. for( int i= 1;i<=n;i++)
  8. sum[i] = sum[i- 1] + in.nextInt(); //前i个数的和
  9. }
  10. }

 

线段树模板

 

 

并查集模板


 
 
  1. static int n,m,cnt= 0;
  2. static int[] f = new int[ 10005]; //初始化一般是f[i]=i
  3. static int find(int x) {
  4. if(f[x]==x)
  5. return x;
  6. return f[x] = find(f[x]);
  7. }
  8. static void union(int x,int y) {
  9. int a = find(x);
  10. int b = find(y);
  11. if(a!=b) {
  12. f[a] = b;
  13. cnt++;
  14. }
  15. }

 

dfs求联通块模板


 
 
  1. static int n,m;
  2. static int[][] vis;
  3. static char[][] ch;
  4. static int[] dx = new int[] { 1, 1, 1, 0, 0,- 1,- 1,- 1};
  5. static int[] dy = new int[] { 0,- 1, 1, 1,- 1, 1, 0,- 1};
  6. static void dfs(int t,int x,int y) { // hdu1241 油田问题 八联通
  7. vis[x][y] = t;
  8. for( int i= 0;i< 8;i++)
  9. if(x+dx[i]>= 0 && x+dx[i]<n && y+dy[i]>= 0 && y+dy[i]<m && ch[x+dx[i]][y+dy[i]]== '@' && vis[x+dx[i]][y+dy[i]]== 0)
  10. dfs(t,x+dx[i],y+dy[i]);
  11. }

 
 
  1. int t= 0;
  2. for( int i= 0;i<n;i++)
  3. for( int j= 0;j<m;j++)
  4. if(ch[i][j]== '@' && vis[i][j]== 0)
  5. dfs(++t,i,j);
  6. System.out.println(t);

最小生成树模板


 
 
  1. static int n,m,cnt= 0,ans= 0;
  2. static int[] f;
  3. static int find(int x) {
  4. if(f[x]==x)
  5. return x;
  6. return f[x] = find(f[x]);
  7. }
  8. static int union(int x,int y) {
  9. int a = find(x);
  10. int b = find(y);
  11. if(a!=b) {
  12. f[a] = b;
  13. return 1;
  14. }
  15. return 0;
  16. }
  17. static class Edge implements Comparable<Edge>{
  18. int a,b,c;
  19. public Edge(int a,int b,int c) {
  20. this.a = a;
  21. this.b = b;
  22. this.c = c;
  23. }
  24. @Override
  25. public int compareTo(Edge o) {
  26. return this.c - o.c;
  27. }
  28. }

 
 
  1. public static void main(String[] args) {
  2. InputReader in = new InputReader(System.in); //用它来代替Scanner。
  3. while( true) {
  4. n = in.nextInt();
  5. if(n== 0)
  6. break;
  7. m = n*(n- 1)/ 2;
  8. cnt= 0;
  9. ans= 0;
  10. f = new int[n+ 5];
  11. for( int i= 1;i<=n;i++)
  12. f[i] = i;
  13. PriorityQueue<Edge> pq = new PriorityQueue<>();
  14. for( int i= 1;i<=m;i++) {
  15. int a = in.nextInt();
  16. int b = in.nextInt();
  17. int c = in.nextInt();
  18. int d = in.nextInt();
  19. if(d== 1)
  20. cnt+=union(a,b);
  21. else
  22. pq.add( new Edge(a, b, c));
  23. }
  24. while(!pq.isEmpty()) {
  25. Edge u = pq.poll();
  26. if(union(u.a, u.b)== 1) {
  27. cnt++;
  28. ans+=u.c;
  29. if(cnt==n- 1)
  30. break;
  31. }
  32. }
  33. System.out.println(ans);
  34. }
  35. }

输入挂模板


 
 
  1. //解决javaIO读取过慢的方法,利用该类读取输入数据,不要用Scanner!!!
  2. static class InputReader {
  3. public BufferedReader reader;
  4. public StringTokenizer tokenizer;
  5. public InputReader(InputStream stream) {
  6. reader = new BufferedReader( new InputStreamReader(stream), 32768);
  7. tokenizer = null;
  8. }
  9. public String next() {
  10. while (tokenizer == null || !tokenizer.hasMoreTokens()) {
  11. try {
  12. tokenizer = new StringTokenizer(reader.readLine());
  13. } catch (IOException e) {
  14. throw new RuntimeException(e);
  15. }
  16. }
  17. return tokenizer.nextToken();
  18. }
  19. public int nextInt() {
  20. return Integer.parseInt(next());
  21. }
  22. }

 

拓扑排序模板

蓝桥杯 卡勒沃夫之弱水路三千(提高型) 拓扑排序+Map


 
 
  1. static ArrayList<Integer> list = new ArrayList<>();
  2. static ArrayList<Integer>[] edge = new ArrayList[ 105];
  3. while(m--> 0) { //建图 邻接表 并且用w[i]记录入度
  4. String s1 = in.next();
  5. String s2 = in.next();
  6. if(!map.containsKey(s1))
  7. map.put(s1,n++);
  8. if(!map.containsKey(s2))
  9. map.put(s2,n++);
  10. w[map.get(s2)]++;
  11. edge[map.get(s1)].add(map.get(s2));
  12. }
  13. for( int i:map.values()) //把边为0的放进队列
  14. if(w[i]== 0)
  15. q.add(i);
  16. while(!q.isEmpty()) {
  17. int u = q.poll();
  18. list.add(u);
  19. for( int v:edge[u]) {
  20. w[v]--;
  21. if(w[v]== 0)
  22. q.add(v);
  23. }
  24. }

dijkstra模板O(n^2)

 

 

dijkstra邻接表+优先队列模板O(nlogn)

 

 

 

 

 

 

 

 

/* * (有向)图的深度优先遍历算法模板 */ package dsa; public abstract class DFS extends GraphTraverse { //变量 protected static int clock = 0;//遍历过程中使用的计时钟 //构造方法 public DFS(Graph g) { super(g); } //深度优先遍历算法 protected Object traverse(Vertex v, Object info) {//从顶点v出发,做深度优先查找 if (UNDISCOVERED != v.getStatus()) return null;//跳过已访问过的顶点(针对非连通图) v.setDStamp(clock++); v.setStatus(DISCOVERED); visit(v, info);//访问当前顶点 for (Iterator it = v.outEdges(); it.hasNext();) {//检查与顶点v Edge e = (Edge)it.getNext();//通过边e = (v, u) Vertex u = (Vertex)e.getVPosInV(1).getElem();//相联的每一顶点u switch (u.getStatus()) {//根据u当前的不同状态,分别做相应处理 case UNDISCOVERED ://若u尚未被发现,则 e.setType(TREE);//e被归类为“树边” traverse(u, info);//从u出发,继续做深度优先查找 break; case DISCOVERED ://若u已经被发现,但对其访问尚未结束,则 e.setType(BACKWARD);//将e归类为“后向跨边” break; default ://VISITED,即对u的访问已经结束 if (u.getDStamp() < v.getDStamp())//若相对于v,u被发现得更早,则 e.setType(CROSS);//将e归类为“横跨边” else//否则 e.setType(FORWARD);//将e归类为“前向跨边” break; } }//至此,v的所有邻居都已访问结束,故 v.setFStamp(clock++); v.setStatus(VISITED);//将v标记为VISITED return null;//然后回溯 } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值