leecode更新

This commit is contained in:
dingjiawen 2022-09-20 13:42:55 +08:00
parent cbf03608b0
commit 2e5f398de6
3 changed files with 623 additions and 0 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}