设计一种算法来查找数组中所有整数对,它们总和为指定值。
我尝试使用哈希表存储数组元素总和的条目,但这不是一个有效的解决方案。
我可以用什么算法有效地解决这个问题?
答案 0 :(得分:32)
我不明白为什么哈希表方法效率低下,至少在算法分析术语中 - 在内存位置术语中无可否认,它可能非常糟糕。无论如何,扫描阵列两次......
第一次扫描 - 将所有数组元素放在哈希表中 - 总共O(n)。单个插入仅按摊销O(1),但关于摊销分析如何工作的一个巧妙的事情意味着O(n)是绝对的 - 不摊销。
第二次扫描 - 检查哈希表中的(sum - current) - 总共O(n)。
这至少在理论上击败了O(n log n)排序和搜索方法。
然后,请注意您可以将两个扫描合并为一个。在第一次扫描期间遇到第二对时,您可以发现一对。在伪代码......
for i in array.range
hashset.insert (array [i])
diff = sum - array [i]
if hashset.includes (diff)
output diff, array [i]
如果您需要项目的位置,请使用散列图并在其中存储项目位置。如果需要处理重复项,则可能需要在哈希映射中存储计数。对于位置和重复项,您可能需要一个起始指针的散列图,用于链接的位置列表。
这假设了哈希表的实现,但是在大多数当前语言和库中通常的实现都是相当安全的。
BTW - 组合扫描不应被视为优化。迭代开销应该是微不足道的。对于非常大的数组,内存局部性问题可能会使单个传递稍微有效,但实际的内存局部性问题无论如何都会在哈希表查找中。IMO是组合扫描的唯一真正原因是因为您只希望每对报告一次 - 以双扫描方式处理它会更麻烦。
答案 1 :(得分:18)
如果数组已排序:
设i = 0,j =数组结束,sum =您要查找的值, 然后做:
如果i + j = sum,则输出(i,j)。
如果i + j<总和,然后将我移动到正确的位置
如果i + j>求和,然后将j移到左边一个位置。
时间复杂度:O(n)。空间复杂度:O(1)。
如果数组未排序,有几种方法可以解决此问题:
对数组进行排序,然后使用上述方法。
HashMap:
将所有元素存储在HashMap中。
a+b=sum
,所以b=sum-a
。对于数组的每个元素a
,从HashMap中查找b
。
HashMap查找需要分摊O(1)。
时间复杂度:O(n)。空间复杂度:O(n)。
<强>位图:强>
迭代输入以创建位图,其中每个位对应于元素值。假设输入为{2,5,8}
,然后我们将位图数组的索引2,5和8从二进制0切换为1.每个元素需要O(1),因此总共为O(n)。
再次浏览输入。我们知道b=sum-a
,因此对于输入中的每个元素a
,请查找其b
,这可以在O(1)
中完成,因为它是位图索引。这也总共需要O(n)。
时间复杂度:O(n)+ O(n)= O(n)。空间复杂度:位图空间= O(n)。
答案 2 :(得分:12)
您甚至不需要将所有元素存储在hashmap中,然后进行扫描。您可以在第一次迭代期间进行扫描。
void foo(int[] A, int sum) {
HashSet<Integer> set = new HashSet<Integer>();
for (int e : A) {
if (set.contains(sum-e)) {
System.out.println(e + "," + (sum-e));
// deal with the duplicated case
set.remove(sum-e);
} else {
set.add(e);
}
}
}
答案 3 :(得分:6)
如何排序数组,然后从两端进入?
答案 4 :(得分:5)
假设所需的sum = R
答案 5 :(得分:2)
如果您不介意在空间中花费O(M)
,M
是您要求的总和,则可以在O(N + M)
时间内执行此操作。在sums[i] = 1
上一次过i <= M
后设置N
,然后在(sums[i] && sums[M-i])
上单次检查M/2
。{/ p>
答案 6 :(得分:1)
#include <iostream>
using namespace std;
#define MAX 15
int main()
{
int array[MAX] = {-12,-6,-4,-2,0,1,2,4,6,7,8,12,13,20,24};
const int find_sum = 0;
int max_index = MAX - 1;
int min_index = 0;
while(min_index < max_index)
{
if(array[min_index] + array[max_index-min_index] == find_sum)
{
cout << array[min_index] << " & " << array[max_index-min_index] << " Matched" << endl;
return 0;
}
if(array[min_index]+array[max_index-min_index] < find_sum)
{
min_index++;
//max_index++;
}
if(array[min_index]+array[max_index-min_index] > find_sum)
{
max_index--;
}
}
cout << "NO MATCH" << endl;
return 0;
}
//-12 & 12 matched
答案 7 :(得分:1)
import itertools
list = [1, 1, 2, 3, 4, 5,]
uniquelist = set(list)
targetsum = 5
for n in itertools.combinations(uniquelist, 2):
if n[0] + n[1] == targetsum:
print str(n[0]) + " + " + str(n[1])
1 + 4
2 + 3
答案 8 :(得分:0)
这是一个考虑重复条目的解决方案。它是用javascript编写的,并假设数组已排序。该解决方案在O(n)时间内运行,除变量外不使用任何额外的内存。
var count_pairs = function(_arr,x) {
if(!x) x = 0;
var pairs = 0;
var i = 0;
var k = _arr.length-1;
if((k+1)<2) return pairs;
var halfX = x/2;
while(i<k) {
var curK = _arr[k];
var curI = _arr[i];
var pairsThisLoop = 0;
if(curK+curI==x) {
// if midpoint and equal find combinations
if(curK==curI) {
var comb = 1;
while(--k>=i) pairs+=(comb++);
break;
}
// count pair and k duplicates
pairsThisLoop++;
while(_arr[--k]==curK) pairsThisLoop++;
// add k side pairs to running total for every i side pair found
pairs+=pairsThisLoop;
while(_arr[++i]==curI) pairs+=pairsThisLoop;
} else {
// if we are at a mid point
if(curK==curI) break;
var distK = Math.abs(halfX-curK);
var distI = Math.abs(halfX-curI);
if(distI > distK) while(_arr[++i]==curI);
else while(_arr[--k]==curK);
}
}
return pairs;
}
所以这里适合所有人。
从数组的两侧开始,慢慢向内工作,确保重复计算(如果存在)。
它只计算对,但可以重新编写
如果它是最好的答案,请尽情享受吧!
答案 9 :(得分:0)
考虑重复的解决方案,只使用一次每个数字:
void printPairs(int[] numbers, int S) {
// toMap(numbers) converts the numbers array to a map, where
// Key is a number from the original array
// Value is a count of occurrences of this number in the array
Map<Integer, Integer> numbersMap = toMap(numbers);
for (Entry<Integer, Integer> entry : numbersMap.entrySet()) {
if (entry.getValue().equals(0)) {
continue;
}
int number = entry.getKey();
int complement = S - number;
if (numbersMap.containsKey(complement) && numbersMap.get(complement) > 0) {
for (int j = 0; j < min(numbersMap.get(number),
numbersMap.get(complement)); j++) {
if (number.equals(complement) && numbersMap.get(number) < 2) {
break;
}
System.out.println(number, complement);
numbersMap.put(number, numbersMap.get(number) - 1);
numbersMap.put(complement, numbersMap.get(complement) - 1);
}
}
}
}
答案 10 :(得分:0)
Hashtable解决方案,在Ruby中(非常简单易懂):
</li>
答案 11 :(得分:0)
我们可以用C ++ STL map解决这个问题
void subsetSum(int arr[], int n, int sum)
{
map<int, int>Map;
for(int i=0; i<n; i++)
{
Map[arr[i]]++;
if(Map.count(sum-arr[i]))
{
cout<<arr[i]<<" "<<sum-arr[i]<<"\n";
}
}
}
答案 12 :(得分:0)
@Test
public void hasPairWithSum() {
assertFalse(hasPairWithSum_Ordered_Logarithmic(new int[] { 1, 2, 3, 9 }, 8));
assertTrue(hasPairWithSum_Ordered_Logarithmic(new int[] { 1, 2, 4, 4 }, 8));
assertFalse(hasPairWithSum_Ordered_Linear(new int[] { 1, 2, 3, 9 }, 8));
assertTrue(hasPairWithSum_Ordered_Linear(new int[] { 1, 2, 4, 4 }, 8));
assertFalse(hasPairWithSum_Unsorted_Linear(new int[] { 9, 1, 3, 2 }, 8));
assertTrue(hasPairWithSum_Unsorted_Linear(new int[] { 4, 2, 1, 4 }, 8));
assertFalse(hasPairWithSum_Unsorted_Quadratic(new int[] { 9, 1, 3, 2 }, 8));
assertTrue(hasPairWithSum_Unsorted_Quadratic(new int[] { 4, 2, 1, 4 }, 8));
}
private boolean hasPairWithSum_Ordered_Logarithmic(int[] data, int sum) {
for (int i = 0; i < data.length; i++) {
int current = data[i];
int complement = sum - current;
int foundIndex = Arrays.binarySearch(data, complement);
if (foundIndex >= 0 && foundIndex != i) {
return true;
}
}
return false;
}
private boolean hasPairWithSum_Ordered_Linear(int[] data, int sum) {
int low = 0;
int high = data.length - 1;
while (low < high) {
int total = data[low] + data[high];
if (total == sum) {
return true;
} else if (total < sum) {
low++;
} else {
high--;
}
}
return false;
}
private boolean hasPairWithSum_Unsorted_Linear(int[] data, int sum) {
Set<Integer> complements = Sets.newHashSet();
for (int current : data) {
if (complements.contains(current)) {
return true;
}
complements.add(sum - current);
}
return false;
}
private boolean hasPairWithSum_Unsorted_Quadratic(int[] data, int sum) {
for (int i = 0; i < data.length; i++) {
int current = data[i];
int complement = sum - current;
for (int j = 0; j < data.length; j++) {
if (data[j] == complement && i != j) {
return true;
}
}
}
return false;
}
答案 13 :(得分:0)
创建哈希表,然后在其中查找值。
function sum_exist(num : number, arr : any[]) {
var number_seen = {};
for(let item of arr){
if(num - item in number_seen){
return true
}
number_seen[item] = 0;
}
return false;
}
测试用例(使用Jest)
test('Given a list of numbers, return whether any two sums equal to the set number.', () => {
expect(sum_exist(17 , [10, 15, 3, 7])).toEqual(true);
});
test('Given a list of numbers, return whether any two sums equal to the set number.', () => {
expect(sum_exist(16 , [10, 15, 3, 7])).toEqual(false);
});
答案 14 :(得分:0)
#python 3.x
def sum_pairs(list_data, number):
list_data.sort()
left = 0
right = len(list_data)-1
pairs = []
while left < right:
if list_data[left]+list_data[right] == number:
find_pairs = [list_data[left], list_data[right]]
pairs.append(find_pairs)
right = right-1
elif list_data[left]+list_data[right] < number:
left = left+1
else:
right = right-1
return pairs