T1:判断矩阵是否是一个X矩阵
思路:正反对角线在i=j和i+j=n-1两条线上,直接遍历所有点即可。
class Solution {
public:
bool checkXMatrix(vector<vector<int>>& grid) {
int n=grid.size();
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i==j||i+j==n-1){
if(!grid[i][j]) return false;
}else{
if(grid[i][j]) return false;
}
return true;
}
};
T2: 统计放置房子的方式数
思路:用0表示该位未放置房子,用1表示该位放置房子,把问题转换为不存在连续两个1的01子序列的方案数(状态机问题:一维表示路径长度,二维表示哪种状态)
class Solution {
public:
int countHousePlacements(int n) {
vector<vector<int>> f(n+1,vector<int>(2));
const int MOD=1e9+7;
f[1][0]=f[1][1]=1;
for(int i=2;i<=n;i++){
f[i][0]=(f[i-1][1]+f[i-1][0])%MOD;//状态0可以由1和0转移来
f[i][1]=f[i-1][0];//状态1只能由0转移来
}
long long res=f[n][0]+f[n][1];//long long 防止下面乘积爆int
return res*res%MOD;
}
};
或者发现其实际上是斐波那契数列的规律
class Solution {
public:
int countHousePlacements(int n) {
int a=1,b=1,MOD=1e9+7;
int c;
while(--n){
c=(a+b)%MOD;
a=b;
b=c;
}
a+=b;
return (long long)a*a%MOD;
}
};
T3:拼接数组的最大分数
思路:比赛时思路,找nums1中对位替换后对nums2之和增大贡献最大的连续子序列,然后再找nums2中对位替换后对nums1之和增大贡献最大的连续子序列,取两值较大的。
class Solution {
public:
int maximumsSplicedArray(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size();
int sum1=0,sum2=0;
for(auto i:nums1) sum1+=i;
for(auto i:nums2) sum2+=i;
//从nums2中找替换子序列
int j=0,sum=0,res=0;
for(int j=0;j<n;j++){
while(j<n&&sum>=0){
sum+=nums2[j]-nums1[j];//替换后对和的贡献
j++;
res=max(res,sum);//子序列每添加一个数更新一次最大贡献
}
sum=0;//当sum<0后,清空贡献,从当前位重新开始找替换子序列
j--;
}
res+=sum1;//贡献与原数组之和相加
//从nums1中找替换子序列
int i=0,num=0,ans=0;
for(int i=0;i<n;i++){
while(i<n&&num>=0){
num+=nums1[i]-nums2[i];
i++;
ans=max(ans,num);
}
num=0;
i--;
}
ans+=sum2;
int ans1=max(ans,res);
return ans1;
}
};
代码简化:
class Solution {
public:
int replace(vector<int>& a,vector<int>& b){
int sum=0;
for(auto x:a) sum+=x;
int dt=0,f=0;
for(int i=0;i<a.size();i++){
f=max(f,0)+b[i]-a[i];
dt=max(dt,f);
}
return sum+dt;
}
int maximumsSplicedArray(vector<int>& nums1, vector<int>& nums2) {
return max(replace(nums1,nums2),replace(nums2,nums1));
}
};
T4:从树中删除边的最小分数
思路:先删除一条边,再选择删除第二条边(枚举+图的遍历)
const int N=1010,M=N*2;
int h[N],e[M],ne[M],idx;//邻接表
class Solution {
public:
int ans=1e9;
vector<int> w;
void add(int a,int b){
e[idx]=b;//存该点的值
ne[idx]=h[a];//存该点的上一个节点的索引
h[a]=idx++;//存与点a距离为1的点的索引
}
int dfs(int u,int fa,int sumx,int sumy){
int res=w[u];//当前节点的权值
for(int i=h[u];i!=-1;i=ne[i]){//遍历与节点u的邻边
int j=e[i];
if(j==fa) continue;//等于父节点则跳过 保证直往下搜索
int t=dfs(j,u,sumx,sumy);
res^=t;
if(sumx!=-1){
int a[3]={sumy,t,sumx^t};//先分出两部分x、y,x部分再分出t,现在x部分异或和为sumx^t
//举例 原本x部分的节点为1 2 3 4 5 sumx=1^2^3^4^5
//分出3 4 现t部分异或和为t=3^4 sumx=1^2^3^4^5^t=1^2^(3^3)^(4^4)^5=1^2^3
sort(a,a+3);
ans=min(ans,a[2]-a[0]);//求最小差值
}
}
return res;
}
int minimumScore(vector<int>& nums, vector<vector<int>>& edges) {
int n=nums.size();
w=nums;
for(int i=0;i<n-1;i++){//枚举n-1条边
memset(h,-1,n*4);//只需要n个,一个int4个字节,不用全部初始化
idx=0;
for(int j=0;j<n-1;j++){
if(i!=j){
int a=edges[j][0],b=edges[j][1];
add(a,b),add(b,a);//建图
}
}
int x=edges[i][0],y=edges[i][1];//删除第i条边
int sumx=dfs(x,-1,-1,-1),sumy=dfs(y,-1,-1,-1);//删除第i条边后两子树异或和
dfs(x,-1,sumx,sumy);//选择从x部分删除第2个条边还是从y部分删除第2条边
dfs(y,-1,sumy,sumx);
}
return ans;
}
};