JAVA程序设计:重构一棵树的方案数(LeetCode:1719)

给你一个数组 pairs ,其中 pairs[i] = [xi, yi] ,并且满足:

pairs 中没有重复元素
xi < yi
令 ways 为满足下面条件的有根树的方案数:

树所包含的所有节点值都在 pairs 中。
一个数对 [xi, yi] 出现在 pairs 中 当且仅当 xi 是 yi 的祖先或者 yi 是 xi 的祖先。
注意:构造出来的树不一定是二叉树。
两棵树被视为不同的方案当存在至少一个节点在两棵树中有不同的父节点。

请你返回:

如果 ways == 0 ,返回 0 。
如果 ways == 1 ,返回 1 。
如果 ways > 1 ,返回 2 。
一棵 有根树 指的是只有一个根节点的树,所有边都是从根往外的方向。

我们称从根到一个节点路径上的任意一个节点(除去节点本身)都是该节点的 祖先 。根节点没有祖先。

 

示例 1:


输入:pairs = [[1,2],[2,3]]
输出:1
解释:如上图所示,有且只有一个符合规定的有根树。
示例 2:


输入:pairs = [[1,2],[2,3],[1,3]]
输出:2
解释:有多个符合规定的有根树,其中三个如上图所示。
示例 3:

输入:pairs = [[1,2],[2,3],[2,4],[1,5]]
输出:0
解释:没有符合规定的有根树。
 

提示:

1 <= pairs.length <= 105
1 <= xi < yi <= 500
pairs 中的元素互不相同。

PS:很久之前的一道周赛压轴题了,仍记得当时写完三道题后挂机一个多小时的无奈,还是自己太菜呀

思路:具体思路我是参考https://leetcode-cn.com/problems/number-of-ways-to-reconstruct-a-tree/solution/onmde-luan-gao-zuo-fa-by-weak-chicken-y2mv/

对于该题,核心内容无非两点:

(1)点u是点v的祖先,则与u相关的关系数要大于等于v,当且仅当u和v在一条链上,并且没有分支的时候取等号

(2)若两个点的关系数相同并且不在v还没有遍历到,我们需要知道此时u和v的祖先,若两个点的祖先相等,我们令v的祖先为u,若不想等,则是非法情况【上述链接讲解的非常清楚,为这边就不过多赘述】。

class Solution {

    private static final int size = 501;

    public int checkWays(int[][] pairs) {
        int ans = 1;
        int m = pairs.length;
        int[] pre = new int[size];
        int[] nums = new int[size];
        boolean[] vis = new boolean[size];
        List<int[]> list = new ArrayList<>();
        List<List<Integer>> edges = new ArrayList<>();
        for (int i = 0; i < size; i++)
            edges.add(new ArrayList<>());
        for (int i = 0; i < m; i++) {
            int u = pairs[i][0];
            int v = pairs[i][1];
            nums[u]++;
            nums[v]++;
            edges.get(u).add(v);
            edges.get(v).add(u);
            pre[u] = pre[v] = -1;
        }
        for (int i = 0; i < size; i++) {
            if (nums[i] == 0)
                continue;
            list.add(new int[]{i, nums[i]});
        }
        int sz = list.size();
        Collections.sort(list, (a, b) -> (b[1] - a[1]));
        if (nums[list.get(0)[0]] != sz - 1) return 0;
        for (int i = 0; i < sz; i++) {
            int u = list.get(i)[0];
            int len = edges.get(u).size();
            for (int j = 0; j < len; j++) {
                int v = edges.get(u).get(j);
                if (nums[v] == nums[u])
                    ans = 2;
                if (!vis[v]) {
                    if (pre[u] != pre[v])
                        return 0;
                    pre[v] = u;
                }
                vis[u] = true;
            }
        }
        return ans;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值