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 所需要的步数:
- 如果 x 是偶数,那么 x = x / 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% 的用户