前序遍历
对当前节点值进行操作,递归左子树,递归右子树。
中序遍历
递归左子树,对当前节点值进行操作,递归右子树。
后序遍历
递归左子树,递归右子树,对当前节点值进行操作。
层序遍历
使用队列Queue,将每一次节点放入queue中,通过遍历queue,每次从头到尾弹出一个节点,然后将下一层节点加入queue中,同时将弹出节点的value值放入需要返回的list集合中。(BFS)
出度入度
出了头结点,其他节点入度均为1,除了尾结点,其他节点出度均为1。可以用来判断序列化是否满足数的结构。 leetCod-331
public class isValidSerialization_331 {
public static void main(String[] args) {
System.out.println(isValidSerialization("#,7,6,9,#,#,#"));
}
private static boolean isValidSerialization(String preorder) {
int in = 0,out = 0;
String[] ss = preorder.split(",");
for (int i = 0; i < ss.length; i++) {
//只有数字有出度,并且每个数字对应出度为2
if(!ss[i].equals("#")) out+=2;
//根节点没有入度,其他每个值入度为1
if(i!=0) in++;
//如果未到最后一个,出度提前大于入度
if(i !=(ss.length-1) && out<=in) return false;
}
return in==out;
}
}
图的遍历
leetcode第778题 找到能将开始和结尾连通的最小根节点
public class swimInWater_778 {
public static void main(String[] args) {
int[][] grid = {
{0,1,2,3,4},
{24,23,22,21,5},
{12,13,14,15,16},
{11,17,18,19,20},
{10,9,8,7,6}};
System.out.println(swimInWater1(grid));
System.out.println(swimInWater2(grid));
}
//解法一:Kruskal算法
//定义三个函数:1、链接函数,将x,y两个点设置为同一根节点。2、判断是否连通。3、找到根节点
static int n;
static int[] p;
private static void union(int x,int y){
//将x,y的根节点进行合并
p[find(x)] = p[find(y)];
}
private static boolean query(int x,int y){
//判断x,y是否在同一个根节点
return find(x) == find(y);
}
//找到x的根节点
private static int find(int x){
if(p[x] != x){
p[x] = find(p[x]);
}
return p[x];
}
public static int swimInWater1(int[][] grid) {
n = grid.length;
//初始化并查集
p = new int[n * n];
for (int i = 0; i < n*n; i++) {
p[i] = i;
}
//预处理边
List<int[]> edges = new ArrayList<>();
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int index = getIndex(i, j);
//将连通的边放入集合中
p[index] = index;
if(i+1<n){
int a = index;
int b = getIndex(i+1,j);
int w = Math.max(grid[i][j],grid[i+1][j]);
edges.add(new int[]{a,b,w});
}
if(j+1<n){
int a = index;
int b = getIndex(i,j+1);
int w = Math.max(grid[i][j],grid[i][j+1]);
edges.add(new int[]{a,b,w});
}
}
}
//对边的权值进行排序
Collections.sort(edges,(a,b)->a[2]-b[2]);
//从最小权值的边开始进行并查集
int start = getIndex(0,0),end = getIndex(n-1,n-1);
for(int[] edge : edges){
int a = edge[0],b = edge[1],w = edge[2];
union(a,b);
if(query(start,end)){
return w;
}
}
return 0;
}
//将二维坐标映射到一维,方便点的表示
private static int getIndex(int i, int j) {
return i * n + j;
}
//解法二:BFS+二分
public static int swimInWater2(int[][] grid){
int len = grid.length;
int left = 0,right = len*len-1;
while (left < right){
int mid = (left+right)>>1;
if(check(grid,mid)){
right = mid;
}else {
left = mid+1;
}
}
return right;
}
private static boolean check(int[][] grid,int time){
int len = grid.length;
boolean[][] isVisited = new boolean[len][len];
int[][] direction = {{0,1},{1,0},{0,-1},{-1,0}};
Deque<int[]> deque = new LinkedList<>();
deque.add(new int[]{0,0});
isVisited[0][0] = true;
while (!deque.isEmpty()){
int[] from = deque.pollLast();
int x = from[0],y = from[1];
if(x== len-1 && y==len-1) return true;
for (int[] dir : direction){
int newX = x+dir[0],newY = y+dir[1];
int[] to = new int[]{newX,newY};
if(inArea(len,newX,newY) && !isVisited[newX][newY]
&& canMove(grid,from,to,time)){
isVisited[newX][newY] = true;
deque.addLast(to);
}
}
}
return false;
}
private static boolean inArea(int len,int x,int y){
return (x>=0 && x<len && y>=0 && y<len);
}
private static boolean canMove(int[][]grid,int[] from,int[] to,int time){
return time>=(Math.max(grid[from[0]][from[1]],grid[to[0]][to[1]]));
}
}
掌握递归与非递归两种遍历树的方法
非递归方法一般使用队列,根据需要使用选择使用队列和双端对列,看此时节点的弹出需要从首段还是尾端,一般建议选择双端队列。