Leetcode 第 411 场周赛题解

Leetcode 第 411 场周赛题解

题目1:3258. 统计满足 K 约束的子字符串数量 I

思路

暴力枚举每一个子字符串,看是否满足 k 约束。

代码

/*
 * @lc app=leetcode.cn id=3258 lang=cpp
 *
 * [3258] 统计满足 K 约束的子字符串数量 I
 */

// @lc code=start
class Solution
{
public:
    int countKConstraintSubstrings(string s, int k)
    {
        int n = s.length();

        function<bool(string)> check = [&](string s) -> bool
        {
            int cnt0 = 0, cnt1 = 0;
            for (char &c : s)
            {
                if (c == '0')
                    cnt0++;
                else
                    cnt1++;
                if (cnt0 > k && cnt1 > k)
                    return false;
            }
            return true;
        };

        int cnt = 0;
        for (int i = 0; i < n; i++)
            for (int j = i; j < n; j++)
            {
                string temp = s.substr(i, j - i + 1);
                if (check(temp))
                    cnt++;
            }
        return cnt;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n2),其中 n 是字符串 s 的长度。

空间复杂度:O(1)。

题目2:3259. 超级饮料的最大强化能量

思路

本题的状态定义 dfs(i,j)。其中 j=0,1,分别表示最后选的是 energyDrinkA[i] 还是 energyDrinkB[i]。

为方便实现,把 energyDrinkA 和 energyDrinkB 加到一个长为 2 的二维数组 c 中。

分类讨论:

  • 继续选 c[j] 中的元素,那么下一个数选 c[j][i−1],需要解决的问题为:从下标 [0,i−1] 中选数字,且最后选的是 c[j] 中的元素的情况下,所选元素之和的最大值,即 dfs(i−1,j)。

  • 改成选 c[j⊕1] 中的元素,那么下一个数选 c[j⊕1][i−2],需要解决的问题为:从下标 [0,i−2] 中选数字,且最后选的是 c[j⊕1] 中的元素的情况下,所选元素之和的最大值,即 dfs(i−2,j⊕1)。其中 ⊕ 为异或运算,通过异或 1,可以把 0 变成 1,把 1 变成 0。

代码

#
# @lc app=leetcode.cn id=3259 lang=python3
#
# [3259] 超级饮料的最大强化能量
#

# @lc code=start
class Solution:
    def maxEnergyBoost(self, energyDrinkA: List[int], energyDrinkB: List[int]) -> int:
        n = len(energyDrinkA)
        energyDrink = (energyDrinkA, energyDrinkB)

        @cache  # 缓存装饰器,避免重复计算 dfs 的结果(记忆化)
        def dfs(i: int, j: int) -> int:
            if i < 0:
                return 0
            res1 = dfs(i - 1, j) + energyDrink[j][i]
            res2 = dfs(i - 2, j ^ 1) + energyDrink[j][i]
            return max(res1, res2)
        
        return max(dfs(n - 1, 0), dfs(n - 1, 1))
# @lc code=end

复杂度分析

时间复杂度:O(n),其中 n 为数组 energyDrinkA/energyDrinkB 的长度。由于每个状态只会计算一次,动态规划的时间复杂度 = 状态个数 × 单个状态的计算时间。本题状态个数等于 O(n),单个状态的计算时间为 O(1),所以总的时间复杂度为 O(n)。

空间复杂度:O(n),其中 n 为数组 energyDrinkA/energyDrinkB 的长度。保存多少状态,就需要多少空间。

题目3:3260. 找出最大的 N 位 K 回文数

思路

找规律,打表。

  • k = 1,3,9:所有位为9。
  • k = 2,4,8:依次为首尾1,2,3位为8,其余位为9。
  • k = 5:首尾位为5,其余位为9。
  • k = 6:n>=3时,首尾位为8,奇数时中间一位为8,偶数时中间两位为7,其余位为9。
  • k = 7:n=3开始,中间1或2位为577944644977循环,其余位为9。

代码

#
# @lc app=leetcode.cn id=3260 lang=python3
#
# [3260] 找出最大的 N 位 K 回文数
#

# @lc code=start
class Solution:
    def largestPalindrome(self, n: int, k: int) -> str:
        if k == 1:
            return '9' * n
        elif k == 2:
            if n == 1:
                return '8'
                
            '''
            1 8
            2 88
            3 898
            4 8998
            5 89998
            6 899998
            7 8999998
            '''
            return '8' + (n-2) * '9' + '8'
        elif k == 3:
            '''
            1 9
            2 99
            3 999
            4 9999
            5 99999
            6 999999
            7 9999999
            '''
            return '9' * n
        elif k == 4:
            '''
            1 8
            2 88
            3 888
            4 8888
            5 88988
            6 889988
            7 8899988
            8 88999988
            9 889999988
            '''
            if n <= 4:
                return '8' * n
            
            return '88' + (n-4) * '9' + '88'
        # 5995
        elif k == 5:
            if n == 1:
                return '5'
                
            return '5' + (n-2) * '9' + '5'
        elif k == 6:
            '''
            1 6
            2 66
            3 888
            4 8778
            5 89898
            6 897798
            7 8998998
            '''
            if n <= 2:
                return '6' * n
            # 8 9999 8 9999 8
            if n % 2 == 1:
                tmp = (n-3) // 2 
                return '8' + tmp * '9' + '8' + tmp * '9' + '8'
            # 8 99 77 99 8
            else:
                tmp = (n-4) // 2
                return '8' + tmp * '9' + '77' + tmp * '9' + '8'

        elif k == 7:
            '''
            1 7
            2 77
            3 959
            4 9779
            5 99799
            6 999999
            7 9994999
            8 99944999
            9 999969999
            '''
            if n <= 2:
                return '7' * n
            
            if n % 2 == 1:
                tmp = (n-1) // 2
                for m in range(9,-1,-1):
                    s = '9' * tmp + str(m) + '9' * tmp
                    t = 0
                    for w in s:
                        t *= 10
                        t += int(w)
                        t %= k
                    if t == 0:
                        return s
            
            else:
                tmp = (n-2) // 2
                for m in range(9,-1,-1):
                    s = '9' * tmp + str(m)  + str(m) + '9' * tmp
                    t = 0
                    for w in s:
                        t *= 10
                        t += int(w)
                        t %= k
                    if t == 0:
                        return s

            
        elif k == 8:
            '''
            1 8
            2 88
            3 888
            4 8888
            5 88888
            6 888888
            7 8889888
            8 88899888
            9 888999888
            '''
            if n <= 6:
                return '8' * n
            
            return '888' + (n-6) * '9' + '888'
        elif k == 9:
            # 同 3
            return '9' * n
# @lc code=end

复杂度分析

时间复杂度:O(1)。

空间复杂度:O(1)。

题目4:3261. 统计满足 K 约束的子字符串数量 II

思路

滑动窗口+前缀和+二分查找/双指针。

题解:https://leetcode.cn/problems/count-substrings-that-satisfy-k-constraint-ii/solutions/2884463/hua-dong-chuang-kou-qian-zhui-he-er-fen-jzo25/

代码

/*
 * @lc app=leetcode.cn id=3261 lang=cpp
 *
 * [3261] 统计满足 K 约束的子字符串数量 II
 */

// @lc code=start
class Solution
{
public:
    vector<long long> countKConstraintSubstrings(string s, int k, vector<vector<int>> &queries)
    {
        int n = s.length();
        vector<int> left(n);
        vector<long long> sum(n + 1);
        int cnt[2]{}, l = 0;

        for (int i = 0; i < n; i++)
        {
            cnt[s[i] & 1]++;
            while (cnt[0] > k && cnt[1] > k)
            {
                cnt[s[l++] & 1]--;
            }
            left[i] = l;
            // 计算 i-left[i]+1 的前缀和
            sum[i + 1] = sum[i] + i - l + 1;
        }

        vector<long long> ans(queries.size());
        for (int i = 0; i < queries.size(); i++)
        {
            int l = queries[i][0], r = queries[i][1];
            int j = lower_bound(left.begin() + l, left.begin() + r + 1, l) - left.begin();
            ans[i] = sum[r + 1] - sum[j] + (long long)(j - l + 1) * (j - l) / 2;
        }
        return ans;
    }
};
// @lc code=end

复杂度分析

时间复杂度:O(n+qlogn),其中 n 是数组 nums 的长度,q 是数组 queries 的长度。注意 l 只会增加不会减少,所以二重循环的时间复杂度为 O(n)。

空间复杂度:O(n),其中 n 是数组 nums 的长度。返回值不计入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

UestcXiye

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

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

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

打赏作者

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

抵扣说明:

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

余额充值