力扣 411周赛

统计满足K约束的子字符串数量 I

给你一个 二进制 字符串 s 和一个整数 k。
如果一个 二进制字符串 满足以下任一条件,则认为该字符串满足 k 约束:
字符串中 0 的数量最多为 k。
字符串中 1 的数量最多为 k。
返回一个整数,表示 s 的所有满足 k 约束 的子字符串的数量。
 
输入:s = "10101", k = 1
输出:12
解释:s 的所有子字符串中,除了 "1010"、"10101" 和 "0101" 外,其余子字符串都满足 k 约束。

提示:
1 <= s.length <= 50
1 <= k <= s.length
s[i] 是 '0' 或 '1'。

分析问题:

  1. 长度不大于K的字符串肯定符合条件
  2. 字符串的长度最大为50,复杂度可以为 l o g ( n 3 ) log(n^3) log(n3)
    我想到的方法是:用前缀和做,表示 0 - i (假设当前位置为i) 分别有多少个0和1,最后,只需要枚举长度大于k的字符串的左右边界加上长度不大于k的字符串的个数 ( n + n − k + 1 ) ∗ ( k − 1 ) / 2 (n + n-k+1) * (k - 1) / 2 (n+nk+1)(k1)/2

const int N = 60;
class Solution {
public:
    
    int cnt[N];
    int countKConstraintSubstrings(string s, int k) {
        int n = s.size();
        int ans = 0;
        int t = min(n, k);
        ans += (n + n - t + 1) * t / 2;
        for (int i = 1; i <= n; i++) {
            if (s[i-1] == '1') cnt[i] = 1;
            cnt[i] += cnt[i - 1];
        }
        for (int i = 0; i < n; i++) {
            for (int j = i + k + 1; j <= n; j++) {
                int t = cnt[j] - cnt[i];
                if (t <= k || j - i - t <= k) ans++;
            }
        }
        return ans;
    }
};

超级饮料的最大强化能量

来自未来的体育科学家给你两个整数数组 energyDrinkA 和 energyDrinkB,数组长度都等于 n。这两个数组分别代表 A、B 两种不同能量饮料每小时所能提供的强化能量。
你需要每小时饮用一种能量饮料来 最大化 你的总强化能量。然而,如果从一种能量饮料切换到另一种,你需要等待一小时来梳理身体的能量体系(在那个小时里你将不会获得任何强化能量)。
返回在接下来的 n 小时内你能获得的 最大 总强化能量。
注意 你可以选择从饮用任意一种能量饮料开始。

示例 1:
输入:energyDrinkA = [1,3,1], energyDrinkB = [3,1,1]
输出:5
解释:
要想获得 5 点强化能量,需要选择只饮用能量饮料 A(或者只饮用 B)。
示例 2:
输入:energyDrinkA = [4,1,1], energyDrinkB = [1,1,3]
输出:7
解释:
第一个小时饮用能量饮料 A。
切换到能量饮料 B ,在第二个小时无法获得强化能量。
第三个小时饮用能量饮料 B ,并获得强化能量。
 
提示:
n == energyDrinkA.length == energyDrinkB.length
3 <= n <= 105
1 <= energyDrinkA[i], energyDrinkB[i] <= 105

解题思路:用动态规划来做。
公式( f[i][0] 表示i位置不喝饮料,f[i][1]表示i位置喝 a 饮料,f[i][2] 表示i位置喝 b 饮料 ):
f [ i ] [ 0 ] = m a x ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 1 ] , f [ i − 1 ] [ 2 ] ) f[i][0] = max(f[i-1][0], f[i-1][1], f[i-1][2]) f[i][0]=max(f[i1][0],f[i1][1],f[i1][2])
f [ i ] [ 1 ] = m a x ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 1 ] ) + a [ i ] f[i][1] = max(f[i-1][0], f[i-1][1]) + a[i] f[i][1]=max(f[i1][0],f[i1][1])+a[i]
f [ i ] [ 2 ] = m a x ( f [ i − 1 ] [ 0 ] , f [ i − 1 ] [ 2 ] ) + b [ i ] f[i][2] = max(f[i-1][0], f[i-1][2]) + b[i] f[i][2]=max(f[i1][0],f[i1][2])+b[i]

找出最大的N位K回文数

我分析的方法:用9填充(n+1)/2位数,从后往前一次递减遍历每位数,从后往前遍历这个数添加到这个数的末尾形成回文数直到可以被k整除。
判断是否是k的倍数,可以每次加一个数时都对加和取余,不影响结果。
这个方法会超时

const int N = 1e5 +10;
class Solution {
public:
    int n, k;
    char str[N];
    string ans;
    void dfs(int pos) {
        if(ans.size()) return;
        int t = (n + 1) >> 1;
        if (pos == t) {
            long long p = 0;
            for (int i = 0; i < n; i++) {
                p = (p * 10 % k + str[i < t ? i : (n / 2 - 1 - i % t)] - '0') % k;
              //  cout << str[i < t ? i : (n / 2 - 1 - i % t)];
            }
          //  cout << endl;
          //  cout << "p=" << p <
            if (!p) {
                ans = "";
                for(int i=0; i < n; i++) ans += str[i < t ? i : (n / 2 - 1 - i % t)];
                return;
            }
            return;
        }
        for (char c = '9'; c >= '0'; c--) {
            str[pos] = c;
            dfs(pos + 1);
        }
    }
    string largestPalindrome(int n, int k) {
        this->n = n;
        this->k = k;
        dfs(0);
        return ans;
    }
};

你可能感兴趣的:(算法,leetcode,深度优先,算法,力扣,c++)