Problem
LeetCode 968. Binary Tree Cameras
1. 题目简述
给出一棵二叉树,我们向节点中加入camera,每个节点可以监控其父节点和左右孩子,求最少需要多少个camera才能监控整棵树(节点不大于1000个,每个节点的value都是0)。例如:
Input: [0,0,null,0,null,0,null,null,0]
Output: 2
Explanation: At least two cameras are needed to monitor all nodes of the tree. The above image shows one of the valid configurations of camera placement.
2. 算法思路
Greedy:
这道题完全没思路,直接看了solution,DP解法没看懂,直接看的Greedy,逻辑思路如下。
对于任何一个节点,它都有两种状态,有camera和没camera,其中没camera又分为两种,一种是它已经被covered了,另一种是还没有。所以一共是有三种状态。我们假设某节点和其左右孩子都需要被cover,那么我们首选肯定是在父节点放入camera,这样它才能辐射范围更广,而不是需要两个孩子放camera,camera更多。所以我们的核心策略就是尽可能把camera设置到上层,而不是叶子节点。
首先我们的定义一个节点的三种状态:
- 有camera – 2
- 无camera但是被cover了 – 1
- 无camera并且需要父亲节点carry – 0
对于null节点,我们不需要考虑,所以其状态为1。
所以逻辑如下:
- 如果当前节点的左右孩子有一个为2(有camera),则当前节点为1;
- 如果当前节点的左右孩子有一个为0(无camera,需要父亲带飞),则当前节点为2;
- 如果当前节点的左右孩子都为1(都不用父亲carry),则当前节点期待父节点carry,当前节点为0;
- 如果根节点为0(没被孩子带飞),则result+1。
时间复杂度为O(n),空间复杂度O(h)。h为树的高度。
3. 解法
- Greedy
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
int res = 0;
public int minCameraCover(TreeNode root) {
return getCameraState(root) == 0 ? res + 1: res;
}
private int getCameraState(TreeNode node) {
if (node == null) {
return 1;
}
int leftState = getCameraState(node.left);
int rightState = getCameraState(node.right);
if (leftState == 1 && rightState == 1) {
return 0; // 当前节点不放camera,期待被父亲carry
} else if (leftState == 0 || rightState == 0) {
res++;
return 2; // 当前节点的孩子节点存在0状态,所以需要放一个camera
} else { // 当前节点的孩子至少有一个2
return 1;
}
}
}
