一、链表
1.1 单链表
package 链表;
public class 单链表 {
static int e[] = new int[11010]; // index号节点的value值(value)
static int ne[] = new int[11010];// index号节点的下一个节点的index(nextNode)
static int head=-1,idx=0; // 头节点的index,当前可用的最小index
public static void main(String[] args) {
// TODO Auto-generated method stub
// 遍历单链表
for(int i=head;i!=-1;i = ne[i]) {
System.out.print(e[i]);
}
}
// 插入——链头
static void add_to_head(int x) {
e[idx] = x; ne[idx] = head; head = idx; idx++;
}
// 插入——第k个节点之后
static void add_afterK(int k,int x) {
e[idx] = x; ne[idx] = ne[k]; ne[k] = idx; idx++;
}
// 删除——第k个节点之后节点
static void remove(int k,int x) {
ne[k] = ne[ne[k]];
}
}
例题: B3631 单向链表 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
import java.util.*;
public class Main {
static int e[] = new int[11011];
static int en[] = new int[11011];
static int head = 0,idx = 1;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
e[0] = 1; en[0] = -1;
int q = in.nextInt();
while(q--!=0) {
int o = in.nextInt();
if(o==1) {
int x = in.nextInt();
int y = in.nextInt();
add(x,y);
}else if(o==2) {
int x = in.nextInt();
int index = find_index(x);
if(en[index]==-1) {
System.out.print("0\n");
}else {
System.out.print(e[en[index]]+"\n");
}
}else {
int x = in.nextInt();
remove(x);
}
}
}
static void add(int x,int y) {
x = find_index(x);
e[idx] = y;
en[idx] = en[x];
en[x] = idx;
idx++;
}
static void remove(int x) {
x = find_index(x);
en[x] = en[en[x]];
}
static int find_index(int x) {
for(int i=head;i!=-1;i = en[i])
if(e[i]==x)
return i;
return -1;
}
}
这个代码会有三个数据超时,应该改成快读就行了。
1.12双向链表
package 链表;
public class 双链表 {
static int e[] = new int[11010]; // index号节点的value值(value)
static int l[] = new int[11010];// index号节点的左边节点的index
static int r[] = new int[11010];// index号节点的右边节点的index
static int idx = 2;
public static void main(String[] args) {
// TODO Auto-generated method stub
}
// 初始化
static void init() {
r[0] = 1; l[1] = 0;
}
// K的右边插入x
static void add_afterK(int k,int x) {
e[idx] = x;
l[idx] = k;
r[idx] = r[k];
l[r[k]] = idx;
r[k] = idx;
}
// K的左边插入x
static void add_beforeK(int k,int x) {
add_afterK(l[k],x);
}
// 删除——第k个节点
static void remove(int k) {
r[l[k]] = r[k];
l[r[k]] = l[k];
}
}
二、栈和队列
2.1 单调栈
问题:找到左边的并且比我小的第一个数
思想:通过构造单调性---求极值
时间复杂度:O(n) # 每个元素最多进栈/出栈一次
package 栈和队列;
import java.util.*;
public class 单调栈 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
int st[] = new int[11010],tt=0;
int n = in.nextInt();
for(int i=0;i<n;i++) {
int x = in.nextInt();
// 栈不空并且栈顶元素都大于等于我 => 出栈
while(tt>0 && st[tt]>=x)
tt--;
if(tt>0) System.out.print(st[tt]+" ");
else System.out.print("-1 ");
st[++tt] = x;
}
}
}
2.2 单调队列
问题:求滑动窗口(队列维护)的最值
package 栈和队列;
import java.util.Scanner;
public class 单调队列 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
int qu[] = new int[1100];
int a[] = new int [1100];
int hh=0, tt=-1;
int n = in.nextInt();
int k = in.nextInt();
for(int i=0;i< n;i++) {
a[i] = in.nextInt();
}
for(int i=0;i< n;i++) {
// 判断队头是否已经滑出窗口
if(hh<=tt && i-k+1 > qu[hh]) hh++;
// 出队
while(hh<=tt && a[qu[tt]]>= a[i]) tt--;
// 队列里存储的是下标
qu[++tt] = i;
if(i >= k-1)
System.out.print(a[qu[hh]]+" ");
}
hh=0;tt=-1;
for(int i=0;i< n;i++) {
// 判断队头是否已经滑出窗口
if(hh<=tt && i-k+1 > qu[hh]) hh++;
// 出队
while(hh<=tt && a[qu[tt]]<= a[i]) tt--;
// 队列里存储的是下标
qu[++tt] = i;
if(i >= k-1)
System.out.print(a[qu[hh]]+" ");
}
}
}
三、KMP
四、Trie树
Trie树又称字典树、单词查找树。是一种能够高效存储和查找字符串集合的数据结构
son[x][26]---代表了x节点的26个孩子、
-------son[1][0]=2表示1结点的一个值为a的子结点为结点2
-------如果son[1][0] = 0,则意味着没有值为a子结点
cnt[x]--从根节点到x节点结尾的单词个数
参考博客:
AcWing 835. 如何理解单(双)链表,Trie树和堆中的idx? - AcWinghttps://www.acwing.com/file_system/file/content/whole/index/content/139574/AcWing 835. Trie字符串统计 - AcWinghttps://www.acwing.com/file_system/file/content/whole/index/content/585887/
package Trie树;
import java.util.*;
public class 模板 {
static int son[][] = new int[11010][26]; // 每个节点的26个孩子结点(a~z)
static int cnt[] = new int[11010]; // 以当前节点结尾的单词有多少个
static int idx = 1; // 当前用到了哪个下标(0是根结点也是空节点)
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
int n = in.nextInt();
while(n--!=0) {
String op = in.next();
String str = in.next();
if(op.equals("I")) insert(str);
else System.out.print(query(str));
}
}
static void insert(String str) {
int p = 0;
for(int i=0;i<str.length();i++) {
int x = str.charAt(i) -'a';
if(son[p][x]==0) son[p][x] = ++idx;
p = son[p][x];
}
cnt[p]++;
}
static int query(String str) {
int p = 0;
for(int i=0;i<str.length();i++) {
int x = str.charAt(i) -'a';
if(son[p][x]==0) return 0;
p = son[p][x];
}
return cnt[p];
}
}
五、并查集
---快速合并两个元素所在的集合
---两个元素是否在同一个集合中
package 并查集;
import java.util.*;
public class 模板 {
static int p[] = new int[10010];
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
// 初始化---每个结点的父结点是自己
int n = in.nextInt();
for(int i=1;i<=n;i++) p[i] = i;
int m = in.nextInt();
while(m--!=0) {
String op = in.next();
int x = in.nextInt();
int y = in.nextInt();
if(op=="M")
p[find(x)] = find(y);
else
if(find(x)==find(y))
System.out.print("yes");
else
System.out.print("yes");
}
}
/**
* 返回x所在集合的编号(祖先结点),融合路径压缩进行优化
* @param x
*/
static int find(int x) {
if(p[x]!=x) p[x] = find(p[x]);
return p[x];
}
}
六、堆
手写小根堆
---核心操作:如果元素变大---down(x);如果元素变小---up(x);
---核心方法:插入一个元素——hp[++size] = x;up(x);
输出集合中的最小值——hp[1];
删除最小值——hp[1] = hp[size];size--;down(1);
修改任意一个元素——hp[x] = k;down(x);up(x);
删除任意一个元素——hp[x] = hp[size];size--;down(x);up(x);
应用——堆排序
import java.util.Scanner;
public class 堆排序 {
static int hp[] = new int[10010];
static int size = 0;
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner in = new Scanner(System.in);
int n = in.nextInt();
size = n;
for(int i=1;i<=n;i++) hp[i] = in.nextInt();
//建堆
for(int i=n/2;i>=1;i--) down(i);
//堆排序
for(int i=1;i<=n;i++) {
System.out.print(hp[1]+" ");
//删除堆顶元素
hp[1] = hp[size]; size--; down(1);
}
}
// 向下调整
static void down(int x) {
int t = x;
if(2*x<=size&&hp[2*x]<hp[t]) t = 2*x;
if(2*x+1<=size&&hp[2*x+1]<hp[t]) t = 2*x+1;
if(t!=x) {
int s = hp[x];
hp[x] = hp[t];
hp[t] = s;
down(t);
}
}
// 向上调整
static void up(int x) {
while(x/2<=size&&hp[x/2]>hp[x]) {
int s = hp[x];
hp[x] = hp[x/2];
hp[x/2] = s;
x = x >> 1;
}
}
}