I\'m having a integer array of 10 Million elements, how to write a function in C# which returns True if the array has a pair which sums up to 75.
My code is:
using System;
using System.Diagnostics;
using System.Linq;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
const int max = 10000000;
const int sum = 75;
var data = new int[max];
var rnd = new Random();
bool found = false;
int c = 1;
Stopwatch sw;
while (!found)
{
sw = Stopwatch.StartNew();
for (int i = 0; i < max; ++i)
{
data[i] = rnd.Next(0, max*25);
}
sw.Stop();
Console.WriteLine("Took {0}ms to create the array", sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
var check75 = new HashSet<int>(data.Where(x => x <= 75));
sw.Stop();
Console.WriteLine("Took {0}ms to create the hashset", sw.ElapsedMilliseconds);
sw = Stopwatch.StartNew();
for (int i = 0; i < max; ++i)
{
if (check75.Contains(sum - data[i]))
{
Console.WriteLine("{0}, {1} ", i, data[i]);
found = true;
}
}
sw.Stop();
Console.WriteLine("Took {0}ms to check75", sw.ElapsedMilliseconds);
Console.WriteLine("Loop #" + c++);
}
Console.WriteLine("Finish");
Console.ReadKey();
}
}
}
You can do a brute force search.
public bool hasPairOf(int[] a, int sum)
{
for(int i=0; i < a.length-1; i++)
{
if(a[i]+a[i+1] == sum)
return true;
}
return false;
}
Alternatively, you could create an enumerator and use LINQ.
public static IEnumerate<int> toSums(this int[] a)
{
for(int i=0; i < a.length-1; i++)
{
yield return a[i]+a[i+1];
}
}
Now you can do the following.
a.toSums().Any(pair=>pair == 75);
Both should have the same performance. If you ask why? that's because C# will only execute the enumerator until the Any
condition is true. The toSums
function uses the yield
keyword to create an enumerator that is only executed when it is evaluated.
EDIT:
To find any pair of values in an array that sum to 75 and not just adjacent. I would do it using nothing but LINQ for easier reading.
function bool hasPairOf(int[] a, int sum)
{
var nums = a.Where(val=>val <= sum)
.Select((v,i)=>new{value=v,index=i})
.ToArray();
return (from a1 in nums
from a2 in nums
where a1.index != a2.index
&& a1.value+a2.value == sum
select true).FirstOrDefault();
}
This is a bucketing problem. You want buckets of 0s to pair with 75s, 1s to pair with 74s, etcetera. Bucketing is a Dictionary jobby. A Dictionary<int, List<int>>
gives you a result in O(n) amortized. If you only care about a bool result then a HashSet<int>
is good enough. You can't get better than O(n).
static bool PairExists(int[] arr, int sum) {
var set = new HashSet<int>();
foreach (int elem in arr) set.Add(elem);
foreach (int elem in set)
if (set.Contains(sum - elem)) return true;
return false;
}
If the array is likely to contain the pair then you could consider testing after the Add() call, still O(n).
This will work if the array is sorted.
public bool ContainsPair(int[] array)
{
int i = 0;
int j = array.Length - 1;
while(i < j)
{
if (array[i] + array[j] == 75)
return true;
else if (array[i] + array[j] < 75)
i++;
else if (array[i] + array[j] > 75)
j--;
}
return false;
}
You use two pointers and walk towards the middle of the array. Pointer i
starts at the beginning of the array, while j
starts at the end. If you find two numbers that sum up to 75, you return true. If the sum is less than 75, then you move pointer i
one step towards the middle and check again. If the sum is more than 75, you move pointer j
one step towards the middle and check again.
If the two pointers meet, then you return false, because no pair was found.
This is O(n), not including sorting the array.
If you can assume the numbers are positive, you can do this:
Example C#:
var bits = new bool[75];
foreach (var n in intArray)
{
if (n <= 75)
{
var diff = 75 - n;
if (bits[diff - 1])
{
MessageBox.Show(string.Format("Found pair: {0} and {1}", n, diff));
break;
}
bits[n - 1] = true;
}
}
But if the numbers in the array can be any valid integer, including negative numbers, you can do something like this:
var set = new HashSet<int>();
foreach (var n in intArray)
{
if (n <= 75)
{
var diff = 75 - n;
if (set.Contains(diff))
{
MessageBox.Show(string.Format("Found pair: {0} and {1}", n, diff));
break;
}
set.Add(n);
}
}