输入输出
- 输入:
需要导入包:import java.util.Scanner;之后Scanner cin = new Scanner(System.in);
之后可以用cin对象配合.nextXXXX()方法接受数据了:XXX可以为Int、Float、Double、空(String类型,遇到空格结束)、Line(Sting类型,读取一行)
最后cin.close();
- 输出:
System.out.printf("%m.nd",a);
暴力枚举
数学
- 进制转换:
1.十进制转其他进制:Integer.toString(k,r) ,将十进制的数k转换为r进制的数。返回一个String。
System.out.println(Integer.toBinaryString(k)); //转二进制
System.out.println(Integer.toOctalString(k)); //转八进制
System.out.println(Integer.toHexString(k)); //转十六进制
System.out.println(Integer.toString(k,r)); //转r进制
System.out.println(Integer.toString(k,r)); //转r进制
System.out.println(Integer.toString(k,r)); //转r进制
2.其他进制转十进制:Integer.parseInt(str,r) ,将r进制的数字字符串str转换为十进制,并返回十进制的数。
System.out.println(Integer.parseInt("10001",2));
System.out.println(Integer.parseInt("21",8));
System.out.println(Integer.parseInt("11",16));
- 质数筛法:输入一个整数 n,求小于这个整数的所有质数。
定义一个长度为 n 的 boolean 数组,true 表示是质数,false 表示不是质数。初始均为 true。
代码:
public static boolean isPrime(int n){
int [] arr = new int[n+1];
// 1:质数 0:非质数
Arrays.fill(arr,1);
for(int i = 2; i <= n; i++){
if(arr[i] == 1){
// 将i的倍数去除掉
for(int j = i+i; j <= n; j += i){
arr[j] = 0;
}
}
}
return arr[n] == 1 ? true : false;
}
排序算法
- 快速排序
基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
代码:
public static void quickSort(int[] arr, int left, int right) {
int l = left, r = right;
int pivot = arr[(l + r) / 2];
while(l < r) {
while(arr[l] < pivot) {
l++;
}
while(arr[r] > pivot) {
r--;
}
if(r == l) {
break;
}
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
if(arr[l] == pivot) {
r -= 1;
}
if(arr[r] == pivot) {
l += 1;
}
}
if(left < right) {
quickSort(arr, left, l - 1);
quickSort(arr, r + 1, right);
}
}
- 归并排序
先将待排序的数组不断拆分,直到拆分到区间里只剩下一个元素的时候。不能再拆分的时候。这个时候我们再想办法合并两个有序的数组,得到长度更长的有序数组。当前合并好的有序数组为下一轮得到更长的有序数组做好了准备。一层一层的合并回去,直到整个数组有序。
代码:
public static void mergeSort(int[] arr, int left, int right, int[] temp) { //总方法
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid, temp);
mergeSort(arr, mid + 1, right, temp);
merge(arr, left, mid, right, temp);
}
}
public static void merge(int[] arr,int left,int mid,int right,int[] temp){ //合并算法
int i = left;
int j = mid+1;
int t = 0;
while (i<=mid && j<=right){
if(arr[i]<=arr[j]){
temp[t] = arr[i];
t += 1;
i += 1;
}else {
temp[t] = arr[j];
t += 1;
j += 1;
}
}
while(i<=mid){//将左边剩余元素填充进temp中
temp[t] = arr[i];
t += 1;
i += 1;
}
while(j<=right){//将右序列剩余元素填充进temp中
temp[t] = arr[j];
t += 1;
j += 1;
}
t = 0;
int tempLeft = left;
while(tempLeft <= right){
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
- 插入排序
基本思想是:把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表中只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。
代码:
- 堆排序:
思想:将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值。如此反复执行,便能得到一个有序序列了。
代码;
public class HeapSort {
public static void main(String[] args) {
int arr[] = {4, 6, 8, 5, 9};
heapSort(arr);
}
public static void heapSort(int arr[]) {
int temp = 0;
for (int i = arr.length / 2 - 1; i >= 0; i--) {
adjustHeap(arr, i, arr.length);
}
for (int j = arr.length - 1; j > 0; j--) {
temp = arr[j];
arr[j] = arr[0];
arr[0] = temp;
adjustHeap(arr, 0, j);
}
}
* @param arr 待调整的数组
* @param i 表示非叶子结点在数组中索引
* @param length 表示对多少个元素继续调整,length 是在逐渐的减少
public static void adjustHeap(int arr[], int i, int length) {
int temp = arr[i];//先取出当前元素的值,保存在临时变量
for (int k = i * 2 + 1; k < length; k = k * 2 + 1) {
if (k + 1 < length && arr[k] < arr[k + 1]) {
k++;
}
if (arr[k] > arr[i]) {
arr[i] = arr[k];
i = k;
} else {
break;
}
}
arr[i] = temp;
}
}
递归
- DFS
基本思想:
1.访问初始结点v,并标记结点v为已访问。
2.查找结点v的第一个邻接结点w。
3.若w存在,则继续执行4,如果w不存在,则回到第1步,将从v的下一个结点继续。
4.若w未被访问,对w进行深度优先遍历递归(即把w当做另一个v,然后进行步骤123)。
5.查找结点v的w邻接结点的下一个邻接结点,转到步骤3。
public class Main {
private List<String> vertexList;//用于存储顶点的集合
private int[][] edges;//用来保存图对应的邻接矩阵
private int edgeOfNums;//显示边的个数
private boolean[] isVisited;
//===========深度优先遍历的方法===========
public int getNextNeighbor(int v1,int v2) {
for (int i = v2 +1;i < vertexList.size();i++) {
if (edges[v1][i] == 1) {
return i;
}
}
return -1;
}
//3.深度优先算法DFS
private void DFS(boolean[] isVisited,int i) {
System.out.print(getVertexByIndex(i)); //访问
isVisited[i] = true;
int w = getNextNeighbor(i, i);
while (w != -1) {
if (!isVisited[w]) {
DFS(isVisited,w);
}
w = getNextNeighbor(i,w);
}
}
public void DFS() {
isVisited = new boolean[vertexList.size()];
for (int i = 0; i < getVertexNum(); i++) {
if (!isVisited[i]) {
DFS(isVisited,i);
}
}
}
- BFS
基本思想:
1.访问初始结点v并标记结点v为已访问。
2.结点v入队列
3.当队列非空时,继续执行,否则算法结束。
4.出队列,取得队头结点u。
5.查找结点u的第一个邻接结点w。
6.若结点u的邻接结点w不存在,则转到步骤3;否则循环执行以下三个步骤:
6.1 若结点w尚未被访问,则访问结点w并标记为已访问。
6.2 结点w入队列
6.3 查找结点u的继w邻接结点后的下一个邻接结点w,转到步骤6。
private void BFS(boolean[] isVisited,int i) {
int u;//表示队列的头结点对应的下标
int w;//表示邻接结点的下标
LinkedList queue = new LinkedList();
System.out.print(i); //访问
isVisited[i] = true;
queue.addLast(i);
while (!queue.isEmpty()) {
u = (Integer)queue.removeFirst();
w = getNextNeighbor(u);
while (w != -1) {//说明w(邻接结点存在)
if (!isVisited[w]) {
System.out.print(i); //访问
isVisited[w] = true;
queue.addLast(w);
}
w = getNextNeighbor(u,w);
}
}
}
public void BFS() {
isVisited = new boolean[vertexList.size()];
for (int i = 0; i < getVertexNum(); i++) {
if (!isVisited[i]) {
BFS(isVisited,i);
}
}
}
数据结构
- 并查集:
//并查集(路径压缩)
//par数组用来存储根节点,par[x]=y表示x的根节点为y
static int[] par = new int[10005];
//初始化
public static void init(int n){
for (int i = 1; i <= n; i++) {
par[i]=i;
}
}
//查找x所在集合的根
public static int find(int x){
if(par[x]!=x) par[x]=find(par[x]); //递归返回的同时压缩路径
return par[x];
}
//合并x与y所在集合
public static void unite(int x,int y){
int tx = find(x);
int ty = find(y);
if(tx!=ty){ //不是同一个根,即不在同一个集合,就合并
par[tx]=ty;
}
}
- 线段树:
public static int[] a = new int[maxd]; //原数组
public static int[] tree = new int[maxd*4]; //树存储
//初始化建树
public static void build(int p,int l,int r){
if(l==r){
tree[p]=a[l];
return ;
}
int mid = (r+l)/2; // 防止爆范围
build(p*2,l,mid); //左子树
build(p*2+1,mid+1,r); //右子树
tree[p]=tree[p*2]+tree[p*2+1];
}
//将x位置的值加上num
public static void update(int p,int l,int r,int x,int num){
if(x>r||x<l) return ;
if(l==r&&l==x){ //找到x位置
tree[p] += num; //灵活变
return ;
}
int mid = (r+l)/2;
update(p*2,l,mid,x,num);
update(p*2+1,mid+1,r,x,num);
tree[p]=tree[p*2]+tree[p*2+1];
}
//查询区间和
public static int query(int p,int l, int r ,int x, int y){
if(x<=l&&r<=y) return tree[p];
if(x>r||y<l) return 0;
int mid = (r+l)/2;
int sum = 0;
sum+=query(p*2,l,mid,x,y);
sum+=query(p*2+1,mid+1,r,x,y);
return sum;
}
动态规划
- 背包问题:
public static int[] dp = new int[maxd]; //最大价值
public static int[] w = new int[maxd]; //每件物品的体积
public static int[] v = new int[maxd]; //每件物品的价值
public static int g = 1
1)01背包问题:
int n = nextInt(); //n件物品
int m = nextInt(); //给出的体积
for(int i=1;i<=n;++i) {
w[i] = nextInt();
v[i] = nextInt();
}
for(int i=1;i<=n;++i){
for(int j=m;j>=w[i];--j){ //与完全背包的区别
dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]);
}
}
- 完全背包:
for(int i=1;i<=n;++i){
for(int j=w[i];j<=m;++j){ //与01背包的区别
dp[j]=Math.max(dp[j],dp[j-w[i]]+v[i]);
}
}
- 多重背包:
//朴素算法
for(int i=1;i<=n;++i){
for(int j=m;j>=w[i];--j){
for (int k = 0; k <= s[i] && k * w[i] <= j; k++) {
dp[j] = Math.max(dp[j], dp[j - k*w[i]] + k*v[i]);
}
}
}
//二进制优化
int n = nextInt();
int m = nextInt();
for(int i=1;i<=n;++i){
int a = nextInt(); //体积
int b = nextInt(); //价值
int c = nextInt(); //数量
for(int j=1;j<=c;j<<=1){
w[g]=j*a;
v[g++]=j*b;
c-=j;
}
if(c>0){
w[g]=c*a;
v[g++]=c*b;
}
}
for(int i=1;i<=g;++i){
for(int j=m;j>=w[i];--j){
dp[j]=Math.max(dp[j],dp[j-w[i]]+v[i]);
}
}
其他
- 二分查找:
代码:
public static int commonBinarySearch(int[] arr,int key){
int low = 0;
int high = arr.length - 1;
int middle = 0; //定义middle
if(key < arr[low] || key > arr[high] || low > high){
return -1;
}
while(low <= high){
middle = (low + high) / 2;
if(arr[middle] > key){
//比关键字大则关键字在左区域
high = middle - 1;
}else if(arr[middle] < key){
//比关键字小则关键字在右区域
low = middle + 1;
}else{
return middle;
}
}
return -1; //最后仍然没有找到,则返回-1
}
- 哈希表:
// 创建 HashMap 对象 Sites
HashMap<Integer, String> Sites = new HashMap<Integer, String>();
// 添加键值对
Sites.put(1, "Google");
HasgMap常用方法:
- boolean remove() 方法用于删除hashMap 中指定键 key 对应的键值对(key-value)
2.put() 方法将指定的键/值对插入到 HashMap 中。如果插入的 key 对应的 value 已经存在,则执行 value 替换操作,返回旧的 value 值,如果不存在则执行插入,返回 null
3.get() 方法获取指定 key 对应对 value,返回与指定 key 所关联的 value。
贪心
图论
- 最短路径:
Floyd算法:
public class FloydAlgorithm {
public static void main(String[] args) {
// 测试看看图是否创建成功
char[] vertex = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };
//创建邻接矩阵
int[][] matrix = new int[vertex.length][vertex.length];
final int N = 65535;
matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };
//创建 Graph 对象
Graph graph = new Graph(vertex.length, matrix, vertex);
//调用弗洛伊德算法
graph.floyd();
}
}
// 创建图
class Graph {
private char[] vertex; // 存放顶点的数组
private int[][] dis; // 保存,从各个顶点出发到其它顶点的距离,最后的结果,也是保留在该数组
private int[][] pre;// 保存到达目标顶点的前驱顶点
// 构造器
/**
*
* @param length
* 大小
* @param matrix
* 邻接矩阵
* @param vertex
* 顶点数组
*/
public Graph(int length, int[][] matrix, char[] vertex) {
this.vertex = vertex;
this.dis = matrix;
this.pre = new int[length][length];
// 对pre数组初始化, 注意存放的是前驱顶点的下标
for (int i = 0; i < length; i++) {
Arrays.fill(pre[i], i);
}
}
//弗洛伊德算法, 比较容易理解,而且容易实现
public void floyd() {
int len = 0; //变量保存距离
//对中间顶点遍历, k 就是中间顶点的下标 [A, B, C, D, E, F, G]
for(int k = 0; k < dis.length; k++) { //
//从i顶点开始出发 [A, B, C, D, E, F, G]
for(int i = 0; i < dis.length; i++) {
//到达j顶点 // [A, B, C, D, E, F, G]
for(int j = 0; j < dis.length; j++) {
len = dis[i][k] + dis[k][j];// => 求出从i 顶点出发,经过 k中间顶点,到达 j 顶点距离
if(len < dis[i][j]) {//如果len小于 dis[i][j]
dis[i][j] = len;//更新距离
pre[i][j] = pre[k][j];//更新前驱顶点
}
}
}
}
}
}
- 最小生成树:
Prim算法基本思想:
代码:
public void prim(MGraph graph, int v) { //从v开始访问
//visited[] 标记结点(顶点)是否被访问过
int visited[] = new int[graph.verxs];
//把当前这个结点标记为已访问
visited[v] = 1;
int min_weight - 0;
//h1 和 h2 记录两个顶点的下标
int h1 = -1;
int h2 = -1;
int minWeight = 10000;
for(int k = 1; k < graph.verxs; k++) {//找到n-1条边
//这个是确定每一次生成的子图 ,和哪个结点的距离最近
for(int i = 0; i < graph.verxs; i++) {// i结点表示被访问过的结点
for(int j = 0; j< graph.verxs;j++) {//j结点表示还没有访问过的结点
if(visited[i] == 1 && visited[j] == 0 && graph.weight[i][j] < minWeight)
minWeight = graph.weight[i][j];
h1 = i;
h2 = j;
}
}
}
//找到一条边是最小h1->h2
min_weight += minWeight;
//将当前这个结点标记为已经访问
visited[h2] = 1;
//minWeight 重新设置为最大值 10000
minWeight = 10000;
}
}
String常用方法
- String substring(int beginIndex, int endIndex):返回字符串的子字符串(begin,end];
- String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分字符串。 . 、 $、 | 和 * 等转义字符,必须得加 \\,多个分隔符,可以用 | 作为连字符
Math常用方法
- int max(int a, int b):返回最大值
- round() 方法返回一个最接近的 int、long 型值,四舍五入。
- double pow(double base, double exponent):返回第一个参数的第二个参数次方
StringBuilder
1.String substring(int start, int end):返回一个新的 String,它包含此序列当前所包含的字符子序列。
Arrays常用方法
- public static void sort(Object[] a):对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。
- public static void fill(int[] a, int val):将指定的 int 值分配给指定 int 型数组指定范围中的每个元素
StringBuilder
- StringBuilder append(Object o) //将指定 Object类型加入这个序列。
- StringBuilder reverse() //导致该字符序列被序列的相反代替。
- String toString() //返回表示此顺序中的数据的字符串
- int length() //返回长度(字符数)。实际大小。
- StringBuilder deleteCharAt(int index) //删除 char在这个序列中的指定位置。
常用数据容器
- ArrayList:(链表)
- 创建:List<Integer> list = new ArrayList<Integer>();
- Boolean add(E e):将指定的元素追加到此列表的末尾(可选操作)
- E get(int index):返回此列表中指定位置的元素。
- int size()返回此列表中的元素数。
- boolean contains(Object o)如果此列表包含指定的元素,则返回 true
- get() 方法通过索引值获取动态数组中的元素。
- Stack:(栈)
- 创建:Stack<Integer> s = new Stack<Integer>();
- E peek()查看栈顶元素。
- E pop()删除栈顶元素,并将该元素作为返回值返回。
- E push(E item)添加元素到堆栈的顶部
- LinkedList(队列):
- LinkedList<String> sites = new LinkedList<String>();创建
- public void addLast(E e) 元素添加到尾部。
- public E getFirst() 返回第一个元素。
- public E removeFirst() 删除并返回第一个元素。
- boolean isEmpty()
日期
(1)Calendar
1. Calendar c = Calendar.getInstance();//默认是当前日期,创建一个代表系统当前日期的Calendar对象
2. public final void set(int year,int month,int date)
3.Calendar.YEAR 年份
Calendar.MONTH 月份
Calendar.DATE 日期
字符串与数字转换
(1)通过包装类的 parseXXX() 方法,可以将字符串转换为想要的基本数据类型:int a = Integer.parseInt(str);
int b = Double.parseDouble(str);
(2) String的 valueOf() 方法:String str1 = String.valueOf(a1);
String str2 = String.valueOf(a2);
二叉树的遍历
- 前序遍历:
public List<Integer> preorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<TreeNode>();
List<Integer> res = new ArrayList<Integer>();
while(root != null || !stack.empty()){
while(root != null){
res.add(root.val);
stack.push(root);
root = root.left;
}
if(!stack.Empty()){
root = stack.pop();
root = root.right;
}
//中序遍历
while(root != null){
res.add(root.val);
stack.push(root);
root = root.left;
}
if(!stack.empty()){
root = stack.pop();
root = root.right;
}
}
return res;
}
- 后序遍历:
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
Deque<TreeNode> stack = new LinkedList<TreeNode>();
TreeNode prev = null;
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (root.right == null || root.right == prev) {
res.add(root.val);
prev = root;
root = null;
} else {
stack.push(root);
root = root.right;
}
}
return res;
}