交换两个序列的元素,使得元素和的差异变得最小。
Posted
技术标签:
【中文标题】交换两个序列的元素,使得元素和的差异变得最小。【英文标题】:Swap the elements of two sequences, such that the difference of the element-sums gets minimal. 【发布时间】:2012-01-28 19:29:00 【问题描述】:面试题:
给定两个无序整数序列
a
和b
,它们的大小为n,所有 数字随机选择:交换a
和b
的元素,使得a
的元素之和减去b
的元素之和最小。
举个例子:
a = [ 5 1 3 ]
b = [ 2 4 9 ]
结果是 (1 + 2 + 3) - (4 + 5 + 9) = -12。
我的算法:将它们排序在一起,然后将第一个最小的 n
整数放入 a
并留在 b
中。它在时间上是 O(n lg n),在空间上是 O(n)。我不知道如何将其改进为时间 O(n) 和空间 O(1) 的算法。 O(1) 意味着我们不需要更多额外的空间,除了 seq 1 和 2 本身。
有什么想法吗?
另一个问题是:如果我们需要最小化差异的绝对值(最小化|sum(a) - sum(b)|
)怎么办?
Python 或 C++ 思维者优先。
【问题讨论】:
听起来像是功课。如果是这样,请相应地标记。 如果考虑原始的 a 和 b 列表,它在空间中不可能是 O(1)。如果您不考虑它们,则只需直接交换值。无论哪种情况,请在问题中提供更多详细信息。 @GaretJax,如何在 O(n) 时间内高效地进行交换? 只需对单个元素使用单个临时变量(O(1) 空间)并遍历列表(O(n) 时间)。 -1 “交换 a 和 b 的元素”非常模糊——我在答案中发现了大约 2.01 种对此的理解。 【参考方案1】:修改后的解决方案:
合并两个列表 x = merge(a,b)。
计算 x 的中位数(复杂度 O(n) 见http://en.wikipedia.org/wiki/Selection_algorithm)
在 a 和 b 之间使用这个中值交换元素。即在a中找到一个小于中位数的元素,在b中找到一个大于中位数的元素并交换它们
最终复杂度:O(n)
最小化绝对差是NP完全的,因为它等价于背包问题。
【讨论】:
您能解释一下等效性吗?我似乎很清楚,OP 的排序解决方案并将最小值放入 a 将最小化 sum(a)-sum(b):我错过了什么? 你说的是第二部分(最小化绝对值)还是两者兼而有之?因为我认为它不适用于第一个,所以要获得最大的负差,将 n/2 最低的数字放在一个列表中,将 n/2 最高的数字放在另一个列表中,正如 OP 所说。 @DSM 我以为你在计算绝对最小值。如果只是最低限度使用新的解决方案。无需排序:) 对于中位数,您必须对 x 进行排序!如果你对 x 进行排序,复杂度不是 O(n)。 @ChristianAmmer 可以在 O(n) 中找到中位数。见:en.wikipedia.org/wiki/Selection_algorithm【参考方案2】:我想到的是以下算法大纲:
-
C = A v B
对 C 的 #A(A 的数量)元素进行部分排序
从 C 中前 #A 元素的总和中减去 C 中最后 #B 元素的总和。
您应该注意到,您不需要对所有元素进行排序,只需找到 A 最小元素的数量即可。你给出的例子:
-
C = 5, 1, 3, 2, 4, 9
C = 1、2、3、5、4、9
(1 + 2 + 3) - (5 + 4 + 9) = -12
C++ 解决方案:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
// Initialize 'a' and 'b'
int ai[] = 5, 1, 3 ;
int bi[] = 2, 4, 9 ;
std::vector<int> a(ai, ai + 3);
std::vector<int> b(bi, bi + 3);
// 'c' = 'a' merged with 'b'
std::vector<int> c;
c.insert(c.end(), a.begin(), a.end());
c.insert(c.end(), b.begin(), b.end());
// partitially sort #a elements of 'c'
std::partial_sort(c.begin(), c.begin() + a.size(), c.end());
// build the difference
int result = 0;
for (auto cit = c.begin(); cit != c.end(); ++cit)
result += (cit < c.begin() + a.size()) ? (*cit) : -(*cit);
// print result (and it's -12)
std::cout << result << std::endl;
【讨论】:
如果我们想要最优解(即 N/2 个最小值),那不是 O(N),而是 O(N log N/2)。 @Voo:你是对的,但是否存在 O(N) 算法——我想不出任何算法?而且我认为中位数的解决方案也不是 O(N),为了获得中位数,必须对序列进行排序,否则你是从中间挑选一个随机元素(或者我错了)? 哦,我同意 O(N log N/2) 似乎是最好的解决方案。毕竟我们需要 N/2 个最小值,我真的不知道在 O(N) 中这怎么可能。以上是关于交换两个序列的元素,使得元素和的差异变得最小。的主要内容,如果未能解决你的问题,请参考以下文章
[微软]有两个序列a,b,大小都为n,序列元素的值任意整数,无序; 要求:通过交换a,b中的元素,使[序列a元素的和]与[序列b元素的和]之间的差最小_利用排列组合思路解决_python版