代码随想录第十五天|
Leetcode 102. 二叉树的层序遍历
题目链接: 二叉树的层序遍历
自己的思路:层序遍历的标准模板,其他的基本上都是在上面进行改动;基本思想就是用队列来存储每一层数的结点。
正确思路:队列。
代码:
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Queue<TreeNode> qe = new LinkedList<>();
if (root!=null) qe.add(root);
while(!qe.isEmpty()){
//记录当前队列中结点数量
int size = qe.size();
//存储每一层的数据
List<Integer> temp = new ArrayList<>();
while(size--!=0){
TreeNode node = qe.peek();
temp.add(node.val);
qe.poll();
//从左到右加入到队列中
if (node.left!=null) qe.add(node.left);
if (node.right!=null) qe.add(node.right);
}
res.add(temp);
}
return res;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
相似题型
Leetcode 107. 二叉树的层序遍历 II
题目链接: 二叉树的层序遍历 II
自己的思路:在模板的基础上增加了反转集合这一操作!
代码:
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
Queue<TreeNode> qe = new LinkedList<>();
if (root!=null) qe.add(root);
while(!qe.isEmpty()){
int size = qe.size();
List<Integer> temp = new ArrayList<>();
while(size--!=0){
TreeNode node = qe.peek();
qe.poll();
temp.add(node.val);
if (node.left!=null) qe.add(node.left);
if (node.right!=null) qe.add(node.right);
}
res.add(temp);
}
Collections.reverse(res);
return res;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
Leetcode 199. 二叉树的右视图
题目链接: 二叉树的右视图
自己的思路:在模版的基础上加了一个判断条件:if(size==0)就把数据加入到res中,因为是右视图,所以只需要把最右边的数据加入到数组里即可。
代码:
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
Queue<TreeNode> qe = new LinkedList<>();
if (root!=null) qe.add(root);
while(!qe.isEmpty()){
int size = qe.size();
while(size--!=0){
TreeNode node = qe.peek();
qe.poll();
if (size==0) res.add(node.val);
if (node.left!=null) qe.add(node.left);
if (node.right!=null) qe.add(node.right);
}
}
return res;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
Leetcode 637. 二叉树的层平均值
题目链接: 二叉树的层平均值
自己的思路:在模板的基础上加了一个求和除以队列长度的过程!
代码:
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<>();
Queue<TreeNode> qe = new LinkedList<>();
if (root!=null) qe.add(root);
while(!qe.isEmpty()){
int size = qe.size();
int temp = size;
double sum = 0.0;
while(size--!=0){
TreeNode node = qe.peek();
qe.poll();
sum += node.val;
if (node.left!=null) qe.add(node.left);
if (node.right!=null) qe.add(node.right);
}
res.add(sum/temp);
}
return res;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
Leetcode 429. N 叉树的层序遍历
题目链接: 叉树的层序遍历
自己的思路:在模板的基础上加个了多叉树,原理都一样,加一个for循环即可!
代码:
class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> res = new ArrayList<>();
Queue<Node> qe = new LinkedList<>();
if (root!=null) qe.add(root);
while(!qe.isEmpty()){
int size = qe.size();
List<Integer> temp = new ArrayList<>();
while(size--!=0){
Node node = qe.peek();
qe.poll();
temp.add(node.val);
List<Node> children = node.children;
for (Node cnode:children){
if (cnode!=null) qe.add(cnode);
}
}
res.add(temp);
}
return res;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
Leetcode 515. 在每个树行中找最大值
题目链接: 在每个树行中找最大值
自己的思路:在模板的基础上每一层定义一个临时变量保存最大值,然后加入到数组中!!
代码:
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
Queue<TreeNode> qe = new LinkedList<>();
if (root!=null) qe.add(root);
while(!qe.isEmpty()){
int size = qe.size();
//定义临时变量保存最大值
int temp = Integer.MIN_VALUE;
while(size--!=0){
TreeNode node = qe.peek();
qe.poll();
temp = Math.max(temp,node.val);
if (node.left!=null) qe.add(node.left);
if (node.right!=null) qe.add(node.right);
}
res.add(temp);
}
return res;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
Leetcode 116. 填充每个节点的下一个右侧节点指针
题目链接: 填充每个节点的下一个右侧节点指针
自己的思路:没想出来!!!
代码:
class Solution {
public Node connect(Node root) {
LinkedList<Node> qe = new LinkedList<>();
if (root!=null) qe.add(root);
while(!qe.isEmpty()){
//连接每一层的结点
int size = qe.size();
Node temp = qe.peek();
for (int i =1;i<size;i++){
temp.next = qe.get(i);
temp = qe.get(i);
}
while(size--!=0){
Node node = qe.peek();
qe.poll();
if (node.left!=null) qe.add(node.left);
if (node.right!=null) qe.add(node.right);
}
}
return root;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
上面的代码不满足常量级的空间复杂度,直接舍弃!!
代码:空间复杂度为1!!
class Solution {
public Node connect(Node root) {
if(root==null) {
return root;
}
Node pre = root;
//循环条件是当前节点的left不为空,当只有根节点
//或所有叶子节点都出串联完后循环就退出了
while(pre.left!=null) {
Node tmp = pre;
while(tmp!=null) {
//将tmp的左右节点都串联起来
tmp.left.next = tmp.right;
//下一个不为空说明上一层已经帮我们完成串联了
//连接下一层非同一根节点的Node
if(tmp.next!=null) {
tmp.right.next = tmp.next.left;
}
//继续右边遍历
tmp = tmp.next;
}
//从下一层的最左边开始遍历
pre = pre.left;
}
return root;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
1
)
\mathcal{O}(1)
O(1)
代码:递归!!!!
class Solution {
public Node connect(Node root) {
dfs(root);
return root;
}
public void dfs(Node node){
if (node==null) return;
Node left = node.left;
Node right = node.right;
while(left!=null){
left.next = right;
left = left.right;
right = right.left;
}
dfs(node.left);
dfs(node.right);
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
h
)
\mathcal{O}(h)
O(h)
h
h
h为树的深度
Leetcode 117. 填充每个节点的下一个右侧节点指针 II
题目链接: 填充每个节点的下一个右侧节点指针 II
正确思路:和116题有点类似,层序遍历的话可以直接照搬过来,但是第二种方法不可以,要进行一些改动,这里我们选择使用类似链表的方法将每一层连接起来!!!
代码:
class Solution {
public Node connect(Node root) {
if (root==null) return root;
Node pre = root;
while(pre!=null){
//定义一个虚拟节点来表示下一层第一个结点
Node dummy = new Node(0);
Node temp = dummy;
while(pre!=null){
//连接下一层
if (pre.left!=null){
temp.next = pre.left;
temp = temp.next;
}
if (pre.right!=null){
temp.next = pre.right;
temp = temp.next;
}
//当前层向右走,连接下一层
pre = pre.next;
}
//开始连接下一层的下一层
pre = dummy.next;
}
return root;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
1
)
\mathcal{O}(1)
O(1)
Leetcode 104. 二叉树的最大深度
题目链接: 二叉树的最大深度
自己的思路:在模板的基础上每遍历一层给res+1即可!!!
代码:
class Solution {
public int maxDepth(TreeNode root) {
int res = 0;
LinkedList<TreeNode> queue = new LinkedList<>();
if (root!=null) queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
while(size--!=0){
TreeNode node = queue.poll();
if (node.left!=null) queue.add(node.left);
if (node.right!=null) queue.add(node.right);
}
res++;
}
return res;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
Leetcode 111. 二叉树的最小深度
题目链接: 二叉树的最小深度
自己的思路:在模板的基础上加一个判断,如果当前节点的左右节点都为空,则说明到达最低点,返回最小深度即可!!
代码:
class Solution {
public int minDepth(TreeNode root) {
int res = 0;
LinkedList<TreeNode> queue = new LinkedList<>();
if (root!=null) queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
res++;
while(size--!=0){
TreeNode node = queue.poll();
if (node.left!=null) queue.add(node.left);
if (node.right!=null) queue.add(node.right);
//当左右结点都为空的时候,说明遍历到了最低点,直接返回即可
if (node.left==null&&node.right==null) return res;
}
}
return res;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
Leetcode 226. 翻转二叉树
题目链接: 翻转二叉树
自己的思路:没想到!!!
正确思路:假设当前结点为node,先交换左右结点,然后再递归交换下面的结点即可!!!不要想递归的本质!!!!没用!!!!!
递归代码:
class Solution {
public TreeNode invertTree(TreeNode root) {
//终止条件,当碰到空指针的时候结束递归
if (root==null) return root;
//交换两个节点
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
//然后再递归交换下面每个节点
invertTree(root.left);
invertTree(root.right);
return root;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
层序遍历代码:
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root==null) return root;
LinkedList<TreeNode> queue = new LinkedList<>();
if (root!=null) queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
while(size--!=0){
TreeNode node = queue.poll();
//交换当前结点的左右结点
TreeNode temp = node.left;
node.left = node.right;
node.right = temp;
if (node.left!=null) queue.add(node.left);
if (node.right!=null) queue.add(node.right);
}
}
return root;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
Leetcode 101. 对称二叉树
题目链接: 对称二叉树
自己的思路:没想到,递归方法一直做不好!!!多练!!!
递归正确思路:主要在于终止条件的判断以及单层递归的逻辑,终止条件就是除了两个结点的值相等之外的情况,因为如果两个结点的值相等的话,还需要继续向下递归比较下面的结点是否对称,其他情况直接就可以返回值,在进行单层递归的时候,一定要注意输入参数的顺序!!!
代码:
class Solution {
public boolean isSymmetric(TreeNode root) {
return recur(root.left,root.right);
}
public boolean recur(TreeNode left,TreeNode right){
//终止条件
if (left==null&&right!=null) return false;
else if (left!=null&&right==null) return false;
else if (left==null&&right==null) return true;
else if (left.val!=right.val) return false;
//当两个节点的值相等时,继续向下递归判断下面的子树是否是对称的
return recur(left.left,right.right)&&recur(left.right,right.left);
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
1
)
\mathcal{O}(1)
O(1)
层序遍历正确思路:主要思想是加入到队列中的二叉树节点的顺序,要按照需要比较的结点的顺序来,这样对队列进行poll的时候,可以正确的比较!!
代码:
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root==null) return true;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.add(root.left);
queue.add(root.right);
while(!queue.isEmpty()){
//需要比较的两个二叉树结点
TreeNode lnode = queue.poll();
TreeNode rnode = queue.poll();
//跳出当前循环的条件
if (lnode==null&&rnode==null) continue;
if (lnode==null||rnode==null) return false;
if (lnode.val!=rnode.val) return false;
//注意加入的顺序即是比较的顺序
queue.add(lnode.left);
queue.add(rnode.right);
queue.add(lnode.right);
queue.add(rnode.left);
}
return true;
}
}
复杂度分析:
时间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)
空间复杂度:
O
(
n
)
\mathcal{O}(n)
O(n)