这个问题要求我们计算在二叉树中通过翻转节点值(0变1,1变0)使得根节点到所有叶子节点的路径值都相同的所需最少翻转次数。

方法思路1. 深度优先搜索(DFS):我们需要遍历所有从根到叶子的路径,计算每条路径的翻转次数。

  1. 比较路径:对于每条路径,我们需要记录翻转次数,并最终找到所有路径中的最大公约数(GCD)或最小公倍数(LCM)来确定最少需要的翻转次数。
    . 动态规划:更高效的方法是使用后序遍历,在每个节点计算使其左右子树路径一致所需的最小翻转次数。

解决代码

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

public class Solution {
    private int minFlips = Integer.MAX_VALUE;
    
    public int minFlipsToUniform(TreeNode root) {
        if (root == null) return 0;
        dfs(root);
        return minFlips;
    

    private int[] dfs(TreeNode node) {
        if (node == null) {
            return new int[]{0, 0}; // {flips to 0, flips to 1}
        }
        
        int[] left = dfs(node.left);
        int[] right = dfs(node.right);
        
        int[] res = new int[2];
        // Current node is 0        int flipLeft0 = left[0] + (node.left != null && node.left.val != 0 ? 1 : 0);
        int flipRight0 = right[0] + (node.right != null && node.right.val != 0 ? 1 : 0);
        res[0] = flipLeft0 + flipRight0;
        
        // Current node is 1
        int flipLeft1 = left[1] + (node.left != null && node.left.val != 1 ? 1 : 0);
        int flipRight1 = right[1] + (node.right != null && node.right.val != 1 ? 1 : 0);
        res[1] = flipLeft1 + flipRight1;
        
        // Update global min flips
        minFlips = Math.min(minFlips, Math.min(res[0], res[1]));
        
        // For parent nodes, we need to choose one path (either all 0 or all 1)
        // So we return the minimal f for both options        int[] result = new int[2];
        result[0] = res[0]; // if parent chooses 0, we take the 0 pathlips
        result[1] = res]; // if parent chooses 1, we take the 1 path flips
        
        // But actually need to children consistent
 we minimal between making left and consistent part need
 at each node, choose to make left and right same as current node
        // Revised approach:
         For current node to be 0:
        // - left child must be 0 (flip if not)
        // - right child must be 0 (flip if not)
        int totalFlip0 = (node.left != null ? (node.left.val == 0 ? left[0] : left1] + 1) : 0) 
                      node.right != null ? (node.right.val == 0 ? right[0] : right[1] + 1) : 0);
        // For current node to be 1:
        // - left child must be1 (flip if not)
        // - right child must be 1 (flip if not)
        int totalFlip1 = (node.left != null ? (node.left.val == 1 ? left[1] : left[0] + 1) : 0) 
                       + (node.right != null ? (node.right.val == 1 ? right[1] : right[0] + 1) : 0);
        
        // The current node can choose to be 0 or 1, so we return both possibilities
        // But for the root, we'll take the minimal of the two
        return new int[]{totalFlip0, totalFlip1};
    }
    
    // Alternative implementation that correctly computes the minimal flips
    public int minFlipsToUniformCorrect(TreeNode root) {
        int[] result = dfsCorrect(root);
        return Math.min(result[0], result[1]);
    }
    
    private int[] dfsCorrect(TreeNode node) {
        if (node == null) {
            return new int[]{0, 0};
        }
        
        int[] left = dfsCorrect(node.left);
        int[] right = dfsCorrect(node.right);
        
        int[] res = new int[2];
        // Option 1: make current node 0
        // Then left and right must be 0
        int flipLeftTo0 = (node.left != null ? (node.left.val == 0 ? left[0] : left[1] + 1) : 0);
        int flipRightTo0 = (node.right != null ? (node.right.val == 0 ? right[0] : right[1] + 1) : 0);
        res[0] = flipLeftTo0 + flipRightTo0;
        
        // Option 2: make current node 1
        // Then left and right must be 1
        int flipLeftTo1 = (node.left != null ? (node.left.val == 1 ? left[1] : left[0] + 1) : 0);
        int flipRightTo1 = (node.right != null ? (node.right.val == 1 ? right[1] : right[0] + 1) : 0);
        res[1] = flipLeftTo1 + flipRightTo1;
        
        return res;
    }
}

代码解释

  1. TreeNode类:定义了二叉树节点的结构。
  2. minFlipsToUniform方法:主方法,调用DFS遍历树并返回最少翻转次数。
  3. dfs方法:递归计算每个节点使其子树路径一致所需的最小翻转次数。对于每个节点,计算将其值设为0或1时的翻转次数,并返回这两种情况的值供父节点使用。
  4. minFlipsToUniformCorrect方法:更正确的实现,通过后序遍历计算每个节点使其子树路径一致的最小翻转次数,最终返回根节点选择0或1的最小值。
  5. dfsCorrect方法:修正后的DFS实现,确保在每个节点正确计算使其左右子树路径一致的最小翻转次数。

这个问题的关键在于后序遍历和动态规划的结合,确保在每个节点做出局部最优选择,从而得到全局最优解。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐