leecode更新
This commit is contained in:
parent
cbf03608b0
commit
2e5f398de6
|
|
@ -0,0 +1,171 @@
|
|||
package com.markilue.leecode.tree;
|
||||
|
||||
import org.junit.Test;
|
||||
import sun.security.krb5.internal.CredentialsUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.tree
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-09-20 11:44
|
||||
* @Description: TODO 力扣102题:二叉树的层序遍历:
|
||||
* 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class LevelOrder {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
TreeNode root = new TreeNode(3);
|
||||
TreeNode TreeNode2 = new TreeNode(9);
|
||||
TreeNode TreeNode3 = new TreeNode(20);
|
||||
// TreeNode TreeNode4 = new TreeNode(4);
|
||||
// TreeNode TreeNode5 = new TreeNode(5);
|
||||
TreeNode TreeNode6 = new TreeNode(15);
|
||||
TreeNode TreeNode7 = new TreeNode(7);
|
||||
|
||||
root.setRight(TreeNode3);
|
||||
root.setLeft(TreeNode2);
|
||||
// TreeNode2.setLeft(TreeNode4);
|
||||
// TreeNode2.setRight(TreeNode5);
|
||||
TreeNode3.setRight(TreeNode7);
|
||||
TreeNode3.setLeft(TreeNode6);
|
||||
|
||||
System.out.println(levelOrder(root));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
|
||||
TreeNode root = new TreeNode(1);
|
||||
TreeNode TreeNode2 = new TreeNode(9);
|
||||
TreeNode TreeNode3 = new TreeNode(20);
|
||||
// TreeNode TreeNode4 = new TreeNode(4);
|
||||
// TreeNode TreeNode5 = new TreeNode(5);
|
||||
TreeNode TreeNode6 = new TreeNode(15);
|
||||
TreeNode TreeNode7 = new TreeNode(7);
|
||||
|
||||
// root.setRight(TreeNode3);
|
||||
// root.setLeft(TreeNode2);
|
||||
//// TreeNode2.setLeft(TreeNode4);
|
||||
//// TreeNode2.setRight(TreeNode5);
|
||||
// TreeNode3.setRight(TreeNode7);
|
||||
// TreeNode3.setLeft(TreeNode6);
|
||||
|
||||
System.out.println(levelOrder(root));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 这里尝试使用之前统一的空指针标记法(将其换成队列):难点在于如何找到下一层的第一个节点
|
||||
* 速度超过58.94%,内存超过37.04%
|
||||
*
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
List<Integer> mid = new ArrayList<>();
|
||||
TreeNode pre = root;
|
||||
//是否需要找下一层
|
||||
boolean flag = true;
|
||||
|
||||
while (deque.size() > 0) {
|
||||
TreeNode node = deque.peek();
|
||||
|
||||
//遍历到了下一层
|
||||
if (pre == node && !flag) {
|
||||
result.add(mid);
|
||||
mid = new ArrayList<Integer>();
|
||||
//需要找到一个不为0的值了
|
||||
flag = true;
|
||||
}
|
||||
|
||||
|
||||
if (node != null) {
|
||||
//访问过还未处理
|
||||
deque.addFirst(null);
|
||||
|
||||
if (node.left != null) {
|
||||
deque.addLast(node.left);
|
||||
//记录下层的第一个指针
|
||||
if (flag) {
|
||||
pre = node.left;
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.right != null) {
|
||||
deque.addLast(node.right);
|
||||
//记录下层的第一个指针
|
||||
if (flag) {
|
||||
pre = node.right;
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//处理访问数据
|
||||
deque.poll();//移除空指针
|
||||
mid.add(deque.poll().val);
|
||||
}
|
||||
}
|
||||
|
||||
if (mid.size() != 0) {
|
||||
result.add(mid);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 官方队列法:使用了固定的size从而避免了找下一次的第一个值
|
||||
* 速度超过100%,内存超过81%
|
||||
*
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<List<Integer>> levelOrder1(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,282 @@
|
|||
package com.markilue.leecode.tree;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.tree
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-09-19 09:45
|
||||
* @Description: TODO 力扣144题 二叉树的前序遍历:
|
||||
* 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class PostOrderTraversal {
|
||||
|
||||
|
||||
@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(postorderTraversal1(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(postorderTraversal1(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(postorderTraversal1(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(postorderTraversal4(root));
|
||||
}
|
||||
|
||||
|
||||
public List<Integer> postorderTraversal(TreeNode root) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
traversal(root, list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自己的递归法
|
||||
* 速度击败100% ,内存击败44.85%
|
||||
*/
|
||||
public void traversal(TreeNode root, List<Integer> list) {
|
||||
|
||||
if (root == null) {
|
||||
return;
|
||||
}
|
||||
traversal(root.left, list);
|
||||
traversal(root.right, list);
|
||||
list.add(root.val);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 自己的非递归法:使用一个栈记录上次还需要进一步遍历的节点,等现在的遍历完了,就可以出栈到这里,让上一次的继续去遍历
|
||||
* 速度击败100%,内存击败90.34%
|
||||
*
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<Integer> postorderTraversal1(TreeNode root) {
|
||||
|
||||
List<Integer> result = new ArrayList<>();
|
||||
Stack<TreeNode> stack = new Stack<>();
|
||||
TreeNode cur = root;
|
||||
|
||||
while (cur != null || stack.size() > 0) {
|
||||
|
||||
//判断是什么条件进来的
|
||||
if (cur != null) {
|
||||
stack.push(cur);
|
||||
cur = cur.left;
|
||||
continue;
|
||||
}else {
|
||||
TreeNode node = stack.peek();
|
||||
//看看他右边还有没有
|
||||
if (node.right != null) {
|
||||
//右边还有,让右边的在继续遍历
|
||||
cur = node.right;
|
||||
//置空防止再次还来遍历
|
||||
node.right=null;
|
||||
} else {
|
||||
//左右都没有了,直接加入结果
|
||||
result.add(node.val);
|
||||
stack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 代码随想录的非递归法:与前序遍历的非递归法类似,前序是中-左-右;后序是左-右-中,因此可以把前序的顺序稍微变一下变成中-右-左,最后的结果再反转一下即可
|
||||
* 速度击败100%,内存击败90.34%
|
||||
*
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<Integer> postorderTraversal3(TreeNode root) {
|
||||
|
||||
ArrayList<Integer> result = new ArrayList<>();
|
||||
Stack<TreeNode> stack = new Stack<>();
|
||||
stack.push(root);
|
||||
|
||||
while (stack.size()>0){
|
||||
TreeNode node = stack.pop();
|
||||
result.add(node.val);
|
||||
if(node.left!=null){
|
||||
stack.push(node.left);
|
||||
}
|
||||
if(node.right!=null){
|
||||
stack.push(node.right);
|
||||
}
|
||||
}
|
||||
|
||||
//反转list
|
||||
ArrayList<Integer> realList = new ArrayList<>();
|
||||
|
||||
for (int i = result.size()-1; i >=0 ; i--) {
|
||||
realList.add(result.get(i));
|
||||
}
|
||||
|
||||
return realList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 官方Morris 遍历:将空间复杂度降到O(1)
|
||||
* TODO 这里实际上就是将前序遍历的顺序稍微变一下中-右-左 最后的结果再反转
|
||||
*
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<Integer> postorderTraversal2(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) {
|
||||
while (p2.right != null && p2.right != p1) {
|
||||
p2 = p2.right;
|
||||
}
|
||||
if (p2.right == null) {
|
||||
p2.right = p1;
|
||||
p1 = p1.left;
|
||||
continue;
|
||||
} else {
|
||||
p2.right = null;
|
||||
addPath(res, p1.left);
|
||||
}
|
||||
}
|
||||
p1 = p1.right;
|
||||
}
|
||||
addPath(res, root);
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void addPath(List<Integer> res, TreeNode node) {
|
||||
int count = 0;
|
||||
while (node != null) {
|
||||
++count;
|
||||
res.add(node.val);
|
||||
node = node.right;
|
||||
}
|
||||
//反转左右
|
||||
int left = res.size() - count, right = res.size() - 1;
|
||||
while (left < right) {
|
||||
int temp = res.get(left);
|
||||
res.set(left, res.get(right));
|
||||
res.set(right, temp);
|
||||
left++;
|
||||
right--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 官方不改变指针的非递归法
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<Integer> postorderTraversal4(TreeNode root) {
|
||||
List<Integer> res = new ArrayList<Integer>();
|
||||
if (root == null) {
|
||||
return res;
|
||||
}
|
||||
|
||||
Deque<TreeNode> stack = new LinkedList<TreeNode>();
|
||||
TreeNode prev = null;
|
||||
while (root != null || !stack.isEmpty()) {
|
||||
while (root != null) {
|
||||
stack.push(root);
|
||||
root = root.left;
|
||||
}
|
||||
root = stack.pop();
|
||||
//第二个条件表示右边的节点是上一次pop出的节点,因为只有pop出的值才会在prev赋值
|
||||
if (root.right == null || root.right == prev) {
|
||||
res.add(root.val);
|
||||
prev = root;
|
||||
root = null;
|
||||
} else {
|
||||
stack.push(root);
|
||||
root = root.right;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
package com.markilue.leecode.tree;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* @BelongsProject: Leecode
|
||||
* @BelongsPackage: com.markilue.leecode.tree
|
||||
* @Author: dingjiawen
|
||||
* @CreateTime: 2022-09-20 11:13
|
||||
* @Description:
|
||||
* TODO stack栈法(一种迭代法)来统一解决前中后序遍历:使用空指针标记法来统一前中后遍历的迭代法
|
||||
* @Version: 1.0
|
||||
*/
|
||||
public class StackUnitTraversal {
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
|
||||
TreeNode root = new TreeNode(5);
|
||||
TreeNode TreeNode4 = new TreeNode(4);
|
||||
TreeNode TreeNode6 = new TreeNode(6);
|
||||
TreeNode TreeNode1 = new TreeNode(1);
|
||||
TreeNode TreeNode2 = new TreeNode(2);
|
||||
root.setRight(TreeNode6);
|
||||
root.setLeft(TreeNode4);
|
||||
TreeNode4.setLeft(TreeNode1);
|
||||
TreeNode4.setRight(TreeNode2);
|
||||
|
||||
|
||||
System.out.println(preorderTraversal(root));
|
||||
}
|
||||
|
||||
/*
|
||||
*空指针标记法的中序遍历
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<Integer> inorderTraversal(TreeNode root) {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
|
||||
//使用栈记录需要遍历的root
|
||||
Stack<TreeNode> stack = new Stack<>();
|
||||
if (root != null) {
|
||||
stack.push(root);
|
||||
}
|
||||
|
||||
//栈中数据:[6,5,null,2,4,null,1,null]
|
||||
while (stack.size() > 0) {
|
||||
TreeNode node = stack.peek();
|
||||
|
||||
if(node!=null){
|
||||
//将该节点弹出,避免重复操作,下面再将右、中、左节点添加到栈中
|
||||
stack.pop();
|
||||
//添加右节点(空节点不入栈)
|
||||
if(node.right!=null){
|
||||
stack.push(node.right);
|
||||
}
|
||||
|
||||
//添加中节点
|
||||
stack.push(node);
|
||||
//中指针访问过,但没有处理,添加空指针节点作为标记
|
||||
stack.push(null);
|
||||
//添加左节点(空节点不入栈)
|
||||
if(node.left!=null){
|
||||
stack.push(node.left);
|
||||
}
|
||||
}else {
|
||||
//只有遇到空节点的时候,才将下一个节点放入结果集
|
||||
stack.pop();//将空指针弹出
|
||||
node = stack.pop(); //重新取出栈中元素
|
||||
result.add(node.val);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*空指针标记法的前序遍历
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<Integer> preorderTraversal(TreeNode root) {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
|
||||
//使用栈记录需要遍历的root
|
||||
Stack<TreeNode> stack = new Stack<>();
|
||||
if (root != null) {
|
||||
stack.push(root);
|
||||
}
|
||||
|
||||
//栈中数据:[6,4,5,null]
|
||||
//栈中数据:[6,2,1,4,null]
|
||||
while (stack.size() > 0) {
|
||||
TreeNode node = stack.peek();
|
||||
|
||||
if(node!=null){
|
||||
//将该节点弹出,避免重复操作,下面再将右、中、左节点添加到栈中
|
||||
stack.pop();
|
||||
//添加右节点(空节点不入栈)
|
||||
if(node.right!=null){
|
||||
stack.push(node.right);
|
||||
}
|
||||
//添加左节点(空节点不入栈)
|
||||
if(node.left!=null){
|
||||
stack.push(node.left);
|
||||
}
|
||||
//添加中节点
|
||||
stack.push(node);
|
||||
//中指针访问过,但没有处理,添加空指针节点作为标记
|
||||
stack.push(null);
|
||||
}else {
|
||||
//只有遇到空节点的时候,才将下一个节点放入结果集
|
||||
stack.pop();//将空指针弹出
|
||||
node = stack.pop(); //重新取出栈中元素
|
||||
result.add(node.val);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*空指针标记法的后序遍历
|
||||
* @param root
|
||||
* @return
|
||||
*/
|
||||
public List<Integer> postorderTraversal(TreeNode root) {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
|
||||
//使用栈记录需要遍历的root
|
||||
Stack<TreeNode> stack = new Stack<>();
|
||||
if (root != null) {
|
||||
stack.push(root);
|
||||
}
|
||||
|
||||
//栈中数据:[5,null,6,4,null,2,1,null]
|
||||
while (stack.size() > 0) {
|
||||
TreeNode node = stack.peek();
|
||||
|
||||
if(node!=null){
|
||||
//将该节点弹出,避免重复操作,下面再将右、中、左节点添加到栈中
|
||||
stack.pop();
|
||||
//添加中节点
|
||||
stack.push(node);
|
||||
//中指针访问过,但没有处理,添加空指针节点作为标记
|
||||
stack.push(null);
|
||||
//添加右节点(空节点不入栈)
|
||||
if(node.right!=null){
|
||||
stack.push(node.right);
|
||||
}
|
||||
//添加左节点(空节点不入栈)
|
||||
if(node.left!=null){
|
||||
stack.push(node.left);
|
||||
}
|
||||
|
||||
}else {
|
||||
//只有遇到空节点的时候,才将下一个节点放入结果集
|
||||
stack.pop();//将空指针弹出
|
||||
node = stack.pop(); //重新取出栈中元素
|
||||
result.add(node.val);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue