【LeetCode周赛】第 389 场周赛

目录

  • [3083. 字符串及其反转中是否存在同一子字符串 简单](#3083. 字符串及其反转中是否存在同一子字符串 简单)
  • [3084. 统计以给定字符开头和结尾的子字符串总数 中等](#3084. 统计以给定字符开头和结尾的子字符串总数 中等)
  • [3085. 成为 K 特殊字符串需要删除的最少字符数 中等](#3085. 成为 K 特殊字符串需要删除的最少字符数 中等)
  • [3086. 拾起 K 个 1 需要的最少行动次数 困难](#3086. 拾起 K 个 1 需要的最少行动次数 困难)

3083. 字符串及其反转中是否存在同一子字符串 简单

3083. 字符串及其反转中是否存在同一子字符串

分析:

易得:当存在 长度≥2 的反转子字符串时,一定会有 长度=2 的反转子字符串,因此只需要判断长度为2的子字符串即可。

法一 :直接判断。
法二:哈希表。

代码:

直接判断:

cpp 复制代码
class Solution {
public:
    bool isSubstringPresent(string s) {
        int n=s.size();
        for(int i=0;i<n-1;i++){
            string str = s.substr(i,2);reverse(str.begin(), str.end());
            if(s.find(str)!=string::npos) return true;
        }
        return false;
    }
};
python 复制代码
class Solution:
    def isSubstringPresent(self, s: str) -> bool:
        n = len(s)
        for i in range(n-1):
            if s[i:i+2] in s[::-1]:
                return True
        return False

哈希表:

cpp 复制代码
class Solution {
public:
    bool isSubstringPresent(string s) {
        int n = s.size();
        vector<long long> vis(26,0);
        for(int i=1;i<n;i++){
            int x = s[i-1]-'a', y = s[i]-'a';
            vis[x] |= 1<<y;// 数字中二进制位 0~25 为分别表示26个字母,对二进制位为 1,则表示 x 代表字母之后出现了该字母
            if(vis[y] >> x & 1) return true;
        } 
        return false;
    }
};
python 复制代码
class Solution:
    def isSubstringPresent(self, s: str) -> bool:
        vis = [0] * 26
        for x, y in pairwise(map(ord, s)):
            x -= ord('a')
            y -= ord('a')
            vis[x] |= 1<<y
            if vis[y] >> x&1:
                return True
        return False

3084. 统计以给定字符开头和结尾的子字符串总数 中等

3084. 统计以给定字符开头和结尾的子字符串总数

分析:

统计给定字符在字符串中出现的次数 cnt

以该字符串开头和结尾的子字符串,即任意选择两个该字符组成的子字符串的个数。 C 2 c n t C^{cnt}_{2} C2cnt

代码:

cpp 复制代码
class Solution {
public:
    long long countSubstrings(string s, char c) {
        int n=s.size();
        long long ans=0,cnt=0;
        for(int i=0;i<n;i++){
            if(s[i]==c){
                ans+=cnt;
                cnt++;
            }
        }
        return ans+cnt;
    }
};
cpp 复制代码
class Solution {
public:
    long long countSubstrings(string s, char c) {
        int cnt=0;
        for(auto& t : s) if(t == c) cnt++;
        return 1LL*(1+cnt)*cnt/2;
    }
};
python 复制代码
class Solution:
    def countSubstrings(self, s: str, c: str) -> int:
        cnt = s.count(c)
        return (cnt+1)*cnt//2

3085. 成为 K 特殊字符串需要删除的最少字符数 中等

3085. 成为 K 特殊字符串需要删除的最少字符数

分析:

需要得到最少删除字符数,我们反向思考,构造字符串。因为要得到最少的删除数,出现次数最少的字符,要么完全删除,要么完全保留。如果删除一部分,那么出现次数过多的也要一起删除,则不会是最少字符数。

枚举最少的字符的数量,再不断枚举其余字符的数量,构建 K特殊字符串,取最长的构造的字符串,结果即为原字符串长度 - 最长的构造的字符串的长度。

代码:

cpp 复制代码
class Solution {
public:
    int minimumDeletions(string word, int k) {
        vector<int> cnt(26,0),t;
        int n=word.size();
        for(int i=0;i<n;i++) cnt[word[i]-'a']++;
        for(int i=0;i<26;i++) if(cnt[i]>0) t.push_back(cnt[i]);
        sort(t.begin(),t.end());
        int all = accumulate(t.begin(), t.end(), 0),ans=all;
        for(int i=0;i<t.size();i++){
            int c=t[i];
            for(int j=i+1;j<t.size();j++){
                c+=min(t[i]+k,t[j]);
            }
            ans=min(ans, all-c);
        }
        return ans;
    }
};
python 复制代码
class Solution:
    def minimumDeletions(self, word: str, k: int) -> int:
        cnt,ans = [0]*26,0
        for i in word:
            cnt[ord(i) - ord('a')]+=1
        cnt = sorted(cnt)
        for i,x in enumerate(cnt):
            if x == 0:
                continue
            c = x
            for j in cnt[i+1:]:
                c+=min(x+k,j)
            ans = max(ans,c)
        return sum(cnt) - ans

3086. 拾起 K 个 1 需要的最少行动次数 困难

3086. 拾起 K 个 1 需要的最少行动次数

分析:

对于获取转换后的1,至少需要两次操作(方法一+方法二)

对于获取原本就存在的1,则需要看对应下标与 i n d e x index index。

注意:并非获取转换后的 1 操作数更少,设原本存在的 1 的下标为x

  • 当 x = = i n d e x x==index x==index ,不需要操作。
  • 当 ∣ x − i n d e x ∣ = = 1 |x - index| == 1 ∣x−index∣==1,仅需要一个操作。

因此在统计时,查看是否存在连续2或者3个 1 出现,同时再看是否能通过生成 1 来获取,否则只能一点一点移动。

代码:

cpp 复制代码
class Solution {
public:
    long long minimumMoves(vector<int>& nums, int k, int maxChanges) {
        int c=0, n=nums.size();
        vector<int> point;
        for(int i=0;i<n;i++){
            if(nums[i]==0) continue;
            point.push_back(i);
            c=max(c,1);// 至少有一个连续的 1
            if(i>0 && nums[i-1]==1){
                if(i>1 && nums[i-2]==1){
                    c=3; // 有三个连续的 1
                }else{
                    c=max(c,2); // 至少有两个连续的 1
                }
            }
        }
        c=min(c,k); // 判断 c 是否满足 k,如果 c>k,那么就不需要这么多连续的 1。
        if(maxChanges >= k-c){ // 在取完连续 1,后,变化操作是否满足
            return max(c-1,0) + (k-c)*2; // 满足的话 直接返回操作次数
        }
        int m=point.size();
        vector<long long> sum(m+1,0);
        for(int i=0;i<m;i++){
            sum[i+1] = sum[i] + 1LL*point[i];
        }
        int size = k-maxChanges; // 还剩下多少需要一个一个移位
        long long ans = LLONG_MAX;
        for(int r = size;r<=m;r++){
            int l = r-size, i=l+size/2;
            long long index = point[i];
            long long s1 = index * (i-l) - (sum[i] - sum[l]); // 将中位数 i 左边的所有 1 移位到 index 所需的操作数
            long long s2 = sum[r] - sum[i]-index*(r-i); // 将中位数 i 右边的所有 1 移位到 index 所需的操作数
            ans = min(ans, s1+s2);
        }
        return ans + maxChanges*2;
    }
};
python 复制代码
class Solution:
    def minimumMoves(self, nums: List[int], k: int, maxChanges: int) -> int:
        pos = []
        n,c = len(nums),0
        for i,n in enumerate(nums):
            if n==0:
                continue
            c=max(c,1)
            pos.append(i)
            if i>0 and nums[i-1]==1:
                if i>1 and nums[i-2]==1:
                    c=3
                else:
                    c=max(c,2)
        c=min(c,k)
        if maxChanges>=k-c:
            return max(c-1,0) + (k-c)*2
        n,ans = len(pos), inf
        pre_sum = list(accumulate(pos, initial=0))
        s = k - maxChanges
        for r in range(s, n+1):
            l = r - s
            i = l + s//2
            index = pos[i]
            s1 = (index * (i-l)) - (pre_sum[i] - pre_sum[l]) 
            s2 = (pre_sum[r] - pre_sum[i]) - index * (r-i)
            ans = min(ans , s1+s2)
        return ans + maxChanges*2
相关推荐
爱吃生蚝的于勒1 小时前
C语言内存函数
c语言·开发语言·数据结构·c++·学习·算法
吾店云建站5 小时前
WordPress 6.7 “Rollins”发布
科技·程序人生·职场和发展·创业创新·程序员创富
ChoSeitaku6 小时前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
DdddJMs__1357 小时前
C语言 | Leetcode C语言题解之第557题反转字符串中的单词III
c语言·leetcode·题解
Fuxiao___7 小时前
不使用递归的决策树生成算法
算法
我爱工作&工作love我7 小时前
1435:【例题3】曲线 一本通 代替三分
c++·算法
白-胖-子7 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
workflower7 小时前
数据结构练习题和答案
数据结构·算法·链表·线性回归
好睡凯7 小时前
c++写一个死锁并且自己解锁
开发语言·c++·算法
Sunyanhui18 小时前
力扣 二叉树的直径-543
算法·leetcode·职场和发展