2121-相同元素的间隔之和
给你一个下标从 0 开始、由 n
个整数组成的数组 arr
。
arr
中两个元素的 间隔 定义为它们下标之间的 绝对差 。更正式地,arr[i]
和 arr[j]
之间的间隔是 |i - j|
。
返回一个长度为 n
的数组 intervals
,其中 intervals[i]
是 __arr[i]
__ 和 __arr
__
中每个相同元素(与 arr[i]
的值相同)的 间隔之和 。
注意:|x|
是 x
的绝对值。
示例 1:
**输入:** arr = [2,1,3,1,2,3,3]
**输出:** [4,2,7,2,4,4,5]
**解释:**
- 下标 0 :另一个 2 在下标 4 ,|0 - 4| = 4
- 下标 1 :另一个 1 在下标 3 ,|1 - 3| = 2
- 下标 2 :另两个 3 在下标 5 和 6 ,|2 - 5| + |2 - 6| = 7
- 下标 3 :另一个 1 在下标 1 ,|3 - 1| = 2
- 下标 4 :另一个 2 在下标 0 ,|4 - 0| = 4
- 下标 5 :另两个 3 在下标 2 和 6 ,|5 - 2| + |5 - 6| = 4
- 下标 6 :另两个 3 在下标 2 和 5 ,|6 - 2| + |6 - 5| = 5
示例 2:
**输入:** arr = [10,5,10,10]
**输出:** [5,0,3,4]
**解释:**
- 下标 0 :另两个 10 在下标 2 和 3 ,|0 - 2| + |0 - 3| = 5
- 下标 1 :只有这一个 5 在数组中,所以到相同元素的间隔之和是 0
- 下标 2 :另两个 10 在下标 0 和 3 ,|2 - 0| + |2 - 3| = 3
- 下标 3 :另两个 10 在下标 0 和 2 ,|3 - 0| + |3 - 2| = 4
提示:
n == arr.length
1 <= n <= 105
1 <= arr[i] <= 105
方法一:数学
思路与算法
每个元素与相同数值元素间隔之和的一种方法是遍历 arr 数组,判断每个元素是否与 arr}[i] 相等,并统计间隔之和。但对于每一个元素,统计的时间复杂度均为 O(n),整体时间复杂度为 O(n^2),不符合题目要求。因此我们需要对统计的过程进行优化。
我们用 res 数组来维护每个元素与相同数值元素间隔之和。对于数组 arr 的第 i 个元素,它与相同数值元素的间隔之和 res}[i] 为:
\textit{res}[i] = \sum_{j,\ \textit{arr}[j] = \textit{arr}[i]} |i - j|.
我们可以将这些满足 arr}[j] = \textit{arr}[i] 的下标 j 按照相对于 i 的大小分成两部分,同时将绝对值展开:
\textit{res}[i] = \sum_{j > i,\ \textit{arr}[j] = \textit{arr}[i]} (j - i) + \sum_{j < i,\ \textit{arr}[j] = \textit{arr}[i]} (i - j).
我们不妨设这些下标 j 中小于 i 的有 n_1 个,大于 i 的有 n_2 个,那么我们可以对上式进一步展开:
\begin{aligned}
\textit{res}[i] &= \sum_{j > i,\ \textit{arr}[j] = \textit{arr}[i]} j - n_2 i + n_1 i - \sum_{j < i,\ \textit{arr}[j] = \textit{arr}[i]} j \
&= (n_1 - n_2) i + \sum_{j > i,\ \textit{arr}[j] = \textit{arr}[i]} j - \sum_{j < i,\ \textit{arr}[j] = \textit{arr}[i]} j.
\end{aligned}
我们可以通过降低计算 n_1, n_2 与两个 j 的求和式的时间复杂度以满足时间复杂度的要求。
一种方法是整体计算每个 res}[i] 对应项的数值。
考虑正向遍历 arr 数组,在遍历的时候利用哈希表维护每个数值迄今为止的出现次数和下标之和,这样就可以在 O(n) 的时间内计算出每个 i 对应的 n_1(即出现次数)与 \sum_{j < i,\ \textit{arr}[j] = \textit{arr}[i]} j(即下标之和)。同理,如果我们**反向**遍历 arr 数组,也可以在 O(n) 的时间内计算出每个 i 对应的 n_2(即出现次数)与 \sum_{j > i,\ \textit{arr}[j] = \textit{arr}[i]} j(即下标之和)。那么我们便可以在 O(n) 的时间内计算出所有的 res}[i]。
我们将 res 数组的初值均设为 0,并对 arr 数组进行两次遍历。在每次遍历时分别维护以数值为键,出现次数为值的哈希表 cnt 以及以数值为键,下标之和为值的哈希表 total。具体地:
在正向遍历到下标 i 时,我们将 res}[i] 加上 cnt}[\textit{arr}[i]] \times i - \textit{total}[\textit{arr}[i]],即为 n_1 i - \sum_{j < i,\ \textit{arr}[j] = \textit{arr}[i]} j;
在反向遍历到下标 i 时,我们将 res}[i] 加上 total}[\textit{arr}[i]] - \textit{cnt}[\textit{arr}[i]] \times i,即为 \sum_{j > i,\ \textit{arr}[j] = \textit{arr}[i]} j - n_2 i。
两次遍历完成后,res 数组即为 arr 中每个元素与相同数值元素间隔之和。我们返回该数组作为答案。
代码
1 | class Solution { |
1 | class Solution: |
复杂度分析
时间复杂度:O(n),其中 n 为 arr 的长度。即为两次遍历维护哈希表与间隔之和数组的时间复杂度。
空间复杂度:O(n),即为遍历时维护出现次数与下标之和的两个哈希表的空间开销。