94. 二叉树的中序遍历 - 力扣(LeetCode)
递归法,懂得都懂
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res=new ArrayList<>();
dfs(res,root);
return res;
}
public void dfs(List<Integer> res,TreeNode root)
{
if(root==null) return;
dfs(res,root.left);
res.add(root.val);
dfs(res,root.right);
}
}
迭代法
注意:stack!=null这样的判断是不正确的 因为stack对象已经被声明,永远都不会为空
stack==null
stack==null
:stack为引用类型。"=="操作符比较的是对象的引用,而不是对象的内容。
对于stack来说,初始化赋值给了 stack 变量。这意味着 stack 引用了一个新创建的 Stack 对象,stack 不再是 null。
正确写法:stack.size()>0
101. 对称二叉树 - 力扣(LeetCode)
对称二叉树定义: 对于树中 任意两个对称节点 L 和 R ,一定有:
L.val = R.val :即此两对称节点值相等。
L.left.val = R.right.val :即 L 的 左子节点 和 R 的 右子节点 对称。
L.right.val = R.left.val :即 L 的 右子节点 和 R 的 左子节点 对称。
根据以上规律,考虑从顶至底递归,判断每对左右节点是否对称,从而判断树是否为对称二叉树。
作者:Krahets
链接:https://leetcode.cn/problems/symmetric-tree/solutions/2361627/101-dui-cheng-er-cha-shu-fen-zhi-qing-xi-8oba/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null) return true;
return recur(root.left,root.right);
}
boolean recur(TreeNode L, TreeNode R) {
//到达叶子节点了
if (L == null && R == null) return true;
//有一个为空或者两个值不相等
if (L == null || R == null || L.val != R.val) return false;
//向下递归 同时要满足两个比较条件:左右孩子的外层相等 左右孩子的内层相等
return recur(L.left, R.right) && recur(L.right, R.left);
}
}
543. 二叉树的直径 - 力扣(LeetCode)
两个关键概念
链:从子树中的叶子节点到当前节点的路径。把最长链的长度,作为 dfs 的返回值。根据这一定义,空节点的链长是 −1,叶子节点的链长是 0。
递归过程中维护的是链长。
直径:等价于由两条(或者一条)链拼成的路径。我们枚举每个 node,假设直径在这里「拐弯」,也就是计算由左右两条从下面的叶子节点到 node 的链的节点值之和,去更新答案的最大值。
- 案一定是某个节点的(左子树深度 + 右子树深度)最大,那么就需要遍历每一个节点,假设答案为在此节点拐弯,维护出现过的最大值。
- 理解-1 +1 场景可以结合节点之间的连线。叶子结点以下已经没有节点,也就没有链条了,所以为0。但是为了递归回去的返回值与+1抵消,故返回-1。+1是为了补充子节点到本节点的这根连线。可以结合case2加深理解:
2.1. 叶子节点:下面已经无链条,下面的空节点返回 left = dfs(root.left) + 1 需要为0.
2.2. 叶子结点的上一个节点(case2即为根节点):下面只有一条链条,则为0 + 1 = 1. - 遍历每一个节点,假设最佳答案是在本节点做拐弯。那么需要 ans = Math.max(ans, left + right) 。注:子节点到本节点的连线已经在上面计算left、right时 +1补充了。
- dfs()的返回值。在本节点结束后,计算下一个节点(以下一个节点作为拐弯点),那么这个节点就只能是子节点场景(不能出现拐弯),返回此子节点的最长连线即 max(left, right)。
-
class Solution { private int ans; public int diameterOfBinaryTree(TreeNode root) { dfs(root); return ans; } private int dfs(TreeNode node) { if(node==null) return -1; int lLen=dfs(node.left)+1;//如果node是叶子节点就会是0 int rLen=dfs(node.right)+1; int length=lLen+rLen;//在本节点拐弯的最大链长 ans=Math.max(length,ans);//更新遇见过的最大链长 return Math.max(lLen, rLen); // 不在本节点拐弯,本节点下面的最大链长 } }
124. 二叉树中的最大路径和 - 力扣(LeetCode)
这道题很像,只不过上一道题dfs维护的是每个结点的最大链长,这道题要维护每个节点左右链和的最大值,以及用在每个节点拐弯的最大值来更新ans
class Solution {
private int ans=Integer.MIN_VALUE;//比负数更小 防止有出现在只有负数的树上为0
public int maxPathSum(TreeNode root) {
dfs(root);
return ans;
}
private int dfs(TreeNode node)
{
//dfs维护的是某节点的最长路径和
//ans维护的是 这棵树上的最大路径和
if(node==null) return 0;
int Lsum=dfs(node.left);
Lsum=Math.max(Lsum,0);//分支最大值为负数,则丢弃考虑分支
int Rsum=dfs(node.right);
Rsum=Math.max(Rsum,0);//分支最大值为负数,则丢弃考虑分支
int sum=node.val+Lsum+Rsum;//至少保证有一个结点
ans=Math.max(sum,ans);
return Math.max(Lsum+node.val,Rsum+node.val);
}
}
108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)
感觉是二分法。。
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return bfs(nums,0,nums.length-1);
}
private TreeNode bfs(int[] nums ,int left,int right)
{
//left可以等于right嘛?可以,模拟一下就知道了
if(left>right) return null;
//明确一下是左闭右闭区间
int mid=left+(right-left)/2;//防止溢出
TreeNode node=new TreeNode(nums[mid]);
node.left=bfs(nums,left,mid-1);
node.right=bfs(nums,mid+1,right);
return node;
}
}
230. 二叉搜索树中第 K 小的元素 - 力扣(LeetCode)
1.二叉搜索树用中序是递增数组。
2.这种找某一个值的,用一个全局变量来记录就好了。
class Solution {
private int res,count=0;
public int kthSmallest(TreeNode root, int k) {
//我的思路:暴力的话中序遍历一遍放到数组里,然后返回数组
//答案
// 递归遍历时计数,统计当前节点的序号。
// 递归到第 k 个节点时,应记录结果 res 。
// 记录结果后,后续的遍历即失去意义,应提前返回。
inOrder(root,k);
return res;
}
private void inOrder(TreeNode node,int k){
if(node==null) return;
inOrder(node.left,k);
count++;
if(count==k) res=node.val;
inOrder(node.right,k);
}
}
114. 二叉树展开为链表 - 力扣(LeetCode)
- 将左子树插入到右子树的地方
- 将原来的右子树接到左子树的最右边节点
- 考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null
层序遍历102. 二叉树的层序遍历 - 力扣(LeetCode)
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> queue =new LinkedList<>();
List<List<Integer>> res=new ArrayList<>();
if(root!=null) queue.add(root);
while(!queue.isEmpty()){
List<Integer> tmp=new ArrayList<>();
for(int i=queue.size();i>0;i--)
{
TreeNode node=queue.poll();
tmp.add(node.val);
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
res.add(tmp);
}
return res;
}
}
相同思想:199. 二叉树的右视图 - 力扣(LeetCode)
437. 路径总和 III - 力扣(LeetCode)
前缀和 与
多了一步,清除经过当前节点的状态 的回溯
体现在删除当前前缀和在map中的一次出现。
class Solution {
int ans = 0;
public int pathSum(TreeNode root, int targetSum) {
// 记录路径中某个前缀和出现的次数
Map<Long, Integer> map = new HashMap<>();
// 防止包含根节点的时候找不到
map.put(0L, 1);
// 开始搜索
dfs(root, map, 0L, targetSum);
// 返回值
return ans;
}
private void dfs(TreeNode node, Map<Long, Integer> map, Long curSum, int targetSum)
{
//curSum相当于k数组那道题的presum
if(node==null) return;
//记录结果
curSum += node.val;
ans+=map.getOrDefault(curSum-targetSum,0);
//先记录结果再加入自己
map.put(curSum,map.getOrDefault(curSum,0)+1);
dfs(node.left,map,curSum,targetSum);
dfs(node.right,map,curSum,targetSum);
//很重要的一点是回溯!!!!恢复map的状态意思是老子不在这走了!!
//curSum不用管因为是参数 把map中加好的curSUm删除即可
map.put(curSum, map.getOrDefault(curSum, 0)-1);
}
}