藍橋杯演算法模板常用套路及API等個人總結
寫這篇部落格的今天是19年的省賽考前的最後一天了,想寫一些小白萌新們受益的東西
從最常考的全排列開始吧~
全排列模板1,最常用的寫法
public class 全排列_模板1 {
public static void main(String[] args) {
dfs(0);
System.out.println(ans);//9的全排有362880種
}
static int[] a = new int[] {1,2,3,4,5,6,7,8,9};
static int n=9,ans=0;
static void dfs(int m) {
if(m>=n) {
System.out.println("一些核心的操作 比如ans:"+ans);
ans++;
for(int i=0;i<n;i++)
System.out.print(a[i]+" ");
System.out.println();
return;
}
for(int i=m;i<n;i++) {
swap(i,m);
dfs(m+1);
swap(i,m);//回溯
}
}
static void swap(int i,int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
全排列模板2,使用標記陣列的寫法
public class 全排列_模板2 {
public static void main(String[] args) {
vis = new boolean[n];
b = new int[n];
dfs(0);
System.out.println(ans);//9的全排有362880種
}
static int[] a = new int[] {1,2,3,4,5,6,7,8,9};
static int[] b;
static boolean[] vis;
static int n=9,ans=0;
static void dfs(int m) {
if(m>=n) {
System.out.println("一些核心的操作 比如ans:"+ans);
ans++;
for(int i=0;i<n;i++)
System.out.print(b[i]+" ");
System.out.println();
return;
}
for(int i=0;i<n;i++)
if(!vis[i]) {
vis[i] = true;
b[m] = a[i];
dfs(m+1);
b[m] = 0;//其實這個也可以不用回溯,它會被覆蓋
vis[i] = false;//回溯
}
}
}
下面是需要排重的全排_模板
在上面模板上使用了雜湊表查重,把一些陣列並接成字串
import java.util.HashSet;
public class 全排列_模板3 {
public static void main(String[] args) {
dfs(0);
System.out.println(ans);//9的全排有362880種
System.out.println(set.size());//1680
}
static int[] a = new int[] {1,1,1,2,2,2,3,3,3};
static int n=9,ans=0;
static HashSet<String> set = new HashSet<>();
static void dfs(int m) {
if(m>=n) {
System.out.println("一些核心的操作 比如ans:"+ans);
ans++;
String s="";
for(int i=0;i<n;i++) {
s+=a[i];
System.out.print(a[i]+" ");
}
System.out.println();
set.add(s);
return;
}
for(int i=m;i<n;i++) {
swap(i,m);
dfs(m+1);
swap(i,m);//回溯
}
}
static void swap(int i,int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
使用雜湊表查重後是無序的,那麼遇到需要列印字典序的有重複元素的全排呢
子集的寫法也和全排很相似
leetcode 78. 子集(Subsets) beat 100%
leetcode 90. 子集 II(Subsets II) beat 98.57%
判斷閏年
static boolean is(int x) {
return x%400==0 || (x%4==0 && x%100!=0);
}
篩素數O()
static boolean is(int n) {
if(n==1)
return false;
for(int i=2;i*i<=Math.sqrt(n);i++)
if(n%i==0)
return false;
return true;
}
倍篩法_素數O(nlogn)
public class 倍篩模板 {
public static void main(String[] args) {
boolean[] is = new boolean[1000005];
is[1] = true;//true表示不是素數
for(int i=2;i<1000005;i++)
if(!is[2])
for(int j=2*i;j<1000005;j+=i)
is[j] = true;
System.out.println(is[2004]);
}
}
01揹包
public class _01揹包 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int m = in.nextInt();//大小
int n = in.nextInt();//物品數
int[] dp = new int[m+5];//開揹包質量的大小
for(int i=1;i<=n;i++) {
int v = in.nextInt();//物品體積
int w = in.nextInt();//物品價值
for(int j=m;j>=v;j--)
dp[j] = Math.max(dp[j], dp[j-v]+w);
}
System.out.println(dp[m]);
}
}
完全揹包
import java.util.Scanner;
public class _完全揹包 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int m = in.nextInt();//大小
int n = in.nextInt();//物品數
int[] dp = new int[m+5];//開揹包質量的大小
for(int i=1;i<=n;i++) {
int v = in.nextInt();//物品體積
int w = in.nextInt();//物品價值
for(int j=v;j<=m;j++)
dp[j] = Math.max(dp[j], dp[j-v]+w);
}
System.out.println(dp[m]);
}
}
最小公倍數gcd
static int gcd(int a,int b) {
return b==0?a:gcd(b,a%b);
}
最大公約數lcm
static int lcm(int a,int b) {
return a*b/gcd(a,b);
}
多個數共同的gcd和lcm模板
static int gcd(int[] a) {
int n = a.length;
int g = a[0];
for(int i=1;i<n;i++)
g = gcd(g,a[i]);
return g;
}
static int lcm(int[] a) {
int n = a.length;
int l = a[0];
for(int i=1;i<n;i++)
l = lcm(l,a[i]);
return l;
}
二分答案_模板
藍橋杯 2017年第八屆真題 分巧克力 經典的二分答案 輸入掛
static void f(int[] a) {
int n = a.length;
int l=0,r=n-1,ans=0;//一般上界需要自己構造
while(l<=r) {
int mid = l + (r-l)/2;
if(ok(a[mid])) {
r = mid-1;
ans = mid;
}else
l = mid+1;
}
System.out.println(ans);
}
static boolean ok(int x) {
return false;//按照題意寫
}
二分lower_bound的實現(找到第一個大於等於給定值key的那個數)如[1,2,2,3]查詢2,會返回第一個2的下標
public static int lowerBound(int []nums,int l,int r,int target){
while(l<=r){//r=n-1
int m = (l+r)/2;
if(nums[m]>=target) r= m-1;
else l = m +1;
}
return l;
}
upper_bound的實現(要求在按照非遞減順序排好序的陣列中找到第一個大於給定值key的那個數)(不常用)
public static int upperBound(int []nums ,int l,int r, int target){
while(l<r){//其中 r = nums.length
int m = (l+r)/2;
if(nums[m]<=target) l = m+1;
else r = m;
}
return l;
}
各種排序實現
- 氣泡排序(學會手寫)
- 選擇排序(沒什麼應用)
- 插入排序(對近乎有序的陣列複雜度提升到O(n))
- 計數排序(給定區間排序)
- 歸併排序(求逆序數)
- 快速排序(找第K大數)
- 堆排序(優先佇列API)
- 希爾排序(插入排序的升級版)
大數類BigInteger和BigDecimal及方法API
考場上查API
進位制問題,如有價值1,2,4,8等價值的硬幣,如何用最小的硬幣數湊出100元
static int f(int n,int k) {//呼叫API轉成k進位制,缺點題目有上界為8
int ans=0;
String s = Integer.toString(n, k);
System.out.println(s);
for(int i=0;i<s.length();i++)
ans+=s.charAt(i)-'0';
return ans;
}
頭條面試題:找錢問題,共1024,64,16,4,1幾種面值
static void solve(){
Scanner cin = new Scanner(System.in);
int N = 1024-cin.nextInt(), ans = 0;
for(int i=0; i<4; i++){
ans += N/arr[i];
N %= arr[i];
}
System.out.println(ans);
}
!
堆的應用,給定一個只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字串,判斷字串是否有效
leetcode 20. 有效的括號(Valid Parentheses)
public boolean isValid(String s) {
if(s==null||s.equals(""))
return true;
char[] ch = s.toCharArray();
Stack<Character> stack = new Stack<>();
for(int i=0;i<ch.length;i++)
{
if(ch[i]=='(' || ch[i]=='[' || ch[i]=='{')
stack.push(ch[i]);
else if(ch[i]==')' || ch[i]==']' || ch[i]=='}')
{
if(!stack.isEmpty())
{
char p = stack.pop();
if(p=='(' && ch[i]==')')
continue;
if(p=='[' && ch[i]==']')
continue;
if(p=='{' && ch[i]=='}')
continue;
}
return false;
}
}
return stack.empty();
}
快速冪及矩陣快速冪模板
static long mpow(long a,long n) {//快速冪,mod一般題目給1e9+7
if(n==0 || a==1)
return 1;
long ans=1;
while(n!=0) {
if(n%2==1)
ans = a*ans%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
矩陣乘法模板
//這裡是矩陣的乘法模板,預設方陣
static int[][] mul(int[][] a,int[][] b){
int n = a.length;
int[][] ans = new int[n][n];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
ans[i][j] =(ans[i][j] + a[i][k]*b[k][j])%MOD;//ans[i][j] += a[i][k]*a[k][j];
return ans;
}
矩陣快速冪模板
//矩陣快速冪_模板
static int[][] mpow(int[][] a,int n){
int N = a.length;
int[][] ans = new int[N][N];
for(int i=0;i<N;i++)
ans[i][i] = 1;//初始化為單位矩陣W
while(n>0) {//寫 n!=0也行,會快些麼,反正位運算是會快的.這個不清楚
if((n&1)==1)
ans = mul(ans,a);
a = mul(a,a);
n>>=1;
}
return ans;
}
階乘逆元求組合數C(n,m)模板_O(nlogn)
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
f = new long[n+5];
inv = new long[n+5];
f[0]=1;
for(int i=1;i<n+5;i++) {
f[i]=f[i-1]*i%mod;
inv[i] = mpow(f[i],mod-2);
}
}
static int n;
static long mod = 1000000009;
static long[] f;
static long[] inv;
static long C(int n,int m) {
return f[n]*inv[m]%mod*inv[n-m]%mod;
}
static long mpow(long a,long n) {//快速冪
if(n==0 || a==1)
return 1;
long ans=1;
while(n!=0) {
if(n%2==1)
ans = a*ans%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
尤拉函式模板 定義:小於n的正整數中與n互質的數的數目(φ(1)=1)
static int Euler(int n) {//O(n) 有時候需要long
int ans=n;
for(int i=2;i<=n;i++)
if(n%i==0) {
ans=ans/i*(i-1);
while(n%i==0)
n/=i;
}
return ans;
}
static int Euler(int n) {//O(sqrt(n))
int ans=n;
for(int i=2;i*i<=n;i++)
if(n%i==0) {
ans=ans/i*(i-1);////n*(1-(1/p))轉化為n/p*(p-1)
while(n%i==0)
n/=i;
}
if(n>1)//優化 O(sqrt(n)) 不過要在出口 if(n>1)ans/n*(n-1) O(n)不用
ans=ans/n*(n-1);
return ans;
}
字首和模板
import java.util.Scanner;
public class 字首和模板 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] sum = new int[n+1];
for(int i=1;i<=n;i++)
sum[i] = sum[i-1] + in.nextInt();//前i個數的和
}
}
線段樹模板
並查集模板
static int n,m,cnt=0;
static int[] f = new int[10005];//初始化一般是f[i]=i
static int find(int x) {
if(f[x]==x)
return x;
return f[x] = find(f[x]);
}
static void union(int x,int y) {
int a = find(x);
int b = find(y);
if(a!=b) {
f[a] = b;
cnt++;
}
}
dfs求聯通塊模板
static int n,m;
static int[][] vis;
static char[][] ch;
static int[] dx = new int[] {1,1,1,0,0,-1,-1,-1};
static int[] dy = new int[] {0,-1,1,1,-1,1,0,-1};
static void dfs(int t,int x,int y) {// hdu1241 油田問題 八聯通
vis[x][y] = t;
for(int i=0;i<8;i++)
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)
dfs(t,x+dx[i],y+dy[i]);
}
int t=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(ch[i][j]=='@' && vis[i][j]==0)
dfs(++t,i,j);
System.out.println(t);
最小生成樹模板
static int n,m,cnt=0,ans=0;
static int[] f;
static int find(int x) {
if(f[x]==x)
return x;
return f[x] = find(f[x]);
}
static int union(int x,int y) {
int a = find(x);
int b = find(y);
if(a!=b) {
f[a] = b;
return 1;
}
return 0;
}
static class Edge implements Comparable<Edge>{
int a,b,c;
public Edge(int a,int b,int c) {
this.a = a;
this.b = b;
this.c = c;
}
@Override
public int compareTo(Edge o) {
return this.c - o.c;
}
}
public static void main(String[] args) {
InputReader in = new InputReader(System.in); //用它來代替Scanner。
while(true) {
n = in.nextInt();
if(n==0)
break;
m = n*(n-1)/2;
cnt=0;
ans=0;
f = new int[n+5];
for(int i=1;i<=n;i++)
f[i] = i;
PriorityQueue<Edge> pq = new PriorityQueue<>();
for(int i=1;i<=m;i++) {
int a = in.nextInt();
int b = in.nextInt();
int c = in.nextInt();
int d = in.nextInt();
if(d==1)
cnt+=union(a,b);
else
pq.add(new Edge(a, b, c));
}
while(!pq.isEmpty()) {
Edge u = pq.poll();
if(union(u.a, u.b)==1) {
cnt++;
ans+=u.c;
if(cnt==n-1)
break;
}
}
System.out.println(ans);
}
}
輸入掛模板
//解決javaIO讀取過慢的方法,利用該類讀取輸入資料,不要用Scanner!!!
static class InputReader {
public BufferedReader reader;
public StringTokenizer tokenizer;
public InputReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
}
拓撲排序模板
static ArrayList<Integer> list = new ArrayList<>();
static ArrayList<Integer>[] edge = new ArrayList[105];
while(m-->0) {//建圖 鄰接表 並且用w[i]記錄入度
String s1 = in.next();
String s2 = in.next();
if(!map.containsKey(s1))
map.put(s1,n++);
if(!map.containsKey(s2))
map.put(s2,n++);
w[map.get(s2)]++;
edge[map.get(s1)].add(map.get(s2));
}
for(int i:map.values())//把邊為0的放進佇列
if(w[i]==0)
q.add(i);
while(!q.isEmpty()) {
int u = q.poll();
list.add(u);
for(int v:edge[u]) {
w[v]--;
if(w[v]==0)
q.add(v);
}
}
dijkstra模板O(n^2)
dijkstra鄰接表+優先佇列模板O(nlogn)
相關文章
- 藍橋杯模板(三)python組Python
- 藍橋杯模板(二)python組Python
- 藍橋杯知識點彙總:基礎知識和常用演算法演算法
- 藍橋杯—演算法訓練演算法
- 藍橋杯--演算法訓練演算法
- 藍橋杯 排序排序
- 藍橋杯演算法提高——字串匹配(Java)演算法字串匹配Java
- 藍橋杯 演算法提高 字串壓縮演算法字串
- 藍橋杯-N皇后
- 藍橋杯真題
- (Day6)演算法復健運動for藍橋杯-常用數學演算法
- 藍橋杯大賽微控制器組國信長天開發板個人總結 | 建立工程
- [藍橋杯][演算法提高VIP]尤拉函式演算法函式
- [藍橋杯][演算法提高VIP]超級瑪麗演算法
- [藍橋杯][演算法提高VIP]大數加法演算法
- 藍橋杯 (java)演算法訓練 數對Java演算法
- 演算法訓練 字首表示式 (藍橋杯)演算法
- 第十五屆藍橋杯C++B組省賽總結C++
- 藍橋杯年號字串字串
- 藍橋杯-帶分數
- 藍橋杯-翻硬幣
- 藍橋杯-螞蟻感冒
- 藍橋杯 計算方程
- 藍橋杯-座次問題
- 藍橋杯-長草(BFS)
- 藍橋杯-日期問題
- 藍橋杯-班級活動
- 藍橋杯歷年(省賽)試題彙總及試題詳解
- [藍橋杯][演算法提高VIP]奪寶奇兵 dp演算法
- [藍橋杯][演算法訓練VIP]方格取數演算法
- Java | 個人總結的Java常用API手冊彙總JavaAPI
- 藍橋杯練習試題程式碼及講解
- 藍橋杯——查詢的妙趣
- 密碼脫落——藍橋杯密碼
- 藍橋杯-串的處理
- 藍橋杯-回形巢狀巢狀
- 藍橋杯-分巧克力
- 藍橋杯-k倍區間