二叉树着色游戏
题目描述
有两位极客玩家参与了一场「二叉树着色」的游戏。游戏中,给出二叉树的根节点 root,树上总共有 n 个节点,且 n 为奇数,其中每个节点上的值从 1 到 n 各不相同。
最开始时:
「一号」玩家从 [1, n] 中取一个值 x(1 <= x <= n);
「二号」玩家也从 [1, n] 中取一个值 y(1 <= y <= n)且 y != x。
「一号」玩家给值为 x 的节点染上红色,而「二号」玩家给值为 y 的节点染上蓝色。
之后两位玩家轮流进行操作,「一号」玩家先手。每一回合,玩家选择一个被他染过色的节点,将所选节点一个 未着色 的邻节点(即左右子节点、或父节点)进行染色(「一号」玩家染红色,「二号」玩家染蓝色)。
如果(且仅在此种情况下)当前玩家无法找到这样的节点来染色时,其回合就会被跳过。
若两个玩家都没有可以染色的节点时,游戏结束。着色节点最多的那位玩家获得胜利 ✌️。
现在,假设你是「二号」玩家,根据所给出的输入,假如存在一个 y 值可以确保你赢得这场游戏,则返回 true ;若无法获胜,就请返回 false 。
样例
样例输入
root = [1,2,3,4,5,6,7,8,9,10,11], n = 11, x = 3
root = [1,2,3], n = 3, x = 1
样例输出
true 第二个玩家可以选择值为 2 的节点。
false
提示
- 树中节点数目为 n
- 1 <= x <= n <= 100
- n 是奇数
- 1 <= Node.val <= n
- 树中所有值 互不相同
思路
贪心思想
最初的思想为,y需要取最大值,如果是一般二叉树,无非就是y的第一步取x的父结点。(然后就错了)。
第一个测试用例有误导,其实如果后手y要赢,第一步应该直接取1,这样y能够染色的区域最大。就是把x的父节点,左子节点,右子节点中的可以染色最多一条通道直接堵死(也就是y取最大的染色数),如果y能够大于1+另外两条通道的染色数量即为true,否则false。
代码实现
写的丑了点,两个dfs其实可以合并起来,最初是这样写的,最后也就到这基础上改。
/**
* 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 {
TreeNode aim;
public boolean btreeGameWinningMove(TreeNode root, int n, int x) {
if(root.val == x) return n > (Math.min(dfs(root.left), dfs(root.right)) + 1) << 1;
query(root, x);
int[] ans = new int[3];
ans[0] = dfs(aim.left);
ans[1] = dfs(aim.right);
ans[2] = n - (1 + ans[0] + ans[1]);
Arrays.sort(ans);
return ans[2] - ans[1] - ans[0] - 1 > 0;
}
// 查找x
private void query(TreeNode cur, int x){
if(cur == null) return ;
if(cur.val == x) aim = cur;
query(cur.left, x);
query(cur.right, x);
}
// 求当前结点与当前结点的子树和。
private int dfs(TreeNode cur){
if(cur == null) return 0;
return 1 + dfs(cur.left) + dfs(cur.right);
}
}