列表

详情


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

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

这里,sorted(arr) 表示将数组 arr 排序后得到的数组。

给你一个下标从 0 开始的整数数组 nums ,请你返回它所有 子数组 的 不平衡数字 之和。

子数组指的是一个数组中连续一段 非空 的元素序列。

 

示例 1:

输入:nums = [2,3,1,4]
输出:3
解释:总共有 3 个子数组有非 0 不平衡数字:
- 子数组 [3, 1] ,不平衡数字为 1 。
- 子数组 [3, 1, 4] ,不平衡数字为 1 。
- 子数组 [1, 4] ,不平衡数字为 1 。
其他所有子数组的不平衡数字都是 0 ,所以所有子数组的不平衡数字之和为 3 。

示例 2:

输入:nums = [1,3,3,3,5]
输出:8
解释:总共有 7 个子数组有非 0 不平衡数字:
- 子数组 [1, 3] ,不平衡数字为 1 。
- 子数组 [1, 3, 3] ,不平衡数字为 1 。
- 子数组 [1, 3, 3, 3] ,不平衡数字为 1 。
- 子数组 [1, 3, 3, 3, 5] ,不平衡数字为 2 。
- 子数组 [3, 3, 3, 5] ,不平衡数字为 1 。
- 子数组 [3, 3, 5] ,不平衡数字为 1 。
- 子数组 [3, 5] ,不平衡数字为 1 。
其他所有子数组的不平衡数字都是 0 ,所以所有子数组的不平衡数字之和为 8 。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int sumImbalanceNumbers(vector<int>& nums) { } };

python3 解法, 执行用时: 56 ms, 内存消耗: 16.2 MB, 提交时间: 2023-07-03 10:03:24

class Solution:
    def sumImbalanceNumbers(self, nums: List[int]) -> int:
        n = len(nums)
        right = [0] * n  # nums[i] 右侧的 x 和 x-1 的最近下标(不存在时为 n)
        idx = [n] * (n + 1)
        for i in range(n - 1, -1, -1):
            x = nums[i]
            right[i] = min(idx[x], idx[x - 1])
            idx[x] = i

        ans = 0
        idx = [-1] * (n + 1)
        for i, (x, r) in enumerate(zip(nums, right)):
            # 统计 x 能产生多少贡献
            ans += (i - idx[x - 1]) * (r - i)  # 子数组左端点个数 * 子数组右端点个数
            idx[x] = i
        # 上面计算的时候,每个子数组的最小值必然可以作为贡献,而这是不合法的
        # 所以每个子数组都多算了 1 个不合法的贡献
        return ans - n * (n + 1) // 2

java 解法, 执行用时: 1 ms, 内存消耗: 41.9 MB, 提交时间: 2023-07-03 10:03:09

class Solution {
    public int sumImbalanceNumbers(int[] nums) {
        int n = nums.length;
        var right = new int[n];
        var idx = new int[n + 1];
        Arrays.fill(idx, n);
        for (int i = n - 1; i >= 0; i--) {
            int x = nums[i];
            // right[i] 表示 nums[i] 右侧的 x 和 x-1 的最近下标(不存在时为 n)
            right[i] = Math.min(idx[x], idx[x - 1]);
            idx[x] = i;
        }

        int ans = 0;
        Arrays.fill(idx, -1);
        for (int i = 0; i < n; i++) {
            int x = nums[i];
            // 统计 x 能产生多少贡献
            ans += (i - idx[x - 1]) * (right[i] - i); // 子数组左端点个数 * 子数组右端点个数
            idx[x] = i;
        }
        // 上面计算的时候,每个子数组的最小值必然可以作为贡献,而这是不合法的
        // 所以每个子数组都多算了 1 个不合法的贡献
        return ans - n * (n + 1) / 2;
    }
}

cpp 解法, 执行用时: 8 ms, 内存消耗: 32.6 MB, 提交时间: 2023-07-03 10:02:36

class Solution {
public:
    int sumImbalanceNumbers(vector<int> &nums) {
        int n = nums.size(), right[n], idx[n + 1];
        fill(idx, idx + n + 1, 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;
        }

        int ans = 0;
        memset(idx, -1, sizeof(idx));
        for (int i = 0; i < n; i++) {
            int x = nums[i];
            // 统计 x 能产生多少贡献
            ans += (i - idx[x - 1]) * (right[i] - i); // 子数组左端点个数 * 子数组右端点个数
            idx[x] = i;
        }
        // 上面计算的时候,每个子数组的最小值必然可以作为贡献,而这是不合法的
        // 所以每个子数组都多算了 1 个不合法的贡献
        return ans - n * (n + 1) / 2;
    }
};

golang 解法, 执行用时: 0 ms, 内存消耗: 3.2 MB, 提交时间: 2023-07-03 10:02:13

// 贡献法,计算每个数字对结果的贡献
func sumImbalanceNumbers(nums []int) (ans int) {
	n := len(nums)
	right := make([]int, n)
	idx := make([]int, n+1)
	for i := range idx {
		idx[i] = n
	}
	for i := n - 1; i >= 0; i-- {
		x := nums[i]
		// right[i] 表示 nums[i] 右侧的 x 和 x-1 的最近下标(不存在时为 n)
		right[i] = min(idx[x], idx[x-1])
		idx[x] = i
	}

	for i := range idx {
		idx[i] = -1
	}
	for i, x := range nums {
		// 统计 x 能产生多少贡献
		ans += (i - idx[x-1]) * (right[i] - i) // 子数组左端点个数 * 子数组右端点个数
		idx[x] = i
	}
	// 上面计算的时候,每个子数组的最小值必然可以作为贡献,而这是不合法的
	// 所以每个子数组都多算了 1 个不合法的贡献
	return ans - n*(n+1)/2
}

func min(a, b int) int { if b < a { return b }; return a }

golang 解法, 执行用时: 12 ms, 内存消耗: 7.3 MB, 提交时间: 2023-07-03 10:01:17

func sumImbalanceNumbers(nums []int) (ans int) {
	n := len(nums)
	for i, x := range nums {
		vis := make([]int, n+2)
		vis[x] = 1
		cnt := 0
		for j := i + 1; j < n; j++ {
			if x := nums[j]; vis[x] == 0 {
				cnt += 1 - vis[x-1] - vis[x+1]
				vis[x] = 1
			}
			ans += cnt
		}
	}
	return
}

cpp 解法, 执行用时: 20 ms, 内存消耗: 32.4 MB, 提交时间: 2023-07-03 10:00:46

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++) {
            memset(vis, 0, sizeof(vis));
            vis[nums[i]] = true;
            int cnt = 0;
            for (int j = i + 1; j < n; j++) {
                int x = nums[j];
                if (!vis[x]) {
                    cnt += 1 - vis[x - 1] - vis[x + 1];
                    vis[x] = true;
                }
                ans += cnt;
            }
        }
        return ans;
    }
};

java 解法, 执行用时: 10 ms, 内存消耗: 41.7 MB, 提交时间: 2023-07-03 10:00:29

class Solution {
    public int sumImbalanceNumbers(int[] nums) {
        int ans = 0, n = nums.length;
        var vis = new boolean[n + 2];
        for (int i = 0; i < n; i++) {
            Arrays.fill(vis, false);
            vis[nums[i]] = true;
            int cnt = 0;
            for (int j = i + 1; j < n; j++) {
                int x = nums[j];
                if (!vis[x]) {
                    cnt++;
                    if (vis[x - 1]) cnt--;
                    if (vis[x + 1]) cnt--;
                    vis[x] = true;
                }
                ans += cnt;
            }
        }
        return ans;
    }
}

python3 解法, 执行用时: 416 ms, 内存消耗: 16.1 MB, 提交时间: 2023-07-03 10:00:10

'''
枚举

由于 n 至多为 1000,我们可以从左到右枚举子数组左端点 i,然后从 i+1 开始向右枚举子数组右端点 j。
一边枚举 j,一边维护不平衡度 cnt:

如果 x=nums[j] 之前出现过,那么子数组排序后必然会和另一个 x 相邻,cnt 不变;
如果 x=nums[j] 之前没出现过,那么看 x−1 和 x+1 是否出现过:都没有,cnt 加一;只有一个,cnt 不变;两个都有,cnt 减一。
遍历过程中,累加 cnt,即为答案。
'''
class Solution:
    def sumImbalanceNumbers(self, nums: List[int]) -> int:
        ans, n = 0, len(nums)
        for i, x in enumerate(nums):
            vis = [False] * (n + 2)
            vis[x] = True
            cnt = 0
            for j in range(i + 1, n):
                x = nums[j]
                if not vis[x]:
                    cnt += 1 - vis[x - 1] - vis[x + 1]
                    vis[x] = True
                ans += cnt
        return ans

上一题