题目:
给你一棵树,树上有 n
个节点,按从 0
到 n-1
编号。树以父节点数组的形式给出,其中 parent[i]
是节点 i
的父节点。树的根节点是编号为 0
的节点。
树节点的第 k
个祖先节点是从该节点到根节点路径上的第 k
个节点。(这句话很关键,第一次看的时候理解错了
实现 TreeAncestor
类:
示例 1:
!https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/06/14/1528_ex1.png
输入:
["TreeAncestor","getKthAncestor","getKthAncestor","getKthAncestor"]
[[7,[-1,0,0,1,1,2,2]],[3,1],[5,2],[6,3]]
输出:
[null,1,0,-1]
解释:
TreeAncestor treeAncestor = new TreeAncestor(7, [-1, 0, 0, 1, 1, 2, 2]);
treeAncestor.getKthAncestor(3, 1); // 返回 1 ,它是 3 的父节点
treeAncestor.getKthAncestor(5, 2); // 返回 0 ,它是 5 的祖父节点
treeAncestor.getKthAncestor(6, 3); // 返回 -1 因为不存在满足要求的祖先节点
提示:
TreeAncestor(int n, int[] parent)
对树和父数组中的节点数初始化对象。getKthAncestor(int node, int k)
返回节点node
的第k
个祖先节点。如果不存在这样的祖先节点,返回1
。1 <= k <= n <= 5 * 104
parent[0] == -1
表示编号为0
的节点是根节点。- 对于所有的
0 < i < n
,0 <= parent[i] < n
总成立 0 <= node < n
- 至多查询
5 * 104
次
(题都没看懂说实话,第一次读完,没搞懂getkthAncestor里(node和第k个祖先是啥意思)
理解上其实就是,需要跳 k 次才能到达的第 k 个祖先节点,例如查找[3,2],会从3跳到1,再跳到0,我想我理解的应该是n=2*
理解好题意后,就到了代码编写,问题就是如何存放和调用这个求n结点的第k个祖先结点问题
我参考了一位我能看的懂的思路,那些什么增倍法真的看不懂阿喂(放在以后研究)
最粗暴的办法还是直接嵌套parent【parent【】】这样,但是其实可以优化,例如:当查询[3,2]时,会从3向上遍历到1,再到0;当查询[1,1]时,会从1遍历到0。可以发现,两者走了重复的路径。
保存路径的方法就要用到二维数组,给每个node一个二维index,index[0]记录了其在哪条路径中(可能存在多条路径中,只存一个就可以,这里也可能是继续优化的点),index[1]记录了其所在path中的下标
举例节点3这个,所有路径用一个数组保存为[[3,1,0], [4,1,0], [5,2,0], [6,2,0]]
比如节点3的index = [0, 0], 要找它的第k个节点,只需要找到path[index[3][0]][index[1] + k]
代码:
class TreeAncestor {
int[] parent;
int n;
List<Integer>[] path;
int[][] index;
public TreeAncestor(int n, int[] parent) {
this.parent=parent;
this.n=n;
boolean[] flag=new boolean[n];
flag[0]=true;
for(int node=1;node<n;++node){
flag[parent[node]]=true;
}
List<Integer> le=new ArrayList<>();
for(int node=1;node<n;++node){
if(!flag[node]){
le.add(node);
}
}
index=new int[n][];
path=new List[le.size()];
int idx=0;
for(int node :le){
int count =1;
index[node]=new int[]{idx,0};
path[idx]=new ArrayList<>();
path[idx].add(node);
int tmp=node;
while(parent[tmp]!=-1){
tmp=parent[tmp];
path[idx].add(tmp);
index[tmp]=new int[]{idx,count++};
}
idx++;
}
System.out.println(1);
}
public int getKthAncestor(int node, int k) {
int[] idx=index[node];
if(path[idx[0]].size()-idx[1]<=k){
return -1;
}
else{
return path[idx[0]].get(k+idx[1]);
}
}
}
/**
* Your TreeAncestor object will be instantiated and called as such:
* TreeAncestor obj = new TreeAncestor(n, parent);
* int param_1 = obj.getKthAncestor(node,k);
*/
还找到一个更加粗暴的:
class TreeAncestor {
private int[] parent;
private List<Integer>[] parentLists;
public TreeAncestor(int n, int[] parent) {
this.parent = parent;
this.parentLists = new List[n];
}
public int getKthAncestor(int node, int k) {
if(parentLists[node] != null) {
if(parentLists[node].size() <= k) {
return -1;
} else {
return parentLists[node].get(k);
}
} else {
dfs(node);
return getKthAncestor(node, k);
}
}
private void dfs(int node) {
List<Integer> parents = new ArrayList<>();
while(node != -1 && this.parentLists[node] == null) {
parents.add(node);
node = this.parent[node];
}
if(node != -1) {
parents.addAll(this.parentLists[node]);
}
for(int i = 0; i < parents.size(); i++) {
if(this.parentLists[parents.get(i)] != null) {
break;
}
this.parentLists[parents.get(i)] = parents.subList(i, parents.size());
}
}
}
作者:野兽先辈 链接:https://leetcode.cn/problems/kth-ancestor-of-a-tree-node/solutions/330507/jiu-shi-bao-li-gan-li-yong-sublist-slicejie-sheng-/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。