题目链接:https://leetcode-cn.com/contest/weekly-contest-146/
5130. 等价多米诺骨牌对的数量
排序一下,相邻判断相等,然后用C(n,2)计算一下。
class Solution {
struct node
{
int u,v;
bool operator <(const node& a)const
{
return u==a.u? v<a.v:u<a.u;
}
}p[40005];
public:
int numEquivDominoPairs(vector<vector<int>>& dominoes) {
for(int i=0;i<dominoes.size();i++)
{
vector<int> t=dominoes[i];
p[i].u=t[0];
p[i].v=t[1];
if(p[i].u>p[i].v)
swap(p[i].u,p[i].v);
}
sort(p,p+dominoes.size());
int ans=0,s=1;
for(int i=1;i<dominoes.size();i++)
{
if(p[i].u==p[i-1].u && p[i].v==p[i-1].v)
s++;
else
{
ans+=s*(s-1)/2;
s=1;
}
}
ans+=s*(s-1)/2;
return ans;
}
};
5132. 颜色交替的最短路径
bfs,记忆化一下。
class Solution {
struct node
{
int step,u,col;
}p;
public:
vector<int> shortestAlternatingPaths(int n, vector<vector<int>>& red_edges, vector<vector<int>>& blue_edges) {
queue<node> q;
bool vis[405][2];
memset(vis,0,sizeof vis);
int inf = 0x3f3f3f3f;
int dis[405][2];
for(int i=0;i<n;i++)
dis[i][0]=dis[i][1]=inf;
p.step=p.u=p.col=0;
q.push(p);
p.col=1;
q.push(p);
while(!q.empty())
{
node top=q.front(); q.pop();
if(vis[top.u][top.col]) continue;
vis[top.u][top.col]=1;
dis[top.u][top.col]=top.step;
if(top.col==0)
{
for(vector<int> t:blue_edges)
{
if(t[0]==top.u)
{
p.step=top.step+1;
p.u=t[1];
p.col=1;
q.push(p);
}
}
}
else
{
for(vector<int> t:red_edges)
{
if(t[0]==top.u)
{
p.step=top.step+1;
p.u=t[1];
p.col=0;
q.push(p);
}
}
}
}
vector<int> ans;
for(int i=0;i<n;i++)
{
int minn=min(dis[i][0],dis[i][1]);
ans.push_back(minn==inf?-1:minn);
}
return ans;
}
};
5131. 叶值的最小代价生成树
分析题目,可以看出来就是一个石子合并题目,只不过计算规则变了。我们可以用一个maxx[i][j]维护区间(i,j)内的最大值。
class Solution {
public:
int mctFromLeafValues(vector<int>& arr) {
int n=arr.size();
long long maxx[45][45];
long long dp[45][45];
long long inf=0x3f3f3f3f3f3fLL;
for(int i=0;i<n;i++)
maxx[i][i]=arr[i],dp[i][i]=0;
for(int i=1;i<n;i++)
{
for(int beg=0;beg<n-i;beg++)
{
int end=beg+i;
maxx[beg][end]=max(maxx[beg][end-1],maxx[end][end]);
dp[beg][end]=inf;
for(int k=beg;k<end;k++)
{
long long sub=0;
dp[beg][end]=min(dp[beg][end],dp[beg][k]+dp[k+1][end]+maxx[beg][k]*maxx[k+1][end]);
}
}
}
return dp[0][n-1];
}
};
5133. 绝对值表达式的最大值
大力分类讨论。O(n)
以下i<j
1,arr1[i]<arr1[j] && arr2[i]<arr2[j]
我们可以合并为一个数组:dis[i]=arr1[i]+arr2[i]+i;
计算用后面的减去前面的,下标的影响为正,表达式值不变。
2,arr1[i]>arr1[j] && arr2[i]>arr2[j]
我们可以合并为一个数组:dis[i]=arr1[i]+arr2[i]-i;
计算用前面的减去后面的,下标的影响为负。
3,arr1[i]<arr1[j] && arr2[i]>arr2[j]
我们可以合并为一个数组:dis[i]=arr1[i]-arr2[i]+i;
计算用后面的减去前面的,下标的影响为正,表达式值不变。
4,arr1[i]>arr1[j] && arr2[i]<arr2[j]
我们可以合并为一个数组:dis[i]=arr1[i]-arr2[i]-i;
计算用前面的减去后面的,下标的影响为负。
计算dis差值时可以用前缀和和后缀和的思想,这样复杂度为On。
class Solution {
public:
int maxAbsValExpr(vector<int>& arr1, vector<int>& arr2) {
int MAXN = 40005;
int n=arr1.size();
int ans=0;
int pre[MAXN],suf[MAXN];
int dis[MAXN];
for(int i=0;i<n;i++)
dis[i]=arr1[i]+arr2[i]+i;
pre[0]=dis[0];
for(int i=1;i<n;i++)
pre[i]=min(pre[i-1],dis[i]);
suf[n-1]=dis[n-1];
for(int i=n-2;i>=0;i--)
suf[i]=max(suf[i+1],dis[i]);
for(int i=0;i<n-1;i++)
ans=max(ans,suf[i+1]-pre[i]);
for(int i=0;i<n;i++)
dis[i]=arr1[i]+arr2[i]-i;
pre[0]=dis[0];
for(int i=1;i<n;i++)
pre[i]=max(pre[i-1],dis[i]);
suf[n-1]=dis[n-1];
for(int i=n-2;i>=0;i--)
suf[i]=min(suf[i+1],dis[i]);
for(int i=0;i<n-1;i++)
ans=max(ans,pre[i]-suf[i+1]);
for(int i=0;i<n;i++)
dis[i]=arr1[i]-arr2[i]+i;
pre[0]=dis[0];
for(int i=1;i<n;i++)
pre[i]=min(pre[i-1],dis[i]);
suf[n-1]=dis[n-1];
for(int i=n-2;i>=0;i--)
suf[i]=max(suf[i+1],dis[i]);
for(int i=0;i<n-1;i++)
ans=max(ans,suf[i+1]-pre[i]);
for(int i=0;i<n;i++)
dis[i]=arr1[i]-arr2[i]-i;
pre[0]=dis[0];
for(int i=1;i<n;i++)
pre[i]=max(pre[i-1],dis[i]);
suf[n-1]=dis[n-1];
for(int i=n-2;i>=0;i--)
suf[i]=min(suf[i+1],dis[i]);
for(int i=0;i<n-1;i++)
ans=max(ans,pre[i]-suf[i+1]);
return ans;
}
};