力扣——6268. 查询树中环的长度

125 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第23天,点击查看活动详情

力扣——6268. 查询树中环的长度

6268. 查询树中环的长度

难度困难1收藏分享切换为英文接收动态反馈

给你一个整数 n ,表示你有一棵含有 2n - 1 个节点的 完全二叉树 。根节点的编号是 1 ,树中编号在[1, 2n - 1 - 1] 之间,编号为 val 的节点都有两个子节点,满足:

  • 左子节点的编号为 2 * val
  • 右子节点的编号为 2 * val + 1

给你一个长度为 m 的查询数组 queries ,它是一个二维整数数组,其中 queries[i] = [ai, bi] 。对于每个查询,求出以下问题的解:

  1. 在节点编号为 aibi 之间添加一条边。
  2. 求出图中环的长度。
  3. 删除节点编号为 aibi 之间新添加的边。

注意:

  • 是开始和结束于同一节点的一条路径,路径中每条边都只会被访问一次。
  • 环的长度是环中边的数目。
  • 在树中添加额外的边后,两个点之间可能会有多条边。

请你返回一个长度为 m 的数组 answer ,其中 answer[i] 是第 i 个查询的结果

示例 1:

img

输入:n = 3, queries = [[5,3],[4,7],[2,3]]
输出:[4,5,3]
解释:上图是一棵有 23 - 1 个节点的树。红色节点表示添加额外边后形成环的节点。
- 在节点 3 和节点 5 之间添加边后,环为 [5,2,1,3] ,所以第一个查询的结果是 4 。删掉添加的边后处理下一个查询。
- 在节点 4 和节点 7 之间添加边后,环为 [4,2,1,3,7] ,所以第二个查询的结果是 5 。删掉添加的边后处理下一个查询。
- 在节点 2 和节点 3 之间添加边后,环为 [2,1,3] ,所以第三个查询的结果是 3 。删掉添加的边。

示例 2:

img

输入:n = 2, queries = [[1,2]]
输出:[2]
解释:上图是一棵有 22 - 1 个节点的树。红色节点表示添加额外边后形成环的节点。
- 在节点 1 和节点 2 之间添加边后,环为 [2,1] ,所以第一个查询的结果是 2 。删掉添加的边。

提示:

  • 2 <= n <= 30
  • m == queries.length
  • 1 <= m <= 105
  • queries[i].length == 2
  • 1 <= ai, bi <= 2n - 1
  • ai != bi

问题解析

首先很明显的1个突破点:

  • 设a点和b点的最近公共祖先为x。那么环的长度应该是:a到x的距离+b到x的距离+1(因为a和b之间多了一个路)

那么这一题的主要问题就是找a和b的最近公共组先了。

注意到,树是一个完全二叉树,树中编号在[1, 2n - 1 - 1] 之间。

在完全二叉树中,点i的左孩子节点是2*i,右孩子节点是2 *i+1。

我们可以反过来,通过将当前点的值变为一半得到这个点的父结点。

我们可以通过将a和b两个点一点点往上挪动,它俩重复走过的第一个点就是它们的最近公共组先。

我的做法:

  1. 对于点a,只要a不为1,每一次就把a变为原来的一半,同时用哈希表mymap记录下a点到达当前点的步骤。
  2. 对于点b,只要b不为1,每一次就把a变为原来的一半,当当前点出现在mymap里时,说明找到最近公共组先。
  3. 答案就为:a到组先的距离+b到组先的距离+1

AC代码

class Solution {
public:
    
    vector<int> cycleLengthQueries(int n, vector<vector<int>>& queries) {
        vector<int>ans;
        for(auto&i:queries)
        {
            int a=i[0],b=i[1],cnt=0;
            unordered_map<int,int>mymap;
            mymap[a]=0;
            while(a!=1)
            {
                cnt++;
                a/=2;
                mymap[a]=cnt;
            }
            cnt=0;
            while(!mymap.count(b))
            {
                cnt++;
                b/=2;
            }
            ans.push_back(cnt+mymap[b]+1);
            
        }
        return ans;
    }
};