二叉树刷题学习笔记1——框架

上一篇:数据结构与算法——树

总结

二叉树解题的思维模式可以总结为以下:

  • 如果是通过遍历一遍二叉树得到的答案,这种是遍历的思维模式
  • 如果是通过子问题推导得到原问题答案的,这种是分解的思维模式

数据遍历框架

普通数组链表遍历:

  • 对数据的遍历无非就是顺序遍历或者递归遍历,遍历的对象无非也就是数组和链表,一般来说,我们遍历数据有以下框架:
/* 迭代遍历数组 */
void traverse(int[] arr) {
    for (int i = 0; i < arr.length; i++) {

    }
}

/* 递归遍历数组 */
void traverse(int[] arr, int i) {
    if (i == arr.length) {
        return;
    }
    // 前序位置
    traverse(arr, i + 1);
    // 后序位置
}

/* 迭代遍历单链表 */
void traverse(ListNode head) {
    for (ListNode p = head; p != null; p = p.next) {

    }
}

/* 递归遍历单链表 */
void traverse(ListNode head) {
    if (head == null) {
        return;
    }
    // 前序位置
    traverse(head.next);
    // 后序位置
}

二叉树的遍历框架如下:

  • 对比上面的数组和链表的遍历,二叉树的遍历其实没有什么很大的区别,只是多了一个中序位置(二叉树的左子树都遍历完后开始遍历右子树的时候的位置)。
  • 但是我这里说的前序位置、中序位置和后续位置和前面说的前序遍历、中序遍历、后续遍历不是一个意思,这里的位置表示的是进入节点的三个特殊的时间点。
void traverse(TreeNode root) {
    if (root == null) {
        return;
    }
    // 前序位置
    traverse(root.left);
    // 中序位置
    traverse(root.right);
    // 后序位置
}

  • 这里我们总结上面的遍历框架,对于递归形式的遍历,会出现一个前序和后序的位置,分别是在递归的前后,其实所谓的前序位置,就是在进入一个节点之前的位置,后续位置就是在进入一个节点之后的位置,这里我们举一个例子倒序打印,解决的方法有很多,比如这里我们可以利用后序位置来打印

代码框架

/* 递归遍历单链表,倒序打印链表元素 */
void traverse(ListNode head) {
    if (head == null) {
        return;
    }
    traverse(head.next);
    // 后序位置
    print(head.val);
}

具体代码

public class Demo {
	public static void main(String[] args) {
		ListNode head=new ListNode();
		head.val=0;
		ListNode p=head;//表示上一级
		
		for (int i = 0; i < 10; i++) {
			ListNode listNode=new ListNode();
			listNode.val=i+1;
			
			p.next=listNode;
			p=p.next;
			
			if(i==9) {//最后一个数据
				p.next=null;
			}
		}
		
		traverse(head);
	}
	
	/* 递归遍历单链表,倒序打印链表元素 */
	static void traverse(ListNode head) {
	    if (head == null) {
	        return;
	    }
	    traverse(head.next);
	    // 后序位置
	    System.out.print(head.val+" ");
	}
}
class ListNode {
    int val;
    ListNode next;
}

结果展示
在这里插入图片描述

  • 通过以上的例子,我们明白我说的前序位置、中序位置、后续位置的重要性,我们对递归算法的应用,就是在我说的这些位置进行操作。
  • 再以前序遍历、中序遍历、后序遍历来讲,我们的实现框架如下:
//递归实现前序遍历
	public void PreOrder(TreeNode root) {
		if(root!=null) {
			return;
		}
		System.out.println(root.val);
		PreOrder(root.left);
		PreOrder(root.right);
	}
	//递归实现中序遍历
	public void InOrder(TreeNode root) {
		if(root!=null) {
			return;
		}
		InOrder(root.left);
		System.out.println(root.val);
		InOrder(root.right);
	}
	//递归实现后序遍历
	public void PostOrder(TreeNode root) {
		if(root!=null) {
			return;
		}
		PostOrder(root.left);
		PostOrder(root.right);
		System.out.println(root.val);
	}

二叉树刷题

力扣题目示例: 二叉树的最大深度

使用递归算法,计算最大深度

class Solution {
	int max=0;//最大的深度
	int count=0;//维护当前的深度
	public int maxDepth(TreeNode root) {
		result(root);
		return max;
	}

	public void result(TreeNode root) {
		if (root == null) {
			max=max>count?max:count;
			return ;
		}
		count++;
		result(root.left);
		result(root.right);
		count--;
	}

}
  • 这里为什么要count--,因为遍历完右子树之后,需要切换到另一颗子树,这样,如果不减掉前一棵树的根节点,与本来的逻辑不符。最后,我们看到代码的框架,其实就是回溯算法的思想

当然,我们也容易发现,二叉树的最大深度是可以通过子树的最大深度度推导出来的,这样就可以使用分解问题计算答案,代码如下:

class Solution {
	public int maxDepth(TreeNode root) {
        if(root==null)
            return 0;

        int leftMax=maxDepth(root.left);
        int rightMax=maxDepth(root.right);

        int result=Math.max(leftMax,rightMax)+1;

        return result;
	}
  
}
  • 而这个,其实就是动态规划的思想。

下一篇:二叉树刷题学习笔记2

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值