【LeetCode周赛】第374场周赛

文章讲述了LeetCode竞赛中的三个问题:找出数组中的峰值,计算添加最少硬币表示所有面值的策略,以及统计满足特定条件的完全子字符串。给出了C++和Python的解决方案,并分析了时间复杂度和空间复杂度。
摘要由CSDN通过智能技术生成

2951. 找出峰值 简单

2951. 找出峰值

分析:
枚举即可。不过要注意第一个和最后一个元素不算峰值。

代码:
C++代码

class Solution {
public:
    vector<int> findPeaks(vector<int>& mountain) {
        int n=mountain.size() - 1;
        vector<int> ans;
        for(int i=1;i<n;i++){
            if(mountain[i]>mountain[i-1] && mountain[i]>mountain[i+1]) ans.push_back(i);
        }
        return ans;
    }
};

python代码:

class Solution:
    def findPeaks(self, mountain: List[int]) -> List[int]:
        ans = []
        for i in range(1,len(mountain)-1):
            if mountain[i]>mountain[i-1] and mountain[i]>mountain[i+1]:
                ans.append(i)
        return ans

时间复杂度: O ( n ) O(n) O(n)

空间复杂度: O ( n ) O(n) O(n)


2952. 需要添加的硬币的最小数量 中等

2952. 需要添加的硬币的最小数量

分析:
题目的目标:选取硬币种类最少的情况,硬币的各个组合和能表示1~target中的任意一个面值(包含边界)。

定义 s,表示当前的硬币能表示 [ 0 , s − 1 ] [0, s-1] [0,s1]中的任意一个面值。此时面对下一个硬币 x 。将其添加进当前硬币序列中,一定选择该硬币的情况下,能表示的范围为 [ x , s + x − 1 ] [x, s+x-1] [x,s+x1]。对于x能不能直接添加进来,有两种情况:

  • x < = s x<=s x<=s :此时大致情况如下图所示,即 [ 0 , s − 1 ] [0, s-1] [0,s1] [ x , s + x − 1 ] [x, s+x-1] [x,s+x1]连接,或者二者存在交集。因此能将这两个区间直接结合,得到 [ 0 , s + x + 1 ] [0, s+x+1] [0,s+x+1]
    在这里插入图片描述
  • x > s x>s x>s:此时大致情况如下图,即 [ 0 , s − 1 ] [0, s-1] [0,s1] [ x , s + x − 1 ] [x, s+x-1] [x,s+x1]中间存在一定的空白区域, [ s , x − 1 ] [s, x-1] [s,x1],如果直接将该硬币加入则会有一段不能表示。此时需要手动添加一个硬币,贪心思路,直接添加一个面值为s的硬币,将硬币能表示的范围扩大到 [ 0 , 2 s − 1 ] [0, 2s-1] [0,2s1](与第一种情况一致,相当于 x = s x=s x=s)。然后再判断x能否直接添加。
    在这里插入图片描述
    为实现最少得硬币添加数,我们对数组先进行升序排序。
    如果不排序,可能会出现多添加硬币的情况,即:当前出现了情况二,但其实后面有能直接添加的较小硬币。
    先将面值小的硬币添加进去,当出现情况二时只能添加硬币解决,因为没有更小的面值的硬币了。

代码:

C++代码

class Solution {
public:
    int minimumAddedCoins(vector<int>& coins, int target) {
        sort(coins.begin(), coins.end());
        int s=1,i=0, ans=0;
        while(s<=target){
            if(i<coins.size() && coins[i]<=s){
                s+=coins[i];
                i++;
            }else{
                s+=s;
                ans++;
            }
        }
        return ans;
    }
};

python代码:

class Solution:
    def minimumAddedCoins(self, coins: List[int], target: int) -> int:
        s=1
        ans=0
        i=0
        coins.sort()
        while s <= target:
            if i<len(coins) and coins[i] <= s:
                s+=coins[i]
                i+=1
            else:
                s+=s
                ans+=1
        return ans

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

空间复杂度: O ( 1 ) O(1) O(1)


2953. 统计完全子字符串 中等

2953. 统计完全子字符串

分析:
数据比较大,直接枚举所有子串,然后判断很容易超时。注意到,题目条件: “相邻字符在字母表中的顺序 至多 相差 2 ”,可以利用该条件,分割得到多个满足要求的子串。

分割出来的子串中,可能包含多个满足要求的子串:aaaak=3,此时有两个子串满足要求,因此我们对于分割下来的子串要再进行滑动窗口的分割:

我们可以枚举 m(1~26) 个字符,此时满足要求的具有m个不同字符的子串长度为 k ∗ m k*m km。采用滑动窗口的方式,不断地从头开始往后移动。采用一维的计数数组来进行计数,判断是否满足要求。

代码:

C++代码:

class Solution {
public:
    int findString(string s, int k){
        int ans=0, n=s.length();
        for(int m=1;m<=26&&k*m<=n;m++){
            int cnt[26]{}; // 计数数组,一维。{} 的作用是将数组的每个值均初始化为0
            function<void()> check = [&](){
                for(int i=0;i<26;i++){
                    if(cnt[i] && cnt[i]!=k) return ;// 如果值为0,则没有该字符。如果值为k则满足要求,如果值不为k,则说明该子串中该字符出现的次数不符合要求。
                }
                ans++;
            };
            for(int i=0;i<n;i++){
                cnt[s[i] - 'a']++;
                int j=i+1-k*m; // j~i,表示的是长度为k*m的子串,j为起始点。j<0:说明当前字符串不够长
                if(j>=0){
                    check();
                    cnt[s[j] - 'a']--; // 要枚举下一个长度为k*m的子串,去掉起点,从后面加上一个字符。
                }
            }
        }
        return ans;
    }

    int countCompleteSubstrings(string word, int k) {
        int n=word.length(), ans=0;
        for(int i=0;i<n;){
            int j=i;i++;
            while(i<n && abs(int(word[i]) - int(word[i-1]))<=2) i++;
            ans += findString(word.substr(j,i-j), k); // 将满足要求的各个子串分割下来,用于进一步判断 
        }
        return ans;
    }
};

python代码:

class Solution:
    def findSubstrings(self, s: str, k: int) -> int:
        ans = 0
        for m in range(1,27):
            if k*m > len(s):
                break
            cnt = Counter()
            def check():
                for _,v in cnt.items():
                    if v!=0 and v!=k:
                        return False
                return True
            for i in range(len(s)):
                cnt[s[i]]+=1
                j = i+1-k*m
                if j >= 0:
                    if check():
                        ans+=1
                    cnt[s[j]]-=1
        return ans

    def countCompleteSubstrings(self, word: str, k: int) -> int:
        n=len(word)
        i=0
        ans=0
        while i<n:
            j=i
            i+=1
            while i<n and abs(ord(word[i]) - ord(word[i - 1]))<=2:
                i+=1
            ans += self.findSubstrings(word[j:i], k)
        return ans

时间复杂度: O ( n ∗ 26 ∗ 26 ) O(n * 26 *26) O(n2626)

空间复杂度: O ( 25 ) O(25) O(25),只创建了计数数组与一些变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值