Find if pair of elements with given sum exists in large integer array

前端 未结 5 2034
独厮守ぢ
独厮守ぢ 2021-01-15 07:45

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:

相关标签:
5条回答
  • 2021-01-15 08:21
    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();
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-15 08:23

    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();
    }
    
    0 讨论(0)
  • 2021-01-15 08:24

    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).

    0 讨论(0)
  • 2021-01-15 08:41

    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.

    0 讨论(0)
  • 2021-01-15 08:43

    If you can assume the numbers are positive, you can do this:

    1. Create a boolean array of 75 elements.
    2. Walk the list of 10,000,000 items. When you see one that's 75 or less:
      • check to see boolean arry has an entry at element 75 - that number. If it does, you found a match.
      • otherwise, set the nth entry of the boolean array.

    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);
                }
            }
    
    0 讨论(0)
提交回复
热议问题