leetcode
leetcode 2301 ~ 2350
等值距离和

等值距离和

难度:

标签:

题目描述

You are given a 0-indexed integer array nums. There exists an array arr of length nums.length, where arr[i] is the sum of |i - j| over all j such that nums[j] == nums[i] and j != i. If there is no such j, set arr[i] to be 0.

Return the array arr.

 

Example 1:

Input: nums = [1,3,1,1,2]
Output: [5,0,3,4,0]
Explanation: 
When i = 0, nums[0] == nums[2] and nums[0] == nums[3]. Therefore, arr[0] = |0 - 2| + |0 - 3| = 5. 
When i = 1, arr[1] = 0 because there is no other index with value 3.
When i = 2, nums[2] == nums[0] and nums[2] == nums[3]. Therefore, arr[2] = |2 - 0| + |2 - 3| = 3. 
When i = 3, nums[3] == nums[0] and nums[3] == nums[2]. Therefore, arr[3] = |3 - 0| + |3 - 2| = 4. 
When i = 4, arr[4] = 0 because there is no other index with value 2. 

Example 2:

Input: nums = [0,5,3]
Output: [0,0,0]
Explanation: Since each element in nums is distinct, arr[i] = 0 for all i.

 

Constraints:

  • 1 <= nums.length <= 105
  • 0 <= nums[i] <= 109

代码结果

运行时间: 280 ms, 内存: 50.5 MB


/*
 * 思路:
 * 1. 使用 Java Stream API 对数组进行处理。
 * 2. 遍历 nums 数组,使用 filter 和 map 操作找到所有相同元素的索引,并计算距离之和。
 * 3. 如果没有其他相同的元素,将对应位置的值设为 0。
 */

import java.util.stream.IntStream;

public class Solution {
    public int[] distanceArray(int[] nums) {
        return IntStream.range(0, nums.length)
            .map(i -> IntStream.range(0, nums.length)
                .filter(j -> i != j && nums[i] == nums[j])
                .map(j -> Math.abs(i - j))
                .sum())
            .toArray();
    }
}

解释

方法:

该题解采用的是使用哈希表来记录每个数字及其出现的所有索引位置。接下来,对于哈希表中的每个条目,如果一个数字出现不止一次,则计算与该数字相等的所有数组元素之间的距离和。为了高效地计算距离和,使用累积和技巧。对于每个索引位置i,使用公式:\(ans[num] = num \times i - pre[i] + pre[-1] - num \times (m - i) - pre[i]\),其中\(pre\)是索引位置的累积和数组,\(m\)是当前数字的出现次数。这种方法避免了对每个索引对的显式距离计算,从而提高了效率。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在构建哈希表时,是否考虑了数组中可能存在相同的数字?如果有,如何处理这些重复的数字?
在构建哈希表时,确实考虑了数组中可能存在的相同数字。这通过使用哈希表的数据结构实现,其中键为数字本身,而值为一个列表,这个列表记录了该数字在数组中出现的所有索引位置。当在遍历数组时遇到相同的数字,我们将其索引追加到哈希表中该数字对应的列表中。这种方法能够确保即使数字重复出现,也能准确记录其所有位置,为后续的距离计算提供必要的信息。
🦆
解题中使用的前缀和数组`pre`是如何定义的,具体是如何计算每个元素的前缀和的?
在解题中,前缀和数组`pre`用于存储数字索引的累积和。具体来说,对于一个给定的数字及其在数组中的所有索引列表,`pre[i]`表示从列表开始到第i个索引之前的所有索引的和。这通过使用`itertools.accumulate`函数计算得到,它会自动累加给定列表中的元素,并生成一个新的列表,其中每个元素是到当前位置的元素累积和。
🦆
在计算距离和时,公式中的`num * i - pre[i] + pre[-1] - num * (m - i) - pre[i]`能否详细解释每一项的意义及计算过程?
公式`num * i - pre[i] + pre[-1] - num * (m - i) - pre[i]`用于计算等值距离和。其中,`num * i`是当前索引乘以数字值,`pre[i]`是到当前索引之前所有索引的和,`pre[-1]`是所有索引的总和,`num * (m - i)`是从当前索引后所有位置的数字值乘以个数,`pre[i]`再次被减去,用于调整前缀和的计算。各项结合起来,可以有效地计算出从当前索引到其他所有相同数字的索引的距离和。
🦆
为什么选择使用累积和技巧来计算距离和,这种方法与直接计算相比有什么优势?
使用累积和技巧来计算距离和主要是为了提高计算效率。如果直接计算每对相同数字之间的距离和,需要双重循环,时间复杂度为O(n^2),这在数字量大时非常低效。而通过使用前缀和,可以将每次的距离计算简化为几个数学运算,从而将时间复杂度降低到O(n)。因此,累积和不仅简化了计算过程,也显著提高了算法的执行效率。

相关问题