【leetcode】图---中等(1)1361. 验证二叉树_并查集(2)1387. 将整数按权重排序_dfs(3)1462. 课程安排 IV_拓扑排序_floyed

1361、二叉树上有 n 个节点,按从 0 到 n - 1 编号,其中节点 i 的两个子节点分别是 leftChild[i] 和 rightChild[i]。

只有 所有 节点能够形成且 只 形成 一颗 有效的二叉树时,返回 true;否则返回 false。

如果节点 i 没有左子节点,那么 leftChild[i] 就等于 -1。右子节点也符合该规则。

注意:节点没有值,本问题中仅仅使用节点编号。

示例 4:

输入:n = 6, leftChild = [1,-1,-1,4,-1,-1], rightChild = [2,-1,-1,5,-1,-1]
输出:false

 

 并查集。几种特殊情况:(1)是否环,(2)是否只有一个联通分支,(3)1、2的结合

// root 不一定是0!!
// (1)是否有环(2)多个联通分支,有些有环
// 并查集
class Solution {
public:
    vector<int> tree;
    int findRoot(int x){
        if(tree[x] == -1) return x;
        int t = findRoot(tree[x]);
        tree[x] = t;
        return t;
    }
    bool validateBinaryTreeNodes(int n, vector<int>& leftChild, vector<int>& rightChild) {
        tree.resize(n, -1);
        for(int i = 0; i < n; i++){
            if(leftChild[i] > -1){
                int a = findRoot(i);
                int b = findRoot(leftChild[i]);
                if(a == b) return false;
                tree[b] = a;
            }
            if(rightChild[i] > -1) {
                int a = findRoot(i);
                int b = findRoot(rightChild[i]);
                if(a == b) return false;
                tree[b] = a;
            }
        }
        int cnt = 0;
        for(int i = 0; i < n; i++) if(tree[i] == -1) cnt++;
        if(cnt != 1) return false;
        else return true;
    }
};

结果:

执行用时:112 ms, 在所有 C++ 提交中击败了56.11% 的用户

内存消耗:31.8 MB, 在所有 C++ 提交中击败了66.67% 的用户

 

1387、我们将整数 x 的 权重 定义为按照下述规则将 x 变成 1 所需要的步数:

  1.     如果 x 是偶数,那么 x = x / 2
  2.     如果 x 是奇数,那么 x = 3 * x + 1

比方说,x=3 的权重为 7 。因为 3 需要 7 步变成 1 (3 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 1)。

给你三个整数 lo, hi 和 k 。你的任务是将区间 [lo, hi] 之间的整数按照它们的权重 升序排序 ,如果大于等于 2 个整数有 相同 的权重,那么按照数字自身的数值 升序排序 。

请你返回区间 [lo, hi] 之间的整数按权重排序后的第 k 个数。

注意,题目保证对于任意整数 x (lo <= x <= hi) ,它变成 1 所需要的步数是一个 32 位有符号整数。

示例 1:

输入:lo = 12, hi = 15, k = 2
输出:13
解释:12 的权重为 9(12 --> 6 --> 3 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 1)
13 的权重为 9
14 的权重为 17
15 的权重为 17
区间内的数按权重排序以后的结果为 [12,13,14,15] 。对于 k = 2 ,答案是第二个整数也就是 13 。
注意,12 和 13 有相同的权重,所以我们按照它们本身升序排序。14 和 15 同理。

// dfs
bool cmp(pair<int,int> &a, pair<int,int> &b){
        if(a.second < b.second) return true;
        else if(a.second == b.second) return a.first < b.first ? true : false;
        else return false;
}
class Solution {
public:
    vector<pair<int,int>> vec;// {target, step}
    
    void dfs(int x, int target, int step){
        if(x == 1) vec.push_back({target, step});
        else if(x % 2 == 0) dfs(x / 2, target, step + 1);
        else dfs(x * 3 + 1, target, step + 1);
    }

    int getKth(int lo, int hi, int k) {
        vec.clear();
        for(; lo <= hi; lo++) dfs(lo, lo, 0);    // 找权值,存入weight
        sort(vec.begin(), vec.end(), cmp);       // 对vec排序,输出升序第k个
        return vec[k - 1].first;
    }
};

结果:

执行用时:144 ms, 在所有 C++ 提交中击败了59.84% 的用户

内存消耗:9 MB, 在所有 C++ 提交中击败了66.67% 的用户

 

1462、你总共需要上 n 门课,课程编号依次为 0 到 n-1 。

有的课会有直接的先修课程,比如如果想上课程 0 ,你必须先上课程 1 ,那么会以 [1,0] 数对的形式给出先修课程数对。

给你课程总数 n 和一个直接先修课程数对列表 prerequisite 和一个查询对列表 queries 。

对于每个查询对 queries[i] ,请判断 queries[i][0] 是否是 queries[i][1] 的先修课程。

请返回一个布尔值列表,列表中每个元素依次分别对应 queries 每个查询对的判断结果。

注意:如果课程 a 是课程 b 的先修课程且课程 b 是课程 c 的先修课程,那么课程 a 也是课程 c 的先修课程。

示例 3:

输入:n = 3, prerequisites = [[1,2],[1,0],[2,0]], queries = [[1,0],[1,2]]
输出:[true,true]

 有先后关系的 -----> 想到  拓扑序列

 先找入度为0的p,其指向的点xi每个入度减一,这些xi的先修课程中加入该p以及p的先修课程,重复找入度为0

// 拓扑
// 先找入度为0的p,其指向的点xi每个入度减一,这些xi的先修课程中加入该p,重复找入度为0
class Solution {
public:
    vector<bool> checkIfPrerequisite(int n, vector<vector<int>>& prerequisites, vector<vector<int>>& queries) {
        // 离线建立关系
        vector<vector<int>> gra(n); // 存图
        vector<int> indegree(n, 0);
        for(auto &i:prerequisites){
            gra[i[0]].push_back(i[1]);
            indegree[i[1]]++;
        }
        queue<int> q;
        vector<set<int>> vec(n);
        for(int i = 0; i < n; i++) if(indegree[i] == 0) q.push(i);
        while(!q.empty()){
            int cur = q.front(); q.pop();
            for(auto &i:gra[cur]){
                indegree[i]--;
                if(indegree[i] == 0) q.push(i);
                vec[i].insert(cur); // i课程的先修课程为cur,把cur的父亲也都确定为先修
                for(auto &k:vec[cur]) vec[i].insert(k);
            }
        }
        // 查询
        vector<bool> ans;
        for(auto &i:queries){
            if(vec[i[1]].count(i[0])) ans.push_back(true);
            else ans.push_back(false);
        }
        return ans;
    }
};

结果:

执行用时:800 ms, 在所有 C++ 提交中击败了40.38% 的用户

内存消耗:68.3 MB, 在所有 C++ 提交中击败了33.33%的用户

 

修改:大佬的floyed算法

// floyed
class Solution{
public:
    
    vector<bool> checkIfPrerequisite(int n, vector<vector<int>>& prerequisites, vector<vector<int>>& queries) {
        vector<vector<int>> buf(n, vector<int>(n, 0));
        for(auto &i:prerequisites) buf[i[0]][i[1]] = 1;
        for(int k = 0; k < n; k++){
            for(int i = 0; i < n; i++){
                for(int j = 0; j < n; j++){
                    if(buf[i][k] && buf[k][j]) buf[i][j] = 1;
                }
            }
        }
        vector<bool> ans;
        for(auto &i:queries) 
            if(buf[i[0]][i[1]]) 
                ans.push_back(true);
            else ans.push_back(false);       
        return ans;
    }
};

结果:

执行用时:524 ms, 在所有 C++ 提交中击败了68.85% 的用户

内存消耗:60.5 MB, 在所有 C++ 提交中击败了33.33% 的用户

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值