比赛前10几分钟才想出来思路,没来得及做。记录一下
首先,不难看出应该要把相同数字的下标一起记下来。这里用一个map记录就行,key是数字,value是一个list,list的内容是数字的下标。
如果用暴力法来解,复杂度是O(n^2),对于10^5次方的输入规模会超时。
比赛时候主要猜测了几个方向:
1.由于下标序列list是个递增的数组,会不会是用二分??
2.dp??
3.找规律
尝试了一轮思考之后还是觉得通过找规律比较靠谱,还有一点是通过前一个数字的和直接推导出下一个,这样才可以避免O(n^2)的复杂度。
最后在草稿纸上画了下才明白,思路如下:
比如对于某个序列:[1,2,5,7,8,11]。
对于2来说,它的绝对值之和是:1 + 3 + 5 + 6 + 9 = 24
对于5,它的绝对值之和是:4 + 3 + 2 + 3 + 6 = 18
5的绝对值之和和2的绝对值之和之间的变化,我们可以分开两部分看。
对于5的右边的3个数:7,8,11。这3个数到2的绝对值都减少了3. 这个3是怎么来的呢? 就是5和2之间的差值。
所以一共少了3 * 3 = 9
对称地,对于左边来说,本来最左边的1只需要计算到2之间的距离绝对值(就是1),但是现在1需要多了2到5这一段的距离(3)。所以左边距离之和增加了1 * 3。
所以,2的绝对值之和到5的绝对值之和的变化是:
1.右边减少了3 * 3
2.左边增加了1 * 3.
因为2的绝对值之和是24,因此5的绝对值之和就是24 + (1 * 3) - (3 * 3) = 24 - 6 = 18
因此算法的思路就是:
分别求出左边增加的距离减去右边减少的距离。增加的个数和减少的个数分别是:i - 1 和list.size() - i - 1
代码如下:
public long[] getDistances(int[] arr) {
Map<Integer, List<Integer>> map = new HashMap<>();
for (int i = 0; i < arr.length; i++) {
List<Integer> list = map.getOrDefault(arr[i], new ArrayList<>());
list.add(i);
map.put(arr[i], list);
}
long[] result = new long[arr.length];
for (List<Integer> l : map.values()) {
solve(l, result);
}
return result;
}
private void solve(List<Integer> l, long[] result) {
long last = -1L;
for (int i = 0; i < l.size(); i++) {
if (i == 0) {
long tmpAbsSum = 0L;
for (int j = 1; j < l.size(); j++) {
tmpAbsSum += (Math.abs(l.get(0) - l.get(j)));
}
result[l.get(0)] = tmpAbsSum;
last = tmpAbsSum;
continue;
}
// 前后之差
long difference = Math.abs(l.get(i) - l.get(i - 1));
// 前面增加的
long add = i - 1;
//后面减少的
long minus = (l.size() - i - 1);
long current = last + (add - minus) * difference;
result[l.get(i)] = current;
last = current;
}
}
func getDistances(arr []int) []int64 {
pos := map[int][]int{}
for i, v := range arr {
pos[v] = append(pos[v], i) // 记录相同元素的位置
}
ans := make([]int64, len(arr))
for _, p := range pos {
sum := 0
for _, i := range p {
sum += i - p[0]
}
ans[p[0]] = int64(sum) // 最左侧元素的间隔和
for i, n := 1, len(p); i < n; i++ { // 计算下一个相同元素的间隔和
sum -= (n - i*2) * (p[i] - p[i-1]) // 到右边的 n-i 个点的距离更近了,同时到左边 i 个点的距离更远了
ans[p[i]] = int64(sum)
}
}
return ans
}