【发布时间】:2010-04-19 10:38:02
【问题描述】:
如何编写算法来检查数组/列表中任意两个数字的总和是否与给定数字匹配
复杂度为nlogn?
【问题讨论】:
-
你期望输出什么?号码?他们的指数?如果可能有多个结果怎么办?
-
你想要一个真/假答案“是的,有一对”还是你想要所有对?或者所有可能的组合都可以提供所需的总和?
标签: algorithm language-agnostic
如何编写算法来检查数组/列表中任意两个数字的总和是否与给定数字匹配
复杂度为nlogn?
【问题讨论】:
标签: algorithm language-agnostic
我确信有更好的方法,但这里有一个想法:
这两个操作都是O(n log n)。
【讨论】:
sum/2 处搜索(不会影响大 O,但仍然:p)
这可以在O(n) 中使用哈希表来完成。用数组中的所有数字初始化表,以数字为键,频率为值。遍历数组中的每个数字,查看表中是否存在(sum - number)。如果是这样,你就有了比赛。遍历数组中的所有数字后,您应该有一个总和为所需数字的所有对的列表。
array = initial array
table = hash(array)
S = sum
for each n in array
if table[S-n] exists
print "found numbers" n, S-n
n 和 table[S-n] 两次引用同一个数的情况可以额外检查处理,但复杂度依然O(n)。
【讨论】:
使用hash table。将每个数字及其索引插入哈希表。然后,让S 成为您想要的总和。对于初始数组中的每个数字array[i],查看您的哈希表中是否存在S - array[i],其索引不同于i。
平均情况是O(n),最坏情况是O(n^2),所以如果您害怕最坏情况,请使用二分搜索解决方案。
【讨论】:
O(1) 进行插入和查找(小心),或者您是否考虑了潜在的哈希冲突?无论如何,这似乎比使用二分搜索更好。
n 的数组 {1, 1, 1, ..., 1, 1, 1, ...}。我们希望总和为 20。您将在哈希表中的相同位置添加所有的。然后,对于每个 1,您将检查 19 是否在数组中。假设值 19 映射到哈希表中与值 1 相同的位置。这意味着对于每个n,您将在哈希表中进行n 检查,从而为您提供二次时间复杂度。对于有解决方案的情况(使用 3 个值 - 一个占优),可以找到类似的示例
1 => 8。例如,当需要 2 的总和时,您可以进行额外检查 - 如果当前数字等于目标数字 (S - array[i]),那么它的频率必须至少为 2。
假设我们想在数组 A 中找到两个数字相加等于 N。
排序可以在 O(n log n) 内完成。搜索是在线性时间内完成的。
【讨论】:
这是在 Java 中:这甚至可以删除可能的重复项。运行时 - O(n^2)
private static int[] intArray = {15,5,10,20,25,30};
private static int sum = 35;
private static void algorithm()
{
Map<Integer, Integer> intMap = new Hashtable<Integer, Integer>();
for (int i=0; i<intArray.length; i++)
{
intMap.put(i, intArray[i]);
if(intMap.containsValue(sum - intArray[i]))
System.out.println("Found numbers : "+intArray[i] +" and "+(sum - intArray[i]));
}
System.out.println(intMap);
}
【讨论】:
containsValue在线性时间内运行,因此总运行时间是O(n^2)。
def sum_in(numbers, sum_):
"""whether any two numbers from `numbers` form `sum_`."""
a = set(numbers) # O(n)
return any((sum_ - n) in a for n in a) # O(n)
例子:
>>> sum_in([200, -10, -100], 100)
True
【讨论】:
[1] 和 [1, 1] 情况。
这是 C 中的一个尝试。这不是标记作业。
// Assumes a sorted integer array with no duplicates
void printMatching(int array[], int size, int sum)
{
int i = 0, k = size - 1;
int curSum;
while(i < k)
{
curSum = array[i] + array[k];
if(curSum == sum)
{
printf("Found match at indices %d, %d\n", i, k);
i++;k--;
}
else if(curSum < sum)
{
i++;
}
else
{
k--;
}
}
}
这是使用int a[] = { 3, 5, 6, 7, 8, 9, 13, 15, 17 };的一些测试输出
Searching for 12..
Found match at indices 0, 5
Found match at indices 1, 3
Searching for 22...
Found match at indices 1, 8
Found match at indices 3, 7
Found match at indices 5, 6
Searching for 4..
Searching for 50..
搜索是线性的,所以 O(n)。如果您使用其中一种好的排序,那么在幕后发生的排序将是 O(n*logn)。
由于 Big-O 背后的数学原理,加法项中的较小项将有效地退出您的计算,最终得到 O(n logn)。
【讨论】:
这个是O(n)
public static bool doesTargetExistsInList(int Target, int[] inputArray)
{
if (inputArray != null && inputArray.Length > 0 )
{
Hashtable inputHashTable = new Hashtable();
// This hash table will have all the items in the input array and how many times they appeard
Hashtable duplicateItems = new Hashtable();
foreach (int i in inputArray)
{
if (!inputHashTable.ContainsKey(i))
{
inputHashTable.Add(i, Target - i);
duplicateItems.Add(i, 1);
}
else
{
duplicateItems[i] = (int)duplicateItems[i] + 1;
}
}
foreach (DictionaryEntry de in inputHashTable)
{
if ((int)de.Key == (int)de.Value)
{
if ((int)duplicateItems[de.Key] > 1)
return true;
}
else if (inputHashTable.ContainsKey(de.Value))
{
return true;
}
}
}
return false;
}
【讨论】:
这是一个算法,如果数组已经排序,则在 O(n) 中运行,如果尚未排序,则在 O(n log n) 中运行。从这里的许多其他答案中获取线索。代码是用 Java 编写的,但这里是一个伪代码,也是从许多现有答案中派生出来的,但通常针对重复项进行了优化
使用这些变量来计算数组中目标的存在; 将 currentValue 设置为 array[ith]; 将 newTarget 设置为目标 - currentValue; 如果 currentValue 等于 newTarget 则将 expectedCount 设置为 2,否则设置为 1
AND 仅当 一种。我们之前从未见过这个整数 AND 湾。我们创建的地图中的 newTarget 有一些价值 C。并且 newTarget 的计数等于或大于 expectedCount
否则 重复第 4 步,直到我们到达数组末尾并返回 false OTHERWISE;
就像我提到的,访问商店的最佳用途是当我们有重复时,如果没有任何元素是重复的,那将永远不会有帮助。
【讨论】:
取决于您是否只想要一个总和 O(N) 或 O(N log N) 或所有总和 O(N^2) 或 O(N^2 log N)。在后一种情况下,最好使用 FFT>
【讨论】:
第 1 步:在 O(n logn) 中对数组进行排序
第 2 步:找到两个索引
0
int i=0,j=n;
while(i<j) {
int sum = a[i]+a[j];
if(sum == k)
print(i,j)
else if (sum < k)
i++;
else if (sum > k)
j--;
}
【讨论】:
public void sumOfTwoQualToTargetSum()
{
List<int> list= new List<int>();
list.Add(1);
list.Add(3);
list.Add(5);
list.Add(7);
list.Add(9);
int targetsum = 12;
int[] arr = list.ToArray();
for (int i = 0; i < arr.Length; i++)
{
for (int j = 0; j < arr.Length; j++)
{
if ((i != j) && ((arr[i] + arr[j]) == targetsum))
{
Console.Write("i =" + i);
Console.WriteLine("j =" + j);
}
}
}
}
【讨论】:
A) 时间复杂度 => 0(n Log n) 空间复杂度 => 0(n)。
B) 时间复杂度 => 0(n^2) 空间复杂度 => 0(1)。
C) 时间复杂度 => 0(n) 空间复杂度 => 0(n)
根据权衡选择解决方案 A、B 或 C。
//***********************Solution A*********************//
//This solution returns TRUE if any such two pairs exist in the array
func binarySearch(list: [Int], key: Int, start: Int, end: Int) -> Int? { //Helper Function
if end < start {
return -1
} else {
let midIndex = (start + end) / 2
if list[midIndex] > key {
return binarySearch(list: list, key: key, start: start, end: midIndex - 1)
} else if list[midIndex] < key {
return binarySearch(list: list, key: key, start: midIndex + 1, end: end)
} else {
return midIndex
}
}
}
func twoPairSum(sum : Int, inputArray: [Int]) -> Bool {
//Do this only if array isn't Sorted!
let sortedArray = inputArray.sorted()
for (currentIndex, value) in sortedArray.enumerated() {
if let indexReturned = binarySearch(list: sortedArray, key: sum - value, start: 0, end: sortedArray.count-1) {
if indexReturned != -1 && (indexReturned != currentIndex) {
return true
}
}
}
return false
}
//***********************Solution B*********************//
//This solution returns the indexes of the two pair elements if any such two pairs exists in the array
func twoPairSum(_ nums: [Int], _ target: Int) -> [Int] {
for currentIndex in 0..<nums.count {
for nextIndex in currentIndex+1..<nums.count {
if calculateSum(firstElement: nums[currentIndex], secondElement: nums[nextIndex], target: target) {
return [currentIndex, nextIndex]
}
}
}
return []
}
func calculateSum (firstElement: Int, secondElement: Int, target: Int) -> Bool {//Helper Function
return (firstElement + secondElement) == target
}
//*******************Solution C*********************//
//This solution returns the indexes of the two pair elements if any such two pairs exists in the array
func twoPairSum(_ nums: [Int], _ target: Int) -> [Int] {
var dict = [Int: Int]()
for (index, value) in nums.enumerated() {
dict[value] = index
}
for (index, value) in nums.enumerated() {
let otherIndex = dict[(target - value)]
if otherIndex != nil && otherIndex != index {
return [index, otherIndex!]
}
}
return []
}
【讨论】:
这个问题缺少更多细节。就像返回值是什么,对输入的限制。
我已经看到了一些与此相关的问题,可能是这个有额外要求的问题,to return the actual elements that result in the input
这是我的解决方案版本,应该是O(n)。
import java.util.*;
public class IntegerSum {
private static final int[] NUMBERS = {1,2,3,4,5,6,7,8,9,10};
public static void main(String[] args) {
int[] result = IntegerSum.isSumExist(7);
System.out.println(Arrays.toString(result));
}
/**
* n = x + y
* 7 = 1 + 6
* 7 - 1 = 6
* 7 - 6 = 1
* The subtraction of one element in the array should result into the value of the other element if it exist;
*/
public static int[] isSumExist(int n) {
// validate the input, based on the question
// This to return the values that actually result in the sum. which is even more tricky
int[] output = new int[2];
Map resultsMap = new HashMap<Integer, Integer>();
// O(n)
for (int number : NUMBERS) {
if ( number > n )
throw new IllegalStateException("The number is not in the array.");
if ( resultsMap.containsKey(number) ) {
output[0] = number;
output[1] = (Integer) resultsMap.get(number);
return output;
}
resultsMap.put(n - number, number);
}
throw new IllegalStateException("The number is not in the array.");
}
}
【讨论】: