第一题:https://leetcode-cn.com/problems/determine-whether-matrix-can-be-obtained-by-rotation/
1886. 判断矩阵经轮转后是否一致
思路:90度顺时针旋转后,(i,j)->(j,n-i-1),分别计算旋转得到的四种情况进行判断即可。
反思:判断两个二维矩阵相等可以之间用vector<vector
代码:
vector<vector<int>> sol(vector<vector<int>> ans){
int n=ans.size();
vector<vector<int>> atm(n,vector<int>(n));
\\以上两行可以改为 auto atm=ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
atm[j][n-i-1]=ans[i][j];
return atm;
}
bool findRotation(vector<vector<int>>& a, vector<vector<int>>& b) {
for(int i=0;i<4;i++){
if(a==b)return true;
a=sol(a);
}
return false;
}
第二题:https://leetcode-cn.com/problems/reduction-operations-to-make-the-array-elements-equal/
1887. 使数组元素相等的减少操作次数
思路:每个数字都要变到最小值,而这个过程中的cost是这个数字到最小数字的距离(两个数字间从小到大不同数值的个数)
反思:不要忘记先排序。
代码:
class Solution {
public:
int reductionOperations(vector<int>& s) {
int ans=0,num=0;
sort(s.begin(),s.end());
for(int i=1;i<s.size();i++){
if(s[i]!=s[i-1])num++;
ans+=num;
}
return ans;
}
};
第三题:https://leetcode-cn.com/problems/minimum-number-of-flips-to-make-the-binary-string-alternating/
1888. 使二进制字符串字符交替的最少反转次数
思路:
方法一:首先根据规律:字符交替的情况只有两种情况:奇数为0或者奇数为1,计算出一种情况下需要第二种变换的次数,然后遍历字符串,计算每一位作为开头,把此位前的移动到最后的情况下需要变换的次数,然后输出最小值即可。由于每种情况都是从上一种情况中转换过来的,所以只需要计算状态转换的影响即可。
规律:字符串两种情况所需要的变换次数关系为:a次和n-a次
代码:
class Solution {
public:
int minFlips(string s) {
int a=0,b=0;
for(int i=0;i<s.size();i++){
if(i%2&&(s[i]-'0')){
//cout<<i<<endl;
a++;
}
if((i%2==0)&&(s[i]=='0')){
//cout<<i<<endl;
a++;
}
}
int len=s.size();
int ans=min(a,len-a);
a=len-a;
for(int i=0;i<s.size();i++){
if(s[i]-'0'){
a--;
}
a=len-1-a;
//cout<<a<<endl;
if(s[i]=='0'&&len%2==0)a++;
if(s[i]=='1'&&len%2==1)a++;
ans=min(ans,len-a);
ans=min(ans,a);
//cout<<i<<" "<<a<<endl;
}
return ans;
}
};
``
方法二:
前缀+后缀:对于偶数情况,操作一并不能改变某一位的奇偶性,当奇数的情况下,操作一可以使前段的奇偶变换,所以可以前段和后端分别求前缀和后枚举操作一结束的点即可。
代码:
```C++
class Solution {
public:
int minFlips(string s) {
const int m=s.size();
int l[2][m],r[2][m];
for(int i=0;i<2;i++)
for(int j=0,num=0,k=i;j<m;j++,k^=1)
{
if((s[j]-'0')==k)num++;
l[i][j]=num;
}
for(int i=0;i<2;i++)
for(int j=m-1,num=0,k=i;j>=0;j--,k^=1){
if((s[j]-'0')==k)num++;
r[i][j]=num;
}
int ans= min(r[0][0],r[1][0]);
if(m%2==0)return ans;
for(int i=0;i<m-1;i++){
ans=min(ans,l[0][i]+r[1][i+1]);
ans=min(ans,l[1][i]+r[0][i+1]);
}
return ans;
}
};
第四题:https://leetcode-cn.com/problems/minimum-space-wasted-from-packaging/
1889. 装包裹的最小浪费空间
思路:排序后二分判断
包裹数据范围是1e5,箱子数目总和数据范围是1e5,所以题目时间复杂度应该在O(NlogN)即可,我们可以对每个箱子供应商的包裹进行判断,箱子数总和为M(<1e5),对于i供应商的j箱子,j箱子能够装的包裹范围为[l,r),产生的浪费空间贡献:\(a[i][j]\times(l-r)-\sum_{k=l}^{r-1}{p[k]}\),此时时间复杂度为NNM,对于\(\sum_{k=l}^{r-1}{p[k]}\)可以通过前缀和优化为O(1),对于查找[l,r),可以用upper_bound二分查找优化到O(logN)所以对箱子判断的时间复杂度为O(MlogN),二分包裹前需要对包裹先排序,同样箱子判断前也需要对箱子排序,总时间复杂度为O(NlogN+MlogM+MlogN)
反思:
1.浪费空间的数据范围应该小于1e10,两种情况比较浪费空间时很明显不应该拿取模后的数值进行比较,可以long long 存储,最后返回时取模即可;
2.无法把所有包裹放入箱子的时候返回-1,则最后的结果初始值应该大于1e10,可以用LLONG_MAX进行初始化,而不是用0x3f3f3f3f(int类型不穷大,小于1e10);
代码:
class Solution {
public:
int minWastedSpace(vector<int>& p, vector<vector<int>>& b) {
int n=p.size(), m=b.size();
const int mod=(int)1e9+7;
vector<long long>qz(n+5);
sort(p.begin(),p.end());
for(int i=1;i<=n;i++){
qz[i]=qz[i-1]+p[i-1];
}
long long ans=LLONG_MAX;
for(int i=0;i<m;i++){
vector<int> & bt=b[i];
sort(bt.begin(),bt.end());
if(bt[bt.size()-1]<p[n-1])continue;
int s=0,t;
long long num=0;
for(int j=0;j<bt.size();j++){
t=upper_bound(p.begin(),p.end(),bt[j])-p.begin();
//cout<<s<<" "<<t<<endl;
num=(num+1LL*(t-s)*bt[j]-(qz[t]-qz[s]));
s=t;
if(t==n)break;
}
//cout<<num<<endl;
ans=min(ans,num);
}
return ans== LLONG_MAX ? -1:ans%mod;
}
};