第一题:按身高排序
思路:开一个索引数组存按身高排序后的下标即可
代码
class Solution {
public:
vector<string> sortPeople(vector<string>& names, vector<int>& heights) {
vector<string> ans;
int n=names.size();
vector<int> idx(n);
iota(idx.begin(),idx.end(),0);
sort(idx.begin(),idx.end(),[&](int a,int b){
return heights[a]>heights[b];
});
for(int i=0;i<n;i++){
ans.push_back(names[idx[i]]);
}
return ans;
}
};
第二题:按位与最大的最长子数组
思路:题意是在保证最大的基础上最长,一个数与其他数按位与运算所得到的值一定是小于等于其中较大的那一个数,所以要想保证最大就要只看最大的数,看数组中最大的数出现的最大连续长度
代码
class Solution {
public:
int longestSubarray(vector<int>& nums) {
int n=nums.size();
int maxm=*max_element(nums.begin(),nums.end());
int ans=0;
for(int i=0;i<n;i++){
int j=i;
while(j<n&&nums[j]==maxm){
j++;
}
ans=max(ans,j-i);
i=j;
}
return ans; //双指针模板
}
};
第三题:找到所有好下标
思路:动态规划 相当于正向逆向求两次非递增子序列的长度 (需要注意的是该题得出来的i不一定是极小值,因为其只是对i的左右两边做了要求,但i本身没有,nums[i]可能比nums[i-1]和nums[i+1]都要大)
代码
class Solution {
public:
vector<int> goodIndices(vector<int>& nums, int k) {
int n=nums.size();
vector<int> f(n),g(n);
for(int i=0;i<n;i++){
f[i]=1;
if(i&&nums[i-1]>=nums[i]) f[i]=f[i-1]+1;
}
for(int i=n-1;i>=0;i--){
g[i]=1;
if(i+1<n&&nums[i]<=nums[i+1]) g[i]=g[i+1]+1;
} //要把长度叠加到i上 所以逆向求非递增当作正向非递减
vector<int> res;
for(int i=k;i<n-k;i++){
if(f[i-1]>=k&&g[i+1]>=k) res.push_back(i);
} //只要i的左右两边同时满足条件则加入答案数组 因为是按顺序遍历所以不用排序
return res;
}
};
第四题:好路径的数目
思路:先排序,然后把权值相同的点分块,相同连通块的点才能组成一条路径
代码
class Solution {
public:
vector<int> p;
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int numberOfGoodPaths(vector<int>& vals, vector<vector<int>>& edges) {
int n=vals.size();
vector<vector<int>> g(n); //存图
for(auto &e:edges){
g[e[0]].push_back(e[1]);
g[e[1]].push_back(e[0]);
}
vector<int> q(n); //排序后的索引数组
p.resize(n);
for(int i=0;i<n;i++) p[i]=q[i]=i; //初始化索引和并查集
sort(q.begin(),q.end(),[&](int a,int b){
return vals[a]<vals[b]; //让索引按照点权值大小排序
});
//q中存的是按权值排序好的各点
int res=0;
for(int i=0;i<n;i++){
int j=i+1;
while(j<n&&vals[q[i]]==vals[q[j]]) j++;
for(int k=i;k<j;k++){ //[i,j)都是权值相同的点
int x=q[k]; //找到点
for(int y:g[x]){ //遍历该点能到达的且权值比自己小的点
if(vals[x]>=vals[y]){
p[find(x)]=find(y); //把该点加入到x的连通块中
}
}
}
unordered_map<int,int> mp;
for(int k=i;k<j;k++) mp[find(q[k])]++; //权值相同的点分块 相同连通块权值相同的点才能练成路径
for(auto &[u,v]:mp) res+=v*(v+1)/2; //单独一个点也算一条路径 n*(n-1)/2+n=n*(n+1)/2
i=j-1; //前面是j=i+1 这里对应
}
return res;
}
};