查找具有给定和的元素对是否存在于大整数数组中

时间:2014-09-18 23:37:49

标签: c#

我有一个包含1000万个元素的整数数组,如何在C#中编写一个函数,如果数组有一个总和最多为75的对,则返回True。

我的代码是:

        int sum = 75, max = 10000000;
        int[] array = new int[max];
        bool checkFlag = false;
        Random rnd = new Random();
        Stopwatch sw = Stopwatch.StartNew();

        for (int i = 0; i < max; i++)
        {
            array[i] = rnd.Next(0, max * 20);
        }
        Array.Sort(array);
        if (array[0] + array[1] <= sum)
        {
            Console.WriteLine("{0} + {1} = {2}", array[0], array[1], array[0] + array[1]);
            checkFlag = true; 
        }
        Console.WriteLine("Sum upto 75 is: " + checkFlag);

5 个答案:

答案 0 :(得分:8)

这是一个问题。你想要0s的桶与75s配对,1s与74s配对,等等。 Bucketing是一个字典作业。 Dictionary<int, List<int>>给出O(n)摊销的结果。如果您只关心bool结果,那么HashSet<int>就足够了。你不能比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;
    }

如果数组可能包含该对,那么您可以考虑在Add()调用之后进行测试,仍然是O(n)。

答案 1 :(得分:1)

如果数组已排序,这将有效。

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;
}

你使用两个指针走向数组的中间。指针i从数组的开头开始,而j从结尾开始。如果您找到两个总和为75的数字,则返回true。如果总和小于75,则将指针i向中间移动一步并再次检查。如果总和超过75,则将指针j向中间移动一步并再次检查。

如果两个指针相遇,则返回false,因为找不到对。

这是O(n),不包括对数组进行排序。

答案 2 :(得分:0)

如果您认为数字是正数,则可以这样做:

  1. 创建一个包含75个元素的布尔数组。
  2. 查看10,000,000个项目列表。当你看到75或更低的时候:
    • 检查以查看布尔arry在元素75处有一个条目 - 该数字。如果是的话,你找到了匹配。
    • 否则,设置布尔数组的第n个条目。
  3. 示例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;
                }
            }
    

    但是如果数组中的数字可以是任何有效整数,包括负数,你可以这样做:

            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);
                }
            }
    

答案 3 :(得分:0)

你可以进行蛮力搜索。

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;
}

或者,您可以创建一个枚举器并使用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];
   }
}

现在您可以执行以下操作。

a.toSums().Any(pair=>pair == 75);

两者都应具有相同的性能。如果你问为什么?这是因为C#只会在Any条件为真之前执行枚举器。 toSums函数使用yield关键字创建仅在评估时执行的枚举器。

修改

要在数组中找到总和为75且不仅仅是相邻的任何值对。除了LINQ之外,我只会使用它来更容易阅读。

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();
}

答案 4 :(得分:0)

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();
        }
    }
}