备战蓝桥杯

一、常用数据类型及其方法

队列

//两种初始化方法(ArrayDeque和LinkedList都是Deque的子类)
Queue<Integer> queue = new LinkedList<Integer>();
Queue<Integer> queue = new ArrayDeque<Integer>();

queue.offer(1); //元素入队
queue.poll(1);  //队头元素出队
queue.peek();   //返回队头元素,元素不出队

BigInteger类(数据范围理论上没有限制,只取决于电脑内存)

BigInteger a = new BigInteger("2"); 
BigInteger b = new BigInteger("3"); //初始化
a.add(b);
a.subtract(b); 
a.multiply(b);
a.devide(b);    // 加减乘除
a.compareTo(b); //比较大小,返回值是1、-1、0对应大于、小于、等于
a.remainder(b); //取余
a.abs();        //取绝对值
a.pow(3);       //取几次幂
a.toString();   //转为字符串

文件操作相关

// 改变System.out.println()的输出流,让它输出到一个文件里
PrintStream ps = new PrintStream(new FileOutputStream("D:\\work.txt"));
System.setOut(ps);

字符串转为整数:Integer.parseInt()、Integer.valueOf()
整数转字符串:Integer.toString()、String.valueOf()、"+"号(注意:3+5+"8"和3+""+5+"8"的区别)
字符串转为字符数组: String.toCharArray()
拆分字符串:String.split()
截取字符串:String.substring(int beginIndex, int endIndex)
比较字符串:String 中 == 比较引用地址是否相同,equals() 比较字符串的内容是否相同
判断字符串中是否存在某个字符或子串:String.indexOf()、String.lastIndexOf()、String.contains()
二维list: List<List<Integer>> ans = new ArrayList<List<Integer>>()
数组排序: Arrays.sort()(给静态数组排序)、Collections.sort()(给动态数组排序,如ArrayList、LinkedList、HashSet等)
Scanner.nextLine():用nextLine()读数据,注意要不要额外接收一个enter键
数组全体赋值: Arrays.fill()
进制转换:

Integer.toBinaryString(i) 十进制转二进制
Integer.toOctalString(i) 十进制转八进制
Integer.toHexString(i) 十进制转十六进制
Integer.toString(int i, int radix) 十进制i转为radix进制(radix默认值是10)
Integer.parseInt((String) s,(int) a) a进制的字符串s转为十进制

模运算法则:

加法:( a + b ) % p = ( a % p + b % p ) % p
减法:( a - b ) % p = ( a % p - b % p + p ) % p
乘法:( a * b ) % p = ( a % p * b % p ) % p
乘方:( a^b ) % p = ( ( a % p )^b ) % p

日期:

//Date类
Date date=new Date();
System.out.print("当前时间"+date);
System.out.print("年份"+(date.getYear()+1900));
System.out.print("月份"+(date.getMonth()+1));
System.out.print("日"+(date.getDate()));

正则:

①构造一个模式.
Pattern p=Pattern.compile("[a-z]*");
②建造一个匹配器
Matcher m = p.matcher(str);
③进行判断,得到结果
boolean b = m.matches();
boolean b = m.find();

//分割字符串
Pattern.split(String s)

StringBuffer、StringBuilder

StringBuffer是线程安全的,而StringBuilder不是线程安全的
因为在StringBuffer的方法上使用synchronized做了修饰。这样的方法一次只能一个人用。

HashSet、TreeSet

HashSet<String> sites = new HashSet<String>();
sites.add("Google");      //增加元素
sites.remove("Taobao");   //删除元素
sites.clear();            //删除集合中所有元素
sites.contains("Taobao"); //判断元素是否在集合当中
sites.size();             //计算HashSet中的元素数量

HashMap、TreeMap

HashMap<Integer, String> Sites = new HashMap<Integer, String>();
Sites.put(1, "Google");  // 添加键值对
Sites.remove(1);         // 删除key对应的键值对
Sites.clear();           // 删除所有键值对
Sites.size();            // 计算HashMap中的元素数量

//遍历哈希表
//第一种
for (Integer i : Sites.keySet()) {
    System.out.println("key: " + i + " value: " + Sites.get(i));
}
//第二种
for (Map.Entry<Integer, Integer> entry : sites.entrySet()) {
	System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

二、双指针

最长不含重复字符的子字符串

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。 
示例:输入: "abcabcbb"
           输出: 3

class Solution {
    public int lengthOfLongestSubstring(String s) {
        Set<Character> set = new HashSet<>(); //哈希表用于判断每个字符是否出现过
        int n = s.length();
        int ans = 0;
        int r = -1;  
        for(int i = 0; i < n; i++) {
            if(i != 0) {
                //左指针就是i,每次循环加1,并在set中删掉之前指着的元素
                set.remove(s.charAt(i-1)); 
            }
            //如果不包含重复字符,右指针就右移
            while(r + 1 < n && !set.contains(s.charAt(r+1))) {
                r++;
                set.add(s.charAt(r));
            }
            //左指针为i,最长无重复子串长度就是r-i+1
            ans = Math.max(ans, r-i+1); 
        }
        return ans;
    }
}

三、DFS

八皇后问题

在一个n×n的棋盘中,放入n个皇后,要求皇后之间不能互相攻击,输出所有的方案。
一个皇后,能攻击同一行,同一列,同一对角线的的所有格子。
输入格式
第一行输入一个整数n。
输出格式
输出若干行,每行输出n个整数,依次表示第1,2,…,n行的皇后的所在的列。
按字典序从小到大输出。

优化:结果先存起来,最后一起输出,比中间多次print要快很多 

import java.util.Scanner;

public class Main {
	static int n;
	static int[] col;
	static StringBuilder ans = new StringBuilder(); //记录答案
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		col = new int[n+1];
		dfs(1);
		System.out.println(ans);
		sc.close();
	}
	
	public static void dfs(int row) {
		if(row == n+1) {
			for(int i = 1; i <= n; i++) {
				ans.append(col[i]+" ");
			}
			ans.append("\n");
			return;
		}
		for(int i = 1; i <= n; i++) {
			int j;
			for(j = 1; j < row; j++) {
				if(i == col[j] || Math.abs(row-j) == Math.abs(col[j]-i)) {
					break;
				}
			}
			if(j == row) {
				col[row] = i;
				dfs(row+1);
			}
		}
	}
}

四、BFS

求细胞数量

一矩形阵列由数字 0 到 9 组成,数字 1 到 9 代表细胞,细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数。
输入格式
第一行两个整数代表矩阵大小 n 和 m。
接下来 n 行,每行一个长度为 m 的只含字符 0 到 9 的字符串,代表这个 n×m 的矩阵。
输出格式
一行一个整数代表细胞个数。 
输入
4 10
0234500067
1034560500
2045600671
0000000089
输出:4

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
	static int n, m;
	static char[][] map; // 存储地图数据
	static int[][] dirs = { { -1, 0 }, { 1, 0 }, { 0, 1 }, { 0, -1 } };
	static boolean[][] vis;
	static int ans = 0;

	private static class Point {
		int x, y;

		public Point(int x, int y) {
			this.x = x;
			this.y = y;
		}
	}

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		n = sc.nextInt();
		m = sc.nextInt();
		sc.nextLine();
		map = new char[n][m];
		vis = new boolean[n][m];
		for (int i = 0; i < n; i++) {
			map[i] = sc.nextLine().toCharArray();
		}
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				if (!vis[i][j] && map[i][j] != '0') {
					bfs(i, j); // 如果没被搜索过且是数字1-9,BFS
				}
			}
		}
		System.out.println(ans);
		sc.close();
	}

	private static void bfs(int x, int y) {
		ans++; // 新的细胞
		vis[x][y] = true;
		Queue<Point> queue = new LinkedList<>();
		queue.offer(new Point(x, y));
		while (!queue.isEmpty()) {
			Point head = queue.poll();
			for (int i = 0; i < 4; i++) {
				int nx = head.x + dirs[i][0];
				int ny = head.y + dirs[i][1];
				if (nx >= 0 && nx < n && ny >= 0 && ny < m && !vis[nx][ny] && map[nx][ny] > '0') {
					queue.offer(new Point(nx, ny));
					vis[nx][ny] = true;
				}
			}
		}
	}
}

五、动态规划

线性dp

最长上升子序列

给定一个长度为 nn 的数组 a1,a2,…,an,问其中的最长上升子序列的长度。也就是说,我们要找到最大的 m 以及数组 p1,p2,…,pm,满足 1≤p1<p2<⋯<pm≤n 并且 ap1<ap2<⋯<apm。
输入格式
第一行一个数字 n。
接下来一行 n 个整数 a1,a2,…,an。
输出格式
一个数,表示答案。

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int[] a = new int[n + 1];
		int[] dp = new int[n + 1]; // dp[i]表示以ai为"终点"的最长上升子序列的长度
		for (int i = 1; i <= n; i++) {
			a[i] = sc.nextInt();
			dp[i] = 1;
		}
		// i=1, dp[i] = 1
		// i>1,dp[i] = max{ dp[j]: 1 <= j < i 且 aj < ai} + 1
		// 如果aj(1<j<i)都大于ai,那么dp[i] = 1
		for (int i = 2; i <= n; i++) {
			for (int j = 1; j < i; j++) {
				if (a[i] > a[j]) {
					dp[i] = Math.max(dp[i], dp[j] + 1);
				}
			}
		}
		int max = 0;
		for (int i = 1; i <= n; i++) {
			max = Math.max(max, dp[i]);
		}
		System.out.println(max);
		sc.close();
	}
}

背包

01背包

有n种物品要放到一个袋子里,袋子的总容量为m,第i种物品的体积为vi,把它放进袋子里会获得wi的收益,每种物品至多能用一次,问如何选择物品,使得在物品的总体积不超过m的情况下,获得最大的收益?请求出最大收益。
输入格式
第一行两个整数n,m。
接下来n行,每行两个整数vi,wi。
输出格式
一个整数,表示答案

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		int[] v = new int[n + 1];
		int[] w = new int[n + 1];
		int[] dp = new int[m + 1]; // 用dp[i]表示容积还剩i,用最优法取得的价值总和
		for (int i = 1; i <= n; i++) {
			v[i] = sc.nextInt();
			w[i] = sc.nextInt();
		}
		for (int i = 1; i <= n; i++) {
			for (int j = m; j >= v[i]; j--) {
				dp[j] = Math.max(dp[j], dp[j - v[i]] + w[i]);
			}
		}
		System.out.print(dp[m]);
		sc.close();
	}
}

完全背包

有n种物品要放到一个袋子里,袋子的总容量为m,第i种物品的体积为vi,把它放进袋子里会获得wi的收益,每种物品能用无限多次,问如何选择物品,使得在物品的总体积不超过m的情况下,获得最大的收益?请求出最大收益。
输入格式
第一行两个整数n,m。
接下来n行,每行两个整数vi,wi。
输出格式
一个整数,表示答案。

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		int[] v = new int[n + 1];
		int[] w = new int[n + 1];
		int[] dp = new int[m + 1]; // 用dp[i]表示容积还剩 i,用最优法取得的价值总和
		for (int i = 1; i <= n; i++) {
			v[i] = sc.nextInt();
			w[i] = sc.nextInt();
		}
		for (int i = 1; i <= n; i++) {
			for (int j = v[i]; j <= m; j++) {
				dp[j] = Math.max(dp[j], dp[j - v[i]] + w[i]);
			}
		}
		System.out.print(dp[m]);
		sc.close();
	}
}

区间dp

石子合并

有 n 堆石子排成一排,第 i 堆石子有 ai 颗,每次我们可以选择相邻的两堆石子合并,代价是两堆石子数目的和,现在我们要一直合并这些石子,使得最后只剩下一堆石子,问总代价最少是多少?
输入格式
第一行一个数字n。
接下来一行n个整数a1,a2,…,an。
输出格式
一行一个整数,表示答案。

import java.util.Scanner;

public class Main {
	static int[] stones;

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		stones = new int[n + 1];
		int[][] dp = new int[n + 1][n + 1]; // dp[i][j]表示区间[ i,j]内的石子合并的最优解
		int[] prefix_sum = new int[n + 1]; // 用前缀和计算区间元素和
		for (int i = 1; i <= n; i++) {
			stones[i] = sc.nextInt();
			prefix_sum[i] = prefix_sum[i - 1] + stones[i];
		}
		// dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum(i,j));(i<=k<=j-1)
		// sum(i,j)表示区间[i,j]所有元素之和
		// namely,把i到j看成一堆,这一堆的最优解是由 由这堆分割的两小堆合并的
		// 枚举区间长度,从2开始,如果从1开始的话就只有一堆了不需要合并
		for (int interval = 2; interval <= n; interval++) {
			for (int i = 1; i + interval - 1 <= n; i++) {
				int j = i + interval - 1; // 右边界
				dp[i][j] = Integer.MAX_VALUE;
				for (int k = i; k < j; k++) {
					dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k + 1][j] + prefix_sum[j] - prefix_sum[i - 1]);
				}
			}
		}
		System.out.println(dp[1][n]);
		sc.close();
	}
}

六、图论

七、其它

全排列模板

public class Main {

	public static void main(String[] args) {
		int[] arr = { 1, 2, 3, 4 };
		all_permutation(arr, 0); // 全排列
	}

	public static void all_permutation(int[] arr, int index) {
		if (index == arr.length) {
			for (int i = 0; i < arr.length; i++) {
				System.out.print(arr[i] + " ");
			}
			System.out.println();
			return;
		}
		// index从0到arr.length-1,arr[index]的值用arr[index]到arr[arr.length-1]各试一遍
		for (int i = index; i < arr.length; i++) {
			swap(arr, index, i);
			all_permutation(arr, index + 1);
			swap(arr, index, i);
		}
	}

	private static void swap(int[] arr, int index, int i) {
		int temp = arr[index];
		arr[index] = arr[i];
		arr[i] = temp;
	}
}

最大公约数

import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int a, b;
		while (sc.hasNextInt()) {
			a = sc.nextInt();
			b = sc.nextInt();
			System.out.println(gcd(a, b));
		}
	}

	private static int gcd(int a, int b) {
		return b == 0 ? a : gcd(b, a % b);
	}
}

最小公倍数

public static int lcm(int a,int b) {
	int A = a, B = b;
	while(B!=0) {
		int temp = B;
		B = A%B;
		A = temp;
	}
	return a*b/A;
}

快速幂

给定正整数 n, 求 1^8 + 2^8 + ··· + n^8 mod 123456789 。

import java.util.Scanner;
 
public class Main {
	static int mod = 123456789;
	
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int n = s.nextInt();
		long ans = 0;
		for(long i = 1; i <= n; ++i) {
			ans = (ans+quickPow(i,8))%mod;  //long型的i防止计算时溢出
		}
		System.out.print(ans);
		s.close();
	}
	
	static long quickPow(long a, int b) {
		long ans = 1;
		while(b>0) {
			if((b&1) == 1) {
				ans = (ans*a)%mod;
			}
			a = (a*a)%mod;  //记录位权
			b >>= 1;
		}
		return ans;
	}
}

组合数

//求组合数
private static long C(long a, long b) {
    long res = 1;
    for (long i = a, j = 1; j <= b; i --, j ++ ) {
        res = res * i / j;
    }
    return res;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漂流の少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值