将 ICollection 成员与其自身进行比较

发布于 2024-12-27 08:41:53 字数 695 浏览 0 评论 0原文

有没有最便宜的方法来将 ICollection 与其自身进行比较。

这是我的代码:

        public IEnumerable<Pet> speciesChecker()
        {
            foreach (Pet pet in _pets)
            {
                bool wantedSpecies = true;
                foreach (Pet pet2 in _pets)
                {
                    if (pet2 != pet && pet.Species == pet2.Species)
                    {
                        wantedSpecies = false;
                        break;
                    }
                }
                if (wantedSpecies) yield return pet;
            }
        }

我的代码的时间复杂度是多少,我所知道的是它小于 O(N^2) 并且如果我从内部 foreach 循环中删除“break”,时间复杂度将为 O (N^2)。如果我错了,请纠正我。

Is there any cheapest way to compare an ICollection with itself.

Here is my code:

        public IEnumerable<Pet> speciesChecker()
        {
            foreach (Pet pet in _pets)
            {
                bool wantedSpecies = true;
                foreach (Pet pet2 in _pets)
                {
                    if (pet2 != pet && pet.Species == pet2.Species)
                    {
                        wantedSpecies = false;
                        break;
                    }
                }
                if (wantedSpecies) yield return pet;
            }
        }

What is the time complexity of my code, all I know is this that it is less than O(N^2) and if I'll remove 'break' from inner foreach loop, the time complexity will be O(N^2). Please correct me if I am wrong.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

可是我不能没有你 2025-01-03 08:41:53

这是我的看法:

var q = list.GroupBy (l => l.Species)
          .Where (l => l.ElementAtOrDefault(1) == null)
          .Select (l => l.Key)

GroupBy 将在内部使用 HashSet,因此 O(N)
ElementAtOrDefault(1) 只需将枚举器移动一步,因此不会为 O(n)

Here is my take on it:

var q = list.GroupBy (l => l.Species)
          .Where (l => l.ElementAtOrDefault(1) == null)
          .Select (l => l.Key)

GroupBy will use HashSet internally so O(N)
ElementAtOrDefault(1) will only need to move the enumerator one step so will not be O(n)

静水深流 2025-01-03 08:41:53

认为这段代码做了同样的事情。在这种情况下,这是一个 O(N) 算法。诀窍是将宠物存储在按物种索引的字典中。

    public IEnumerable<Pet> speciesChecker()
    {
        var species = new Dictionary<Species, List<Pet>>();
        foreach (Pet pet in _pets)
        {
            // create the list if it doesn't exist
            if (!species.ContainsKey(pet.Species))
                species[pet.Species] = new List<Pet>();
            species[pet.Species].Add(pet);
        }

        // foreach species, if there is only one pet of that species, then return it
        foreach (var speciesPets in species.Values)
        {
            if (speciesPets.Count() == 1)
                yield return speciesPets.First();
        }

        yield break;
    }

I think that this code does the same thing. In that case, this is an O(N) algorithm. The trick is to store the pets in a dictionary indexed by species.

    public IEnumerable<Pet> speciesChecker()
    {
        var species = new Dictionary<Species, List<Pet>>();
        foreach (Pet pet in _pets)
        {
            // create the list if it doesn't exist
            if (!species.ContainsKey(pet.Species))
                species[pet.Species] = new List<Pet>();
            species[pet.Species].Add(pet);
        }

        // foreach species, if there is only one pet of that species, then return it
        foreach (var speciesPets in species.Values)
        {
            if (speciesPets.Count() == 1)
                yield return speciesPets.First();
        }

        yield break;
    }
合约呢 2025-01-03 08:41:53

您还可以使用类似以下内容,也应该是 O(N):

public IEnumerable<Pet> speciesChecker ()
{
    _pets.GroupBy (p => p.Species)
         .Select (g => new List<Pet> (g))
         .Where (l => l.Count == 1)
         .SelectMany (l => l);
}

额外的 Select (g => new List(g)) may是多余的,但我相信这将有助于避免再次迭代整个分组逻辑,我相信这会导致 O(N^2) 。

编辑: Magnus 对 List 构造函数在 O(n) 中运行的良好评论违背了目的...

怎么样:

public IEnumerable<Pet> speciesChecker ()
{
    var groups = _pets.GroupBy (p => p.Species);

    foreach (var grp in _pets.GroupBy (p => p.Species))
    using (var e = grp.GetEnumerator ()) {
        if (!e.MoveNext ())
            continue;

        var first = e.Current;

        if (e.MoveNext ())
            continue;

        yield return first;
    }
}

认为这是你能得到的最优化的,并且将在 O(n) 内工作。我们也避免使用 IEnumerable.Any ()IEnumerable.Count () 扩展方法。

想法?

You can also use something like the following, which should also be O(N):

public IEnumerable<Pet> speciesChecker ()
{
    _pets.GroupBy (p => p.Species)
         .Select (g => new List<Pet> (g))
         .Where (l => l.Count == 1)
         .SelectMany (l => l);
}

The extra Select (g => new List<Pet> (g)) may be superfluous, but I believe that will help avoid iterating the whole grouping logic a second time, which I believe would result in O(N^2) .

Edit: Good comment from Magnus about the List constructor operating in O(n) defeating the purpose...

How about:

public IEnumerable<Pet> speciesChecker ()
{
    var groups = _pets.GroupBy (p => p.Species);

    foreach (var grp in _pets.GroupBy (p => p.Species))
    using (var e = grp.GetEnumerator ()) {
        if (!e.MoveNext ())
            continue;

        var first = e.Current;

        if (e.MoveNext ())
            continue;

        yield return first;
    }
}

I think this is as optimized as you can get, and will work in O(n). We avoid using the IEnumerable<T>.Any () or IEnumerable<T>.Count () extension method as well.

Thoughts?

完美的未来在梦里 2025-01-03 08:41:53

n_pets集合的长度,

需要带break的步骤数:

1+2+3+...+n = n*(n+1)/2 =n^2/2 + n/2 = O(n^2) (for each pet in _pets);

有两个简单的规则如何从wiki计算O:

  1. 如果f(x)是几项之和,其中最大的一项
    保留增长率,忽略所有其他项。

  2. 如果 f(x) 是多个因子的乘积,则任何常数(中的项)
    不依赖于 x) 的乘积被忽略。

不间断所需步骤数:

n+n+n+...+n = n^2 = O(n^2)

let n is the length of _pets collection

number of required steps with break:

1+2+3+...+n = n*(n+1)/2 =n^2/2 + n/2 = O(n^2) (for each pet in _pets);

There are two simple rules how to calculate O from wiki:

  1. If f(x) is a sum of several terms, the one with the largest
    growth rate is kept, and all others omitted.

  2. If f(x) is a product of several factors, any constants (terms in
    the product that do not depend on x) are omitted.

number of required steps without break:

n+n+n+...+n = n^2 = O(n^2)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文