题目列表
一、仅含置位位的最小整数
题目要求我们返回二进制数位全为1,且大于 n 的最小的整数,我们可以直接从小到大枚举答案,也可以直接计算出答案,比如 5 的二进制为 101,返回 111,即7,8的二进制为1000,返回1111,即15,也就是说我们返回的值的二级制位数等于 n 的二进制位数,即返回值为 (1<<bit_length)-1,其中 bit_length 为 n 的二进制位数,代码如下
cpp
// 1、模拟
class Solution {
public:
int smallestNumber(int n) {
int ans = 0;
for(int i = 0; i < 32; i++){
if(ans >= n) return ans;
ans |= 1 << i;
}
return -1;
}
};
// 2、直接按公式计算
class Solution {
public:
int smallestNumber(int n) {
// __builtin_clz 用来计算 n 的二进制前导零的个数
return (1 << (32 - __builtin_clz(n))) - 1;
}
};
二、识别数组中的最大异常值
首先,我们要先清楚数组中元素的关系,设异常值为 x,特殊值为 y,则 x + 2y = sum,sum为数组和,根据等式的关系,我们可以枚举异常值 x,然后看是否存在一个元素 y = (sum - x)/2 (可以用哈希表记录每个元素的出现次数) 如果存在,则 y 可以为异常值,取 max 即可,代码如下
cpp
class Solution {
public:
int getLargestOutlier(vector<int>& nums) {
int n = nums.size(), sum = 0, ans = INT_MIN;
unordered_map<int,int>mp;
for(auto x:nums) mp[x]++, sum += x;
for(auto x:nums){
if((sum - x) % 2 == 0){ // 必须是偶数
int y = (sum - x) / 2;
if(mp.count(y) && (x != y || mp[x] > 1)){ // 可能会出现 x = y 的情况,此时 mp[x] > 1
ans = max(ans, x);
}
}
}
return ans;
}
};
三、连接两棵树后最大目标结点个数 I
首先,我们来思考一棵树中每个结点的最大目标结点个数如何计算?由于数据范围比较小,我们可以给每一个结点都用 dfs 计算一次目标节点个数。
那么如果两个树要连接在一起呢?我们需要考虑枚举哪两个结点连接的问题吗?不需要
1、对于Tree1,根据题目中目标节点的定义,我们肯定是将需要计算的结点当作连接的结点,这样才能让该结点到Tree2的结点的边数尽可能少,从而让目标节点的个数尽可能的多
2、对Tree2,根据(1),其实问题就变成了Tree2中哪个结点的目标结点的个数最多,只不过距离变为 k - 1,可以用相同的方法计算出每个结点的目标节点的个数,然后取max即可
代码如下
cpp
class Solution {
vector<int> getTargetNodes(vector<vector<int>>& edges, int k){
int n = edges.size();
vector<vector<int>> g(n + 1);
for(auto e : edges){
g[e[0]].push_back(e[1]);
g[e[1]].push_back(e[0]);
}
int i;
vector<int> ret(n + 1);
function<void(int,int,int)> dfs = [&](int x, int fa, int d){
if(d <= k) {
ret[i]++;
for(int y : g[x]){
if(y != fa){
dfs(y, x, d + 1);
}
}
}
};
for(i = 0; i < n + 1; i++)
dfs(i, -1, 0);
return ret;
}
public:
vector<int> maxTargetNodes(vector<vector<int>>& edges1, vector<vector<int>>& edges2, int k) {
int mx = ranges::max(getTargetNodes(edges2, k - 1)); // 由于Tree2需要和Tree1连接,会多出一条边,所以计算目标结点时的 k 需要减一
auto ans = getTargetNodes(edges1, k);
for(auto & x : ans) x += mx;
return ans;
}
};
四、连接两棵树后最大目标结点个数 II
注意:这题的题目和第三题并不一样,一定要仔细读题,但是思路大题相同。
题目说结点之间的距离为偶数时,互为目标节点,这里我们只用关心奇偶性即可,同时,如果我们手玩一下示例一,就会发现:
所以我们只要对一棵树进行一次 dfs 就能算出该树上所有结点的目标节点的个数,然后依旧是将两棵树分别进行计算即可,代码如下
cpp
class Solution {
vector<int> getCnt(vector<vector<int>>& g){
int n = g.size();
vector<int> cnt(2);
// 距离 0 结点为 偶数 的数字互为目标结点
// 距离 0 结点为 奇数 的数字互为目标节点
auto dfs = [&](auto&& dfs, int x, int fa, int d)->void{
cnt[d]++;
for(int y: g[x]){
if(y != fa){
dfs(dfs, y, x, d ^ 1);
}
}
};
dfs(dfs, 0, -1, 0);
return cnt;
}
public:
vector<int> maxTargetNodes(vector<vector<int>>& edges1, vector<vector<int>>& edges2) {
int n = edges1.size() + 1;
int m = edges2.size() + 1;
vector<vector<int>> g1(n), g2(m);
for(auto e:edges1){
g1[e[0]].push_back(e[1]);
g1[e[1]].push_back(e[0]);
}
for(auto e:edges2){
g2[e[0]].push_back(e[1]);
g2[e[1]].push_back(e[0]);
}
vector<int> cnt = getCnt(g1);
int mx = ranges::max(getCnt(g2));
vector<int> ans(n, mx);
auto dfs = [&](auto&& dfs, int x, int fa, int d)->void{
ans[x] += cnt[d];
for(int y:g1[x]){
if(y != fa){
dfs(dfs, y, x, d ^ 1);
}
}
};
dfs(dfs, 0, -1, 0);
return ans;
}
};