1)之前涉及dfs,用递归比较多,但是若递归次数非常多,可能栈溢出,那么就需要用非递归的方式解决了,递归是jvm自动分配方法栈,那非递归可以基于自定义栈实现最终逻辑;
二叉树的中序遍历
方法一基于递归(递归次数多了,可能会引起栈溢出)
public static List<Integer> zhongxuBianli(TreeNode root){
List<Integer> res = new ArrayList();
inorder(root,res);
System.out.println(res.toString());
return res;
}
//力扣,94 二叉树的中序遍历 子方法
public static void inorder(TreeNode root ,List<Integer> list){
if(root == null)return;
inorder(root.left,list);
list.add(root.val);
inorder(root.right,list);
}
方法二基于自定义栈(不存在栈溢出问题)
public static List<Integer> zhongxuBianliSelfStack(TreeNode root){
LinkedList<TreeNode> linkedList = new LinkedList();
ArrayList<Integer> list = new ArrayList();
while (root!=null || !linkedList.isEmpty()){
while (root!=null){
linkedList.push(root);
root=root.left;
}
root = linkedList.pop();
list.add(root.val);
root=root.right;
}
return list;
}
公共类
public static class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
public TreeNode(int val) {
this.val = val;
}
public TreeNode() {
}
}
2)上述方法2稍作修改,就可以判断一棵树是否是二叉查找树,因为上边是中序遍历,如果是二叉查找树则满足升序排列,所以可以将当前pop出的一个数与前一个pop的数比较,若当前数小或等于前一个值,则直接返回false,表明当前不是二叉查找树;
public static boolean panDuanErChaChaZhaoShu(TreeNode root){
LinkedList<TreeNode> linkedList = new LinkedList();
long beforeVal=Long.MIN_VALUE;
while (root!=null || !linkedList.isEmpty()){
while (root!=null){
linkedList.push(root);
root=root.left;
}
root = linkedList.pop();
if(root.val <= beforeVal){
return false;
}
beforeVal=root.val;
root=root.right;
}
return true;
}
3)上述方法继续变化,可以应对求二叉树最大深度问题
public static int erChaShuMaxDepth(TreeNode root){
LinkedList<TreeNode> linkedList = new LinkedList();
int max=0;
TreeNode pop=null;
while (root!=null || !linkedList.isEmpty()){
while (root!=null){
linkedList.push(root);
root=root.left;
max=Math.max(max,linkedList.size());
}
//这里用peek主要是如果右边有子节点则需要先看下右边子树的深度,而不能一概pop
TreeNode peek = linkedList.peek();
//第一个条件意思是如果右边无子节点,则直接pop当前节点
// 第二个条件意思是如果右边是刚弹出的子节点,则表明是已经计算过深度的,可以直接pop当前节点
if(peek.right ==null || peek.right == pop){
pop = linkedList.pop();
}else{
//如果右边子节点存在且还没有遍历过,则更新root,准备下一轮循环放入栈中
root=peek.right;
}
}
return max;
}
4)上述erChaShuMaxDepth方法其实是基于后序遍历,稍作修改即可实现二叉树的后序遍历,代码如下
public static List<Integer> houXuBianLi(TreeNode root){
LinkedList<TreeNode> linkedList = new LinkedList();
ArrayList<Integer> list = new ArrayList();
TreeNode pop=null;
while (root !=null || !linkedList.isEmpty()){
while (root!=null){
linkedList.push(root);
root=root.left;
}
TreeNode peek = linkedList.peek();
if(peek.right==null || peek.right==pop){
pop=linkedList.pop();
list.add(pop.val);
}else{
//如果右节点存在且还未遍历,则准备进行处理
root=peek.right;
}
}
return list;
}
或者不用peek方法,直接pop,但需要记录子节点pre,需要通过pre确认已经遍历过右子节点
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;
}
前序遍历也是做一些修改
public static List<Integer> qianXuBianLi(TreeNode root){
LinkedList<TreeNode> linkedList = new LinkedList();
ArrayList<Integer> list = new ArrayList();
TreeNode pop=null;
while (root !=null || !linkedList.isEmpty()){
while (root!=null){
list.add(root.val);
linkedList.push(root);
root=root.left;
}
root=linkedList.pop();
root=root.right;
}
return list;
}
5)深度优先算法的回溯是一个常用方式,如二叉树从根到叶子,每到一个叶子,接着回溯即倒退,才能前往下一个叶子,当同一深度的节点遍历完了,再次倒退到上一深度,才能遍历另一边;
力扣第113题 路径总和 II
LinkedList list1 = new LinkedList<List<Integer>>();
LinkedList list2 = new LinkedList();
public List<List<Integer>> pathSum(TreeNode root,int targetSum){
dfs113(root,targetSum);
return list1;
}
public void dfs113(TreeNode root,int targetSum){
if(root==null)return;
list2.offerLast(root.val);
targetSum-=root.val;
if(root.left==null && root.right==null && targetSum==0){
list1.add(new LinkedList<>(list2));
}
dfs113(root.left,targetSum);
dfs113(root.right,targetSum);
//回溯
list2.pollLast();
}
6)有的题目需要上下左右都进行搜索,如力扣第130题和力扣第200题就几乎一样;
力扣第130题 被围绕的区域
public static void slove(char[][] board){
int m = board.length;
int n = board[0].length;
for (int i = 0; i < m; i++) {
dfs130(board,i,0);
dfs130(board,i,n-1);
}
for (int i = 1; i < n-1; i++) {
dfs130(board,0,i);
dfs130(board,m-1,i);
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if(board[i][j]=='A'){
board[i][j]='O';
}else if(board[i][j]=='O'){
board[i][j]='X';
}
}
}
}
//力扣 130 子方法
public static void dfs130(char[][] board,int m,int n){
if(m<0 || m>=board.length|| n<0 ||n>=board[0].length || board[m][n]!='O'){
return;
}
board[m][n]='A';
dfs130(board,m-1,n);
dfs130(board,m+1,n);
dfs130(board,m,n-1);
dfs130(board,m,n+1);
}
力扣第200题
public int numIslands(char[][] grid) {
int m = grid.length;
int n = grid[0].length;
int count=0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if(grid[i][j]=='1'){
count++;
dfs200(grid,i,j);
}
}
}
return count;
}
//力扣 200 子方法
public void dfs200(char[][] grid ,int i,int j){
if(i<0 ||j<0 ||i>=grid.length ||j>=grid[0].length || grid[i][j]=='0'){
return;
}
grid[i][j]='0';
dfs200(grid,i-1,j);
dfs200(grid,i+1,j);
dfs200(grid,i,j-1);
dfs200(grid,i,j+1);
}
力扣第417题,也套用第130题解题框架,但结果有点不对,目前还未找到原因
//成员变量
int[][] heights417;
int m417, n417;
public List<List<Integer>> pacificAtlantic(int[][] heights) {
this.heights417 = heights;
this.m417 = heights.length;
this.n417 = heights[0].length;
boolean[][] pacific = new boolean[m417][n417];//默认值为false,数组只要分配内存就会给默认值,即使作为局部变量;
boolean[][] atlantic = new boolean[m417][n417];
for (int i = 0; i < m417; i++) {
dfs417(i, 0, pacific,0);
}
for (int i = 1; i < n417; i++) {
dfs417(0, i, pacific,0);
}
for (int i = 0; i < m417; i++) {
dfs417(i, n417-1, atlantic,0);
}
for (int i = 0; i < m417-1; i++) {
dfs417(m417-1, i, atlantic,0);
}
List<List<Integer>> result = new ArrayList<List<Integer>>();
for (int i = 0; i < m417; i++) {
for (int j = 0; j < n417; j++) {
if (pacific[i][j] && atlantic[i][j]) {
List<Integer> cell = new ArrayList<Integer>();
cell.add(i);
cell.add(j);
result.add(cell);
}
}
}
return result;
}
//417. 太平洋大西洋水流问题 子方法
public void dfs417(int row,int col,boolean[][] ocean,int diff){
if(row < 0 || row>=m417 || col < 0 || col>=n417 || ocean[row][col] || diff < 0){
return;
}
ocean[row][col]=true;
if(row-1>=0){
dfs417(row-1,col,ocean,heights417[row-1][col]-heights417[row][col]);
}
if(row+1 < m417){
dfs417(row+1,col,ocean,heights417[row+1][col]-heights417[row][col]);
}
if(col-1 >=0){
dfs417(row,col-1,ocean,heights417[row][col-1]-heights417[row][col]);
}
if(col+1 <n417){
dfs417(row,col+1,ocean,heights417[row][col+1]-heights417[row][col]);
}
}
测试用例
new int[][]{{19,12,0,19,17,4,13,10,6,1,7,18,2,17,0,18,0,18,8,9,19,4,5,4,12,18,17,8,3,15,12,4,11},
{5,9,10,19,4,8,5,4,9,14,16,5,7,16,6,19,12,9,1,5,18,8,3,19,8,11,15,11,15,19,13,13,14},
{4,1,18,13,7,1,16,11,11,18,5,7,10,8,9,17,10,12,17,11,13,3,18,10,17,6,3,16,13,13,5,7,12},
{11,5,19,15,16,19,14,15,6,10,17,5,19,19,17,16,12,12,19,13,3,18,0,4,7,3,12,2,16,6,17,19,18},
{4,7,16,12,9,11,15,10,16,5,2,4,12,6,1,14,12,18,7,4,3,17,17,11,5,1,19,19,1,0,4,4,7},
{19,8,16,9,14,5,15,11,15,12,5,10,19,14,10,11,13,15,8,8,2,14,6,2,2,7,1,5,19,10,14,3,4}}