每日一道leetcode(2026.04.23):等值距离和

每日一道leetcode(2026.04.23):等值距离和

  • [1. 题目](#1. 题目)
  • [2. 分析](#2. 分析)
  • [3. 代码实现](#3. 代码实现)

1. 题目

给你一个下标从 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 <= 10e5

0 <= nums[i] <= 10e9

2. 分析

这道题是求数组中所有相同元素的距离之和,主要难点在于nums的长度和值的范围是10e5和10e9级别。同样的,先尝试暴力解法,通过一层遍历,将所有相同的元素放到哈希表的数组中,再遍历进行遍历计算所有的距离和。这种解法能通过90%以上的用例。

记得之前有道与之类似的题,也是放哈希表,然后遍历遇到超时,当时的解法是当list长度超过64时,使用双向指针来优化,有不错的效果。然后这道题使用策略明显不适用,因为无论咋地,都得全遍历所有值相同的下标。用例里面有个全是相同的数值,基数有很大,这样层层遍历必超时。

官方解法是通过哈希表分组+前缀和,涉及到一定的公式推导。

我大概花了下面这个图,其实也能快速得出结论。

假设有a到g这7个相同的数值,所有数值到a的距离我们先通过一层遍历计算出来,注意,是使用分组之后的下标列表进行计算,不是原nums来进行全遍历。然后,在计算所有元素到b的距离和时,其实是有规律的,根据箭头的方向,我们将元素左边的距离和暂且称为前缀后,元素右边的距离和称为后缀和,从a移动到b后,前缀和增加了b-a,而后缀和减少了5(b-a)。

继续从b移动到c,前缀和增加了2(c-b),而后缀和减少了4(c-b)。

这样,在有距离a的距离和的基础上,遍历时又能很容易获得b-a的距离,对应的系数,也很容易观察得来,就可以快速计算出同类数值的距离和啦。

3. 代码实现

java 复制代码
class Solution {
    public long[] distance(int[] nums) {
        long[] arr = new long[nums.length];
        Map<Integer, List<Integer>> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (!map.containsKey(nums[i])) {
                map.put(nums[i], new ArrayList<>());
            }
            List<Integer> list = map.get(nums[i]);
            list.add(i);
        }
        for (Map.Entry<Integer, List<Integer>> next : map.entrySet()) {
            List<Integer> list = next.getValue();
            if (list.size() == 1) {
                arr[list.get(0)] = 0;
            }
            // 计算其它下标到第一个下标的距离和
            long dis = 0;
            int first = list.get(0);
            for (int j = 1; j < list.size(); j++) {
                dis += list.get(j) - first;
            }
            // 遍历计算所有通知的距离和
            long preDis = 0;
            long suffixDis = dis;

            int preCount = 0;
            for (int j = 0; j < list.size(); j++) {
                // 当前下标距离前一个下标的距离
                long curDis = 0L;
                if (j > 0) {
                    curDis = list.get(j) - list.get(j - 1);
                }
                preDis += preCount * curDis;
                suffixDis -= curDis * (list.size() - preCount);
                arr[list.get(j)] = preDis + suffixDis;
                preCount++;
            }
        }
        return arr;
    }
}
相关推荐
浅念-2 小时前
递归解题指南:LeetCode经典题全解析
数据结构·算法·leetcode·职场和发展·排序算法·深度优先·递归
Kiling_07042 小时前
Java集合进阶:Set与Collections详解
算法·哈希算法
智者知已应修善业3 小时前
【51单片机89C51及74LS273、74LS244组成】2022-5-28
c++·经验分享·笔记·算法·51单片机
洛水水3 小时前
【力扣100题】33.验证二叉搜索树
算法·leetcode·职场和发展
SimpleLearingAI3 小时前
聚类算法详解
算法·数据挖掘·聚类
刀法如飞4 小时前
Go 字符串查找的 20 种实现方式,用不同思路解决问题
算法·面试·程序员
Dlrb12116 小时前
C语言-指针数组与数组指针
c语言·数据结构·算法·指针·数组指针·指针数组·二级指针
WL_Aurora6 小时前
Python 算法基础篇之集合
python·算法
平行侠6 小时前
A15 工业路由器IP前缀高速检索与内存压缩系统
网络·tcp/ip·算法
阿旭超级学得完7 小时前
C++11包装器(function和bind)
java·开发语言·c++·算法·哈希算法·散列表