摘要:一周写的树数据结构的算法题,总结一下。
判断一棵树是否平衡:对于任何一个节点,其两棵子树的高度不超过1。
示例1
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。
思路:递归遍历找到高度。
难点:获取树的高度,递归遍历左右节点。
class Solution{
public boolean isBalanced(TreeNode root){
if (root == null) return true;
if(Math.abs(getDepth(root.left) - getDepth(root.right)) > 1) return false;
return isBalanced(root.left)&&isBalanced(root.right);
}
private int getDepth(TreeNode root){
if(root == null) return 0;
return Math.max(getDepth(root.left),getDepth(root.right)) + 1;
}
}
public class TreeNode{
int val;
TreeNode left;
TreeNode right;
TreeNode(int x){
val = x;
}
}
递归的重要思想是:1.找到最简单的子问题求解。2其他问题不考虑内在细节,只考虑整体逻辑。
最简单的子问题,递归停止的条件
if(root == null){
return 0;
}
根据题目要求
考虑三部分
难点:怎样去求以当前节点作为头节点的路径数量?
答案:每到一个节点让sum-root.val,并判断sum是否为0,如果为零的话,则找到满足条件的一条路径。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int pathSum(TreeNode root, int sum) {
if(root == null){
return 0;
}
int result = countPath(root,sum);
int a = pathSum(root.left,sum);
int b = pathSum(root.right,sum);
return result+a+b;
}
public int countPath(TreeNode root,int sum){
if(root == null){
return 0;
}
sum = sum - root.val;
int result = sum == 0 ? 1:0;
return result + countPath(root.left,sum) + countPath(root.right,sum);
}
}
实现一个二叉搜索树迭代器,你将使用二叉搜索树的根节点初始化迭代器。调用next()
将返回二叉搜索树中的下一个最小的数。
知识点:来看看迭代器
new_iterator = BSTIterator(root);
while(new_iterator.hasNext())
process(new_iterator.next());
重点:二叉搜索树的一个重要特性是二叉树搜索的中序遍历是升序遍历;因此,中序遍历是该解决方案的核心。
方法一:用一个空数组来存放二叉搜索树的中序序列。
class BSTIterator {
ArrayList<Integer> nodeSorted;
int index;
public BSTIterator(TreeNode root) {
this.nodeSorted = new ArrayList<>();
this.index = -1;
this._inorder(root);
}
private void _inorder(TreeNode root){
if(root == null) return;
this._inorder(root.left);
this.nodeSorted.add(root.val);
this._inorder(root.right);
}
/** @return the next smallest number */
public int next() {
return nodeSorted.get(++this.index);
}
/** @return whether we have a next smallest number */
public boolean hasNext() {
return this.index + 1 < this.nodeSorted.size();
}
}
class BSTIterator{
Stack<TreeNode> stack;
public BSTIterator(TreeNode root){
this.stack = new Stack<TreeNode>();
this._leftmostInorder(root);
}
private void _leftmostInorder(TreeNode root){
while(root!=null){
this.stack.push(root);
root = root .left;
}
}
public int next(){
TreeNode topmostNode = this.stack.pop();
if(topmostNode.right != null){
this._leftmostInorder(topmostNode.right);
}
return topmostNode.val;
}
public boolean hasNext(){
return this.stack.size() > 0;
}
}
给定一颗二叉树,想象自己站在他的右侧,按照从顶部到底部的顺序,返回从右侧能看到的节点值。
示例:
输入: [1,2,3,null,5,null,4]
输出: [1, 3, 4]
解释:
1 <---
/ \
2 3 <---
\ \
5 4 <---
难点:不知道树长什么样子。
思路:进行深度优先搜索,对树进行优先搜索时,先访问右子树。
这个题用树的深度进行判断是否需要向map
中添加节点,利用了一个map
来保持当前节点的高度,当高度小于等于map
中储存的高度时,不进行存储当前节点。
class Solution{
public List<Integer> rightSideView(TreeNode root){
Map<Integer,Integer> rightmostValueAtDepth = new HashMap<Integer,Integer>();
int max_depth = -1;
Stack<TreeNode> nodeStack = new Stack<TreeNode>();
Stack<Integer> depthStack = new Stack<Integer>();
nodeStack.push(root);
depthStack.push(0);
while(!nodeStack.isEmpty()){
TreeNode node = nodeStack.pop();
int depth = depthStack.pop();
if(node != null){
max_depth = Math.max(max_depth,depth);
if(!rightmostValueAtDepth.containsKey(depth)){
rightmostValueAtDepth.put(depth, node.val);
}
nodeStack.push(node.left);
nodeStack.push(node.right);
depthStack.push(depth + 1);
depthStack.push(depth + 1);
}
}
List<Integer> rightView = new ArrayList<Integer>();
for(int depth = 0;depth <= max_depth;depth++){
rightView.add(rightmostValueAtDepth.get(depth));
}
}
}
方法二:通过层次遍历,对每一行的最后一个节点进行保存。
class Solution{
public List<Integer> rightSideView(TreeNode root){
if(root == null){
return new ArrayList<>();
}
Queue<TreeNode> queue = new LinkedList<>();
List<Integer> ret = new ArrayList<>();
queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
for(int i = 0;i<size;i++){
TreeNode node = queue.poll();
if(i == size - 1){
ret.add(node.val);
}
if(node.left != null){
queue.add(node.left);
}
if(node.right != null){
queue.add(node.right);
}
}
}
return ret;
}
}
思路:优先右子树的深度优先遍历,deepest
表示目前存的最大深度
class Solution{
List<Integer> ans = new ArrayList<>();
int deepest = 0;
public List<Integer> rightSideView(TreeNode root){
helper(root,0);
return ans;
}
private void helper(TreeNode root, int now){
if(root == null) return;
if(now == deepest){
ans.add(root.val);
deepest++;
}
helper(root.right,now+1);
helper(root.left, now+1);
}
}
方法:模拟打印矩阵的路径,初始位置是矩阵的左上角,初始方向是向右,当路径超过界限或者进入之间访问的位置时,则顺时针旋转,进入下一个方向。
难点:怎样定义方向,怎样判断和更新方向。
class Solution{
public int[] spiralOrder(int[][] matrix){
if(matrix == null){
return new int[0];
}
int rows = matrix.length, columns = matrix.length;
boolean[][] visited = new boolean[rows][columns];
int total = rows * columns;
int[] order = new int[total];
int row = 0, column = 0;
int[][] directions = {{0,1},{1,0},{0,-1},{-1,0}};
int directionIndex = 0;
for(int i=0;i<total;i++){
order[i] = matrix[row][column];
visited[row][column] = true;
int nextRow = row + dirctions[dirctionIndex][0], nextColumn = column + dirctions[dirctionIndex][1];
if(nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn]){
directionIndex = (directionIndex + 1) % 4;
}
row += directions[directionIndex][0];
column += dirctions[directionIndex][1];
}
return order;
}
}
二叉树序列化的本质就是对其值和结构进行编码
对于DFS搜索根据根节点、左节点和右节点之间的相对顺序,可进一步将DFS策略分为:
对于这个题我的难点,怎样控制输出空节点时,再怎样进行递归返回。
本题用了字符串连接的方式连接节点和None
。
public class Codec{
public String reseriable(TreeNode root, String str){
if(root == null){
str += "None";
}else{
str += str.valueOf(root.val) + ",";
str = reseriable(root.left, str);
str = reseriable(root.right,str);
}
return str;
}
public String serialize(TreeNode root){
return reseriable(root,"");
}
public TreeNode rdeseriable(List<String> l){
if(l.get(0).equals("None")){
l.remove(0);
return null;
}
TreeNode root = new TreeNode(Integer.valueOf(l.get(0)));
l.remove(0);
root.left = rdeseriable(l);
root.right = rdeseriable(l);
return root;
}
public TreeNode deserialize(String data){
String[] data_array = data.split(",");
List<String> data_list = new LinkedList<>();
return rdeserialize(data_list);
}
}
参考
1.力扣-Tree