【题目列表】
对角线上的质数
遍历对角线上的数,维护最大质数就行了。
class Solution {
public:
bool isprime(int n){
if(n==1)return false;
if(n==2)return true;
for(int i=2;i<=sqrt(n);i++){
if(n%i==0)return false;
}
return true;
}
int diagonalPrime(vector<vector<int>>& nums) {
int res=0;
for(int i=0;i<nums.size();i++){
if(isprime(nums[i][i])){
res=max(res,nums[i][i]);
}
if(isprime(nums[i][nums.size() - i - 1])){
res=max(res,nums[i][nums.size() - i - 1]);
}
}
return res;
}
};
等值距离和
假设当前数为
n
u
m
s
[
i
]
=
7
nums[i]=7
nums[i]=7 ,当前
7
7
7 与其左边的
7
7
7 的距离和为
d
i
s
[
i
]
dis[i]
dis[i] ,前缀数组中存在
a
n
s
ans
ans 个
7
7
7 且上一个
7
7
7 的位置为
i
d
x
idx
idx ,则前缀中的
7
7
7 对当前
7
7
7 的贡献值为
d
i
s
[
i
d
x
]
+
a
n
s
∗
(
i
−
i
d
x
)
dis[idx]+ans*(i-idx)
dis[idx]+ans∗(i−idx)。
这只是计算了前缀,所以我们再从后往前跑一遍,每个位置上前缀贡献和后缀贡献的和即为最终的答案。
class Solution {
public:
vector<long long> distance(vector<int>& nums) {
int n=nums.size();
vector<long long> res(n,0);
vector<long long> cnt(n,0);
map<int,int> idx;
map<int,int> ans;
for(auto num:nums)idx[num]=-1,ans[num]=0;
for(int i=0;i<n;i++){
//其实这里可以不用绝对值函数,比赛时间紧懒得改了
if(idx[nums[i]]!=-1) res[i]=res[idx[nums[i]]]+ans[nums[i]]*abs(i-idx[nums[i]]);
idx[nums[i]]=i;
ans[nums[i]]++;
}
for(auto num:res)cout<<num<<" ";
for(auto num:nums)idx[num]=-1,ans[num]=0;
for(int i=n-1;i>=0;i--){
if(idx[nums[i]]!=-1) cnt[i]=cnt[idx[nums[i]]]+ans[nums[i]]*abs(i-idx[nums[i]]);
idx[nums[i]]=i;
ans[nums[i]]++;
res[i]+=cnt[i];
}
cout<<endl;
for(auto num:res)cout<<num<<" ";
return res;
}
};
最小化数对的最大差值
首先不可能在原数组里面枚举,所以排序是肯定的,排序会更方便计算最小的差值。然后就是一个特点:最优解里的每一对数对一定是相邻的。可以反证得到,如果选择的数对之间隔了一个和左右两个数都不相等的数,那中间那个数和区间以外的数组成一对,就会造成重复区间。如果存在连续相同的数,如
[
1
,
2
,
2
,
2
,
4
]
[1,2,2,2,4]
[1,2,2,2,4] ,可以发现,存在不相邻的选择方法,但是和相邻的方法最终结果相等,最优数对之间依然是相邻的。但是存在这样一个问题,对于头尾的数,每个数都可以选择与其左边的或右边的数组成一队,我们也没法在前面就确定当前组合对于后续来说一定是最优解。
别人都说看到最大最小值,最小最大值都应该首先想到二分。因为这个题只能反推,我们假设数对差值的最大值是
X
X
X,我们可以用二分的方法查找可能的
X
X
X ,并统计差值小于这个值的数对的数量,如果这个数量等于
p
p
p,则
X
X
X 即为满足条件的结果。
class Solution {
public:
int minimizeMax(vector<int>& nums, int p) {
if(p==0) return 0;
int n=nums.size();
sort(nums.begin(),nums.end());
// for(auto num:nums)cout<<num<<" ";
// cout<<endl;
auto check=[&](int limit){
int ans=0;
for(int i=1;i<n;i++) if(nums[i]-nums[i-1]<=limit) ans++,i++;
return ans>=p;
};
int l=0,r=(nums[n-1]-nums[0]);
while(l<r){
int mid=(l+r)/2;
if(check(mid)) r=mid;//数量大于p说明当前X太大了
else l=mid+1;
}
return l;
}
};
网络图中最少访问的格子数
我之前没做过记忆化BFS,觉得还挺新奇的,竟然每次很多走法的题也能用BFS做。后来想想,其实我们每一步都尽最大可能走,然后步长又是逐渐增大的,所以我们能保证每个格子第一次被访问,都是最小步长走到的。很amazing。
class Solution {
public:
int minimumVisitedCells(vector<vector<int>>& grid) {
int m=grid.size(),n=grid[0].size();
vector<vector<bool>> vis(m,vector<bool> (n,false));
queue<pair<int,int>> q;
q.push({0,0});
vis[0][0]=true;
int res=0;
while(!q.empty()){
res++;
int ans=q.size();
for(int i=0;i<ans;i++){
auto [r,c]=q.front();
q.pop();
if(r==m-1&&c==n-1) return res;
int k=grid[r][c];
if(k==0)continue;//寸步难行
if(r+k>=m-1&&c==n-1) return res+1;//下一步就能走到终点
if(r==m-1&&c+k>=n-1) return res+1;
for(int j=c+1;j<n&&j<=k+c;j++){//向右走
if(!vis[r][j]){
q.push({r,j});
vis[r][j]=true;
}
}
for(int j=r+1;j<m&&j<=r+k;j++){//向下走
if(!vis[j][c]){
q.push({j,c});
vis[j][c]=true;
}
}
}
}
return -1;
}
};