【问题标题】:Find missing and overlapping numbers in sequences在序列中查找缺失和重叠的数字
【发布时间】:2011-08-11 10:06:06
【问题描述】:

假设我们有这样的数据结构:

var sequences = new List<Tuple<int, int>>
                {
                    new Tuple<int, int>(1, 10),
                    new Tuple<int, int>(8, 101),
                    new Tuple<int, int>(102, 103),
                    new Tuple<int, int>(104, 104),
                    new Tuple<int, int>(110, 200)
                };

我想从这个集合中得到两个结果:

  • 所有缺失的数字(在本例中:105、106、107、108、109)
  • 所有重叠的数字(在本例中:8、9、10)

我可以编写一个包含几个循环和辅助集合的算法。这当然可行,但我想知道这是否可以在 LINQ 和/或其他更简单、更短的算法的帮助下实现?

编辑: 我上面例子中的数据结构代表 5 个序列,第一个包含从 1 到 10 的数字,第二个包含从 8 到 101 的数字,依此类推......因为在生产中,序列可以更大(最多到数百万),它们不是用实际的集合来表示的(例如用具有所有数字的列表),而是用元组来表示,它表示每个序列的最小和最大数量。

【问题讨论】:

  • 我不明白您为什么称 8、9 和 10 为“重叠数字”。我不明白您为什么拨打 105、106、107、108、109 缺少号码。 -1
  • 系列不连续 - 缺少数字
  • @Matt Ellen:元组中的数字代表一个序列中的第一个和最后一个数字,所以序列1..10与序列8..101重叠,并且序列@987654324之间存在间隙@ 和 110..120.
  • @Matt Ellen Д:我假设每个元组的第一个和第二个数字代表一个包含数字范围的下限和上限。 8、9 和 10 是“重叠的”,因为它们同时包含在第一个范围(1 到 10)和第二个范围(8 到 101)中。 105、106、107、108 和 109 是“缺失”的,因为它们不包含在任何范围内。

标签: c# linq range sequence


【解决方案1】:

你可以通过

var missing = 
      Enumerable.Range(1, 200)
               .Where(i => sequences.All(t => t.Item1 > i || t.Item2 < i));
var overlapping = 
      Enumerable.Range(1, 200)
                .Where(i => sequences.Count(t => t.Item1 <= i && t.Item2 >= i) > 1);

【讨论】:

  • 美丽——正是我想要的:)
  • 但是你需要知道序列范围的上下界
  • 嗯...失败:var list = new List> { new Tuple(-1000, 0), new Tuple (10, 1000) };是的,我已将下限和上限设置为正确的值(-1000、1000)。缺失值列表为空。
  • 它将为每个可能的值或 (2*)N*M 迭代整个元组列表两次,其中 N 是可能值的数量,M 是元组的数量。有数百万个可能的值,我会说这是很多迭代!
  • @sven:你需要使用Enumerable.Range(-1000, 2000)。第一个是第一个数字,第二个是项目数(不是最后一个)
【解决方案2】:

我知道这个问题的算法(它是伪代码)。 (复杂度类 O(nlog(n)) 其中 n 是元组数)

所以解决方案是按函数对元组进行排序:

  int comparer( Tuple a, Tuple b) {
      if ( a.first.compareTo(b.first) == 0 ) {
          return a.second.compareTo(b.second);
      } else 
          return a.first.compareTo(b.first);
  }

所以示例元组:(1, 10), (1, 5), (2, 8) 将被排序为: (1,5), (1, 10), (2, 8)。

下一步是累积这个结果。迭代这个结果并:

 Tuple result = SortedList[0];
 foreach ( Tuple tuple in SortedList ) {

     if ( result.second < tuple.first ) {

        // here you have missing number (result.second, tuple.first)

        result.first = tuple.first; 
        result.second = tuple.second
     } else if ( result.second > tuple.first ) {

        // here you have overlapping number (tuple.first, min( result.second,tuple.second ))

        if ( result.second < tuple.second ) {
              result.second = tuple.second;
        }
     } else {
        result.second = tuple.second;
     }

 }

我们知道,如果将被迭代下一个元组第一个数字大于或等于 result.first。代码中的注释告诉你哪里有重叠和缺失的数字

【讨论】:

  • 如果 T2 是 T1 的子集并且 T3 与 T2 不重叠的 T1 的一部分重叠,则该操作将失败。其中数字代表他们遇到的顺序
  • 你是对的,所以第一作者的问题可以正常工作,但第二个不行。
【解决方案3】:

试试这个

var expandedSequences = sequences.Select(t => Enumerable.Range(t.Item1, t.Item2-t.Item1)).SelectMany(t => t).OrderBy(i => i);
var dupes = expandedSequences.GroupBy(i => i).Where(g => g.Count() > 1).Select(g => g.Key);
var missing = Enumerable.Range(expandedSequences.Min(), expandedSequences.Max()).Except(expandedSequences);

【讨论】:

    【解决方案4】:

    一次性完成:

    var sequences = new List<Tuple<int, int>>
        {
            new Tuple<int, int>(1, 10),
            new Tuple<int, int>(8, 101),
            new Tuple<int, int>(102, 103),
            new Tuple<int, int>(104, 104),
            new Tuple<int, int>(110, 200)
        };
    var missing = new List<int>();
    var overlap = new List<int>();
    
    sequences.Aggregate((prev, current) => {
        if (prev.Item2 >= current.Item1) {
            overlap.AddRange(Enumerable.Range(current.Item1, prev.Item2 - current.Item1 + 1));
        }
        if (current.Item1 > prev.Item2 + 1) {
            missing.AddRange(Enumerable.Range(prev.Item2 + 1, current.Item1 - prev.Item2 - 1));
        }
        return current;
    });
    

    【讨论】:

    • 如果 T2 是 T1 的子集并且 T3 与 T2 不重叠的 T1 的一部分重叠,它不会失败。其中数字代表他们遇到的顺序
    【解决方案5】:

    有一些边缘情况我只能假设您希望如何处理。我选择不处理其中之一(在代码中注释)。由于您没有说明您希望如何表示缺失/重叠的序列,因此我选择了您自己的格式,使用元组来识别序列的开始和结束。

    //Assumes they are sorted on item1
            Tuple<IEnumerable<Tuple<int,int>>,IEnumerable<Tuple<int,int>>> FindMissingAndOverLapping(IEnumerable<Tuple<int,int>> sequences){
                var previous = Tuple.Create(0, 0);
                var missing = new List<Tuple<int,int>>();
                var overlapping = new List<Tuple<int, int>>();
                var max = 0;
                foreach (var sequence in sequences){
                    var end = previous.Item2;
                    max = end > max ? end : max;
                    if (previous.Item2 < sequence.Item1 + 1){
                        missing.Add(Tuple.Create(previous.Item2 + 1, sequence.Item1 - 1));
                    } else if (max < sequence.Item1){
                        overlapping.Add(Tuple.Create(sequence.Item1, max));
                    }
                }
                //The sequences in ovrelapping can be ovrelapping them self
                return new Tuple<IEnumerable<Tuple<int,int>>,IEnumerable<Tuple<int,int>>>(missing, overlapping);
            }
    

    【讨论】:

      猜你喜欢
      • 2011-11-11
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 2013-08-22
      • 1970-01-01
      • 2017-11-07
      • 2012-07-08
      • 2023-04-11
      相关资源
      最近更新 更多