如何才能找到最大子集的最大差异为5的大小?

问题描述:

我有一个数组数组,我试图找到最大子集的大小,使得子集中的所有数字相距小于5。如有必要,他们可以假设进行了排序。如何才能找到最大子集的最大差异为5的大小?

例如:

[1, 2, 5, 6, 8, 9, 15] 

4是最大的子集。 (5,6,8,9)

我希望有一个简单的LINQ答案,但我没有想到它。我可以对它进行排序,然后用每个起始数字遍历它,跟踪该数字中的最多数量,但这看起来非常难看,效率低下。有任何想法吗?


澄清什么,我想避免:

(1,2,5) - 3 
(2,5,6) - 3 
(5,6,8,9) - 4 
(6,8,9) - 3 
(8,9) - 2 
(9) - 1 
(15) - 1 
+2

你怎么downvote这么快???我在不到10秒钟之前就发布了这个问题。我想你想看看我正在避免的示例代码? – Evorlor

+0

我将在本周晚些时候(和犹太年)工作。 同时看看:https://*.com/questions/1624341/getting-pair-set-using-linq 与ConvertAll或Select功能一起使用。这将是丑陋的... – pashute

这个问题可以通过维护两个指针leftright来解决。

假设您有一个排序数组arrayn数字。

left = 0 
right = 0 
ans = INT_MIN 
while right == n : 
    if array[right] - array[left] < 5: 
     right++ 
    else: 
     left++ 
    ans = max(right - left + 1, ans) 
+0

这是找到连续的序列,而不是一个子集的答案。而且它甚至不是C#。 –

+0

@AntonínLejsek正如我的问题所述,它可以假定为排序。没有它不是C#,但它仍然是一个有用的答案。 – Evorlor

+0

这个贪婪的策略会奏效。可以证明排序后的数组中最长的连续序列是所需的子集。 – Prince

首先在排序列表的开始处设置最大可能集。然后继续从前面删除值,直到下一个值适合,并在下一个值之后添加尽可能多的值。这使得一套新的。在任何特定时刻保持最大的跟踪。

像这样的东西在C#中:作为

static IEnumerable<T[]> CloseSublists<T>(this IEnumerable<T> values, Func<T, T, bool> isClose) where T : IComparable<T> { 
    var window = new Queue<T>(); 
    var enumerator = values.GetEnumerator(); 

    if (!enumerator.MoveNext()) { 
     return; 
    } 

    bool more; 

    do { 
     window.Enqueue(enumerator.Current); 
    } while ((more = enumerator.MoveNext()) && isClose(window.Peek(), enumerator.Current)); 

    yield return window.ToArray(); 

    while (more) { 
     do { 
      window.Dequeue(); 
     } while (window.Count != 0 && !isClose(window.Peek(), enumerator.Current)); 

     do { 
      window.Enqueue(enumerator.Current); 
     } while ((more = enumerator.MoveNext()) && isClose(window.Peek(), enumerator.Current)); 

     yield return window.ToArray(); 
    } 
} 

public static T MaxBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> key) where TKey : IComparable<TKey> { 
    var enumerator = items.GetEnumerator(); 
    enumerator.MoveNext(); 

    var max = enumerator.Current; 
    TKey maxKey = key(max); 

    while (enumerator.MoveNext()) { 
     T current = enumerator.Current; 
     TKey currentKey = key(current); 
     int relation = currentKey.CompareTo(maxKey); 

     if (relation > 0) { 
      max = current; 
      maxKey = currentKey; 
     } 
    } 

    return max; 
} 

int[] x = {1, 2, 5, 6, 8, 9, 15}; 
x.CloseSublists((a, b) => b < a + 5).MaxBy(l => l.Length) 
+0

这有一些不必要的复制'window.ToArray()';你可以通过将'MaxBy'和'CloseSublists'结合来避免它。这样做也是有道理的;我原本以为'MaxBy'是内置于.NET中的。 – Ryan

+0

真棒和通用,谢谢! – Evorlor

基于王子的回答,我把它改写成C#和改进一点:

protected int MaxSubLen(int[] arr, int diffLessThan) 
{ 
    int l = 0, r = 0; 
    while (r < arr.Length) 
    { 
     if (arr[r] - arr[l] >= diffLessThan) 
     { 
      ++l; 
     } 
     ++r; 
    } 
    return r - l; 
} 

和,只是为了好玩,返回通用版本序列:

protected IEnumerable<T> MaxSubarray<T>(IList<T> arr, Func<T, T, bool> isClose_L_R) 
{ 
    int l = 0, r = 0, start = 0; 
    while (r < arr.Count) 
    { 
     if (isClose_L_R(arr[l], arr[r])) 
     { 
      start = l; 
     } 
     else 
     { 
      ++l; 
     } 
     ++r; 
    } 
    for (int i = start; i < start + r - l; ++i) 
    { 
     yield return arr[i]; 
    }; 
} 
+0

这看起来像是最后一个子数组,而不是最大的子数组? – Ryan

+1

以某种方式。它返回找到的最后一个子数组,但是当它找到例如长度为3的子数组时,它从不会查找短于4的子数组。因此最后找到的是最长的可用子数组。 –

+0

哦,'r'在那最后一个位置就是一个简短的'arr.Count'。尼斯。 – Ryan