假设我有一个项目清单:
[a,b,b,a,c,d,a,d,b,c]
并且我需要知道,对于每个项目,我必须遍历多少项目,直到我获得n个唯一项目,(并返回例如-1,或以其他方式指示是否不可能)
所以在这里,如果n = 4,我会返回
[6,5,4,6,5,5,4,-1,-1,-1]
自
a,b,b,a,c,d包含4个独特元素
b,b,a,c,d包含4个独特元素
b,a,c,d包含4个唯一元素
a,c,d,a,d,b包含4个独特元素
等
答案 0 :(得分:0)
我用过
List.Select((x,i) => {
var range = List.Skip(i).GroupBy(y => y).Take(n);
if (range.Count() == n)
return range.SelectMany(y => y).Count();
return -1;
});
虽然我非常确定这是非常不具备性能的。
答案 1 :(得分:0)
为了尽量减少开销,我创建了一个ListSpan
扩展类来管理List
的子部分 - 类似于ArraySegment
的{{1}},但是(松散地)建模List
:
Span
然后我创建了一个扩展方法来返回从public class ListSpan<T> : IEnumerable<T>, IEnumerable {
List<T> baseList;
int start;
int len;
public ListSpan(List<T> src, int start = 0, int? len = null) {
baseList = src;
this.start = start;
this.len = len ?? (baseList.Count - start);
if (this.start + this.len > baseList.Count)
throw new ArgumentException("start+len > Count for ListSpan");
}
public T this[int n]
{
get
{
return baseList[start + n];
}
set
{
baseList[start + n] = value;
}
}
public class ListSpanEnumerator<Te> : IEnumerator<Te>, IEnumerator {
int pos;
List<Te> baseList;
int end;
Te cur = default(Te);
public ListSpanEnumerator(ListSpan<Te> src) {
pos = src.start - 1;
baseList = src.baseList;
end = src.start + src.len;
}
public Te Current => cur;
object IEnumerator.Current => Current;
public bool MoveNext() {
if (++pos < end) {
cur = baseList[pos];
return true;
}
else {
cur = default(Te);
return false;
}
}
public void Reset() => pos = 0;
public void Dispose() { }
}
public IEnumerator<T> GetEnumerator() => new ListSpanEnumerator<T>(this);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public static class ListExt {
public static ListSpan<T> Slice<T>(this List<T> src, int start = 0, int? len = null) => new ListSpan<T>(src, start, len);
}
获取n个唯一项所需的距离(Take
个术语):
IEnumerable
现在答案相对简单:
public static class IEnumerableExt {
public static int DistanceToUnique<T>(this IEnumerable<T> src, int n, IEqualityComparer<T> cmp = null) {
var hs = new HashSet<T>(cmp ?? EqualityComparer<T>.Default);
var pos = 0;
using (var e = src.GetEnumerator()) {
while (e.MoveNext()) {
++pos;
hs.Add(e.Current);
if (hs.Count == n)
return pos;
}
}
return -1;
}
}
基本上,我会检查原始(var ans = Enumerable.Range(0, src.Count).Select(p => src.Slice(p).DistanceToUnique(n));
)src
中的每个位置,并使用List
的{{1}}来计算距该位置的n个唯一值的距离在那个位置。
这仍然不是非常有效,因为我正在为原始ListSpan
中的每个元素创建List
并将所有以下元素放入其中,并将元素遍历到k ! k元素HashSet
的时间。仍然试图想出一些非常有效的东西。