所有子数组中不平衡数字之和

一个长度为 n 下标从 0 开始的整数数组 arr 的 不平衡数字 定义为,在 sarr = sorted(arr) 数组中,满足以下条件的下标数目:

  • 0 <= i < n - 1
  • sarr[i+1] - sarr[i] > 1

这里,sorted(arr) 表示将数组 arr 排序后得到的数组。
给你一个下标从 0 开始的整数数组 nums ,请你返回它所有子数组的不平衡数字之和。

1. 哈希

class Solution {
public:
    int sumImbalanceNumbers(vector<int> &nums) {
        int ans = 0, n = nums.size();
        bool vis[n + 2]; //注意这里数据大小小于长度,使用哈希代替排序,因为只需判断相邻
        for (int i = 0; i < n; i++) { //以i为左边界
            memset(vis, 0, sizeof(vis)); //重置
            vis[nums[i]] = true;
            int cnt = 0; //记录当前数组不平衡数
            for (int j = i + 1; j < n; j++) { //以j为右边界
                int x = nums[j];
                if (!vis[x]) { //更改当前不平衡数,重复数不记
                    cnt += 1 - vis[x - 1] - vis[x + 1];
                    vis[x] = true;
                }
                ans += cnt; //累加
            }
        }
        return ans;
    }
};

2. 贡献法

class Solution {
public:
    int sumImbalanceNumbers(vector<int> &nums) {
        int n = nums.size(), right[n], idx[n + 1];
        fill(idx, idx + n + 1, n); //初始右侧边界下标默认为n
        for (int i = n - 1; i >= 0; i--) {//从右往左遍历,记录右侧
            int x = nums[i];
            // right[i] 表示 nums[i] 右侧的 x 和 x-1 的最近下标(不存在时为 n)
            right[i] = min(idx[x], idx[x - 1]);
            idx[x] = i;
        }
        //x作为不平衡数字的贡献值的数组
        int ans = 0;
        memset(idx, -1, sizeof(idx)); //重置下标,左侧边界下标默认为-1
        for (int i = 0; i < n; i++) {//枚举以i为
            int x = nums[i];
            // 统计 x 能产生多少贡献
            ans += (i - idx[x - 1]) * (right[i] - i); // 子数组左端点个数 * 子数组右端点个数
            idx[x] = i;
        }
        // 上面计算的时候,每个子数组的最小值必然可以作为贡献,而这是不合法的
        // 所以每个子数组都多算了 1 个不合法的贡献
        return ans - n * (n + 1) / 2;
    }
};
posted @ 2023-07-08 22:18  失控D大白兔  阅读(8)  评论(0编辑  收藏  举报