【LeetCode】计算贡献系列题

424 阅读1分钟

828. 统计子串中的唯一字符

image.png

枚举每个字符贡献的个数

image.png

class Solution {
public:
    int uniqueLetterString(string s) {
        int n = s.size();
        int mod = 1e9+7;
        int res = 0;
        for(int i=0; i<n; i++){
            int left = i-1;
            int right = i+1;
            while(left >=0 && s[left] != s[i]) left--;
            while(right < n && s[right] != s[i]) right++;
            res += (i-left)*(right-i)%mod;
        }
        return res;
    }
};

907. 子数组的最小值之和

image.png

暴力超时

class Solution {
public:
    int sumSubarrayMins(vector<int>& arr) {
        int n = arr.size();
        long long res = 0;
         int mod=1e9+7;
        for(int i=0; i<n; i++){
            int left = i-1;
            int right = i+1;
            while(left >=0 && arr[left] >= arr[i]) left--;
            while(right < n && arr[right] > arr[i]) right++;
            long t = arr[i] *(i-left)*(right-i)%mod;
            res = (res + t)%mod;
        }
        return res;
    }
};

单调栈, 维护一个单调递减的栈,arr[i] 最为最小值出现的次数。

class Solution {
public:
    int sumSubarrayMins(vector<int>& arr) {
        long res = 0;
        int mod=1e9+7;
        arr.push_back(0);
        int n = arr.size();
        stack<int> st;
        for(int i=0; i<n; i++){
            while(!st.empty() && arr[i] <= arr[st.top()]){
                int idx = st.top();st.pop();
                int next = -1;
                if(!st.empty()){
                    next = st.top();
                }
                res += long(arr[idx]) *(i-idx) *(idx - next)%mod;
                res %= mod;
            }
            st.push(i);
        }
        return res;
    }

};

1498. 满足条件的子序列数目

image.png

双指针, 子序列,不需要管顺序。

class Solution {
public:
    int numSubseq(vector<int>& nums, int target) {
        int res = 0;
        int mod = 1e9+7;
        int n = nums.size();
        sort(nums.begin(), nums.end());
        vector<int> p(n+1);
        p[0] = 1;
        for(int i=1; i<=n; i++){
            p[i] = p[i-1]*2%mod;
        }
        if(nums[0] > target) return 0;
        int l = 0, r = n-1;
        while(l <= r){
            if(target >= nums[l]+nums[r]){
                res += p[r-l];
                res %= mod;
                l++;
            }else r--;
        }
        return res;
    }
};

2104. 子数组范围和

image.png

单调栈,sum((s[i]最大值的次数 - s[i]最小值次数)* arr[i])

class Solution {
public:
    int n;
    long long get(vector<int> nums){
        stack<int> st;
        long long res = 0;
        nums.push_back(1e9+1);
        int m = n+1;
        for(int i=0; i<m; i++){
            while(!st.empty() && nums[i] > nums[st.top()]){
                int idx = st.top();st.pop();
                int next = -1;
                if(!st.empty()){
                    next = st.top();
                }
                res += ((long long)nums[idx]) *(i-idx)*(idx - next);
            }
            st.push(i);
        }
        return res;
    }
    
    long long subArrayRanges(vector<int>& nums) {
       n = nums.size();
       // 最大值
       long long maxv = get(nums);
       // 反转
       for(int i=0; i<n; i++) nums[i] = -nums[i];
       // 最小值
       long long minv = get(nums);
       // 最大值 和 最小值差值
       return maxv + minv;
    }
};