leetcode
leetcode 2351 ~ 2400
所有子数组中不平衡数字之和

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

难度:

标签:

题目描述

The imbalance number of a 0-indexed integer array arr of length n is defined as the number of indices in sarr = sorted(arr) such that:

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

Here, sorted(arr) is the function that returns the sorted version of arr.

Given a 0-indexed integer array nums, return the sum of imbalance numbers of all its subarrays.

A subarray is a contiguous non-empty sequence of elements within an array.

 

Example 1:

Input: nums = [2,3,1,4]
Output: 3
Explanation: There are 3 subarrays with non-zero imbalance numbers:
- Subarray [3, 1] with an imbalance number of 1.
- Subarray [3, 1, 4] with an imbalance number of 1.
- Subarray [1, 4] with an imbalance number of 1.
The imbalance number of all other subarrays is 0. Hence, the sum of imbalance numbers of all the subarrays of nums is 3. 

Example 2:

Input: nums = [1,3,3,3,5]
Output: 8
Explanation: There are 7 subarrays with non-zero imbalance numbers:
- Subarray [1, 3] with an imbalance number of 1.
- Subarray [1, 3, 3] with an imbalance number of 1.
- Subarray [1, 3, 3, 3] with an imbalance number of 1.
- Subarray [1, 3, 3, 3, 5] with an imbalance number of 2. 
- Subarray [3, 3, 3, 5] with an imbalance number of 1. 
- Subarray [3, 3, 5] with an imbalance number of 1.
- Subarray [3, 5] with an imbalance number of 1.
The imbalance number of all other subarrays is 0. Hence, the sum of imbalance numbers of all the subarrays of nums is 8. 

 

Constraints:

  • 1 <= nums.length <= 1000
  • 1 <= nums[i] <= nums.length

代码结果

运行时间: 35 ms, 内存: 16.1 MB


/*
 * 思路:
 * 1. 使用流的方式生成所有子数组。
 * 2. 对每个子数组排序,计算不平衡数字。
 * 3. 累加所有子数组的不平衡数字。
 */

import java.util.*;
import java.util.stream.*;

public class SolutionStream {
    public int sumOfImbalanceNumbers(int[] nums) {
        int n = nums.length;
        return IntStream.range(0, n)
                .flatMap(i -> IntStream.range(i, n)
                        .map(j -> countImbalance(Arrays.stream(Arrays.copyOfRange(nums, i, j + 1)).sorted().toArray()))
                ).sum();
    }

    private int countImbalance(int[] sortedArray) {
        return (int) IntStream.range(0, sortedArray.length - 1)
                .filter(i -> sortedArray[i + 1] - sortedArray[i] > 1)
                .count();
    }
}

解释

方法:

题解通过两个主要步骤来解决问题:第一步是使用两个数组 right 和 idx 来存储关于每个元素右侧最近的 x 和 x-1 的信息。具体地,right 数组记录对于每个元素 nums[i],在它右侧最近的 x 或 x-1 的索引,如果不存在,则记录为 n。第二步是通过扫描每个元素并计算每个元素对于子数组不平衡数字的贡献。计算方式是,对于每个元素 x,在数组 nums 中位置为 i,它对于所有以 x 为最小值的子数组的贡献都是由两部分组成:从该位置左侧最近的 x-1 的位置到 i 的所有可能的子数组的数量与从 i 到它右侧最近的 x 或 x-1 的位置的所有可能的子数组的数量的乘积。由于在计算过程中,每个子数组的最小值被错误地计入了贡献,因此最后需要从总贡献中减去这部分不合法的贡献。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在题解中提到了`使用两个数组right和idx`,这种方法的选择是基于什么考虑?是否有其他数据结构可以提供同样的效率?
在这种问题中,使用数组`right`和`idx`的方法主要是为了高效地访问和更新元素的索引信息。数组可以提供O(1)的时间复杂度进行索引访问和更新,这对于算法的整体性能至关重要。虽然可以使用其他数据结构如哈希表来实现类似的功能,哈希表提供平均O(1)时间复杂度的访问和更新,但是相对于直接使用数组,哈希表在处理碰撞时可能会有额外的性能开销,并且在空间使用上通常比数组要高。因此,在这个特定情况下,直接使用数组是一个既简单又高效的选择。
🦆
题解中的边界处理,如`idx数组初始化为n+1大小并全部设为n`的原因是什么?这种初始化方式对算法的影响如何?
在题解中,`idx`数组的每个位置用来存储某个数值最后一次出现的索引。将`idx`数组初始化为`n`(`nums`的长度)是为了处理那些在数组`nums`中未出现或者在某个位置右侧不再出现的情况。当`idx[x]`为`n`时,表示数值`x`在当前位置右侧不存在,这是一种边界标记方法,使得算法能正确处理所有元素的右侧边界条件。这种初始化方法简化了边界条件的处理,避免了额外的条件判断,从而提高了代码的整洁性和执行效率。
🦆
在计算每个元素对子数组不平衡数字的贡献时,为什么选择从`数组的左端点到i的所有可能的子数组的数量与从i到它右侧最近的x或x-1的位置的所有可能的子数组的数量的乘积`来计算?这样的计算逻辑是怎样推导出来的?
这种计算方式是基于子数组结构的性质。对于每个元素`x`于位置`i`,要找到所有以`x`为最小值的子数组。子数组可以从`i`的左侧任何一个比`x`大的位置开始,直到遇到一个比`x`小的数(即`x-1`),同样子数组可以向右延伸到任何一个位置,直到`x`或`x-1`。因此,对于每个位置`i`,可以通过`i`左侧到最近的`x-1`的距离(子数组可能的左端点数)乘以从`i`到右侧最近的`x`或`x-1`的距离(子数组可能的右端点数)来计算以`i`为起点的所有子数组中,`x`作为最小值的情况数。这种计算方法能够准确并有效地统计出所有符合条件的子数组,因此被采用在算法中。

相关问题