有一棵根节点为 0
的 家族树 ,总共包含 n
个节点,节点编号为 0
到 n - 1
。给你一个下标从 0 开始的整数数组 parents
,其中 parents[i]
是节点 i
的父节点。由于节点 0
是 根 ,所以 parents[0] == -1
。
总共有 105
个基因值,每个基因值都用 闭区间 [1, 105]
中的一个整数表示。给你一个下标从 0 开始的整数数组 nums
,其中 nums[i]
是节点 i
的基因值,且基因值 互不相同 。
请你返回一个数组 ans
,长度为 n
,其中 ans[i]
是以节点 i
为根的子树内 缺失 的 最小 基因值。
节点 x
为根的 子树 包含节点 x
和它所有的 后代 节点。
提示:
n == parents.length == nums.length
2 <= n <= 105
i != 0
,满足 0 <= parents[i] <= n - 1
parents[0] == -1
parents
表示一棵合法的树。1 <= nums[i] <= 105
nums[i]
互不相同。【DFS】
class Solution {
public:
vector<int> smallestMissingValueSubtree(vector<int>& parents, vector<int>& nums) {
int n=parents.size();
vector<int> ans(n,1);
auto it=find(nums.begin(),nums.end(),1);
if(it==nums.end()){
//不存在基因值为1的点
return ans;
}
//建树
vector<vector<int>> g(n);
for(int i=1;i<n;i++){
g[parents[i]].push_back(i);
}
unordered_set<int> vis;
function<void(int)> dfs=[&](int x)->void{
//标记基因值
vis.insert(nums[x]);
for(int son: g[x]){
if(!vis.count(nums[son])){
dfs(son);
}
}
};
//缺失的最小基因值
int mex=2;
int node=it-nums.begin();
while(node>=0){
dfs(node);
while(vis.count(mex)){
//node子树包含这个基因值
mex++;
}
//缺失的最小基因值
ans[node]=mex;
//上行
node=parents[node];
}
return ans;
}
};
一个公司准备组织一场会议,邀请名单上有 n
位员工。公司准备了一张 圆形 的桌子,可以坐下 任意数目 的员工。
员工编号为 0
到 n - 1
。每位员工都有一位 喜欢 的员工,每位员工 当且仅当 他被安排在喜欢员工的旁边,他才会参加会议。每位员工喜欢的员工 不会 是他自己。
给你一个下标从 0 开始的整数数组 favorite
,其中 favorite[i]
表示第 i
位员工喜欢的员工。请你返回参加会议的 最多员工数目 。
提示:
n == favorite.length
2 <= n <= 105
0 <= favorite[i] <= n - 1
favorite[i] != i
【拓扑】
int maximumInvitations(int* favorite, int favoriteSize){
int n=favoriteSize;
//构建入度
int indeg[n];
memset(indeg,0,sizeof(indeg));
for(int i=0;i<n;i++){
indeg[favorite[i]]++;
}
//used:是否访问过
//f[i] 表示到节点 i 为止的最长「游走」路径经过的节点个数
int used[n],f[n];
memset(used,0,sizeof(used));
for (int i=0;i<n;i++) {
f[i]=1;
}
//q:统计没有人被喜欢的人次?
int q[n];
int head=0,tail=0;
for(int i=0;i<n;i++){
if(!indeg[i]){
//如果这个人没人喜欢,把这个人push到q里面
q[tail++]=i;
}
}
//dp,求解「基环内向树」上的最长的「双向游走」路径
while(head!=tail){
int u=q[head++]; //u是第head个没人喜欢的人
used[u]=1; //访问过u了
int v=favorite[u]; //v是u喜欢的人
//状态转移
f[v]=fmax(f[v],f[u]+1);
indeg[v]--; //v的入度减去这个u
if(!indeg[v]){ //如果v也变成没人喜欢的点了
q[tail++]=v; //把v点push到q里面
}
}
//ring最大环的大小,total所有环长度为2的最长链
int ring=0,total=0;
for(int i=0;i<n;i++){
//如果没有访问过i
if(!used[i]){
//j是i喜欢的人
int j=favorite[i];
//环的大小为2,即i也是j喜欢的人
if(favorite[j]==i){
total+=f[i]+f[j]; //统计i和j处的最长链
used[i]=used[j]=1; //访问过i和j了
}
//环的大小至少为3
else{
int u=i,cnt=0; //u是i,增加计数变量
while(1){
cnt++; //cnt自增
u=favorite[u]; //更新u为u喜欢的对象
used[u]=1; //访问过上一个u喜欢的对象了
if(u==i){ //如果回到最开始的起点了
break; //退出循环
}
}
ring=fmax(ring,cnt); //更新最大环的大小
}
}
}
//等价于求出图的最大环的长度,以及所有长度为 2 的环加上其最长链,返回二者的最大值
return fmax(ring,total);
}
总计有 n
个环,环的颜色可以是红、绿、蓝中的一种。这些环分别穿在 10 根编号为 0
到 9
的杆上。
给你一个长度为 2n
的字符串 rings
,表示这 n
个环在杆上的分布。rings
中每两个字符形成一个 颜色位置对 ,用于描述每个环:
i
对中的 第一个 字符表示第 i
个环的 颜色('R'
、'G'
、'B'
)。i
对中的 第二个 字符表示第 i
个环的 位置,也就是位于哪根杆上('0'
到 '9'
)。例如,"R3G2B1"
表示:共有 n == 3
个环,红色的环在编号为 3 的杆上,绿色的环在编号为 2 的杆上,蓝色的环在编号为 1 的杆上。
找出所有集齐 全部三种颜色 环的杆,并返回这种杆的数量。
提示:
rings.length == 2 * n
1 <= n <= 100
i
是 偶数 ,则 rings[i]
的值可以取 'R'
、'G'
或 'B'
(下标从 0 开始计数)i
是 奇数 ,则 rings[i]
的值可以取 '0'
到 '9'
中的一个数字(下标从 0 开始计数)【模拟】
int countPoints(char * rings){
int len=strlen(rings),cnt=0;
int *r=malloc(sizeof(int)*10);
int *g=malloc(sizeof(int)*10);
int *b=malloc(sizeof(int)*10);
for(int i=0;i<10;i++){
r[i]=0;
g[i]=0;
b[i]=0;
}
int i=len-1;
while(i>0){
int j=i-1;//show color
if(rings[j]=='R'){
r[rings[i]-'0']=1;
}
else if(rings[j]=='G'){
g[rings[i]-'0']=1;
}
else{
b[rings[i]-'0']=1;
}
i-=2;
}
for(int i=0;i<10;i++){
if(r[i]==1 && g[i]==1 && b[i]==1){
cnt++;
}
}
return cnt;
}
给定一个二叉树:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL
。
初始状态下,所有 next 指针都被设置为 NULL
。
提示:
[0, 6000]
内-100 <= Node.val <= 100
进阶:
【层序遍历】
/**
* Definition for a Node.
* struct Node {
* int val;
* struct Node *left;
* struct Node *right;
* struct Node *next;
* };
*/
struct Node* connect(struct Node* root) {
if(!root) return NULL;
struct Node *q[10001];
int left=0,right=0;
q[right++]=root;
while(left<right){
int n=right-left;
struct Node *last=NULL;
for(int i=1;i<=n;i++){
struct Node *f=q[left++];
if(f->left){
q[right++]=f->left;
}
if(f->right){
q[right++]=f->right;
}
if(i!=1){
last->next=f;
}
last=f;
}
}
return root;
}
给你一个整数数组 nums
,返回 nums[i] XOR nums[j]
的最大运算结果,其中 0 ≤ i ≤ j < n
。
提示:
1 <= nums.length <= 2 * 105
0 <= nums[i] <= 231 - 1
【hash】421. 数组中两个数的最大异或值 - 力扣(LeetCode)
class Solution {
static constexpr int HIGH_BIT=30;
public:
int findMaximumXOR(vector<int>& nums) {
int x=0;
for(int k=HIGH_BIT;k>=0;k--){
unordered_set<int> seen;
for(int num:nums){
seen.insert(num>>k);
//保留从最高位开始到第k个二进制位为止的部分
}
int x_next=2*x+1;
bool found=0;
//枚举
for(int num:nums){
if(seen.count(x_next ^ (num>>k))){
found=1;
break;
}
}
if(found){
x=x_next;
}
else{
x=x_next-1;
}
}
return x;
}
};
DNA序列 由一系列核苷酸组成,缩写为 'A'
, 'C'
, 'G'
和 'T'
.。
"ACGAATTCCG"
是一个 DNA序列 。在研究 DNA 时,识别 DNA 中的重复序列非常有用。
给定一个表示 DNA序列 的字符串 s
,返回所有在 DNA 分子中出现不止一次的 长度为 10 的序列(子字符串)。你可以按 任意顺序 返回答案。
提示:
0 <= s.length <= 105
s[i]``==``'A'
、'C'
、'G'
or 'T'
【hash】把每个长度为10的substring都push到hash表里面,看计数>1的substring个数
class Solution {
const int L=10;
public:
vector<string> findRepeatedDnaSequences(string s) {
vector<string> ans;
unordered_map<string,int> cnt;
int n=s.length();
for(int i=0;i<=n-L;i++){
string sub=s.substr(i,L);
if(++cnt[sub]==2){
ans.push_back(sub);
}
}
return ans;
}
};
【hash + 滑动窗口 + 位运算】同官解
/*
A:00
C:01
G:10
T:11
*/
class Solution {
const int L = 10;
//定义substring的长度
unordered_map<char, int> bin = {{'A', 0}, {'C', 1}, {'G', 2}, {'T', 3}};
//映射字母和对应编号
public:
vector<string> findRepeatedDnaSequences(string s) {
vector<string> ans;
int n = s.length();
if (n <= L) {
return ans;
//如果string就不够10个字符,则自动返回
}
int x = 0;
//当前窗口对应的整数
for (int i = 0; i < L - 1; ++i) {
x = (x << 2) | bin[s[i]];
//计算第一个窗口
}
unordered_map<int, int> cnt;
for (int i = 0; i <= n - L; ++i) {
x = ((x << 2) | bin[s[i + L - 1]]) & ((1 << (L * 2)) - 1);
//x<<2,左移2位,以开辟一个新的字符空间
//一个新字符进入,x=x|bin[t],bin[t]为计算字符t的二进制
//高2位离开x,即低20位保留,高位置0,x=x&((1 << (L * 2)) - 1)
if (++cnt[x] == 2) {
ans.push_back(s.substr(i, L));
}
}
return ans;
}
};
给你一个字符串数组 words
,找出并返回 length(words[i]) * length(words[j])
的最大值,并且这两个单词不含有公共字母。如果不存在这样的两个单词,返回 0
。
提示:
2 <= words.length <= 1000
1 <= words[i].length <= 1000
words[i]
仅包含小写字母【str库函数】(偷懒)
int maxProduct(char ** words, int wordsSize){
int res = 0;
for (int i = 0; i < wordsSize; i++) {
for (int j = i; j < wordsSize; j++) {
if (strpbrk(words[i], words[j]) == NULL) {
res = fmax(res, strlen(words[i]) * strlen(words[j]));
}
}
}
return res;
}
cpp可用位运算(不会orz)