LeetCode---384周赛

题目列表

3033. 修改矩阵

3034. 匹配模式数组的子数组数目 I

3035. 回文字符串的最大数量

3036. 匹配模式数组的子数组数目 II

一、修改矩阵

简单模拟即可,代码如下

class Solution {
public:
    vector<vector<int>> modifiedMatrix(vector<vector<int>>& matrix) {
        int n=matrix.size(),m=matrix[0].size();
        for(int i=0;i<m;i++){
            int mx=0;
            for(int j=0;j<n;j++)
                mx=max(mx,matrix[j][i]);
            for(int j=0;j<n;j++)
                if(matrix[j][i]<0)
                    matrix[j][i]=mx;
        }
        return matrix;
    }
};

 二、匹配模式数组的子数组数目I&II

(二、四题目相同就一起讲了,暴力的做法就不在说了)

这题说实话,也不是很难,关键在于我们要将题目中的信息就行转化,即要将nums数组转换成1/0/-1的数组,然后就是该数组与pattern数组的匹配问题,等价于字符串匹配问题,只不过将字符变成了数字,用kmp算法,代码如下

class Solution {
public:
    int countMatchingSubarrays(vector<int>& nums, vector<int>& pattern) {
        int n=nums.size();
        vector<int> v(n-1);
        for(int i=0;i<n-1;i++)
            v[i]=(nums[i]<nums[i+1])-(nums[i]>nums[i+1]);//利用布尔值0/1来得到1/0/-1,也可以用if语句
        int m=pattern.size();
        vector<int>next(m);
        for(int i=1,j=0;i<m;i++){
            while(j&&pattern[i]!=pattern[j])
                j=next[j-1];
            if(pattern[j]==pattern[i])
                j++;
            next[i]=j;
        }
        int ans=0;
        for(int i=0,j=0;i<n-1;i++){
            while(j&&v[i]!=pattern[j])
                j=next[j-1];
            if(v[i]==pattern[j])
                j++;
            if(j==m){
                ans++;
                j=next[j-1];
            }
        }
        return ans;
    }
};

当然这题也可以用上周赛中的z函数来解答,这里既然又说到z函数,就具体讲解一下z函数的原理和操作,如下图。

那么如何用z函数这个算法来求解字符串匹配问题呢?

代码如下

class Solution {
public:
    int countMatchingSubarrays(vector<int>& nums, vector<int>& pattern) {
        int n=nums.size(),m=pattern.size(),ans=0;
        vector<int> v(pattern);
        for(int i=0;i<n-1;i++)
            v.push_back((nums[i]<nums[i+1])-(nums[i]>nums[i+1]));
        vector<int> z(v.size());
        z[0]=v.size();
        int l=0,r=0;//维护z-box的区间
        for(int i=1;i<v.size();i++){
            if(i<=r) z[i]=min(r-i+1,z[i-l]);
            while(i+z[i]<v.size()&&v[z[i]]==v[i+z[i]]) z[i]++;
            if(r<i+z[i]-1) l=i,r=i+z[i]-1;
            
            if(i>=pattern.size()&&z[i]>=pattern.size()) ans++;
        }
        return ans;
    }
};

三、回文字符串的最大数量

这题算是一个构造题,即如何构造回文串使得回文串的个数尽可能得多,首先我们必然要统计各个字母出现的次数,然后进行分配,从贪心的角度来思考,我们肯定是优先从字符串长度短的开始构造回文串。接下来就是如何构造回文串的问题。

对于回文串,我们只要考虑它的对称的两边是否够用即可(对于奇数长度,中间的那个我们不用考虑,因为字符的个数是足够的,大家可以细品一下这句话),换句话说,我们可以看"成双的字符"的个数有多少,能满足多少个回文串即可,代码如下

class Solution {
public:
    int maxPalindromesAfterOperations(vector<string>& words) {
        int cnt[26]={0};
        int n=words.size();
        vector<int>v;
        for(auto str:words){
            v.push_back(str.size());
            for(auto e:str){
                cnt[e-'a']++;
            }
        }
        int p=0,ans=0;
        for(auto x:cnt) p+=x/2;//得到有几对
        sort(v.begin(),v.end());
        for(auto x:v){
            if(p>=x/2)
                ans++,p-=x/2;
            else
                break;
        }
        return ans;
    }
};
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值