leecode更新
This commit is contained in:
parent
d6b00cd3b8
commit
0b8049f176
|
|
@ -0,0 +1,276 @@
|
|||
package com.markilue.leecode.tree;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.tree
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-09-25 09:58
|
||||
* @Description: TODO 力扣106题 从中序与后序遍历序列构造二叉树:
|
||||
* 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗二叉树。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class BuildTree {
|
||||
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
int[] inorder = {9, 3, 15, 20, 7}, postorder = {9, 15, 7, 20, 3};
|
||||
TreeNode root = buildTree(inorder, postorder);
|
||||
|
||||
System.out.println(levelOrder(root));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1(){
|
||||
int[] inorder = {2,1}, postorder = {2,1};
|
||||
TreeNode root = buildTree(inorder, postorder);
|
||||
|
||||
System.out.println(levelOrder(root));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2(){
|
||||
int[] inorder = {15,9,10,3,20,5,7,8,4}, postorder = {15,10,9,5,4,8,7,20,3};
|
||||
TreeNode root = buildTree2(inorder, postorder);
|
||||
|
||||
System.out.println(levelOrder(root));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 对于这题本人没有任何思路,代码随想录思路:本质上就是寻找中间节点来划分左右树,而后序遍历的最后一个节点一定是中间节点:
|
||||
* TODO 以后序数组的最后一个元素作为切割点,先切割中序数组,然后根据中序数组,反过来切割后序数组。一层一层切下去,每次后序数组额最后一个元素就是节点元素
|
||||
* 递归法:
|
||||
* 速度超过5.22%,内存超过5.01%
|
||||
* @param inorder
|
||||
* @param postorder
|
||||
* @return
|
||||
*/
|
||||
public TreeNode buildTree(int[] inorder, int[] postorder) {
|
||||
|
||||
TreeNode root = new TreeNode();
|
||||
|
||||
if (inorder.length == 0) {
|
||||
return root;
|
||||
}
|
||||
build1(inorder, postorder, root);
|
||||
return root;
|
||||
|
||||
}
|
||||
|
||||
public void build(int[] inorder, int[] postorder, TreeNode node) {
|
||||
|
||||
node.val = postorder[postorder.length - 1];
|
||||
int length=postorder.length;
|
||||
|
||||
if (length == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
//分别分割左右节点的inorder和postorder
|
||||
int[] newIn1 = new int[length];
|
||||
int[] newPost1 = new int[length];
|
||||
|
||||
int[] newIn2 = new int[length];
|
||||
int[] newPost2 = new int[length];
|
||||
|
||||
int size = 0;
|
||||
boolean flag = true;
|
||||
for (int i = 0,j=0; i < length; i++) {
|
||||
if(node.val==inorder[i]){
|
||||
flag=false;
|
||||
continue;
|
||||
}
|
||||
if (flag) {
|
||||
newIn1[i] = inorder[i];
|
||||
newPost1[i]=postorder[i];
|
||||
size+=1;
|
||||
}else {
|
||||
//这里-1因为root节点需要被跳过,但是post不用
|
||||
newIn2[j] = inorder[i];
|
||||
newPost2[j]=postorder[i-1];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
//这里需要判断是否大于0再做递归
|
||||
if(size>0){
|
||||
newIn1 = Arrays.copyOf(newIn1, size);
|
||||
newPost1=Arrays.copyOf(newPost1,size);
|
||||
node.left=new TreeNode();
|
||||
build(newIn1,newPost1,node.left);
|
||||
}
|
||||
|
||||
if(length-size-1>0){
|
||||
newIn2=Arrays.copyOf(newIn2,length-size-1);
|
||||
newPost2=Arrays.copyOf(newPost2,length-size-1);
|
||||
node.right=new TreeNode();
|
||||
build(newIn2,newPost2,node.right);
|
||||
}
|
||||
}
|
||||
|
||||
//可以改进,只需要找到索引避免一直复制,速度击败9.2%,内存击败5.01%
|
||||
public void build1(int[] inorder, int[] postorder, TreeNode node) {
|
||||
|
||||
node.val = postorder[postorder.length - 1];
|
||||
int length=postorder.length;
|
||||
|
||||
if (length == 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
//分别分割左右节点的inorder和postorder
|
||||
int size = 0;
|
||||
for (; size < length; size++) {
|
||||
if(inorder[size]==node.val){
|
||||
break;
|
||||
}
|
||||
}
|
||||
//这里需要判断是否大于0再做递归
|
||||
if(size>0){
|
||||
node.left=new TreeNode();
|
||||
//copyOfRange是左闭右开
|
||||
build(Arrays.copyOfRange(inorder,0, size),Arrays.copyOfRange(postorder,0,size),node.left);
|
||||
}
|
||||
|
||||
if(length-size-1>0){
|
||||
node.right=new TreeNode();
|
||||
build(Arrays.copyOfRange(inorder,size+1,length),Arrays.copyOfRange(postorder,size,length-1),node.right);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int post_idx;
|
||||
int[] postorder;
|
||||
int[] inorder;
|
||||
Map<Integer, Integer> idx_map = new HashMap<Integer, Integer>();
|
||||
|
||||
/**
|
||||
* 官方的递归法,只用传索引,不传一个数组,避免了数组的一直赋值操作,加快进度
|
||||
* 速度超过99.46%。内存超过34.84%
|
||||
* @param inorder
|
||||
* @param postorder
|
||||
* @return
|
||||
*/
|
||||
public TreeNode buildTree1(int[] inorder, int[] postorder) {
|
||||
this.postorder = postorder;
|
||||
this.inorder = inorder;
|
||||
// 从后序遍历的最后一个元素开始
|
||||
post_idx = postorder.length - 1;
|
||||
|
||||
// 建立(元素,下标)键值对的哈希表
|
||||
int idx = 0;
|
||||
for (Integer val : inorder) {
|
||||
idx_map.put(val, idx++);
|
||||
}
|
||||
|
||||
return helper(0, inorder.length - 1);
|
||||
}
|
||||
|
||||
public TreeNode helper(int in_left, int in_right) {
|
||||
// 如果这里没有节点构造二叉树了,就结束
|
||||
if (in_left > in_right) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 选择 post_idx 位置的元素作为当前子树根节点
|
||||
int root_val = postorder[post_idx];
|
||||
TreeNode root = new TreeNode(root_val);
|
||||
|
||||
// 根据 root 所在位置分成左右两棵子树
|
||||
int index = idx_map.get(root_val);
|
||||
|
||||
// 下标减一
|
||||
post_idx--;
|
||||
// 构造右子树
|
||||
root.right = helper(index + 1, in_right);
|
||||
// 构造左子树
|
||||
root.left = helper(in_left, index - 1);
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方迭代法:
|
||||
* 1)我们用一个栈和一个指针辅助进行二叉树的构造。初始时栈中存放了根节点(后序遍历的最后一个节点),指针指向中序遍历的最后一个节点;
|
||||
* 2)我们依次枚举后序遍历中除了第一个节点以外的每个节点。如果 index 恰好指向栈顶节点,
|
||||
* 那么我们不断地弹出栈顶节点并向左移动 index,并将当前节点作为最后一个弹出的节点的左儿子;
|
||||
* 如果 index 和栈顶节点不同,我们将当前节点作为栈顶节点的右儿子;
|
||||
* 3)无论是哪一种情况,我们最后都将当前的节点入栈。
|
||||
*
|
||||
* 最后得到的二叉树即为答案。
|
||||
*
|
||||
* @param inorder
|
||||
* @param postorder
|
||||
* @return
|
||||
*/
|
||||
public TreeNode buildTree2(int[] inorder, int[] postorder) {
|
||||
if (postorder == null || postorder.length == 0) {
|
||||
return null;
|
||||
}
|
||||
TreeNode root = new TreeNode(postorder[postorder.length - 1]);
|
||||
Deque<TreeNode> stack = new LinkedList<TreeNode>();
|
||||
stack.push(root);
|
||||
int inorderIndex = inorder.length - 1;
|
||||
for (int i = postorder.length - 2; i >= 0; i--) {
|
||||
int postorderVal = postorder[i];
|
||||
TreeNode node = stack.peek();
|
||||
//前面的如果不等,那么就是其右节点
|
||||
if (node.val != inorder[inorderIndex]) {
|
||||
node.right = new TreeNode(postorderVal);
|
||||
stack.push(node.right);
|
||||
} else {
|
||||
//右节点处理完毕,处理其左节点;如果出栈就证明遇上了需要处理的左节点
|
||||
while (!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]) {
|
||||
//同步处理stack和inorder
|
||||
node = stack.pop();
|
||||
inorderIndex--;
|
||||
}
|
||||
node.left = new TreeNode(postorderVal);
|
||||
stack.push(node.left);
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public List<List<Integer>> levelOrder(TreeNode root) {
|
||||
|
||||
List<List<Integer>> result = new ArrayList<>();
|
||||
|
||||
//使用队列完成
|
||||
Deque<TreeNode> deque = new LinkedList<TreeNode>();
|
||||
|
||||
if (root != null) {
|
||||
deque.addLast(root);
|
||||
}
|
||||
while (deque.size() > 0) {
|
||||
List<Integer> mid = new ArrayList<>();
|
||||
|
||||
int size = deque.size();
|
||||
|
||||
//注意这里必须使用size,而不是deque.size,因为deque的size一直在发生变化
|
||||
for (int i = 0; i < size; i++) {
|
||||
TreeNode poll = deque.poll();
|
||||
mid.add(poll.val);
|
||||
if (poll.left != null) deque.offer(poll.left);
|
||||
if (poll.right != null) deque.offer(poll.right);
|
||||
}
|
||||
result.add(mid);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
package com.markilue.leecode.tree;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.tree
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-09-25 12:45
|
||||
* @Description: TODO 力扣105题 从前序与中序遍历序列构造二叉树:
|
||||
* 给定两个整数数组preorder 和 inorder,其中preorder 是二叉树的先序遍历, inorder是同一棵树的中序遍历,请构造二叉树并返回其根节点。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class BuildTreeII {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
int[] preorder = {3, 9, 20, 15, 7}, inorder = {9, 3, 15, 20, 7};
|
||||
TreeNode node = buildTree(preorder, inorder);
|
||||
|
||||
System.out.println(levelOrder(node));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 核心其实一致,即中序遍历可以确定左右节点,前后序遍历可以确定根节点;因此根据前后序一直找根节点即可
|
||||
* 这里运用递归法:
|
||||
* 速度超过99.46%,内存超过60.36%
|
||||
*
|
||||
* @param preorder
|
||||
* @param inorder
|
||||
* @return
|
||||
*/
|
||||
int[] preorder;
|
||||
//<val,index>
|
||||
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
|
||||
int wanted=0;
|
||||
|
||||
public TreeNode buildTree(int[] preorder, int[] inorder) {
|
||||
this.preorder = preorder;
|
||||
for (int i = 0; i < inorder.length; i++) {
|
||||
map.put(inorder[i], i);
|
||||
}
|
||||
|
||||
return build(0, inorder.length-1);
|
||||
}
|
||||
|
||||
public TreeNode build(int leftIndex, int rightIndex) {
|
||||
|
||||
if(leftIndex>rightIndex){
|
||||
return null;
|
||||
}
|
||||
TreeNode node = new TreeNode(preorder[wanted]);
|
||||
Integer index = map.get(preorder[wanted++]);
|
||||
node.left=build(leftIndex,index-1);
|
||||
node.right=build(index+1,rightIndex);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方迭代法:
|
||||
* 1)我们用一个栈和一个指针辅助进行二叉树的构造。初始时栈中存放了根节点(前序遍历的第一个节点),指针指向中序遍历的第一个节点;
|
||||
* 2)我们依次枚举前序遍历中除了第一个节点以外的每个节点。
|
||||
* 如果 index 恰好指向栈顶节点,那么我们不断地弹出栈顶节点并向右移动 index,并将当前节点作为最后一个弹出的节点的右儿子;
|
||||
* 如果 index 和栈顶节点不同,我们将当前节点作为栈顶节点的左儿子;
|
||||
* 3)无论是哪一种情况,我们最后都将当前的节点入栈。
|
||||
*
|
||||
* @param preorder
|
||||
* @param inorder
|
||||
* @return
|
||||
*/
|
||||
public TreeNode buildTree1(int[] preorder, int[] inorder) {
|
||||
if (preorder == null || preorder.length == 0) {
|
||||
return null;
|
||||
}
|
||||
TreeNode root = new TreeNode(preorder[0]);
|
||||
Deque<TreeNode> stack = new LinkedList<TreeNode>();
|
||||
stack.push(root);
|
||||
int inorderIndex = 0;
|
||||
for (int i = 1; i < preorder.length; i++) {
|
||||
int preorderVal = preorder[i];
|
||||
TreeNode node = stack.peek();
|
||||
if (node.val != inorder[inorderIndex]) {
|
||||
node.left = new TreeNode(preorderVal);
|
||||
stack.push(node.left);
|
||||
} else {
|
||||
while (!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]) {
|
||||
node = stack.pop();
|
||||
inorderIndex++;
|
||||
}
|
||||
node.right = new TreeNode(preorderVal);
|
||||
stack.push(node.right);
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<List<Integer>> levelOrder(TreeNode root) {
|
||||
|
||||
List<List<Integer>> result = new ArrayList<>();
|
||||
|
||||
//使用队列完成
|
||||
Deque<TreeNode> deque = new LinkedList<TreeNode>();
|
||||
|
||||
if (root != null) {
|
||||
deque.addLast(root);
|
||||
}
|
||||
while (deque.size() > 0) {
|
||||
List<Integer> mid = new ArrayList<>();
|
||||
|
||||
int size = deque.size();
|
||||
|
||||
//注意这里必须使用size,而不是deque.size,因为deque的size一直在发生变化
|
||||
for (int i = 0; i < size; i++) {
|
||||
TreeNode poll = deque.poll();
|
||||
mid.add(poll.val);
|
||||
if (poll.left != null) deque.offer(poll.left);
|
||||
if (poll.right != null) deque.offer(poll.right);
|
||||
}
|
||||
result.add(mid);
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue