LCP 26. 导航装置
小扣参加的秋日市集景区共有 $N$ 个景点,景点编号为 $1$~$N$。景点内设有 $N-1$ 条双向道路,使所有景点形成了一个二叉树结构,根结点记为 root
,景点编号即为节点值。
由于秋日市集景区的结构特殊,游客很容易迷路,主办方决定在景区的若干个景点设置导航装置,按照所在景点编号升序排列后定义装置编号为 1 ~ M。导航装置向游客发送数据,数据内容为列表 [游客与装置 1 的相对距离,游客与装置 2 的相对距离,...,游客与装置 M 的相对距离]
。由于游客根据导航装置发送的信息来确认位置,因此主办方需保证游客在每个景点接收的数据信息皆不相同。请返回主办方最少需要设置多少个导航装置。
示例 1:
输入:
root = [1,2,null,3,4]
输出:
2
解释:在景点 1、3 或景点 1、4 或景点 3、4 设置导航装置。
{:height="250px"}
示例 2:
输入:
root = [1,2,3,4]
输出:
1
解释:在景点 3、4 设置导航装置皆可。
{:height="200px"}
提示:
2 <= N <= 50000
1~N
的一个排列。原站题解
golang 解法, 执行用时: 264 ms, 内存消耗: 16.7 MB, 提交时间: 2023-10-25 23:24:22
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ var res int func navigation(root *TreeNode) int { /* 每个三叉点(该节点既有不为空的左右子树,又有父亲节点)的三条支路中,至少两条支路上有导航装置( */ res=0 if root==nil{ return 0 } left:=dfs(root.Left) right:=dfs(root.Right) //下面这行代码是多种状态综合处理的表现形式,具体如下: //左右孩子状态集(左右交换就不写了): //[0,0]:左右都没放导航(包含子树为空的情况),那么要必须放一个导航,即res+1,而且总共放一个导航; //[0,1]:一个孩子没放导航,再和根节点放一起,视为最近的三叉点的一条支路。由于另一个孩子状态为1,表示该三叉点有两条支路未放导航,所以还要再增加一个导航,那么res+1; //[0,2]:一个孩子没放导航,再和根节点放一起,视为最近的三叉点的一条支路。另一个孩子状态为2,表示该三叉点有两条支路已放导航,所以不用再增加导航,返回res即可; //[1,1]:其中一个孩子和根节点放一起,视为一条支路,那么就表示该合并后的支路上有导航(只要有就可以了),所以该三叉点的两条支路有导航,返回res即可; //[1,2]:前面同上,该三叉点的三条支路都有导航,返回res即可; //[2,2]:直接同上。 //综合上面分类情况,左右返回的状态值相加left+right>=2时,返回res即可,其他情况都要再加一个导航。 if left+right>=2{ return res } return res+1 } // 0 代表该点及孩子节点都不会放导航装置 // 1 代表左右孩子都没有导航装置时,必须选一个孩子支路放一个导航装置,另一个暂时不放,以1状态标记交上面节点去处理 // 2 表示左右孩子支路都有导航装置,该节点的父节点支路可以放也可以不放导航装置 func dfs(root *TreeNode)int{ if root==nil{ return 0 } left:=dfs(root.Left) right:=dfs(root.Right) //这里只要左右不为空,即为三叉点 if root.Left!=nil&&root.Right!=nil{ //左右子树都没放导航,那么必须选一条支路放一个导航,另一条支路暂时不放,返回状态1 if left==0&&right==0{ res+=1 return 1 } //一条支路有导航,另一条支路没有导航,继续暂时不放,返回状态1,要不要加交给上面节点来判断处理; if left==0||right==0{ return 1 } //左右孩子支路都有导航,那么就返回状态2 return 2 }else if root.Left==nil{ //左孩子为空,该节点状态等于右孩子 return right }else if root.Right==nil{ //like return left } return 0 }
golang 解法, 执行用时: 252 ms, 内存消耗: 12.8 MB, 提交时间: 2023-10-25 23:24:07
/** * Definition for a binary tree node. * type TreeNode struct { * Val int * Left *TreeNode * Right *TreeNode * } */ var res = 0 var s = 1 func dfs(root *TreeNode) bool { if root == nil { return false } l := dfs(root.Left) r := dfs(root.Right) if root.Left != nil && root.Right != nil { if !l && !r { res++ } if !(l && r) { s = 1 } else { s = 0 } return true } return l || r } func navigation(root *TreeNode) int { res = 0 s = 1 l := dfs(root.Left) r := dfs(root.Right) if l && r { return res } return res + s }
python3 解法, 执行用时: 984 ms, 内存消耗: 81.5 MB, 提交时间: 2023-10-25 23:23:43
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def navigation(self, root: TreeNode) -> int: def get(node): if node is None: return [0, 1, 1, 1] elif hasattr(node, 'result'): return node.result if not node.left and not node.right: result = [0, 1, 1, 1] elif not node.left or not node.right: result = get(node.left) if node.left else get(node.right) result[1] = min(result[0] + 1, result[3]) else: result = [0xffffffff] * 4 l, r = get(node.left), get(node.right) result[3] = min(l[1] + r[3], l[3] + r[1], l[2] + r[2]) result[2] = min(result[3], l[0] + r[2], l[2] + r[0]) result[1] = min(result[3], l[0] + r[3], l[3] + r[0]) result[0] = min(result[1], result[2], l[0] + r[2], l[2] + r[0]) setattr(node, 'result', result) return node.result return get(root)[1]
java 解法, 执行用时: 9 ms, 内存消耗: 56.2 MB, 提交时间: 2023-10-25 23:23:05
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { int res = 0; public int navigation(TreeNode root) { if (root == null) return 0; //根节点单独处理 int left = dfs(root.left); int right = dfs(root.right); //下面这行代码是多种状态综合处理的表现形式,具体如下: //左右孩子状态集(左右交换就不写了): //[0,0]:左右都没放导航(包含子树为空的情况),那么要必须放一个导航,即res+1,而且总共放一个导航; //[0,1]:一个孩子没放导航,再和根节点放一起,视为最近的三叉点的一条支路。由于另一个孩子状态为1,表示该三叉点有两条支路未放导航,所以还要再增加一个导航,那么res+1; //[0,2]:一个孩子没放导航,再和根节点放一起,视为最近的三叉点的一条支路。另一个孩子状态为2,表示该三叉点有两条支路已放导航,所以不用再增加导航,返回res即可; //[1,1]:其中一个孩子和根节点放一起,视为一条支路,那么就表示该合并后的支路上有导航(只要有就可以了),所以该三叉点的两条支路有导航,返回res即可; //[1,2]:前面同上,该三叉点的三条支路都有导航,返回res即可; //[2,2]:直接同上。 //综合上面分类情况,左右返回的状态值相加left+right>=2时,返回res即可,其他情况都要再加一个导航。 if(left + right >= 2){ return res; } return res + 1; } public int dfs(TreeNode root) { //为空时,表示没放导航 if (root == null) return 0; int left = dfs(root.left); int right = dfs(root.right); //由于上面根节点单独处理,所以这里只要左右不为空,即为三叉点 if (root.left != null && root.right != null) { //左右子树都没放导航,那么必须选一条支路放一个导航,另一条支路暂时不放,返回状态1; if(left == 0 && right == 0){ res += 1; return 1; } //一条支路有导航,另一条支路没有导航,继续暂时不放,返回状态1,要不要加交给上面节点来判断处理; //这里多说一句,由于该三叉节点一条有导航另一条没导航,那么对于之前已经遍历的下面的三叉点来说,相当于它的父节点支路有导航了,所以当时处理它时,是否有一条支路未放导航就无所谓了; if(left == 0 || right == 0){ return 1; } //左右孩子支路都有导航,那么就返回状态2 return 2; }else if(root.left == null){//左孩子为空,该节点状态等于右孩子,或者说把最近的三叉点状态往上传递 return right; }else if(root.right == null){//同上理 return left; } //由于编译器的原因,加这么一句,这里是你永远到不了的地方 return 0; } }
python3 解法, 执行用时: 676 ms, 内存消耗: 80.4 MB, 提交时间: 2023-10-25 23:22:37
# Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def navigation(self, root: TreeNode) -> int: self.res = 0 self.s = 1 # 根是否要加一个 def dfs(node): if not node: return False l = dfs(node.left) r = dfs(node.right) # 这是一个三叉 if node.left and node.right: # 左右如果目前都没有,那必须左右至少有一个 if (not l) and (not r): self.res += 1 # 左右不是俩都有,那无论如何根得加一个 if not (l and r): self.s = 1 else: self.s = 0 return True return l or r l = dfs(root.left) r = dfs(root.right) # 如果左右都有,根就不需要了 if l and r: return self.res # 如果左右只有一个,那么我们就拿那棵没有的树当父树然后 + s(对父树有需求+1,没需求不加) else: return self.res + self.s
cpp 解法, 执行用时: 436 ms, 内存消耗: 283.8 MB, 提交时间: 2023-10-25 23:22:19
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: int res = 0, s = 1; int dfs(TreeNode* root) { if(!root) { return 0; } int l = dfs(root->left), r = dfs(root->right); if(root->left && root->right) { res += !l && !r; s = !(l && r); return 1; } return l || r; } int navigation(TreeNode* root) { int l = dfs(root->left), r = dfs(root->right); return res + ((l && r)? 0 : s); } };