Codeforces
CF Step
Youtube Linkedin Discord Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Code : Count Substrings That Can Be Rearranged to Contain a String I

class Solution {
  public:
    long long validSubstringCount(string word1, string word2);
};

long long Solution ::validSubstringCount(string word1, string word2) {
    int n = word1.length();
    vector<int> need(26, 0);
    for (char ch : word2) {
        need[ch - 'a']++;
    }

    vector<vector<int>> freq(26, vector<int>(n, 0));
    for (int i = 0; i < n; i++) {
        freq[word1[i] - 'a'][i] = 1;
    }
    for (int c = 0; c < 26; c++) {
        auto &pref = freq[c];
        for (int i = 1; i < n; i++) {
            pref[i] += pref[i - 1];
        }
    }

    auto query_sum = [&](int c, int l, int r) {
        auto &pref = freq[c];
        return pref[r] - (l ? pref[l - 1] : 0);
    };

    auto is_good = [&](int low, int high) {
        for (int c = 0; c < 26; c++) {
            if (query_sum(c, low, high) < need[c]) {
                return false;
            }
        }
        return true;
    };

    // dp[i] is the number of good substrings starting at index i.
    vector<int> dp(n);
    for (int i = 0; i < n; i++) {
        int low = i, high = n - 1, res = -1;
        while (low <= high) {
            int mid = (low + high) / 2;
            if (is_good(i, mid)) {
                res = mid;
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
        // res is now pointing at the smallest good index.
        if (res != -1) {
            dp[i] = n - res;
        }
    }

    return accumulate(dp.begin(), dp.end(), 0LL);
}
class Solution {
  public:
    long long validSubstringCount(string word1, string word2);
};

long long Solution ::validSubstringCount(string word1, string word2) {
    int n = word1.length();
    vector<int> need(26, 0);
    for (char ch : word2) {
        need[ch - 'a']++;
    }

    vector<vector<int>> freq(26, vector<int>(n, 0));
    for (int i = 0; i < n; i++) {
        freq[word1[i] - 'a'][i] = 1;
    }
    for (int c = 0; c < 26; c++) {
        auto &pref = freq[c];
        for (int i = 1; i < n; i++) {
            pref[i] += pref[i - 1];
        }
    }

    auto query_sum = [&](int c, int l, int r) {
        auto &pref = freq[c];
        return pref[r] - (l ? pref[l - 1] : 0);
    };

    auto is_good = [&](int low, int high) {
        for (int c = 0; c < 26; c++) {
            if (query_sum(c, low, high) < need[c]) {
                return false;
            }
        }
        return true;
    };

    // dp[i] is the number of good substrings starting at index i.
    vector<int> dp(n);
    int j = 0; // j points to the first good index.
    for (int i = 0; i < n; i++) {
        while (j < n && !is_good(i, j)) {
            j++;
        }
        dp[i] = n - j;
    }

    return accumulate(dp.begin(), dp.end(), 0LL);
}
class Solution {
  public:
    long long validSubstringCount(string word1, string word2);
};

long long Solution ::validSubstringCount(string word1, string word2) {
    int n = word1.length();
    vector<int> need(26, 0);
    for (char ch : word2) {
        need[ch - 'a']++;
    }

    int bad = 0;
    for (int c = 0; c < 26; c++) {
        bad += (need[c] > 0);
    }
    vector<int> have(26, 0);

    // dp[i] is the number of good substrings starting at index i.
    vector<int> dp(n);
    int j = -1; // j points to the first good index.
    for (int i = 0; i < n; i++) {
        while (j < n && bad) {
            j++;
            if (j == n) {
                break;
            }
            int c = word1[j] - 'a';
            // Add j.
            have[c]++;
            if (have[c] == need[c]) {
                bad--;
            }
        }
        dp[i] = n - j;
        // Remove i.
        int c = word1[i] - 'a';
        have[c]--;
        if (have[c] == need[c] - 1) {
            bad++;
        }
    }

    return accumulate(dp.begin(), dp.end(), 0LL);
}