数据结构-Tree(一周写的)

摘要:一周写的树数据结构的算法题,总结一下。

检查平衡性

判断一棵树是否平衡:对于任何一个节点,其两棵子树的高度不超过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       <---

难点:不知道树长什么样子。

数据结构-Tree(一周写的)_第1张图片

思路:进行深度优先搜索,对树进行优先搜索时,先访问右子树。

这个题用树的深度进行判断是否需要向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

你可能感兴趣的:(数据结构)