leetcode863. 二叉树中所有距离为 K 的结点

leetcode863. 二叉树中所有距离为 K 的结点

三月 22, 2020

leetcode863. 二叉树中所有距离为 K 的结点


给定一个二叉树(具有根结点 root), 一个目标结点 target ,和一个整数值 K 。

返回到目标结点 target 距离为 K 的所有结点的值的列表。 答案可以以任何顺序返回。

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], target = 5, K = 2

输出:[7,4,1]

解释:
所求结点为与目标结点(值为 5)距离为 2 的结点,
值分别为 7,4,以及 1
在这里插入图片描述
提示:

  • 给定的树是非空的,且最多有 K 个结点。
  • 树上的每个结点都具有唯一的值 0 <= node.val <= 500 。
  • 目标结点 target 是树上的结点。
  • 0 <= K <= 1000.

思路一:转化成图,再变成bfs

遍历一次树,主要是为了把当前节点的父节点记录下来,这样bfs时候可以访问到父节点了.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class Solution {
HashMap<TreeNode,TreeNode>map=new HashMap<>();
ArrayList<Integer>list=new ArrayList<>();
public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
init(root,null);
Queue<TreeNode>queue=new LinkedList<>();
queue.offer(target);
Set<TreeNode>set=new HashSet<>();
set.add(target);//set防止重复访问某个节点

while(!queue.isEmpty()){
int size=queue.size();
if(K==0){
for(TreeNode node:queue){
list.add(node.val);
}
}
for(int i=0;i<size;i++){
TreeNode node=queue.poll();
if(node.left!=null&&!set.contains(node.left)){
queue.offer(node.left);
set.add(node.left);
}
if(node.right!=null&&!set.contains(node.right)){
queue.offer(node.right);
set.add(node.right);
}
if(map.get(node)!=null&&!set.contains(map.get(node))){
queue.offer(map.get(node));
set.add(map.get(node));
}
}
K--;
}
return list;
}
public void init(TreeNode curNode,TreeNode parent){
if(curNode==null)return;
map.put(curNode,parent);
init(curNode.left,curNode);
init(curNode.right,curNode);
}
}

思路二:霍夫曼树

看到评论区有提示说霍夫曼树,我试着写了一下,左子树代表 1,右子树代表 3 .用字符串表示每个节点的编号,任意两个节点之间的距离需要用前缀计算.
比如 113,和 131.前缀是1,所以是13(两位)+31(两位)=4(位).我是一条边一个编号,根节点编号为””.也就是空字符串.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class Solution {
HashMap<TreeNode,String>map=new HashMap<>();
public TreeNode targetNode=null;
public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
map.put(root,"");
init(root,"");
return traverse(target,map.get(target),K);

}
public List<Integer> traverse(TreeNode target,String targetString,int k){
ArrayList<Integer>list=new ArrayList<>();
for(TreeNode key:map.keySet()){
int diff=diff(map.get(key),targetString);//计算路径
if(diff==k)list.add(key.val);
}
return list;
}
public int diff(String s1,String s2){
int length=Math.min(s1.length(),s2.length());
int i=0;
for(i=0;i<length;i++){
if(s1.charAt(i)!=s2.charAt(i))break;
}
return s1.length()-i+s2.length()-i;
}
public void init(TreeNode node,String s){//对每个节点编号
if(node==null)return;
if(node.left!=null){
StringBuffer sbf=new StringBuffer(s);
sbf.append("1");
map.put(node.left,new String(sbf));
init(node.left,new String(sbf));
}
if(node.right!=null){
StringBuffer sbf=new StringBuffer(s);
sbf.append("3");
map.put(node.right,new String(sbf));
init(node.right,new String(sbf));
}

}
}

霍夫曼树2

题解用long整数编码,而不是字符串,减少了一次for循环,并且根节点编号为1.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
   class Solution {
Map<Integer,Long> map = new HashMap<>();
public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
List<Integer> list = new ArrayList<>();
codeTree(root,1);
long targetCode = 0;

for(Integer key:map.keySet()) {
if(key==target.val) {
targetCode = map.get(key);
break;
}
}
for(Integer key:map.keySet()) {
if(distanceCode(map.get(key),targetCode)==K) {
list.add(key);
}
}
return list;
}
public void codeTree(TreeNode root, long value){
if(root==null) return;
map.put(root.val, value);
codeTree(root.right, value*10+1);
codeTree(root.left, value*10+3);
}

public int distanceCode (long val, long target) {
long sameL = 0;
long more = Math.max(val, target);
long less = Math.min(val, target);

long L1 =(long)Math.log10(more)+1;
long L2 =(long)Math.log10(less)+1;

double temp = Math.abs(less*(Math.pow(10, L1 - L2)) - more);

sameL = (temp==0)?L1:L1 - (long)(Math.log10(temp+1)) - 1;

return (int)(L1 + L2 - 2*sameL);
}
}

leetcode 58/100