classSolution: defdistance(self, nums: List[int]) -> List[int]: groups = defaultdict(list) for i, x inenumerate(nums): groups[x].append(i) # 相同元素分到同一组,记录下标 ans = [0] * len(nums) for a in groups.values(): n = len(a) s = list(accumulate(a, initial=0)) # 前缀和 for j, target inenumerate(a): left = target * j - s[j] # 蓝色面积 right = s[n] - s[j] - target * (n - j) # 绿色面积 ans[target] = left + right return ans
classSolution { public: vector<longlong> distance(vector<int> &nums){ int n = nums.size(); unordered_map<int, vector<int>> groups; for (int i = 0; i < n; ++i) groups[nums[i]].push_back(i); // 相同元素分到同一组,记录下标
vector<longlong> ans(n); longlong s[n + 1]; s[0] = 0; for (auto &[_, a]: groups) { int m = a.size(); for (int i = 0; i < m; ++i) s[i + 1] = s[i] + a[i]; // 前缀和 for (int i = 0; i < m; ++i) { longlong target = a[i]; longlong left = target * i - s[i]; // 蓝色面积 longlong right = s[m] - s[i] - target * (m - i); // 绿色面积 ans[target] = left + right; } } return ans; } };
funcdistance(nums []int) []int64 { groups := map[int][]int{} for i, x := range nums { groups[x] = append(groups[x], i) // 相同元素分到同一组,记录下标 } ans := make([]int64, len(nums)) for _, a := range groups { n := len(a) s := make([]int, n+1) for i, x := range a { s[i+1] = s[i] + x // 前缀和 } for i, target := range a { left := target*i - s[i] // 蓝色面积 right := s[n] - s[i] - target*(n-i) // 绿色面积 ans[target] = int64(left + right) } } return ans }
复杂度分析
时间复杂度:O(n),其中 n 为 nums 的长度。
空间复杂度:O(n)。
方法二:相同元素分组+考虑增量
分组后,对于其中一个组 a,我们先暴力计算出 a[0] 到其它元素的距离之和,设为 s。
然后计算 a[1],我们不再暴力计算,而是思考:s 增加了多少?(增量可以是负数)
设 n 为 a 的长度,从 a[0] 到 a[1],有 1 个数的距离变大了 a[1]-a[0],有 n-1 个数的距离变小了 a[1]-a[0]。
所以对于 a[1],我们可以 O(1) 地知道它到其它元素的距离之和为
s + (2-n) \cdot (a[1]-a[0])
一般地,设 a[i-1] 到其它元素的距离之和为 s,那么 a[i] 到其它元素的距离之和为
s + (2i-n) \cdot (a[i]-a[i-1])
[sol2-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
classSolution: defdistance(self, nums: List[int]) -> List[int]: groups = defaultdict(list) for i, x inenumerate(nums): groups[x].append(i) # 相同元素分到同一组,记录下标 ans = [0] * len(nums) for a in groups.values(): n = len(a) s = sum(x - a[0] for x in a) # a[0] 到其它下标的距离之和 ans[a[0]] = s for i inrange(1, n): # 从计算 a[i-1] 到计算 a[i],考虑 s 增加了多少 s += (i * 2 - n) * (a[i] - a[i - 1]) ans[a[i]] = s return ans
classSolution { publiclong[] distance(int[] nums) { intn= nums.length; vargroups=newHashMap<Integer, List<Integer>>(); for (inti=0; i < n; ++i) // 相同元素分到同一组,记录下标 groups.computeIfAbsent(nums[i], k -> newArrayList<>()).add(i);
varans=newlong[n]; for (var a : groups.values()) { intm= a.size(); longs=0; for (int x : a) s += x - a.get(0); // a[0] 到其它下标的距离之和 ans[a.get(0)] = s; for (inti=1; i < m; ++i) // 从计算 a[i-1] 到计算 a[i],考虑 s 增加了多少 ans[a.get(i)] = s += (long) (i * 2 - m) * (a.get(i) - a.get(i - 1)); } return ans; } }
classSolution { public: vector<longlong> distance(vector<int> &nums){ int n = nums.size(); unordered_map<int, vector<int>> groups; for (int i = 0; i < n; ++i) groups[nums[i]].push_back(i); // 相同元素分到同一组,记录下标
vector<longlong> ans(n); for (auto &[_, a]: groups) { int m = a.size(); longlong s = 0; for (int x: a) s += x - a[0]; // a[0] 到其它下标的距离之和 ans[a[0]] = s; for (int i = 1; i < m; ++i) // 从计算 a[i-1] 到计算 a[i],考虑 s 增加了多少 ans[a[i]] = s += (longlong) (i * 2 - m) * (a[i] - a[i - 1]); } return ans; } };
funcdistance(nums []int) []int64 { groups := map[int][]int{} for i, x := range nums { groups[x] = append(groups[x], i) // 相同元素分到同一组,记录下标 } ans := make([]int64, len(nums)) for _, a := range groups { n := len(a) s := int64(0) for _, x := range a { s += int64(x - a[0]) // a[0] 到其它下标的距离之和 } ans[a[0]] = s for i := 1; i < n; i++ { // 从计算 a[i-1] 到计算 a[i],考虑 s 增加了多少 s += int64(i*2-n) * int64(a[i]-a[i-1]) ans[a[i]] = s } } return ans }