7.3 二刷二叉树
This commit is contained in:
parent
6976c55204
commit
f4e0ac9f81
@ -11,7 +11,28 @@ import java.util.Map;
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
//思路会 代码不会写
|
//思路会 代码不会写
|
||||||
|
//二刷会做
|
||||||
public class BuildTree {
|
public class BuildTree {
|
||||||
|
int findpos(int a,int[] b,int left,int right){
|
||||||
|
for (int i = left; i <= right; i++) {
|
||||||
|
if(b[i]==a)return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
TreeNode helper(int preleft,int preright,int inleft,int inright,int[] preorder,int[] inorder){
|
||||||
|
if(preleft>preright|| inleft>inright)return null;
|
||||||
|
int pos=findpos(preorder[preleft],inorder,inleft,inright);
|
||||||
|
int leftcnt=pos-inleft;
|
||||||
|
TreeNode root=new TreeNode(inorder[pos]);
|
||||||
|
root.left=helper(preleft+1,preleft+1+leftcnt-1,inleft,pos-1,preorder,inorder);
|
||||||
|
root.right=helper(preleft+1+leftcnt,preright,pos+1,inright,preorder,inorder);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
public TreeNode buildTree1(int[] preorder, int[] inorder) {
|
||||||
|
int cnt=preorder.length;
|
||||||
|
return helper(0,cnt-1,0,cnt-1,preorder,inorder);
|
||||||
|
}
|
||||||
|
|
||||||
private Map<Integer, Integer> indexMap;
|
private Map<Integer, Integer> indexMap;
|
||||||
|
|
||||||
public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorder_left, int preorder_right, int inorder_left) {
|
public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorder_left, int preorder_right, int inorder_left) {
|
||||||
|
@ -10,10 +10,12 @@ import java.util.List;
|
|||||||
* 描述:给你二叉树的根结点 root ,请你将它展开为一个单链表:
|
* 描述:给你二叉树的根结点 root ,请你将它展开为一个单链表:
|
||||||
* 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
|
* 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
|
||||||
* 展开后的单链表应该与二叉树 先序遍历 顺序相同。
|
* 展开后的单链表应该与二叉树 先序遍历 顺序相同。
|
||||||
|
进阶:你可以使用原地算法(O(1) 额外空间)展开这棵树吗?
|
||||||
* 链接:https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/
|
* 链接:https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
//二刷会普通方法 不会空间O1的
|
||||||
|
//todo:学习一下思路。
|
||||||
public class Flatten {
|
public class Flatten {
|
||||||
public void inOrderTraversal(TreeNode root,List<TreeNode>list){
|
public void inOrderTraversal(TreeNode root,List<TreeNode>list){
|
||||||
if(root!=null) {
|
if(root!=null) {
|
||||||
@ -23,10 +25,9 @@ public class Flatten {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//O(N)空间复杂度 递归前序
|
//O(N)空间复杂度 递归前序
|
||||||
public void flatten(TreeNode root) {
|
public void flatten2(TreeNode root) {
|
||||||
List<TreeNode>list=new ArrayList<>();
|
List<TreeNode>list=new ArrayList<>();
|
||||||
TreeNode head=new TreeNode(0);
|
TreeNode tp= new TreeNode(0);
|
||||||
TreeNode tp=head;
|
|
||||||
inOrderTraversal(root,list);
|
inOrderTraversal(root,list);
|
||||||
for (TreeNode treeNode : list) {
|
for (TreeNode treeNode : list) {
|
||||||
tp.left=null;
|
tp.left=null;
|
||||||
@ -34,7 +35,7 @@ public class Flatten {
|
|||||||
tp=tp.right;
|
tp=tp.right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//迭代前序遍历也要回
|
//迭代前序遍历也要会!
|
||||||
public void flatten1(TreeNode root) {
|
public void flatten1(TreeNode root) {
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
return;
|
return;
|
||||||
@ -58,21 +59,40 @@ public class Flatten {
|
|||||||
prev = curr;
|
prev = curr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//O(1)空间
|
//O(1)空间 很妙
|
||||||
public void flatten2(TreeNode root) {
|
/**
|
||||||
TreeNode curr = root;
|
* 原地展开二叉树为单链表(先序顺序)
|
||||||
|
* 思路:Morris 遍历的变形 —— 每到一个有左子树的节点,就把
|
||||||
|
* ① 左子树插到右边
|
||||||
|
* ② 左子树最右节点 (predecessor) 的 right 指针接到原来的右子树
|
||||||
|
* ③ 左指针置空
|
||||||
|
* 然后继续沿着 curr = curr.right 前进
|
||||||
|
* 时间复杂度:O(n) — 每条边最多访问两次
|
||||||
|
* 空间复杂度:O(1) — 仅用常数指针
|
||||||
|
* https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/solutions/356853/er-cha-shu-zhan-kai-wei-lian-biao-by-leetcode-solu/?envType=study-plan-v2&envId=top-100-liked
|
||||||
|
*/
|
||||||
|
public void flatten(TreeNode root) {
|
||||||
|
TreeNode curr = root; // 当前遍历到的节点
|
||||||
while (curr != null) {
|
while (curr != null) {
|
||||||
if (curr.left != null) {
|
if (curr.left != null) { // 只处理存在左子树的节点
|
||||||
TreeNode next = curr.left;
|
TreeNode next = curr.left; // 1) 记录左子树的根,稍后会挪到右边
|
||||||
|
|
||||||
|
// 2) 找到左子树中的最右节点(先序遍历的“前驱”)
|
||||||
TreeNode predecessor = next;
|
TreeNode predecessor = next;
|
||||||
while (predecessor.right != null) {
|
while (predecessor.right != null) {
|
||||||
predecessor = predecessor.right;
|
predecessor = predecessor.right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3) 把当前节点原本的右子树接到 predecessor 的右侧
|
||||||
predecessor.right = curr.right;
|
predecessor.right = curr.right;
|
||||||
|
|
||||||
|
// 4) 把左子树搬到右边,左指针清空
|
||||||
curr.left = null;
|
curr.left = null;
|
||||||
curr.right = next;
|
curr.right = next;
|
||||||
}
|
}
|
||||||
|
// 5) 向“链表”右侧移动,继续处理下一个节点
|
||||||
curr = curr.right;
|
curr = curr.right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,17 @@ import java.util.Map;
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
//前缀和想到了,代码不会写
|
//前缀和想到了,代码不会写
|
||||||
|
//二刷不会
|
||||||
public class PathSum {
|
public class PathSum {
|
||||||
|
/**
|
||||||
|
* prefix 这张哈希表只应该保存“当前递归栈(从根结点到正在访问的那个结点)”这条路径上出现过的前缀和。!!!!
|
||||||
|
* 当递归函数从一个结点返回到它的父结点时,这个结点及其子树已经遍历完毕,它对应的前缀和在后面的兄弟子树中就再也不会出现在
|
||||||
|
* “从父结点往下的路径”里了;如果不把它从 prefix 里去掉,那么后续兄弟子树在查询 prefix.get(curr-target)
|
||||||
|
* 时就可能误用这条“已经不存在的”前缀和,从而把 跨越两条不同分支 的路径算进去——而题目只允许一直“向下”的路径。
|
||||||
|
* @param root
|
||||||
|
* @param targetSum
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
// 主函数:用于计算路径和等于 targetSum 的路径个数
|
// 主函数:用于计算路径和等于 targetSum 的路径个数
|
||||||
public int pathSum(TreeNode root, int targetSum) {
|
public int pathSum(TreeNode root, int targetSum) {
|
||||||
// 使用一个哈希表来记录前缀和出现的次数
|
// 使用一个哈希表来记录前缀和出现的次数
|
||||||
@ -25,12 +35,6 @@ public class PathSum {
|
|||||||
return dfs(root, prefix, 0, targetSum);
|
return dfs(root, prefix, 0, targetSum);
|
||||||
}
|
}
|
||||||
|
|
||||||
// dfs函数:递归遍历树,并统计满足路径和为 targetSum 的路径个数
|
|
||||||
// 参数说明:
|
|
||||||
// root:当前节点
|
|
||||||
// prefix:记录前缀和及其出现次数的哈希表
|
|
||||||
// curr:当前节点的累计前缀和(从根节点到当前节点的和)
|
|
||||||
// targetSum:目标路径和
|
|
||||||
public int dfs(TreeNode root, Map<Long, Integer> prefix, long curr, int targetSum) {
|
public int dfs(TreeNode root, Map<Long, Integer> prefix, long curr, int targetSum) {
|
||||||
// 终止条件:当前节点为空,返回0条路径
|
// 终止条件:当前节点为空,返回0条路径
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
@ -55,6 +59,7 @@ public class PathSum {
|
|||||||
|
|
||||||
// 回溯操作:在返回父节点之前,去掉当前节点对前缀和的贡献
|
// 回溯操作:在返回父节点之前,去掉当前节点对前缀和的贡献
|
||||||
// 防止当前路径的前缀和影响到其他分支的计算
|
// 防止当前路径的前缀和影响到其他分支的计算
|
||||||
|
//不会减到负数,因为进来的时候一定+1了。
|
||||||
prefix.put(curr, prefix.getOrDefault(curr, 0) - 1);
|
prefix.put(curr, prefix.getOrDefault(curr, 0) - 1);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -12,8 +12,9 @@ import java.util.Queue;
|
|||||||
* 链接:https://leetcode.cn/problems/binary-tree-right-side-view/description/
|
* 链接:https://leetcode.cn/problems/binary-tree-right-side-view/description/
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
//二刷会做
|
||||||
public class RightSideView {
|
public class RightSideView {
|
||||||
public List<Integer> rightSideView(TreeNode root) {
|
public List<Integer> rightSideView1(TreeNode root) {
|
||||||
Queue<TreeNode>queue=new ArrayDeque<>();
|
Queue<TreeNode>queue=new ArrayDeque<>();
|
||||||
List<Integer>res=new ArrayList<>();
|
List<Integer>res=new ArrayList<>();
|
||||||
if(root==null)
|
if(root==null)
|
||||||
@ -33,4 +34,17 @@ public class RightSideView {
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Integer> rightSideView(TreeNode root) {
|
||||||
|
List<Integer> res = new ArrayList<>();
|
||||||
|
dfs(root, 0, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
private void dfs(TreeNode node, int depth, List<Integer> res) {
|
||||||
|
if (node == null) return;
|
||||||
|
if (depth == res.size()) res.add(node.val); // 第一次到此深度 ⇒ 最右 只添加最右侧的节点。
|
||||||
|
dfs(node.right, depth + 1, res); // 先右
|
||||||
|
dfs(node.left, depth + 1, res);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user