【问题标题】:How can I check if 3 out of 5 integer are the same如何检查 5 个整数中的 3 个是否相同
【发布时间】:2014-02-05 22:12:58
【问题描述】:

假设我有 5 个整数。

int a = 1;
int b = 2;
int c = 5;
int d = 1;
int f = 1;

我想检查这 5 个整数中的 3 个是否相同。

我尝试了一些东西,但是它很长(500 多行),并且认为这不是一个好方法。

【问题讨论】:

  • 您需要知道哪些是相同的,还是只想知道哪些是相同的?
  • 我只需要知道其中一些是不是。

标签: c# integer


【解决方案1】:

首先将它们全部放在一个集合中,而不是使用单独的变量:

var numbers = new[]{a,b,c,d,f};

然后将它们分组,找到每个组的计数,看看是否有任何符合您的条件。

var isLargeGroup = numbers.GroupBy(n => n, (key, group) => group.Count() )
    .Any(count => count >= 3);

【讨论】:

  • 它无法编译。 The type arguments for method ... cannot be inferred from the usage.Try specifying type argument explicitly
  • @Selman22 对。我总是假设第二个参数的委托应该只有一个IGrouping 参数。这将使世界变得如此简单。可悲的是它没有。微不足道的修复。
  • @キャタ 我在帖子本身中做到了。它读起来也很像它的作用。根据每个数字对集合中的所有项目进行分组,然后将每个组映射到它的计数中(这是 GroupBy 的第二个参数正在做的事情)。最后,如果其中任何一个计数大于或等于三,则为真,否则为假。
  • @DavidHaney 考虑到groupICollection 的事实,计算组的大小将是一个O(1) 操作,因此Count 中的优化可以让它快速抓取计数将生效,但即使 不是 的情况,两种解决方案 仍然 为 O(n)。毕竟,O(2*n) 等于 O(n/2)。至于垃圾收集,这实际上是微不足道的。分配一个即使单次 GC 也无法幸存的对象几乎没有任何成本。它通过一个有成本的集合来保持对象的活力。并不是说这里创建了 那么多 对象。
  • @DavidHaney 从技术上讲,你不能保证它,不,但是虽然创建了相当数量的对象,但同时没有很多对象都活着。少数对象可能会通过 GC,但大量对象不会(由于 LINQ 的流式传输性质),因此在运行时发生 GC 的性能影响(这本身不太可能)不会非常棒。
【解决方案2】:

对于大型集合(例如 10000 个数字),其他两种解决方案都可能很昂贵,需要完整的枚举并创建许多将被垃圾收集的对象。试试这个,它可能会在完整枚举之前很久就停止执行:

private bool AreNumbersTheSame(int[] numbers, int duplicateCount)
{
    var numberCounts = new Dictionary<int, int>();
    for (int i = 0; i < numbers.Length; i++)
    {
        var current = numbers[i];
        if (!numberCounts.ContainsKey(current))
        {
            numberCounts[current] = 1;
            continue;
        }

        if (numberCounts[current] == duplicateCount - 1)
        {
            return true;
        }

        numberCounts[current]++;
    }
    return false;
}

这样称呼:

var result = AreNumbersTheSame(new[] { a, b, c, d, f }, 3);

【讨论】:

  • 对于大小为 5 的集合,我认为在不短路的情况下完全迭代它是可行的。
  • 收集大小为 5000,不是那么多。
  • 但是问题具体说它的大小是5。
  • 过早的优化是万恶之源。重要的是要意识到什么值得优化,什么不值得优化。您需要花时间认识到哪些优化正在产生足够的差异以值得开发人员的时间,以及增加的代码复杂性。在这里,考虑到小数据集,性能差异几乎为零。代码的清晰性和明显的正确性远比这些解决方案之间的几微秒差异更有价值。
  • 我以某种方式忽略了您的方法。和我的非常相似。所以我要 +1。
【解决方案3】:

我会做以下事情:-

  1. 将所有号码添加到列表中。

  2. 创建一个字典,其中数字为 KEY,其出现为 VALUE。

  3. 在迭代列表时,需要检查一个数字是否不在字典中,然后使用数字作为 KEY 和 1 作为其值来添加它。

  4. 如果数字再次出现,只需将字典 VALUE 增加 1。

  5. 一旦等于3,就跳出循环。

            int a = 1;
            int b = 2;
            int c = 5;
            int d = 1;
            int f = 1;
            var listOfNumbers = new List<int> {a, b, c, d, f};
    
            var dict = new Dictionary<int, int>();
            foreach (var number in listOfNumbers)
            {
                if (dict.ContainsKey(number))
                {
                    dict[number] = dict[number] + 1; //if a key repeats => increment the value by 1
                    if (dict[number] == 3)
                        break; //found the number
                }
                else
                    dict.Add(number, 1); //for first occurence of the key => initialize the value with 1 
            }
    

【讨论】:

    【解决方案4】:

    对于它的价值,这里有另一个选项,它不如GroupBy 优雅,但如果序列很大,则效率更高。在我看来,隐藏在扩展方法中的可读性并不那么重要。

    public static bool HasDuplicateCount<T>(this IEnumerable<T> seq, int maxCount)
    {
        Dictionary<T, int> counts = new Dictionary<T, int>();
        foreach (T t in seq)
        {
            int count;
            if (counts.TryGetValue(t, out count))
                ++count;
            else
                count = 1;
            if (count == maxCount)
                return true;
            counts[t] = count;
        }
        return false;
    }
    

    你可以这样使用它:

    bool threeDups = new[] { a, b, c, d, f }.HasDuplicateCount(3);
    

    【讨论】:

      【解决方案5】:

      这也可以使用Majority Vote 算法来解决,只要您要查看是否有超过一半的元素相同(如 5 个元素中的 3 个):

      public static bool HasMajorityElement(int[] a)
      {
          int candidate = 0;
          int count = 0;
          foreach (int i in a)
          {
              if (count == 0)
              { 
                  candidate = i;
                  count = 1;
              }
              else 
              {
                  count += candidate == i ? 1 : -1;
              }
          }
          count = 0;
          foreach (int i in a)
          {
              if (i == candidate) ++count;
          }
          return count > a.Length / 2;
      }
      

      @ideone.com 上的Test it

      或者根据您的具体情况:

      public static bool ThreeOutOfFive(int a, int b, int c, int d, int e)
      {
          return ((a==b?1:0)+(a==c?1:0)+(a==d?1:0)+(a==e?1:0) > 1)
              || ((b==c?1:0)+(b==d?1:0)+(b==e?1:0) > 1)
              || ((c==d?1:0)+(c==e?1:0) > 1);
      }
      

      【讨论】:

      • 有趣。但是解决了一个不同的问题。 OP 只想知道数组中是否存在重复至少 3 次的重复项。因此,如果数组包含 6 个数字而不是三个重复项,那么您的方法将返回错误的结果(假而不是真)。
      • 是的,但是 OP 特别要求 5 个中的 3 个。我已经添加说明,您必须寻找一半以上的元素是相同的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多