LeetCode291周赛题解,附‘字符串总引力‘详解

LeetCode291周赛题解 '字符串总引力’详解直接跳到最后

LeetCode291周赛题解

第一题:移除指定数字得到的最大结果
可以直接使用字符串比较(题目指明字符串只包含数字),枚举移除后的字符串,直接比较维护最大值

class Solution {
public:
    string removeDigit(string s, char d) {
        int n = s.size();
        string ans ="0";
        for(int i = 0; i < n; i++)
        {
            string t = "";
            if(s[i] == d)
            {
                t += s.substr(0, i - 0);
                t += s.substr(i + 1, n - i);
            }
            ans = max(ans, t);
        }
        return ans;
    }
};

第二题:必须拿起的最小连续卡牌数
hash维护相同牌的下标,找到距离最短的两个相同牌的长度即为答案,剪枝没有相同牌时返回-1

class Solution {
public:
    int minimumCardPickup(vector<int>& c) {
        unordered_map<int,int> mp;
        int n = c.size();
        int ans = INT_MAX;
        bool f = false;
        for(int i = 0; i < n; i++)
        {
            if(mp.find(c[i]) == mp.end())
            {
                mp[c[i]] = i;
            }
            else
            {
                ans = min(ans, i - mp[c[i]] + 1);
                mp[c[i]] = i;
                f = true;
            }
        }
        if(!f)
            return -1;
        return ans;
    }
};

第三题:含最多 K 个可整除元素的子数组
数组长度200, 直接枚举所有组合,再利用SET的唯一性,来保证不重复。再按照题意,处理大于K的情况(博主这里使用set<string> 是偷懒之举,建议使用set<vector<int>>,并重开vector<int>来维护)

class Solution {
public:
    int countDistinct(vector<int>& nums, int k, int p) {
        int n = nums.size();
        set<string> s;
    
        for(int i = 0; i < n; i++)
        {
            string str = "";
            int t = 0;
            for(int j = i; j < n; j++)
            {
                str += to_string(nums[j]);
                str += ',';
                
                if(nums[j] % p == 0)
                    t++;
                if(t > k)
                    break;
                s.insert(str);
            }
            
        }
        
        return s.size();
    }
};

第四题:字符串总引力 -详解

第四题:字符串总引力
这里放上灵佬的题解附链接灵茶山艾府题解

提示 1-1
将所有子串按照其末尾字符的下标分组。

提示 1-2
考虑两组相邻的子串:以 s [ i − 1 ] s[i−1] s[i1]结尾的子串、以 s [ i ] s[i] s[i]结尾的子串。

提示 1-3
s [ i ] s[i] s[i] 结尾的子串,可以看成是以 s [ i − 1 ] s[i−1] s[i1] 结尾的子串,在末尾添加上 s[i]组成。

上面这一串提示是思考子串统计类问题的通用技巧之一。

提示 2-1
从左往右遍历 s s s,考虑将 s [ i ] s[i] s[i] 添加到以 s [ i − 1 ] s[i−1] s[i1] 结尾的子串的末尾。添加后,这些子串的引力值会增加多少?

提示 2-2
分类讨论:

  • 如果 s [ i ] s[i] s[i] 之前没有遇到过,那么这些子串的引力值都会增加 1 1 1,这些子串的引力值之和会增加 i i i,再加上 1 1 1,即 s [ i ] s[i] s[i] 单独组成的子串的引力值;

  • 如果 s [ i ] s[i] s[i] 之前遇到过,设其上次出现的下标为 j j j,那么向子串 s [ 0.. i − 1 ] , s [ 1.. i − 1 ] , s [ 2.. i − 1 ] , ⋯ , s [ j . . i − 1 ] s[0..i−1], s[1..i−1], s[2..i−1],⋯,s[j..i−1] s[0..i1],s[1..i1],s[2..i1],,s[j..i1]的末尾添加 s [ i ] s[i] s[i] 后,这些子串的引力值是不会变化的,因为 s [ i ] s[i] s[i] 已经在 s [ j ] s[j] s[j] 处出现过了;而子 s [ j + 1.. i − 1 ] , s [ j + 2.. i − 1 ] , ⋯ , s [ i − 1.. i − 1 ] s[j+1..i−1], s[j+2..i−1],⋯,s[i−1..i−1] s[j+1..i1],s[j+2..i1],,s[i1..i1] 由于不包含字符 s [ i ] s[i] s[i],这些子串的引力值都会增加 1 1 1,因此有 i − j − 1 i−j−1 ij1 个子串的引力值会增加 1 1 1,这些子串的引力值之和会增加 i − j − 1 i−j−1 ij1,再加上 1 1 1,即 s [ i ] s[i] s[i] 单独组成的子串的引力值。

模拟上述过程,遍历 s s s 的过程中用一个变量 s u m G sumG sumG 维护以 s [ i ] s[i] s[i] 结尾的子串的引力值之和,同时用一个数组 p o s pos pos 记录每个字符最近一次出现的下标。

累加遍历中的 s u m G sumG sumG 即为答案。

这里附上我的理解图(讨论样例一,包含特殊情况,abbca):

请添加图片描述

结合灵佬的题解:

  • 我们在遍历字符串的时候,就是在向前面已经组成的子串后面添加字符(蓝色方框):如刚开始只有 a a a,遍历到 b b b 时,则有了 a b 、 b ab、b abb,遍历到第二个 b b b 时,有了 a b b , b b , b . abb,bb,b. abbbbb.(可理解为,斜对角包括蓝色,就是遍历当前字符之后,产生的子串)
  • 找到子串的规律之后,我们就是来处理“引力数”的问题。根据我们前边的分析,某一次遍历(某一个斜对角)的引力数肯定会增加,这取决于遍历的字符是否出现过
  • 如果没有出现过,则当前字符贡献引力数为斜对角的层数,又因为 i i i 是从 0 0 0 开始的,所以归纳为 i + 1 i + 1 i+1
  • 如果出现过,如最后一层 a a a,它却取决于前面层 c c c产生的子串,受影响的是上一次 a 出现的位置一列和之前列(读者仔细理解这句话),以为这个罗列的是一个正三角,所以影响的引力数也可以用i来表示,所以我们想到了更新出现字符的下标,就有了当前层的引力数 i − j − 1 + 1 = i − j i - j - 1 + 1 = i - j ij1+1=ij

至此,所有的情况均分析完,最后的结果,我们可以一直累加当前斜对角层的引力数,当前斜对角层的引力数又等于上一层的加上当前层字符贡献的。代码如下:

class Solution {
public:
    long long appealSum(string &s) {
        long ans = 0L, sum_g = 0L;
        vector<int> pos(26, -1);// -1初始化,刚好处理了,字符没出现过 i + 1
        for (int i = 0; i < s.length(); ++i) {
            char c = s[i] - 'a';
            sum_g += i - pos[c]; //上一斜对角层 + 这一层字符贡献
            ans += sum_g; //总的 累加 这一斜对角层
            pos[c] = i;//维护字符位置
        }
        return ans;
    }
};


觉得文章有用,点个赞,点个收藏,支持一下

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BiuPsYao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值