每日一道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;
    }
}
相关推荐
wayz1111 小时前
Momentum:PSL(心理线指标)技术指标详解
算法·金融·数据分析·量化交易·特征工程
8Qi812 小时前
LeetCode 213:打家劫舍 II(House Robber II)—— 题解 ✅
算法·leetcode·职场和发展·动态规划
三品吉他手会点灯12 小时前
C语言学习笔记 - 44.运算符和表达式 - 运算符2 - 除法与取余运算符
c语言·开发语言·笔记·算法
乐迪信息13 小时前
乐迪信息:AI算法盒子实时识别船舶烟雾与火焰异常
大数据·人工智能·算法·安全·目标跟踪
J-Tony1113 小时前
【JVM】根可达算法
jvm·算法
艾iYYY13 小时前
string 类的模拟实现
android·服务器·c语言·c++·算法
Lsk_Smion13 小时前
力扣实训 _ [75].颜色分类 _ 杨辉三角
数据结构·算法·leetcode
jidaowansui14 小时前
P11375 [GESP202412 六级] 树上游走
数据结构·算法
cuso4win14 小时前
Feed 流面试笔记
笔记·面试·职场和发展