3.14 3.16 LeetCode第 247 场周赛

本文涵盖了四个算法问题的解决方案,包括寻找序列中四个数的最大乘积差、矩阵的循环轮转、计算字符串中满足特定条件的子字符串数量,以及蚂蚁建造房间的合法序列计数。每个问题都提供了详细的思路解析和C++代码实现,涉及排序、模拟、动态规划和递归等算法技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1913. 两个数对之间的最大乘积差

  • 题目大意
    在一个长度为n的序列中找出4个数使得 a ∗ b − c ∗ d a*b-c*d abcd最大。
  • 思路
  • code
class Solution {
public:
    int maxProductDifference(vector<int>& nums) {
        int n = nums.size();
        sort(nums.begin(), nums.end());
        
        return nums[n-1]*nums[n-2]-nums[0]*nums[1];
    }
};

1914. 循环轮转矩阵

  • 题目大意
    给一个n*m的矩阵,给一个k,输出每一层(从外到里分层)逆时针转k圈后的矩阵。
  • 思路
    模拟 写了好久 烦
  • code
class Solution {
public:
    vector<vector<int>> rotateGrid(vector<vector<int>>& grid, int k) {
        
        int n = grid.size(), m = grid[0].size();
        int ans[55][55]={0};
        int ceng=min(n,m)/2;
        int nn=n, mm=m;

        for(int i=0;i<ceng;i++)
        {
            int num=2 * nn + 2 * (mm - 2);
            int kk=k%num;
            cout<<kk<<endl;
            for(int j=1;j<=kk;j++)
            {
                for(int x=i;x<n-i-1;x++){
                 ans[x+1][i]=grid[x][i];   
                }
                for(int y=i;y<m-i-1;y++){
                 ans[n-i-1][y+1]=grid[n-i-1][y];   
                }
                for(int x=n-i-1;x>i;x--){
                 ans[x-1][m-i-1]=grid[x][m-i-1];   
                }
                for(int y=m-i-1;y>i;y--){
                 ans[i][y-1]=grid[i][y];   
                } 
                //重新装回grid数组
                for(int x=i;x<n-i-1;x++){
                 grid[x][i]=ans[x][i];   
                }
                for(int y=i;y<m-i-1;y++){
                 grid[n-i-1][y]=ans[n-i-1][y];   
                }
                for(int x=n-i-1;x>i;x--){
                 grid[x][m-i-1]=ans[x][m-i-1];   
                }
                for(int y=m-i-1;y>i;y--){
                 grid[i][y]=ans[i][y];   
                } 
            }
            nn-=2,mm-=2;
        }

        return grid;
    }
};

1915. 最美子字符串的数目

  • 题目大意
    给定长度为n的仅含有小写字母 a − j a-j aj的字符串,求“漂亮子字符串”的数量。定义漂亮字符串:最多有一个字母的个数为奇数。

  • 思路
    最简单考虑 O ( n 2 ) O(n^2) O(n2)的DP,优化:把对于目前状态一样的状态放到一起统计。
    用10位二进制数表示每个字母出现的奇偶性。
    p r e [ i ] pre[i] pre[i]表示0-i位的子串的奇偶性数字。
    p r e [ i ] = p r e [ i − 1 ] ⊕ ( 1 < < w o r d [ i ] ) pre[i]=pre[i-1] \oplus (1<<word[i]) pre[i]=pre[i1](1<<word[i])
    使用map记录每个状态在之前出现了多少次。
    统计答案:
    1.遍历每一个字母在二进制数状态的位置,分别使其翻转(其他的字母奇偶性相同,只有这一位奇偶相反相减为奇数);表示前面有一段区间的字符串奇偶性满足条件。
    2.前面存在与目前状态一致(奇数-奇数=偶数, 偶数-偶数=偶数)的字符串段答案也要统计。

  • code

class Solution {
public:
    long long wonderfulSubstrings(string word) {
        #define ll long long
        #define N 100010
        int n = word.size();
        int s[N];
        int pre[N]={0};
        map<int,ll> mp;
        pre[0] = 1<<(word[0]-'a');
        mp[0]=1;
        mp[pre[0]]++;
        ll ans=1;
        for(int i=1;i<n;i++)
        {
            pre[i]=pre[i-1] ^ (1<<(word[i]-'a'));
            ans+=mp[pre[i]];
            for(int j=0;j<10;j++) ans+=mp[pre[i]^(1<<j)];
            mp[pre[i]]++;
        } 
        return ans;
    }
};  

1916. 统计为蚁群构筑房间的不同顺序

  • 题目大意
    蚂蚁盖房子,房子有n个房间,每个房间有一个唯一的先序房间(即只有他的先序房间建完了之后才能建他),0号房间已经建好了。问有多少种合法的建房间序列,答案对 1 e 9 + 7 1e9+7 1e9+7取余
  • 思路
    考虑1-n构成的任意排列中,有多少种排符合 1 − m − 1 ( m < n ) 1-m-1(m<n) 1m1(m<n) m m m之前:
    只需考虑m在这m个数中的最后位置的序列数即可。这m个数中每个数在m个数最后面的概率相等,即均为 1 m \frac{1}{m} m1。因此m在m个数最后的概率是 1 m \frac{1}{m} m1。因此在 n ! n! n!排列中满足要求的数量为 n ! m \frac{n!}{m} mn!
    \
    由于合法的建房间序列是 n ! n! n!种排列中的一些,并且对于每个前驱来说只要满足他在他的所有后继之前被建造就是合法的,即对于每个节点 i i i来说他在他的后继之前被建造就相当于他排在所有后继的最前面,其概率为 1 s i z e [ i ] \frac{1}{size[i]} size[i]1。并且每个前驱的计算互相不影响,即答案满足乘法原理,
    所以最终的答案是 n ! ∏ i = 0 n − 1 s i z e [ i ] \frac{n!}{\prod \limits_{i=0}^{n-1}{size[i]}} i=0n1size[i]n!
    \
    注意除法取余操作。
  • code
class Solution {
#define N 100010
#define mod 1000000007
#define ll long long
ll sz[N]={0},fac[N]={0},mul[N]={0};
int n;
vector<int> v[N];

int dfs(int x)
{
    sz[x]=1; 
    for(auto i:v[x]) sz[x]=sz[x]+dfs(i);
    return sz[x];
}
ll quikp(ll x, ll p)
{
    ll ans=1;
    while(p)
    {
        if(p%2) ans = (ans * x) % mod;
        p>>=1;
        x=x*x%mod;
    }
    return ans;
}

public:
    int waysToBuildRooms(vector<int>& prevRoom) {
        n = prevRoom.size();
        for(int i=1;i<n;i++) v[prevRoom[i]].push_back(i);
        dfs(0);
        fac[0]=1;mul[0]=sz[0];
        //for(int i=0;i<n;i++) cout<<sz[i]<<endl;
        for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
        for(int i=1;i<n;i++) mul[i]=mul[i-1]*sz[i]%mod;
        //for(int i=0;i<n;i++) cout<<mul[i]<<' ';
        return fac[n]*quikp(mul[n-1],mod-2)%mod;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值