LeetCode 2615. 等值距离和

2615. 等值距离和

给你一个下标从 0 开始的整数数组 nums 。现有一个长度等于 nums.length 的数组 arr 。对于满足 nums[j] == nums[i] 且 j != i 的所有 j ,arr[i] 等于所有 |i - j| 之和。如果不存在这样的 j ,则令 arr[i] 等于 0 。

返回数组 arr 。

示例 1:

输入:nums = [1,3,1,1,2]
输出:[5,0,3,4,0]
解释:
i = 0 ,nums[0] == nums[2] 且 nums[0] == nums[3] 。因此,arr[0] = |0 - 2| + |0 - 3| = 5 。 
i = 1 ,arr[1] = 0 因为不存在值等于 3 的其他下标。
i = 2 ,nums[2] == nums[0] 且 nums[2] == nums[3] 。因此,arr[2] = |2 - 0| + |2 - 3| = 3 。
i = 3 ,nums[3] == nums[0] 且 nums[3] == nums[2] 。因此,arr[3] = |3 - 0| + |3 - 2| = 4 。 
i = 4 ,arr[4] = 0 因为不存在值等于 2 的其他下标。

示例 2:

输入:nums = [0,5,3]
输出:[0,0,0]
解释:因为 nums 中的元素互不相同,对于所有 i ,都有 arr[i] = 0 。

提示:

  • 1 <= nums.length <= 10^5
  • 0 <= nums[i] <= 10^9

提示 1

Can we use the prefix sum here?


提示 2

For each number x, collect all the indices where x occurs, and calculate the prefix sum of the array.


提示 3

For each occurrence of x, the indices to the right will be regular subtraction while the indices to the left will be reversed subtraction.

解法1:前缀和 + 距离和 + 哈希表

若此题难以理解,可以先做类似题型:LeetCode 1685. 有序数组中差绝对值之和-CSDN博客

题目描述

想象一下,你手中有一串编号的珠子,每个珠子上都刻有一个数字,这些数字可能相同也可能不同。现在,我们要为每个珠子计算一个特殊的分数,这个分数是它与所有刻有相同数字的其他珠子之间的距离之和。如果某个珠子是独一无二的,即没有其他珠子与它刻有相同的数字,那么它的分数就是0。

算法思路

这个问题的关键在于如何高效地计算每个珠子与其他珠子的距离之和。我们可以采用以下步骤:

  1. 分组:首先,我们将所有刻有相同数字的珠子分为一组。这可以通过使用一个哈希表来实现,其中键是珠子上的数字,值是包含所有对应珠子编号的列表。

  2. 前缀和:对于每组珠子,我们计算一个前缀和数组,这个数组的第i个元素表示从组的第一个珠子到第i个珠子的编号之和。

  3. 计算距离和:对于组内的每个珠子,我们使用前缀和来快速计算它与其他珠子的距离和。有一个的公式,可以避免我们对每个珠子都进行遍历:

    • 对于组内的第i个珠子,它左边有i-1个珠子,右边有m-1- i个珠子(其中m是组内珠子的总数)。
    • 它与左边每个珠子的距离和可以通过 index * i - presum[i] 来计算。
    • 它与右边每个珠子的距离和可以通过 index * (m-1-i) + presum[m] - presum[i +1]  来计算。
  4. 填充结果数组:最后,我们将计算得到的距离和填充到结果数组中,对应每个珠子的分数。

Java版:

class Solution {
    public long[] distance(int[] nums) {
        int n = nums.length;
        Map<Integer, List<Integer>> groups = new HashMap<>();
        for (int i = 0; i < n; i++) {
            if (!groups.containsKey(nums[i])) {
                groups.put(nums[i], new ArrayList<>());
            }
            groups.get(nums[i]).add(i);
        }

        long[] arr = new long[n];
        for (List<Integer> indices : groups.values()) {
            int m = indices.size();
            long[] presum = new long[m + 1];
            for (int i = 0; i < m; i++) {
                presum[i + 1] = presum[i] + indices.get(i);
            }
            for (int i = 0; i < m; i++) {
                int index = indices.get(i);
                // long left = index * i - presum[i];
                // long right = presum[m] - presum[i + 1] - index * (m - 1 - i)
                arr[index] = (long) index * (2 * i + 1 - m) - presum[i] + presum[m] - presum[i + 1];
            }
        }
        return arr;
    } 
}

Python3版:

class Solution:
    def distance(self, nums: List[int]) -> List[int]:
        n = len(nums) 
        groups = dict()
        for i in range(n):
            if nums[i] not in groups:
                groups[nums[i]] = []
            groups[nums[i]].append(i)
        
        arr = [0] * n 
        for indices in groups.values():
            m = len(indices) 
            presum = [0] * (m + 1)
            for i in range(m): 
                presum[i + 1] = presum[i] + indices[i] 
            
            for i in range(m):
                index = indices[i] 
                arr[index] = index * (2 * i + 1 - m) - presum[i] + presum[m] - presum[i + 1]
        
        return arr

复杂度分析

  • 时间复杂度: O(n),其中 n 为数组 nums 的长度。
  1. 分组:遍历整个数组nums,将相同数字的索引存储在哈希表中。这一步的时间复杂度是O(n),其中n是数组nums的长度。

  2. 计算前缀和:对于哈希表中的每个键(即数组中的不同数字),我们计算对应索引列表的前缀和。最坏情况下,如果数组中所有元素都相同,这一步的时间复杂度是O(k),其中k是数组中不同数字的数量。但在平均情况下,k远小于n,因此这一步的时间复杂度可以认为是O(n)。

  3. 计算距离和:对于每个索引,我们计算它与其他索引的距离和。这一步涉及到访问前缀和数组和一些基本的算术运算。对于每个组,这一步的时间复杂度是O(m),其中m是该组中元素的数量。由于我们对所有组都执行了这个操作,总的时间复杂度是O(n)。

综上所述,整个算法的时间复杂度主要由三个O(n)的操作组成,因此最终的时间复杂度是O(n)。

  • 空间复杂度: O(n)。
  1. 哈希表:我们使用了一个哈希表来存储每个数字及其索引的映射。在最坏情况下,如果数组中的所有元素都不相同,这个哈希表将包含n个键值对,因此空间复杂度是O(n)。

  2. 前缀和数组:对于每个组,我们创建了一个前缀和数组。最坏情况下,如果一个组包含n个元素,前缀和数组的长度将是n+1。但由于我们为每个不同的数字都创建了一个前缀和数组,总的空间复杂度仍然是O(n)。

  3. 结果数组:我们创建了一个长度为n的结果数组来存储最终的距离和。这个数组的空间复杂度是O(n)。

因此,整个算法的空间复杂度主要由哈希表和结果数组决定,总的空间复杂度是O(n)。

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值