序文
LeetCode の質問ブラッシングで遭遇したバイナリ ツリー関連の質問を記録します (パート 3)
1302. 層内の最も深いリーフ ノードの合計
最深層の maxDepth を維持しながらバイナリ ツリーをトラバースし、res を使用して最深層のノードの数値合計を維持します。
class Solution {
int maxDepth;
int res;
public void rec(TreeNode t,int depth){
if(t == null) return;
//遍历到比 maxDepth 更大的层数就更新maxDepth同时重置res
if(depth > maxDepth){
res = t.val;
maxDepth = depth;
}
else if(depth == maxDepth) res += t.val;
rec(t.left,depth + 1);
rec(t.right,depth + 1);
}
public int deepestLeavesSum(TreeNode root) {
maxDepth = -1;
rec(root,0);
return res;
}
}
404.左葉の和
public int sumOfLeftLeaves(TreeNode root) {
if(root == null) return 0;
//如何判断左叶子,从左叶子自身并不能知道它是左叶子,
//只能从父亲节点才能判断
if(root.left != null && root.left.left == null && root.left.right == null){
return root.left.val + sumOfLeftLeaves(root.right);
}
return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}
114. バイナリ ツリーをリンク リストに展開します
事前順序トラバーサルに基づいて、以前にトラバースしたノードも同時に維持され、現在のノードをトラバースする場合、前のノードの右側が現在のノードを指します。同時に、現在のノードの左側を null に設定する必要があり、左側のサブツリーがトラバースされると、現在のノードの右側が変更されるため、現在のノードの左右の子が最初に記録される必要があります。
class Solution {
TreeNode prv; //记录先序遍历时上一个访问的数
public void flatten(TreeNode root) {
if(root == null) return;
if(prv != null) prv.right = root;
prv = root;
TreeNode l = root.left;
TreeNode r = root.right;
root.left = null;
flatten(l);
flatten(r);
}
}
109. 順序付きリンクリストから二分探索木への変換
順序付きリンク リストの番号シーケンスは、実際には、変換された二分探索ツリーの順序トラバーサル シーケンスであるため、順序トラバーサルに基づいてツリーを構築できます。その過程で、上のノードの値は、リンク リストはノードに順番に割り当てられます。
ツリー構築の終点は、リンクリストの長さに応じて判断する必要があります。
class Solution {
ListNode list;
public TreeNode sortedListToBST(ListNode head) {
list = head;
int length = getLength(head);
return buildTree(0, length - 1);
}
public TreeNode buildTree(int left, int right) {
//当 left > right 其实就相当于遍历到了空结点,返回 null
if (left > right) {
return null;
}
//当[left,right]中只有偶数个数时,(left + right) >> 1 会取到两个中位数中偏小的那个数
//但应该取偏大的那个数,所以要 (left + right + 1) >> 1
//而当有奇数个数时,(left + right) >> 1 跟 (left + right + 1) >> 1是等价的
int mid = (left + right + 1) >> 1;
TreeNode root = new TreeNode();
root.left = buildTree(left, mid - 1);
root.val = list.val;
list = list.next;
root.right = buildTree(mid + 1, right);
return root;
}
//计算原有序链表的长度
public int getLength(ListNode head) {
int count = 0;
while (head != null) {
count++;
head = head.next;
}
return count;
}
}
199.二分木の右側面図
階層横断に基づいて、各層が最後の要素に到達すると、その値が res に追加されます。
class Solution {
private ArrayList<Integer> res = new ArrayList<>();
public List<Integer> rightSideView(TreeNode root) {
if(root != null){
TreeNode t = root;
LinkedList<TreeNode> queue = new LinkedList<>();
LinkedList<TreeNode> queue1 = new LinkedList<>();
queue.offer(t);
while(!queue.isEmpty()){
ArrayList<Integer> list = new ArrayList<>();
while(!queue.isEmpty()){
t = queue.poll();
//当弹出t后栈为空,说明t是当前这一层的最后一个元素,也就是题目要的右视图在这一层的元素,所以把他的值加入res
if(queue.isEmpty()) res.add(t.val);
if(t.left != null) queue1.offer(t.left);
if(t.right != null) queue1.offer(t.right);
}
while(!queue1.isEmpty()){
queue.offer(queue1.poll());
}
}
}
return res;
}
}
2 番目のブラシでは、次のバージョンのコードを作成しました。
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root != null){
TreeNode t = root;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.offer(t);
while(!queue.isEmpty()){
int size = queue.size();
for(int i = 0;i < size;i++){
t = queue.poll();
if(t.left != null) queue.offer(t.left);
if(t.right != null) queue.offer(t.right);
}
res.add(t.val);
}
}
return res;
}
コードの最初のバージョンとの違いは、最初のバージョンでは、この走査で新しく追加されたノードの次の層を走査せずにキューを走査するために、この走査で走査されたノードの情報を保存するために 2 番目のキューが使用されることです。子ノード、このトラバーサルの終了後にそれらの子ノードを元のキューに追加します。
2 番目のバージョンでは、トラバースする前にキュー内の要素の数だけをカウントします。これらの要素が今回トラバースするノードです。その数に従ってトラバースすれば、新しく追加されたノードをトラバースすることを恐れることはありません。
637. 二分木のレベル平均
class Solution {
private ArrayList<Double> res = new ArrayList<>();
public List<Double> averageOfLevels(TreeNode root) {
if(root != null){
TreeNode t = root;
LinkedList<TreeNode> queue = new LinkedList<>();
LinkedList<TreeNode> queue1 = new LinkedList<>();
queue.offer(t);
while(!queue.isEmpty()){
//tem记录每层所有节点值之和
Double tem = 0D;
//count记录每层结点个数
int count = 0;
while(!queue.isEmpty()){
t = queue.poll();
tem += t.val;
count++;
if(t.left != null) queue1.offer(t.left);
if(t.right != null) queue1.offer(t.right);
}
//每遍历完一层计算一个平均值加入res
res.add(tem / count);
while(!queue1.isEmpty()){
queue.offer(queue1.poll());
}
}
}
return res;
}
}
515. ツリーの各行の最大値を見つける
class Solution {
ArrayList<Integer> res = new ArrayList<>();
public List<Integer> largestValues(TreeNode root) {
if(root != null){
TreeNode t = root;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.offer(t);
while(!queue.isEmpty()){
//初始化最大值为最小值
int max = Integer.MIN_VALUE;
int count = queue.size();
for(int i = 1;i <= count;i++){
t = queue.poll();
//如果当前节点的值大于记录的最大值那么它的值就是新的最大值
max = t.val > max ? t.val : max;
if(t.left != null) queue.offer(t.left);
if(t.right != null) queue.offer(t.right);
}
res.add(max);
}
}
return res;
}
}
116. 各ノードの右隣のノードを記入します
class Solution {
private ArrayList<Integer> res = new ArrayList<>();
public Node connect(Node root) {
if(root != null){
Node t = root;
Node tem = null;
LinkedList<Node> queue = new LinkedList<>();
queue.offer(t);
while(!queue.isEmpty()){
int count = queue.size();
//先让t指向当前层次第一个结点,然后从第二个结点开始遍历,tem指向新遍历到的结点,让t的next指向tem,然后再往后移动t跟tem,相当于t为前一个结点,tem为当前结点,才可以连接起来
t = queue.poll();
if(t.left != null) queue.offer(t.left);
if(t.right != null) queue.offer(t.right);
for(int i = 2;i <= count;i++){
tem = queue.poll();
t.next = tem;
t = tem;
if(tem.left != null) queue.offer(tem.left);
if(tem.right != null) queue.offer(tem.right);
}
//从循环可以看出来遍历完最后一个结点时它的next还没设定,应该设为null
t.next = null;
}
}
return root;
}
}
117 の質問、同じアイデア、同じコード