leecode更新
This commit is contained in:
parent
571f1185f5
commit
7d9b21790c
|
|
@ -1,9 +1,9 @@
|
||||||
package com.markilue.leecode.tree;
|
package com.markilue.leecode.tree;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 中序遍历二叉排序树
|
* 中序遍历二叉排序树
|
||||||
|
|
@ -25,34 +25,34 @@ public class InorderTraversal {
|
||||||
TreeNode2.setRight(TreeNode5);
|
TreeNode2.setRight(TreeNode5);
|
||||||
TreeNode3.setLeft(TreeNode6);
|
TreeNode3.setLeft(TreeNode6);
|
||||||
|
|
||||||
List<Integer> integers = inorderTraversal1(root);
|
List<Integer> integers = inorderTraversal4(root);
|
||||||
|
|
||||||
System.out.println(integers);
|
System.out.println(integers);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<TreeNode> list =new ArrayList<TreeNode>();
|
public static List<TreeNode> list = new ArrayList<TreeNode>();
|
||||||
public static List<Integer> list2 =new ArrayList<Integer>();
|
public static List<Integer> list2 = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归法:中序遍历
|
* 递归法:中序遍历
|
||||||
|
*
|
||||||
* @param root
|
* @param root
|
||||||
*/
|
*/
|
||||||
public static void inorderTraversal(TreeNode root){
|
public static void inorderTraversal(TreeNode root) {
|
||||||
|
|
||||||
if(root == null){
|
if (root == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(root.left !=null){
|
if (root.left != null) {
|
||||||
inorderTraversal(root.left);
|
inorderTraversal(root.left);
|
||||||
|
|
||||||
}
|
}
|
||||||
list.add(root);
|
list.add(root);
|
||||||
|
|
||||||
if(root.right !=null){
|
if (root.right != null) {
|
||||||
inorderTraversal(root.right);
|
inorderTraversal(root.right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -60,26 +60,63 @@ public class InorderTraversal {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 递归法原题:中序遍历 => O(n)
|
* 递归法原题:中序遍历 => O(n)
|
||||||
|
*
|
||||||
* @param root
|
* @param root
|
||||||
*/
|
*/
|
||||||
public static List<Integer> inorderTraversal2(TreeNode root){
|
public static List<Integer> inorderTraversal2(TreeNode root) {
|
||||||
|
|
||||||
if(root == null){
|
if (root == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if(root.left !=null){
|
if (root.left != null) {
|
||||||
inorderTraversal2(root.left);
|
inorderTraversal2(root.left);
|
||||||
|
|
||||||
}
|
}
|
||||||
list2.add(root.val);
|
list2.add(root.val);
|
||||||
|
|
||||||
if(root.right !=null){
|
if (root.right != null) {
|
||||||
inorderTraversal2(root.right);
|
inorderTraversal2(root.right);
|
||||||
}
|
}
|
||||||
return list2;
|
return list2;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自己的非递归法:使用一个栈记录上次还需要进一步遍历的节点,等现在的遍历完了,就可以出栈到这里,让上一次的继续去遍历
|
||||||
|
*
|
||||||
|
* @param root
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static List<Integer> inorderTraversal3(TreeNode root) {
|
||||||
|
List<Integer> list = new ArrayList<>();
|
||||||
|
|
||||||
|
if (root == null) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
//使用栈记录需要遍历的root
|
||||||
|
Stack<TreeNode> stack = new Stack<>();
|
||||||
|
TreeNode node = root;
|
||||||
|
|
||||||
|
//核心理念是:先找到当前节点的最左节点,把这个值pop出之后就可以加入result,然后看看他的右子树
|
||||||
|
while (stack.size() > 0 || node != null) {
|
||||||
|
//指针访问节点,访问到底层
|
||||||
|
if (node != null) {
|
||||||
|
//将访问的节点放入栈
|
||||||
|
stack.push(node);
|
||||||
|
node = node.left;
|
||||||
|
} else {
|
||||||
|
//从栈里弹出的数据就是要处理的数据(放入result数组的数据)
|
||||||
|
node = stack.pop();
|
||||||
|
list.add(node.val);
|
||||||
|
node = node.right;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 非递归法:中序遍历(题解第三种方法) ->空间复杂度 O(1)Morris 中序遍历
|
* 非递归法:中序遍历(题解第三种方法) ->空间复杂度 O(1)Morris 中序遍历
|
||||||
* 循环:
|
* 循环:
|
||||||
|
|
@ -89,44 +126,97 @@ public class InorderTraversal {
|
||||||
* 寻找当前节点的左子树最右节点flag,判断flag的右子节点是否为空:
|
* 寻找当前节点的左子树最右节点flag,判断flag的右子节点是否为空:
|
||||||
* 如果为空:当前节点左移,设置flag的右子节点为当前节点
|
* 如果为空:当前节点左移,设置flag的右子节点为当前节点
|
||||||
* 如果不为空:说明已经遍历完当前节点的左子树,将flag的右子节点为置空,将当前节点加入list,当前节点右移
|
* 如果不为空:说明已经遍历完当前节点的左子树,将flag的右子节点为置空,将当前节点加入list,当前节点右移
|
||||||
|
*
|
||||||
* @param root
|
* @param root
|
||||||
*/
|
*/
|
||||||
public static List<Integer> inorderTraversal1(TreeNode root){
|
public static List<Integer> inorderTraversal1(TreeNode root) {
|
||||||
|
|
||||||
List<Integer> list1 =new ArrayList<Integer>();
|
List<Integer> list1 = new ArrayList<Integer>();
|
||||||
|
|
||||||
while (root != null){
|
while (root != null) {
|
||||||
if(root.left ==null){
|
if (root.left == null) {
|
||||||
//如果左子树为空
|
//如果左子树为空
|
||||||
list1.add(root.val);
|
list1.add(root.val);
|
||||||
root=root.right;
|
root = root.right;
|
||||||
}else {
|
} else {
|
||||||
//如果左子树不为空:
|
//如果左子树不为空:
|
||||||
|
|
||||||
//记录左子树最右节点
|
//记录左子树最右节点
|
||||||
TreeNode p=root.left;
|
TreeNode p = root.left;
|
||||||
//寻找flag
|
//寻找flag
|
||||||
while (p.right !=null &&p.right != root){
|
while (p.right != null && p.right != root) {
|
||||||
p=p.right;
|
p = p.right;
|
||||||
}
|
}
|
||||||
TreeNode flag=p;
|
TreeNode flag = p;
|
||||||
|
|
||||||
//判断flag是根据什么条件出来的,是flag.right ==null还是p.right != root
|
//判断flag是根据什么条件出来的,是flag.right ==null还是p.right != root
|
||||||
if(flag.right == null){
|
if (flag.right == null) {
|
||||||
//flag无右子节点,第一次遍历
|
//flag无右子节点,第一次遍历
|
||||||
flag.right =root;
|
flag.right = root;
|
||||||
root=root.left;
|
root = root.left;
|
||||||
}else if(flag.right == root){
|
} else if (flag.right == root) {
|
||||||
//flag已经被加载过了,即当前节点的左子树已经被遍历完了
|
//flag已经被加载过了,即当前节点的左子树已经被遍历完了
|
||||||
flag.right =null;
|
flag.right = null;
|
||||||
list1.add(root.val);
|
list1.add(root.val);
|
||||||
root=root.right;
|
root = root.right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return list1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自己尝试Morris中序遍历
|
||||||
|
* 速度超过100%,内存超过81.82%
|
||||||
|
* @param root
|
||||||
|
*/
|
||||||
|
public static List<Integer> inorderTraversal4(TreeNode root) {
|
||||||
|
|
||||||
|
List<Integer> list1 = new ArrayList<Integer>();
|
||||||
|
|
||||||
|
TreeNode node1 = root;
|
||||||
|
TreeNode node2 = null;
|
||||||
|
|
||||||
|
while (node1 != null) {
|
||||||
|
node2 = node1.left;
|
||||||
|
|
||||||
|
//判断左边还有没有值
|
||||||
|
if(node2!=null){
|
||||||
|
//首先找到遍历node1之前的最后一个节点
|
||||||
|
while (node2.right != null && node2.right != node1) {
|
||||||
|
node2 = node2.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
//判断是从哪个条件出来的
|
||||||
|
if (node2.right == null) {
|
||||||
|
//如果是从第一个条件出来的,那么就是没有遍历过得节点
|
||||||
|
|
||||||
|
//将这个节点的右边定为node1方便以后回来,找到node1
|
||||||
|
node2.right = node1;
|
||||||
|
//node1已经可以回溯,放心将node1左移
|
||||||
|
node1 = node1.left;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
//如果是从第二个条件出来的,那么就是遍历过的节点
|
||||||
|
|
||||||
|
//那么他的左边一定是遍历完了,这时将node的值加入结果
|
||||||
|
list1.add(node1.val);
|
||||||
|
//左边遍历完了,往右移
|
||||||
|
node1 = node1.right;
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
//左边没值了
|
||||||
|
list1.add(node1.val);
|
||||||
|
node1=node1.right;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return list1;
|
return list1;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,211 @@
|
||||||
|
package com.markilue.leecode.tree;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.omg.CORBA.PUBLIC_MEMBER;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @BelongsProject: Leecode
|
||||||
|
* @BelongsPackage: com.markilue.leecode.tree
|
||||||
|
* @Author: dingjiawen
|
||||||
|
* @CreateTime: 2022-09-19 09:45
|
||||||
|
* @Description:
|
||||||
|
* TODO 力扣144题 二叉树的前序遍历:
|
||||||
|
* 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
|
||||||
|
* @Version: 1.0
|
||||||
|
*/
|
||||||
|
public class PreOrderTraversal {
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
|
||||||
|
TreeNode root = new TreeNode(1);
|
||||||
|
// TreeNode TreeNode2 = new TreeNode(2);
|
||||||
|
// TreeNode TreeNode3 = new TreeNode(3);
|
||||||
|
// TreeNode TreeNode4 = new TreeNode(1);
|
||||||
|
// TreeNode TreeNode5 = new TreeNode(3);
|
||||||
|
// TreeNode TreeNode6 = new TreeNode(5);
|
||||||
|
|
||||||
|
// root.setRight(TreeNode2);
|
||||||
|
// TreeNode2.setLeft(TreeNode3);
|
||||||
|
// TreeNode2.setLeft(TreeNode4);
|
||||||
|
// TreeNode2.setRight(TreeNode5);
|
||||||
|
// TreeNode3.setLeft(TreeNode6);
|
||||||
|
System.out.println(preorderTraversal1(root));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1(){
|
||||||
|
|
||||||
|
TreeNode root = new TreeNode(1);
|
||||||
|
TreeNode TreeNode2 = new TreeNode(2);
|
||||||
|
TreeNode TreeNode3 = new TreeNode(3);
|
||||||
|
// TreeNode TreeNode4 = new TreeNode(1);
|
||||||
|
// TreeNode TreeNode5 = new TreeNode(3);
|
||||||
|
// TreeNode TreeNode6 = new TreeNode(5);
|
||||||
|
|
||||||
|
root.setRight(TreeNode2);
|
||||||
|
TreeNode2.setLeft(TreeNode3);
|
||||||
|
// TreeNode2.setLeft(TreeNode4);
|
||||||
|
// TreeNode2.setRight(TreeNode5);
|
||||||
|
// TreeNode3.setLeft(TreeNode6);
|
||||||
|
System.out.println(preorderTraversal1(root));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test2(){
|
||||||
|
|
||||||
|
TreeNode root = new TreeNode(1);
|
||||||
|
TreeNode TreeNode2 = new TreeNode(2);
|
||||||
|
TreeNode TreeNode3 = new TreeNode(3);
|
||||||
|
// TreeNode TreeNode4 = new TreeNode(1);
|
||||||
|
// TreeNode TreeNode5 = new TreeNode(3);
|
||||||
|
// TreeNode TreeNode6 = new TreeNode(5);
|
||||||
|
|
||||||
|
root.setRight(TreeNode2);
|
||||||
|
TreeNode2.setLeft(TreeNode3);
|
||||||
|
// TreeNode2.setLeft(TreeNode4);
|
||||||
|
// TreeNode2.setRight(TreeNode5);
|
||||||
|
// TreeNode3.setLeft(TreeNode6);
|
||||||
|
System.out.println(preorderTraversal1(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test3(){
|
||||||
|
|
||||||
|
TreeNode root = new TreeNode(1);
|
||||||
|
TreeNode TreeNode2 = new TreeNode(2);
|
||||||
|
TreeNode TreeNode3 = new TreeNode(3);
|
||||||
|
TreeNode TreeNode4 = new TreeNode(4);
|
||||||
|
TreeNode TreeNode5 = new TreeNode(5);
|
||||||
|
TreeNode TreeNode6 = new TreeNode(6);
|
||||||
|
TreeNode TreeNode7 = new TreeNode(7);
|
||||||
|
|
||||||
|
root.setRight(TreeNode2);
|
||||||
|
root.setLeft(TreeNode3);
|
||||||
|
TreeNode2.setLeft(TreeNode4);
|
||||||
|
TreeNode2.setRight(TreeNode5);
|
||||||
|
TreeNode3.setRight(TreeNode6);
|
||||||
|
TreeNode3.setLeft(TreeNode7);
|
||||||
|
System.out.println(preorderTraversal2(root));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public List<Integer> preorderTraversal(TreeNode root) {
|
||||||
|
List<Integer> list = new ArrayList<>();
|
||||||
|
traversal(root, list);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自己的递归法
|
||||||
|
* 速度击败100% ,内存击败76.4%
|
||||||
|
*/
|
||||||
|
public void traversal(TreeNode root,List<Integer> list) {
|
||||||
|
|
||||||
|
if(root==null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
list.add(root.val);
|
||||||
|
traversal(root.left,list);
|
||||||
|
traversal(root.right,list);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自己的非递归法:使用一个栈记录上次还需要进一步遍历的节点,等现在的遍历完了,就可以出栈到这里,让上一次的继续去遍历
|
||||||
|
* 速度击败100%,内存击败18%
|
||||||
|
* @param root
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<Integer> preorderTraversal1(TreeNode root) {
|
||||||
|
List<Integer> list = new ArrayList<>();
|
||||||
|
|
||||||
|
if(root==null){
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
//使用栈记录需要遍历的root
|
||||||
|
Stack<TreeNode> stack = new Stack<>();
|
||||||
|
stack.push(root);
|
||||||
|
|
||||||
|
while (stack.size()>0){
|
||||||
|
TreeNode node = stack.pop();
|
||||||
|
list.add(node.val);
|
||||||
|
//如果右子树还需要遍历,等左子树遍历完了再遍历右子树
|
||||||
|
if(node.right!=null){
|
||||||
|
stack.push(node.right);
|
||||||
|
}
|
||||||
|
//如果左子树还需要遍历
|
||||||
|
if(node.left!=null){
|
||||||
|
stack.push(node.left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Morris 遍历:将空间复杂度降到O(1)
|
||||||
|
*Morris 遍历的核心思想是利用树的大量空闲指针,实现空间开销的极限缩减。其前序遍历规则总结如下:
|
||||||
|
*
|
||||||
|
* 1.新建临时节点,令该节点为 root;
|
||||||
|
* 2.如果当前节点的左子节点为空,将当前节点加入答案,并遍历当前节点的右子节点;
|
||||||
|
* 3.如果当前节点的左子节点不为空,在当前节点的左子树中找到当前节点在中序遍历下的前驱节点:
|
||||||
|
* 如果前驱节点的右子节点为空,将前驱节点的右子节点设置为当前节点。然后将当前节点加入答案,并将前驱节点的右子节点更新为当前节点。当前节点更新为当前节点的左子节点。
|
||||||
|
* 如果前驱节点的右子节点为当前节点,将它的右子节点重新设为空。当前节点更新为当前节点的右子节点。
|
||||||
|
* 4.重复步骤 2 和步骤 3,直到遍历结束。
|
||||||
|
*
|
||||||
|
* TODO 核心理念是如何回到root节点的:
|
||||||
|
* 1)传统方法使用stack去回到root
|
||||||
|
* 2)这种方法利用叶子结点闲置的右指针,因为回到root的前提是左边的遍历完了,那么遍历完了之前的一个节点一定是叶子节点,可以提前找到这个叶子结点,将其右指针置为root,就可以回到root了
|
||||||
|
*
|
||||||
|
* @param root
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public List<Integer> preorderTraversal2(TreeNode root) {
|
||||||
|
List<Integer> res = new ArrayList<Integer>();
|
||||||
|
if (root == null) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode p1 = root, p2 = null;
|
||||||
|
|
||||||
|
while (p1 != null) {
|
||||||
|
p2 = p1.left;
|
||||||
|
if (p2 != null) {
|
||||||
|
//通过这个循环找到回到root的最后一个节点,第二个条件是判断是否遍历过这个节点
|
||||||
|
while (p2.right != null && p2.right != p1) {
|
||||||
|
p2 = p2.right;
|
||||||
|
}
|
||||||
|
//从第一个条件出来的,证明这个节点没遍历过且是回到root前的最后一个节点
|
||||||
|
if (p2.right == null) {
|
||||||
|
res.add(p1.val);
|
||||||
|
//让下次得以回到之前遍历的节点
|
||||||
|
p2.right = p1;
|
||||||
|
//找到了回来的节点,放心的将root左移
|
||||||
|
p1 = p1.left;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
//从第二个条件出来的,证明这个节点遍历过了,那么就把他的右边置空
|
||||||
|
p2.right = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//左边遍历完了
|
||||||
|
res.add(p1.val);
|
||||||
|
}
|
||||||
|
p1 = p1.right;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue