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

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

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

1. 题目

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

返回数组 arr 。

示例 1:

输入:nums = 1,3,1,1,2

输出:5,0,3,4,0

解释:

i = 0 ,nums0 == nums2 且 nums0 == nums3 。因此,arr0 = |0 - 2| + |0 - 3| = 5 。

i = 1 ,arr1 = 0 因为不存在值等于 3 的其他下标。

i = 2 ,nums2 == nums0 且 nums2 == nums3 。因此,arr2 = |2 - 0| + |2 - 3| = 3 。

i = 3 ,nums3 == nums0 且 nums3 == nums2 。因此,arr3 = |3 - 0| + |3 - 2| = 4 。

i = 4 ,arr4 = 0 因为不存在值等于 2 的其他下标。

示例 2:

输入:nums = 0,5,3

输出:0,0,0

解释:因为 nums 中的元素互不相同,对于所有 i ,都有 arri = 0 。

提示:

1 <= nums.length <= 10e5

0 <= numsi <= 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;
    }
}
相关推荐
冻柠檬飞冰走茶42 分钟前
字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)
c语言·开发语言·数据结构·算法·动态规划
文丑颜不良啊1 小时前
LeetCode2161~2180题目解析
java·leetcode
雪落漂泊1 小时前
C++算法 二分查找篇(上)
开发语言·c++·算法
文丑颜不良啊3 小时前
LeetCode2141~2160题目解析
java·leetcode
LabVIEW开发3 小时前
LabVIEW 连接板:28 个端子怎么排,优先级怎么定
java·算法·labview
严肃小白兔4 小时前
MATLAB 数值计算中的精度与误差问题:浮点运算、误差传播与数值稳定性
人工智能·算法·matlab
青少儿编程课堂5 小时前
蓝桥杯青少组图形化省考报名倒计时·全国青少年信息素养大赛·电子学会图形化考级:校园黑白棋人机对战解析
c++·python·算法·bfs·信息学竞赛
jktantan6 小时前
注解式脱敏:用 Jackson 的 ContextualSerializer 做字段级策略(一)
spring boot·后端·算法·spring cloud·系统架构
Dream it possible!19 小时前
LeetCode 面试经典 150_多维动态规划_交错字符串(97_C++_中等)
算法·leetcode·面试·动态规划
心抵鹊19 小时前
算法之双指针系列(一)
算法·leetcode