leetcode
leetcode 1451 ~ 1500
奇偶树

奇偶树

难度:

标签:

题目描述

如果一棵二叉树满足下述几个条件,则可以称为 奇偶树

  • 二叉树根节点所在层下标为 0 ,根的子节点所在层下标为 1 ,根的孙节点所在层下标为 2 ,依此类推。
  • 偶数下标 层上的所有节点的值都是 整数,从左到右按顺序 严格递增
  • 奇数下标 层上的所有节点的值都是 整数,从左到右按顺序 严格递减

给你二叉树的根节点,如果二叉树为 奇偶树 ,则返回 true ,否则返回 false

 

示例 1:

输入:root = [1,10,4,3,null,7,9,12,8,6,null,null,2]
输出:true
解释:每一层的节点值分别是:
0 层:[1]
1 层:[10,4]
2 层:[3,7,9]
3 层:[12,8,6,2]
由于 0 层和 2 层上的节点值都是奇数且严格递增,而 1 层和 3 层上的节点值都是偶数且严格递减,因此这是一棵奇偶树。

示例 2:

输入:root = [5,4,2,3,3,7]
输出:false
解释:每一层的节点值分别是:
0 层:[5]
1 层:[4,2]
2 层:[3,3,7]
2 层上的节点值不满足严格递增的条件,所以这不是一棵奇偶树。

示例 3:

输入:root = [5,9,1,3,5,7]
输出:false
解释:1 层上的节点值应为偶数。

示例 4:

输入:root = [1]
输出:true

示例 5:

输入:root = [11,8,6,1,3,9,11,30,20,18,16,12,10,4,2,17]
输出:true

 

提示:

  • 树中节点数在范围 [1, 105]
  • 1 <= Node.val <= 106

代码结果

运行时间: 190 ms, 内存: 0.0 MB


/*
思路:
1. 由于Java的Stream API不适合直接处理二叉树的遍历,这里先使用BFS遍历树,将每一层的节点值收集为List。
2. 对于每一层使用Stream API进行奇偶性检查和顺序检查。
3. 如果发现任何一层不满足条件,返回false;否则,返回true。
*/

import java.util.*;
import java.util.stream.*;

public class Solution {
    public boolean isEvenOddTree(TreeNode root) {
        if (root == null) return true;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int level = 0;
        while (!queue.isEmpty()) {
            List<Integer> levelValues = new ArrayList<>();
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                levelValues.add(node.val);
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
            boolean valid = level % 2 == 0 ? 
                levelValues.stream().allMatch(v -> v % 2 != 0) && 
                IntStream.range(1, levelValues.size()).allMatch(i -> levelValues.get(i) > levelValues.get(i - 1)) :
                levelValues.stream().allMatch(v -> v % 2 == 0) && 
                IntStream.range(1, levelValues.size()).allMatch(i -> levelValues.get(i) < levelValues.get(i - 1));
            if (!valid) return false;
            level++;
        }
        return true;
    }
}

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

解释

方法:

该解法使用宽度优先搜索(BFS)来遍历二叉树的各层。使用一个队列来存储当前层的所有节点,并使用一个布尔变量 `isEvenLevel` 来标记当前层是否是偶数层。对于每层,我们使用一个变量 `prevVal` 来记录前一个节点的值以便进行比较。对于偶数层,所有节点的值应为奇数且严格递增;对于奇数层,所有节点的值应为偶数且严格递减。如果任何节点不符合这些条件,函数立即返回 `false`。如果成功遍历完整棵树,则返回 `true`。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在算法中,如何确保每一层的节点值都是按照题目要求的顺序(偶数层严格递增,奇数层严格递减)进行检查的?
在算法中,通过使用队列(queue)存储每一层的节点,并在遍历当前层的每个节点时,使用变量`prevVal`来记录当前层前一个节点的值。对于偶数层,检查当前节点值(`currVal`)是否比`prevVal`大并且是奇数;对于奇数层,检查当前节点值是否比`prevVal`小并且是偶数。这种方式确保了每一层的节点值都按照题目要求的递增或递减顺序进行比较和验证。
🦆
为什么在判断节点值是否符合当前层级要求时,使用了`prevVal < currVal`和`prevVal > currVal`的条件?
在偶数层,所有节点的值必须是奇数并且比前一个节点的值大,所以使用`prevVal < currVal`来确保值是递增的;在奇数层,所有节点的值必须是偶数并且比前一个节点的值小,所以使用`prevVal > currVal`来确保值是递减的。这些条件帮助确保每个节点的值不仅符合其奇偶性要求,还符合所在层级的顺序要求。
🦆
在BFS遍历中,节点值的奇偶性检查(`currVal % 2 == 1`或`currVal % 2 == 0`)为何要与节点值的比较顺序(递增或递减)同时进行?
这是因为题目特定地要求每一层的节点不仅遵守严格的递增或递减顺序,还要求节点值满足特定的奇偶性:偶数层的节点值必须是奇数,奇数层的节点值必须是偶数。因此,在遍历时,同时检查节点值的奇偶性和它们的递增或递减顺序,可以确保所有条件同时满足,从而验证树是否为一个有效的奇偶树。
🦆
为什么在处理每一层的节点时使用了`prevVal`初始化为`0`或`float('inf')`,这种初始化方式对算法的正确性有什么影响?
初始化`prevVal`为`0`或`float('inf')`是因为它们分别为偶数层和奇数层设定了一个起始比较值。对于偶数层,节点值需要是严格递增的奇数,因此从`0`(一个偶数)开始比较可以确保第一个节点值(必须是奇数)总是有效的。对于奇数层,由于节点值需要是严格递减的偶数,因此从无限大(`float('inf')`)开始可以确保第一个节点值(必须是偶数)总是有效的。这种方式是确保每层首个节点值检查的正确性,以及后续节点值能正确按照题目要求递增或递减。

相关问题