我需要找到数组中元素与数组中k元素集合之间距离的最小和,不包括该索引。
例如:
arr = {5,7,4,9}
K=2
min_sum(5) =\x{e76f}5-4\x{##**$$}5-7=3
min_sum(7) =_
min_sum(4) =区4-5区+4-7区=4
min_sum(9) =\x{e76f}9-7\x{##**$$}9-5=6
因此,一个简单的解决方案是从数组的每个元素中减去第一个元素,然后对数组进行排序并计算排序数组中前k个元素的和。但太久了..。我相信这是一个dp问题或者类似的问题(可能是脚步声)。
输入:
N-数组元素数
K-集合中的元素数
数组
制约因素:
2 <= n <= 350 000
1 <= k
1 <= ai <= 10^9
时限:2秒
输入:
4.
2
5 7 4 9
输出:
3 4 4 6
解决这个问题最有效的方法是什么?如何优化最小和的搜索?
这是我在C++中的代码,它在n=35万,k=15万的情况下工作约3分钟:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, k, tp;
unsigned long long temp;
cin >> n >> k;
vector<unsigned int> org;
vector<unsigned int> a;
vector<unsigned long long> cum(n, 0);
//unordered_map <int, long long> ans;
unordered_map <int, long long> mp;
for (int i = 0; i < n; i++){
cin >> tp;
org.push_back(tp);
a.push_back(tp);
}
/*
srand(time(0));
for (int i = 0; i < n; i++){
org.push_back(rand());
a.push_back(org[i]);
}
*/
sort(a.begin(), a.end());
partial_sum(a.begin(), a.end(), cum.begin());
mp[a[0]] = cum[k] - cum[0] - a[0] * k;
//ans[a[0]] = mp[a[0]];
for (int i = 1; i <= k; i++) {
mp[a[i]] = a[i] * i - cum[i-1] + cum[k] - cum[i] - a[i] * (k-i);
}
for (int i = 1; i < n-k; i++){
for (int j = 0; j <= k; j++){
//if (ans.find(a[i+j]) != ans.end()) {continue;}
temp = ( (a[i+j] * j) - (cum[i+j-1] - cum[i-1]) ) + ( cum[i+k] - cum[i+j] - a[i+j] * (k-j) );
if (mp.find(a[i+j]) == mp.end()) { mp[a[i+j]] = temp; }
else if (mp[a[i+j]] > temp) { mp[a[i+j]] = temp; }
//else { ans[a[i+j]] = mp[a[i+j]]; }
}
}
for (int i = 0; i < n; i++) {
cout << mp[org[i]] << " ";
}
return 0;
}发布于 2021-02-11 14:56:20
我觉得这个更好:
首先对数组进行排序,然后您就可以知道这一事实--对于数组中的每个元素i,它与其他元素集的最小距离将是与数组中k个元素周围的元素之间的距离。(当然,它可能在右边,左边,或者两边)。
因此,对于计算min_sum(ai)的每一个元素,都要这样做:
首先,min_sum(ai) = 0。
然后,使用两个索引,将它们标记为r(i的右边)和l(i的左边),并将距离(ai-ar)与距离(ai-al)进行比较。你会把最小的加入到min_sum(ai)中,如果它是右边的,那么增量指数r,如果它是左边的,那么减小指数l。当然,如果左边等于0,右边的是n,你就会从另一边取长度。无论如何,你要这样做,直到你把k个字母相加,仅此而已。
这样,除了主数组之外,您没有对任何东西进行排序。
https://stackoverflow.com/questions/66155449
复制相似问题